From: Owen Yamauchi <oyamauchi@fb.com>
Date: Fri, 3 May 2013 17:43:36 +0000 (-0700)
Subject: Break dependency on byteswap.h
X-Git-Tag: v0.22.0~983
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=29ad1ec90ccf41d985a69de6c59f0fde1a9e4502;p=folly.git

Break dependency on byteswap.h

Summary:
Unfortunately, this doesn't exist on all platforms. Fortunately, both
gcc and clang support builtins that do the same thing as the bswap_*
functions we were including byteswap.h for.

I changed the test file to hardcode expected results for the swapping
functions. Is that OK? It seemed a little silly to be testing the
Endian::whatever functions by comparing them against the functions that
they're implemented in terms of.

Test Plan:
fbconfig/fbmake runtests with gcc 4.6 and 4.7. Verified
separately that clang supports these builtins.

Reviewed By: simpkins@fb.com

FB internal diff: D799244
---

diff --git a/folly/Bits.h b/folly/Bits.h
index b206968b..d9bf1ad0 100644
--- a/folly/Bits.h
+++ b/folly/Bits.h
@@ -65,11 +65,15 @@
 #error GCC required
 #endif
 
+#include "folly/folly-config.h"
 #include "folly/detail/BitsDetail.h"
 #include "folly/detail/BitIteratorDetail.h"
 #include "folly/Likely.h"
 
-#include <byteswap.h>
+#if FOLLY_HAVE_BYTESWAP_H
+# include <byteswap.h>
+#endif
+
 #include <cassert>
 #include <cinttypes>
 #include <endian.h>
@@ -230,19 +234,37 @@ struct EndianIntBase {
   static T swap(T x);
 };
 
+/**
+ * If we have the bswap_16 macro from byteswap.h, use it; otherwise, provide our
+ * own definition.
+ */
+#ifdef bswap_16
+# define our_bswap16 bswap_16
+#else
+
+template<class Int16>
+inline constexpr typename std::enable_if<
+  sizeof(Int16) == 2,
+  Int16>::type
+our_bswap16(Int16 x) {
+  return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
+}
+#endif
+
 #define FB_GEN(t, fn) \
 template<> inline t EndianIntBase<t>::swap(t x) { return fn(x); }
 
 // fn(x) expands to (x) if the second argument is empty, which is exactly
-// what we want for [u]int8_t
+// what we want for [u]int8_t. Also, gcc 4.7 on Intel doesn't have
+// __builtin_bswap16 for some reason, so we have to provide our own.
 FB_GEN( int8_t,)
 FB_GEN(uint8_t,)
-FB_GEN( int64_t, bswap_64)
-FB_GEN(uint64_t, bswap_64)
-FB_GEN( int32_t, bswap_32)
-FB_GEN(uint32_t, bswap_32)
-FB_GEN( int16_t, bswap_16)
-FB_GEN(uint16_t, bswap_16)
+FB_GEN( int64_t, __builtin_bswap64)
+FB_GEN(uint64_t, __builtin_bswap64)
+FB_GEN( int32_t, __builtin_bswap32)
+FB_GEN(uint32_t, __builtin_bswap32)
+FB_GEN( int16_t, our_bswap16)
+FB_GEN(uint16_t, our_bswap16)
 
 #undef FB_GEN
 
diff --git a/folly/configure.ac b/folly/configure.ac
index 8ec537db..38927fb9 100644
--- a/folly/configure.ac
+++ b/folly/configure.ac
@@ -38,7 +38,7 @@ AX_BOOST_SYSTEM
 
 # Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h stdint.h stdlib.h string.h sys/time.h unistd.h mutex.h malloc.h emmintrin.h])
+AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h stdint.h stdlib.h string.h sys/time.h unistd.h mutex.h malloc.h emmintrin.h byteswap.h])
 
 AC_CHECK_HEADER(double-conversion.h, [], [AC_MSG_ERROR(
                 [Couldn't find double-conversion.h, please download from \
diff --git a/folly/test/EndianTest.cpp b/folly/test/EndianTest.cpp
index e2e5cd81..cc65d803 100644
--- a/folly/test/EndianTest.cpp
+++ b/folly/test/EndianTest.cpp
@@ -22,13 +22,13 @@ using namespace folly;
 
 TEST(Endian, Basic) {
   uint8_t v8 = 0x12;
-  uint8_t v8s = v8;
+  uint8_t v8s = 0x12;
   uint16_t v16 = 0x1234;
-  uint16_t v16s = bswap_16(v16);
+  uint16_t v16s = 0x3412;
   uint32_t v32 = 0x12345678;
-  uint32_t v32s = bswap_32(v32);
+  uint32_t v32s = 0x78563412;
   uint64_t v64 = 0x123456789abcdef0ULL;
-  uint64_t v64s = bswap_64(v64);
+  uint64_t v64s = 0xf0debc9a78563412ULL;
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN