X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FBits.h;h=b818655e2a347c6d301a7723fa0bf823c0ed1970;hb=96791c4516497b4ea2ad08af12e4267bd1c4e796;hp=cb4234c48f18c62a2b350e8370057adb59e02966;hpb=80430673da1e696f7fcd910cc6a64b7aef2edd8f;p=folly.git diff --git a/folly/Bits.h b/folly/Bits.h index cb4234c4..b818655e 100644 --- a/folly/Bits.h +++ b/folly/Bits.h @@ -71,6 +71,7 @@ #include #include +#include #include #include #include @@ -232,43 +233,48 @@ inline typename std::enable_if< */ namespace detail { -template -struct EndianIntBase { - public: - static T swap(T x); -}; +template +struct uint_types_by_size; -#define FB_GEN(t, fn) \ - template <> \ - inline t EndianIntBase::swap(t x) { \ - return t(fn(std::make_unsigned::type(x))); \ - } +#define FB_GEN(sz, fn) \ + static inline uint##sz##_t byteswap_gen(uint##sz##_t v) { \ + return fn(v); \ + } \ + template <> \ + struct uint_types_by_size { \ + using type = uint##sz##_t; \ + }; -// fn(x) expands to (x) if the second argument is empty, which is exactly -// what we want for [u]int8_t. -FB_GEN( int8_t,) -FB_GEN(uint8_t,) +FB_GEN(8, uint8_t) #ifdef _MSC_VER -FB_GEN( int64_t, _byteswap_uint64) -FB_GEN(uint64_t, _byteswap_uint64) -FB_GEN( int32_t, _byteswap_ulong) -FB_GEN(uint32_t, _byteswap_ulong) -FB_GEN( int16_t, _byteswap_ushort) -FB_GEN(uint16_t, _byteswap_ushort) +FB_GEN(64, _byteswap_uint64) +FB_GEN(32, _byteswap_ulong) +FB_GEN(16, _byteswap_ushort) #else -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, __builtin_bswap16) -FB_GEN(uint16_t, __builtin_bswap16) +FB_GEN(64, __builtin_bswap64) +FB_GEN(32, __builtin_bswap32) +FB_GEN(16, __builtin_bswap16) #endif #undef FB_GEN template -struct EndianInt : public EndianIntBase { - public: +struct EndianInt { + static_assert( + (std::is_integral::value && !std::is_same::value) || + std::is_floating_point::value, + "template type parameter must be non-bool integral or floating point"); + static T swap(T x) { + // we implement this with memcpy because that is defined behavior in C++ + // we rely on compilers to optimize away the memcpy calls + constexpr auto s = sizeof(T); + using B = typename uint_types_by_size::type; + B b; + std::memcpy(&b, &x, s); + b = byteswap_gen(b); + std::memcpy(&x, &b, s); + return x; + } static T big(T x) { return kIsLittleEndian ? EndianInt::swap(x) : x; }