sizeof(T) <= sizeof(unsigned int)),
unsigned int>::type
findLastSet(T x) {
- return x ? 8 * sizeof(unsigned int) - __builtin_clz(x) : 0;
+ // 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 <class T>
sizeof(T) <= sizeof(unsigned long)),
unsigned int>::type
findLastSet(T x) {
- return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
+ return x ? ((8 * sizeof(unsigned long) - 1) ^ __builtin_clzl(x)) + 1 : 0;
}
template <class T>
sizeof(T) <= sizeof(unsigned long long)),
unsigned int>::type
findLastSet(T x) {
- return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
+ return x ? ((8 * sizeof(unsigned long long) - 1) ^ __builtin_clzll(x)) + 1
+ : 0;
}
template <class T>
}
template <class T>
-inline constexpr
-typename std::enable_if<
- std::is_integral<T>::value && std::is_unsigned<T>::value,
- bool>::type
+inline FOLLY_INTRINSIC_CONSTEXPR typename std::
+ enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type
+ prevPowTwo(T v) {
+ return v ? (T(1) << (findLastSet(v) - 1)) : 0;
+}
+
+template <class T>
+inline constexpr typename std::enable_if<
+ std::is_integral<T>::value && std::is_unsigned<T>::value,
+ bool>::type
isPowTwo(T v) {
return (v != 0) && !(v & (v - 1));
}
EXPECT_EQ(1ull << 63, nextPowTwo((1ull << 62) + 1));
}
+TEST(Bits, prevPowTwoClz) {
+ EXPECT_EQ(0, prevPowTwo(0u));
+ EXPECT_EQ(1, prevPowTwo(1u));
+ EXPECT_EQ(2, prevPowTwo(2u));
+ EXPECT_EQ(2, prevPowTwo(3u));
+ EXPECT_EQ(4, prevPowTwo(4u));
+ EXPECT_EQ(4, prevPowTwo(5u));
+ EXPECT_EQ(4, prevPowTwo(6u));
+ EXPECT_EQ(4, prevPowTwo(7u));
+ EXPECT_EQ(8, prevPowTwo(8u));
+ EXPECT_EQ(8, prevPowTwo(9u));
+ EXPECT_EQ(8, prevPowTwo(13u));
+ EXPECT_EQ(16, prevPowTwo(16u));
+ EXPECT_EQ(256, prevPowTwo(510u));
+ EXPECT_EQ(256, prevPowTwo(511u));
+ EXPECT_EQ(512, prevPowTwo(512u));
+ EXPECT_EQ(512, prevPowTwo(513u));
+ EXPECT_EQ(512, prevPowTwo(777u));
+ EXPECT_EQ(1ul << 30, prevPowTwo((1ul << 31) - 1));
+ EXPECT_EQ(1ull << 31, prevPowTwo((1ull << 32) - 1));
+ EXPECT_EQ(1ull << 62, prevPowTwo((1ull << 62) + 1));
+}
+
TEST(Bits, isPowTwo) {
EXPECT_FALSE(isPowTwo(0u));
EXPECT_TRUE(isPowTwo(1ul));