From 35054c8b8eefa0abaded33ff4150d195c9bf0e80 Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Fri, 8 Dec 2017 00:24:44 -0800 Subject: [PATCH] Move folly/Bits.h to folly/lang/ Summary: [Folly] Move `folly/Bits.h` to `folly/lang/`. Reviewed By: phoad, Orvid Differential Revision: D6495547 fbshipit-source-id: a93159321df8277f8a4b4f10a5e4e0fc58cb6022 --- CMakeLists.txt | 4 +- folly/AtomicHashArray-inl.h | 2 +- folly/AtomicUnorderedMap.h | 2 +- folly/BitIterator.h | 2 +- folly/Bits.h | 369 +------------------ folly/GroupVarint.h | 2 +- folly/MacAddress.h | 2 +- folly/Makefile.am | 1 + folly/compression/Compression.cpp | 2 +- folly/compression/Utils.h | 2 +- folly/experimental/BitVectorCoding.h | 2 +- folly/experimental/Bits.h | 2 +- folly/experimental/EliasFanoCoding.h | 2 +- folly/experimental/EventCount.h | 3 +- folly/hash/Hash.h | 2 +- folly/io/Cursor.h | 2 +- folly/io/async/AsyncSSLSocket.cpp | 2 +- folly/io/async/AsyncSSLSocket.h | 2 +- folly/io/async/HHWheelTimer.cpp | 2 +- folly/json.cpp | 2 +- folly/lang/Bits.h | 384 ++++++++++++++++++++ folly/{ => lang}/test/BitsTest.cpp | 2 +- folly/test/BitsBenchmark.cpp | 2 +- folly/test/EndianTest.cpp | 2 +- folly/test/IPAddressTest.cpp | 2 +- folly/tracing/test/StaticTracepointTest.cpp | 2 +- 26 files changed, 411 insertions(+), 392 deletions(-) create mode 100644 folly/lang/Bits.h rename folly/{ => lang}/test/BitsTest.cpp (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index fc0084dc..ae6ab6d0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -517,6 +517,9 @@ if (BUILD_TESTS) DIRECTORY io/async/ssl/test/ TEST ssl_errors_test SOURCES SSLErrorsTest.cpp + DIRECTORY lang/test/ + TEST bits_test SOURCES BitsTest.cpp + DIRECTORY memory/test/ TEST arena_test SOURCES ArenaTest.cpp TEST thread_cached_arena_test SOURCES ThreadCachedArenaTest.cpp @@ -560,7 +563,6 @@ if (BUILD_TESTS) TEST atomic_struct_test SOURCES AtomicStructTest.cpp TEST atomic_unordered_map_test SOURCES AtomicUnorderedMapTest.cpp TEST bit_iterator_test SOURCES BitIteratorTest.cpp - TEST bits_test SOURCES BitsTest.cpp TEST cacheline_padded_test SOURCES CachelinePaddedTest.cpp TEST clock_gettime_wrappers_test SOURCES ClockGettimeWrappersTest.cpp TEST concurrent_skip_list_test SOURCES ConcurrentSkipListTest.cpp diff --git a/folly/AtomicHashArray-inl.h b/folly/AtomicHashArray-inl.h index f8251f33..4333e5a0 100644 --- a/folly/AtomicHashArray-inl.h +++ b/folly/AtomicHashArray-inl.h @@ -20,8 +20,8 @@ #include -#include #include +#include namespace folly { diff --git a/folly/AtomicUnorderedMap.h b/folly/AtomicUnorderedMap.h index ca867fc1..edf3b1da 100644 --- a/folly/AtomicUnorderedMap.h +++ b/folly/AtomicUnorderedMap.h @@ -26,11 +26,11 @@ #include -#include #include #include #include #include +#include #include #include diff --git a/folly/BitIterator.h b/folly/BitIterator.h index b7545701..0446bd13 100644 --- a/folly/BitIterator.h +++ b/folly/BitIterator.h @@ -38,9 +38,9 @@ #include -#include #include #include +#include namespace folly { diff --git a/folly/Bits.h b/folly/Bits.h index 889b3a0b..a3cff3ea 100644 --- a/folly/Bits.h +++ b/folly/Bits.h @@ -14,371 +14,4 @@ * limitations under the License. */ -/** - * Various low-level, bit-manipulation routines. - * - * findFirstSet(x) [constexpr] - * find first (least significant) bit set in a value of an integral type, - * 1-based (like ffs()). 0 = no bits are set (x == 0) - * - * findLastSet(x) [constexpr] - * find last (most significant) bit set in a value of an integral type, - * 1-based. 0 = no bits are set (x == 0) - * for x != 0, findLastSet(x) == 1 + floor(log2(x)) - * - * nextPowTwo(x) [constexpr] - * Finds the next power of two >= x. - * - * isPowTwo(x) [constexpr] - * return true iff x is a power of two - * - * popcount(x) - * return the number of 1 bits in x - * - * Endian - * convert between native, big, and little endian representation - * Endian::big(x) big <-> native - * Endian::little(x) little <-> native - * Endian::swap(x) big <-> little - * - * @author Tudor Bosman (tudorb@fb.com) - */ - -#pragma once - -// MSVC does not support intrinsics constexpr -#if defined(_MSC_VER) -#define FOLLY_INTRINSIC_CONSTEXPR const -#else -#define FOLLY_INTRINSIC_CONSTEXPR constexpr -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace folly { - -// Generate overloads for findFirstSet as wrappers around -// appropriate ffs, ffsl, ffsll gcc builtins -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) <= sizeof(unsigned int)), - unsigned int>::type - findFirstSet(T x) { - return static_cast(__builtin_ffs(static_cast(x))); -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) > sizeof(unsigned int) && - sizeof(T) <= sizeof(unsigned long)), - unsigned int>::type - findFirstSet(T x) { - return static_cast(__builtin_ffsl(static_cast(x))); -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) > sizeof(unsigned long) && - sizeof(T) <= sizeof(unsigned long long)), - unsigned int>::type - findFirstSet(T x) { - return static_cast(__builtin_ffsll(static_cast(x))); -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && std::is_signed::value), - unsigned int>::type - findFirstSet(T x) { - // Note that conversion from a signed type to the corresponding unsigned - // type is technically implementation-defined, but will likely work - // on any impementation that uses two's complement. - return findFirstSet(static_cast::type>(x)); -} - -// findLastSet: return the 1-based index of the highest bit set -// for x > 0, findLastSet(x) == 1 + floor(log2(x)) -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) <= sizeof(unsigned int)), - unsigned int>::type - findLastSet(T x) { - // If X is a power of two X - Y = ((X - 1) ^ Y) + 1. Doing this transformation - // allows GCC to remove its own xor that it adds to implement clz using bsr - return x ? ((8 * sizeof(unsigned int) - 1) ^ __builtin_clz(x)) + 1 : 0; -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) > sizeof(unsigned int) && - sizeof(T) <= sizeof(unsigned long)), - unsigned int>::type - findLastSet(T x) { - return x ? ((8 * sizeof(unsigned long) - 1) ^ __builtin_clzl(x)) + 1 : 0; -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) > sizeof(unsigned long) && - sizeof(T) <= sizeof(unsigned long long)), - unsigned int>::type - findLastSet(T x) { - return x ? ((8 * sizeof(unsigned long long) - 1) ^ __builtin_clzll(x)) + 1 - : 0; -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - (std::is_integral::value && - std::is_signed::value), - unsigned int>::type - findLastSet(T x) { - return findLastSet(static_cast::type>(x)); -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR -typename std::enable_if< - std::is_integral::value && std::is_unsigned::value, - T>::type -nextPowTwo(T v) { - return v ? (T(1) << findLastSet(v - 1)) : 1; -} - -template -inline FOLLY_INTRINSIC_CONSTEXPR typename std:: - enable_if::value && std::is_unsigned::value, T>::type - prevPowTwo(T v) { - return v ? (T(1) << (findLastSet(v) - 1)) : 0; -} - -template -inline constexpr typename std::enable_if< - std::is_integral::value && std::is_unsigned::value, - bool>::type -isPowTwo(T v) { - return (v != 0) && !(v & (v - 1)); -} - -/** - * Population count - */ -template -inline typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) <= sizeof(unsigned int)), - size_t>::type - popcount(T x) { - return size_t(__builtin_popcount(x)); -} - -template -inline typename std::enable_if< - (std::is_integral::value && - std::is_unsigned::value && - sizeof(T) > sizeof(unsigned int) && - sizeof(T) <= sizeof(unsigned long long)), - size_t>::type - popcount(T x) { - return size_t(__builtin_popcountll(x)); -} - -/** - * Endianness detection and manipulation primitives. - */ -namespace detail { - -template -struct uint_types_by_size; - -#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; \ - }; - -FB_GEN(8, uint8_t) -#ifdef _MSC_VER -FB_GEN(64, _byteswap_uint64) -FB_GEN(32, _byteswap_ulong) -FB_GEN(16, _byteswap_ushort) -#else -FB_GEN(64, __builtin_bswap64) -FB_GEN(32, __builtin_bswap32) -FB_GEN(16, __builtin_bswap16) -#endif - -#undef FB_GEN - -template -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; - } - static T little(T x) { - return kIsBigEndian ? EndianInt::swap(x) : x; - } -}; - -} // namespace detail - -// big* convert between native and big-endian representations -// little* convert between native and little-endian representations -// swap* convert between big-endian and little-endian representations -// -// ntohs, htons == big16 -// ntohl, htonl == big32 -#define FB_GEN1(fn, t, sz) \ - static t fn##sz(t x) { return fn(x); } \ - -#define FB_GEN2(t, sz) \ - FB_GEN1(swap, t, sz) \ - FB_GEN1(big, t, sz) \ - FB_GEN1(little, t, sz) - -#define FB_GEN(sz) \ - FB_GEN2(uint##sz##_t, sz) \ - FB_GEN2(int##sz##_t, sz) - -class Endian { - public: - enum class Order : uint8_t { - LITTLE, - BIG - }; - - static constexpr Order order = kIsLittleEndian ? Order::LITTLE : Order::BIG; - - template static T swap(T x) { - return folly::detail::EndianInt::swap(x); - } - template static T big(T x) { - return folly::detail::EndianInt::big(x); - } - template static T little(T x) { - return folly::detail::EndianInt::little(x); - } - -#if !defined(__ANDROID__) - FB_GEN(64) - FB_GEN(32) - FB_GEN(16) - FB_GEN(8) -#endif -}; - -#undef FB_GEN -#undef FB_GEN2 -#undef FB_GEN1 - - -template struct Unaligned; - -/** - * Representation of an unaligned value of a POD type. - */ -FOLLY_PACK_PUSH -template -struct Unaligned< - T, - typename std::enable_if::value>::type> { - Unaligned() = default; // uninitialized - /* implicit */ Unaligned(T v) : value(v) { } - T value; -} FOLLY_PACK_ATTR; -FOLLY_PACK_POP - -/** - * Read an unaligned value of type T and return it. - */ -template -inline T loadUnaligned(const void* p) { - static_assert(sizeof(Unaligned) == sizeof(T), "Invalid unaligned size"); - static_assert(alignof(Unaligned) == 1, "Invalid alignment"); - if (kHasUnalignedAccess) { - return static_cast*>(p)->value; - } else { - T value; - memcpy(&value, p, sizeof(T)); - return value; - } -} - -/** - * Write an unaligned value of type T. - */ -template -inline void storeUnaligned(void* p, T value) { - static_assert(sizeof(Unaligned) == sizeof(T), "Invalid unaligned size"); - static_assert(alignof(Unaligned) == 1, "Invalid alignment"); - if (kHasUnalignedAccess) { - // Prior to C++14, the spec says that a placement new like this - // is required to check that p is not nullptr, and to do nothing - // if p is a nullptr. By assuming it's not a nullptr, we get a - // nice loud segfault in optimized builds if p is nullptr, rather - // than just silently doing nothing. - folly::assume(p != nullptr); - new (p) Unaligned(value); - } else { - memcpy(p, &value, sizeof(T)); - } -} - -template -T bitReverse(T n) { - auto m = static_cast::type>(n); - m = ((m & 0xAAAAAAAAAAAAAAAA) >> 1) | ((m & 0x5555555555555555) << 1); - m = ((m & 0xCCCCCCCCCCCCCCCC) >> 2) | ((m & 0x3333333333333333) << 2); - m = ((m & 0xF0F0F0F0F0F0F0F0) >> 4) | ((m & 0x0F0F0F0F0F0F0F0F) << 4); - return static_cast(Endian::swap(m)); -} - -} // namespace folly +#include // @shim diff --git a/folly/GroupVarint.h b/folly/GroupVarint.h index ed7dae63..ad0bb361 100644 --- a/folly/GroupVarint.h +++ b/folly/GroupVarint.h @@ -30,9 +30,9 @@ #if FOLLY_X64 || defined(__i386__) || FOLLY_PPC64 || FOLLY_AARCH64 #define HAVE_GROUP_VARINT 1 -#include #include #include +#include #include #if FOLLY_SSE >= 3 diff --git a/folly/MacAddress.h b/folly/MacAddress.h index ef7c3ac1..2a2c1fc4 100644 --- a/folly/MacAddress.h +++ b/folly/MacAddress.h @@ -18,8 +18,8 @@ #include -#include #include +#include namespace folly { diff --git a/folly/Makefile.am b/folly/Makefile.am index 121c1eeb..2b077c75 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -325,6 +325,7 @@ nobase_follyinclude_HEADERS = \ io/async/test/Util.h \ json.h \ lang/Assume.h \ + lang/Bits.h \ lang/ColdClass.h \ lang/Launder.h \ lang/RValueReferenceWrapper.h \ diff --git a/folly/compression/Compression.cpp b/folly/compression/Compression.cpp index 6f288b5c..f94a381b 100644 --- a/folly/compression/Compression.cpp +++ b/folly/compression/Compression.cpp @@ -48,7 +48,6 @@ #include #endif -#include #include #include #include @@ -56,6 +55,7 @@ #include #include #include +#include #include #include diff --git a/folly/compression/Utils.h b/folly/compression/Utils.h index 8d23723f..4804548b 100644 --- a/folly/compression/Utils.h +++ b/folly/compression/Utils.h @@ -18,9 +18,9 @@ #include -#include #include #include +#include /** * Helper functions for compression codecs. diff --git a/folly/experimental/BitVectorCoding.h b/folly/experimental/BitVectorCoding.h index 99c9c576..a24b9550 100644 --- a/folly/experimental/BitVectorCoding.h +++ b/folly/experimental/BitVectorCoding.h @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #if !FOLLY_X64 diff --git a/folly/experimental/Bits.h b/folly/experimental/Bits.h index 0b1960c2..f6ab45d7 100644 --- a/folly/experimental/Bits.h +++ b/folly/experimental/Bits.h @@ -22,9 +22,9 @@ #include -#include #include #include +#include namespace folly { diff --git a/folly/experimental/EliasFanoCoding.h b/folly/experimental/EliasFanoCoding.h index 04a0f158..8936ef0d 100644 --- a/folly/experimental/EliasFanoCoding.h +++ b/folly/experimental/EliasFanoCoding.h @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #if !FOLLY_X64 diff --git a/folly/experimental/EventCount.h b/folly/experimental/EventCount.h index 1496b8b1..95594f38 100644 --- a/folly/experimental/EventCount.h +++ b/folly/experimental/EventCount.h @@ -22,13 +22,12 @@ #include -#include #include #include +#include #include #include - namespace folly { /** diff --git a/folly/hash/Hash.h b/folly/hash/Hash.h index 8f0743de..6b6f137a 100644 --- a/folly/hash/Hash.h +++ b/folly/hash/Hash.h @@ -24,10 +24,10 @@ #include #include -#include #include #include #include +#include /* * Various hashing functions. diff --git a/folly/io/Cursor.h b/folly/io/Cursor.h index ba0dd36f..c32e3042 100644 --- a/folly/io/Cursor.h +++ b/folly/io/Cursor.h @@ -23,13 +23,13 @@ #include #include -#include #include #include #include #include #include #include +#include #include /** diff --git a/folly/io/async/AsyncSSLSocket.cpp b/folly/io/async/AsyncSSLSocket.cpp index 0cb7c73a..bfcb8b9e 100644 --- a/folly/io/async/AsyncSSLSocket.cpp +++ b/folly/io/async/AsyncSSLSocket.cpp @@ -26,12 +26,12 @@ #include #include -#include #include #include #include #include #include +#include #include using folly::SocketAddress; diff --git a/folly/io/async/AsyncSSLSocket.h b/folly/io/async/AsyncSSLSocket.h index 1f1d6798..c3e38bbe 100644 --- a/folly/io/async/AsyncSSLSocket.h +++ b/folly/io/async/AsyncSSLSocket.h @@ -18,7 +18,6 @@ #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/folly/io/async/HHWheelTimer.cpp b/folly/io/async/HHWheelTimer.cpp index 57bb1ce9..dd7301f5 100644 --- a/folly/io/async/HHWheelTimer.cpp +++ b/folly/io/async/HHWheelTimer.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include diff --git a/folly/json.cpp b/folly/json.cpp index 029278e2..db80b332 100644 --- a/folly/json.cpp +++ b/folly/json.cpp @@ -22,8 +22,8 @@ #include #include -#include #include +#include #include #include diff --git a/folly/lang/Bits.h b/folly/lang/Bits.h new file mode 100644 index 00000000..889b3a0b --- /dev/null +++ b/folly/lang/Bits.h @@ -0,0 +1,384 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Various low-level, bit-manipulation routines. + * + * findFirstSet(x) [constexpr] + * find first (least significant) bit set in a value of an integral type, + * 1-based (like ffs()). 0 = no bits are set (x == 0) + * + * findLastSet(x) [constexpr] + * find last (most significant) bit set in a value of an integral type, + * 1-based. 0 = no bits are set (x == 0) + * for x != 0, findLastSet(x) == 1 + floor(log2(x)) + * + * nextPowTwo(x) [constexpr] + * Finds the next power of two >= x. + * + * isPowTwo(x) [constexpr] + * return true iff x is a power of two + * + * popcount(x) + * return the number of 1 bits in x + * + * Endian + * convert between native, big, and little endian representation + * Endian::big(x) big <-> native + * Endian::little(x) little <-> native + * Endian::swap(x) big <-> little + * + * @author Tudor Bosman (tudorb@fb.com) + */ + +#pragma once + +// MSVC does not support intrinsics constexpr +#if defined(_MSC_VER) +#define FOLLY_INTRINSIC_CONSTEXPR const +#else +#define FOLLY_INTRINSIC_CONSTEXPR constexpr +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace folly { + +// Generate overloads for findFirstSet as wrappers around +// appropriate ffs, ffsl, ffsll gcc builtins +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) <= sizeof(unsigned int)), + unsigned int>::type + findFirstSet(T x) { + return static_cast(__builtin_ffs(static_cast(x))); +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) > sizeof(unsigned int) && + sizeof(T) <= sizeof(unsigned long)), + unsigned int>::type + findFirstSet(T x) { + return static_cast(__builtin_ffsl(static_cast(x))); +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) > sizeof(unsigned long) && + sizeof(T) <= sizeof(unsigned long long)), + unsigned int>::type + findFirstSet(T x) { + return static_cast(__builtin_ffsll(static_cast(x))); +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && std::is_signed::value), + unsigned int>::type + findFirstSet(T x) { + // Note that conversion from a signed type to the corresponding unsigned + // type is technically implementation-defined, but will likely work + // on any impementation that uses two's complement. + return findFirstSet(static_cast::type>(x)); +} + +// findLastSet: return the 1-based index of the highest bit set +// for x > 0, findLastSet(x) == 1 + floor(log2(x)) +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) <= sizeof(unsigned int)), + unsigned int>::type + findLastSet(T x) { + // If X is a power of two X - Y = ((X - 1) ^ Y) + 1. Doing this transformation + // allows GCC to remove its own xor that it adds to implement clz using bsr + return x ? ((8 * sizeof(unsigned int) - 1) ^ __builtin_clz(x)) + 1 : 0; +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) > sizeof(unsigned int) && + sizeof(T) <= sizeof(unsigned long)), + unsigned int>::type + findLastSet(T x) { + return x ? ((8 * sizeof(unsigned long) - 1) ^ __builtin_clzl(x)) + 1 : 0; +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) > sizeof(unsigned long) && + sizeof(T) <= sizeof(unsigned long long)), + unsigned int>::type + findLastSet(T x) { + return x ? ((8 * sizeof(unsigned long long) - 1) ^ __builtin_clzll(x)) + 1 + : 0; +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + (std::is_integral::value && + std::is_signed::value), + unsigned int>::type + findLastSet(T x) { + return findLastSet(static_cast::type>(x)); +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR +typename std::enable_if< + std::is_integral::value && std::is_unsigned::value, + T>::type +nextPowTwo(T v) { + return v ? (T(1) << findLastSet(v - 1)) : 1; +} + +template +inline FOLLY_INTRINSIC_CONSTEXPR typename std:: + enable_if::value && std::is_unsigned::value, T>::type + prevPowTwo(T v) { + return v ? (T(1) << (findLastSet(v) - 1)) : 0; +} + +template +inline constexpr typename std::enable_if< + std::is_integral::value && std::is_unsigned::value, + bool>::type +isPowTwo(T v) { + return (v != 0) && !(v & (v - 1)); +} + +/** + * Population count + */ +template +inline typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) <= sizeof(unsigned int)), + size_t>::type + popcount(T x) { + return size_t(__builtin_popcount(x)); +} + +template +inline typename std::enable_if< + (std::is_integral::value && + std::is_unsigned::value && + sizeof(T) > sizeof(unsigned int) && + sizeof(T) <= sizeof(unsigned long long)), + size_t>::type + popcount(T x) { + return size_t(__builtin_popcountll(x)); +} + +/** + * Endianness detection and manipulation primitives. + */ +namespace detail { + +template +struct uint_types_by_size; + +#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; \ + }; + +FB_GEN(8, uint8_t) +#ifdef _MSC_VER +FB_GEN(64, _byteswap_uint64) +FB_GEN(32, _byteswap_ulong) +FB_GEN(16, _byteswap_ushort) +#else +FB_GEN(64, __builtin_bswap64) +FB_GEN(32, __builtin_bswap32) +FB_GEN(16, __builtin_bswap16) +#endif + +#undef FB_GEN + +template +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; + } + static T little(T x) { + return kIsBigEndian ? EndianInt::swap(x) : x; + } +}; + +} // namespace detail + +// big* convert between native and big-endian representations +// little* convert between native and little-endian representations +// swap* convert between big-endian and little-endian representations +// +// ntohs, htons == big16 +// ntohl, htonl == big32 +#define FB_GEN1(fn, t, sz) \ + static t fn##sz(t x) { return fn(x); } \ + +#define FB_GEN2(t, sz) \ + FB_GEN1(swap, t, sz) \ + FB_GEN1(big, t, sz) \ + FB_GEN1(little, t, sz) + +#define FB_GEN(sz) \ + FB_GEN2(uint##sz##_t, sz) \ + FB_GEN2(int##sz##_t, sz) + +class Endian { + public: + enum class Order : uint8_t { + LITTLE, + BIG + }; + + static constexpr Order order = kIsLittleEndian ? Order::LITTLE : Order::BIG; + + template static T swap(T x) { + return folly::detail::EndianInt::swap(x); + } + template static T big(T x) { + return folly::detail::EndianInt::big(x); + } + template static T little(T x) { + return folly::detail::EndianInt::little(x); + } + +#if !defined(__ANDROID__) + FB_GEN(64) + FB_GEN(32) + FB_GEN(16) + FB_GEN(8) +#endif +}; + +#undef FB_GEN +#undef FB_GEN2 +#undef FB_GEN1 + + +template struct Unaligned; + +/** + * Representation of an unaligned value of a POD type. + */ +FOLLY_PACK_PUSH +template +struct Unaligned< + T, + typename std::enable_if::value>::type> { + Unaligned() = default; // uninitialized + /* implicit */ Unaligned(T v) : value(v) { } + T value; +} FOLLY_PACK_ATTR; +FOLLY_PACK_POP + +/** + * Read an unaligned value of type T and return it. + */ +template +inline T loadUnaligned(const void* p) { + static_assert(sizeof(Unaligned) == sizeof(T), "Invalid unaligned size"); + static_assert(alignof(Unaligned) == 1, "Invalid alignment"); + if (kHasUnalignedAccess) { + return static_cast*>(p)->value; + } else { + T value; + memcpy(&value, p, sizeof(T)); + return value; + } +} + +/** + * Write an unaligned value of type T. + */ +template +inline void storeUnaligned(void* p, T value) { + static_assert(sizeof(Unaligned) == sizeof(T), "Invalid unaligned size"); + static_assert(alignof(Unaligned) == 1, "Invalid alignment"); + if (kHasUnalignedAccess) { + // Prior to C++14, the spec says that a placement new like this + // is required to check that p is not nullptr, and to do nothing + // if p is a nullptr. By assuming it's not a nullptr, we get a + // nice loud segfault in optimized builds if p is nullptr, rather + // than just silently doing nothing. + folly::assume(p != nullptr); + new (p) Unaligned(value); + } else { + memcpy(p, &value, sizeof(T)); + } +} + +template +T bitReverse(T n) { + auto m = static_cast::type>(n); + m = ((m & 0xAAAAAAAAAAAAAAAA) >> 1) | ((m & 0x5555555555555555) << 1); + m = ((m & 0xCCCCCCCCCCCCCCCC) >> 2) | ((m & 0x3333333333333333) << 2); + m = ((m & 0xF0F0F0F0F0F0F0F0) >> 4) | ((m & 0x0F0F0F0F0F0F0F0F) << 4); + return static_cast(Endian::swap(m)); +} + +} // namespace folly diff --git a/folly/test/BitsTest.cpp b/folly/lang/test/BitsTest.cpp similarity index 99% rename from folly/test/BitsTest.cpp rename to folly/lang/test/BitsTest.cpp index 1d722cb5..e2708f8b 100644 --- a/folly/test/BitsTest.cpp +++ b/folly/lang/test/BitsTest.cpp @@ -16,7 +16,7 @@ // @author Tudor Bosman (tudorb@fb.com) -#include +#include #include #include diff --git a/folly/test/BitsBenchmark.cpp b/folly/test/BitsBenchmark.cpp index 5d2ba9e1..da0cab43 100644 --- a/folly/test/BitsBenchmark.cpp +++ b/folly/test/BitsBenchmark.cpp @@ -16,7 +16,7 @@ // @author Tudor Bosman (tudorb@fb.com) -#include +#include #include diff --git a/folly/test/EndianTest.cpp b/folly/test/EndianTest.cpp index ab7d21c2..30809c1e 100644 --- a/folly/test/EndianTest.cpp +++ b/folly/test/EndianTest.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include diff --git a/folly/test/IPAddressTest.cpp b/folly/test/IPAddressTest.cpp index 02f54676..23ab3c01 100644 --- a/folly/test/IPAddressTest.cpp +++ b/folly/test/IPAddressTest.cpp @@ -19,12 +19,12 @@ #include #include -#include #include #include #include #include #include +#include #include #include diff --git a/folly/tracing/test/StaticTracepointTest.cpp b/folly/tracing/test/StaticTracepointTest.cpp index d6b76ec8..75a89b7c 100644 --- a/folly/tracing/test/StaticTracepointTest.cpp +++ b/folly/tracing/test/StaticTracepointTest.cpp @@ -22,12 +22,12 @@ #include #include -#include #include #include #include #include #include +#include #include #include #include -- 2.34.1