isPowTwo
authorMichael Curtiss <mcurtiss@fb.com>
Fri, 17 Aug 2012 05:31:16 +0000 (22:31 -0700)
committerTudor Bosman <tudorb@fb.com>
Sun, 26 Aug 2012 18:13:40 +0000 (11:13 -0700)
Summary:
a la Hacker's Delight.

Also, fix nonsensical nextPowTwo benchmark.

Test Plan: Added test and benchmark.

Reviewed By: tudorb@fb.com

FB internal diff: D551510

folly/Bits.h
folly/test/BitsTest.cpp

index 8ecac77c9f8066cb2665837d66dd8b4751bd3054..3a05047d3def22c479e94b300ee07becc0f218f2 100644 (file)
@@ -32,6 +32,9 @@
  * nextPowTwo(x)
  *    Finds the next power of two >= x.
  *
+ * isPowTwo(x)
+ *    return true iff x is a power of two
+ *
  * Endian
  *    convert between native, big, and little endian representation
  *    Endian::big(x)      big <-> native
@@ -178,6 +181,15 @@ nextPowTwo(T v) {
   return 1ul << findLastSet(v - 1);
 }
 
+template <class T>
+inline
+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)));   // yes, this is endian-agnostic
+}
+
 /**
  * Population count
  */
index 99bdcb484f1e0ee9148e9d315e13744fdcdc2d46..8634246a02b7a84a6a025917b9bccfd6ea1c0a82 100644 (file)
@@ -109,9 +109,42 @@ TEST(Bits, nextPowTwoClz) {
   testPowTwo(nextPowTwo);
 }
 
-int x; // prevent the loop from getting optimized away
 BENCHMARK(nextPowTwoClz, iters) {
-  x = folly::nextPowTwo(iters);
+  for (unsigned long i = 0; i < iters; ++i) {
+    auto x = folly::nextPowTwo(iters);
+    folly::doNotOptimizeAway(x);
+  }
+}
+
+TEST(Bits, isPowTwo) {
+  EXPECT_FALSE(isPowTwo(0u));
+  EXPECT_TRUE(isPowTwo(1ul));
+  EXPECT_TRUE(isPowTwo(2ull));
+  EXPECT_FALSE(isPowTwo(3ul));
+  EXPECT_TRUE(isPowTwo(4ul));
+  EXPECT_FALSE(isPowTwo(5ul));
+  EXPECT_TRUE(isPowTwo(8ul));
+  EXPECT_FALSE(isPowTwo(15u));
+  EXPECT_TRUE(isPowTwo(16u));
+  EXPECT_FALSE(isPowTwo(17u));
+  EXPECT_FALSE(isPowTwo(511ul));
+  EXPECT_TRUE(isPowTwo(512ul));
+  EXPECT_FALSE(isPowTwo(513ul));
+  EXPECT_FALSE(isPowTwo((1ul<<31) - 1));
+  EXPECT_TRUE(isPowTwo(1ul<<31));
+  EXPECT_FALSE(isPowTwo((1ul<<31) + 1));
+  EXPECT_FALSE(isPowTwo((1ull<<63) - 1));
+  EXPECT_TRUE(isPowTwo(1ull<<63));
+  EXPECT_FALSE(isPowTwo((1ull<<63) + 1));
+}
+
+BENCHMARK_DRAW_LINE();
+BENCHMARK(isPowTwo, iters) {
+  bool b;
+  for (unsigned long i = 0; i < iters; ++i) {
+    b = folly::isPowTwo(i);
+    folly::doNotOptimizeAway(b);
+  }
 }
 
 TEST(Bits, popcount) {