blob: 528fc07cfa7882fabc64c48c71a013c1bc0e5862 [file] [log] [blame]
/*
* Copyright 2015 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.
*/
// @author Tudor Bosman (tudorb@fb.com)
#include <gflags/gflags.h>
#include <folly/Bits.h>
#include <folly/Benchmark.h>
#include <gtest/gtest.h>
using namespace folly;
// Test constexpr-ness.
#ifndef __clang__
static_assert(findFirstSet(2u) == 2, "findFirstSet");
static_assert(findLastSet(2u) == 2, "findLastSet");
static_assert(nextPowTwo(2u) == 2, "nextPowTwo");
static_assert(isPowTwo(2u), "isPowTwo");
#endif // __clang__
namespace {
template <class INT>
void testFFS() {
EXPECT_EQ(0, findFirstSet(static_cast<INT>(0)));
size_t bits = std::numeric_limits<
typename std::make_unsigned<INT>::type>::digits;
for (size_t i = 0; i < bits; i++) {
INT v = (static_cast<INT>(1) << (bits - 1)) |
(static_cast<INT>(1) << i);
EXPECT_EQ(i+1, findFirstSet(v));
}
}
template <class INT>
void testFLS() {
typedef typename std::make_unsigned<INT>::type UINT;
EXPECT_EQ(0, findLastSet(static_cast<INT>(0)));
size_t bits = std::numeric_limits<UINT>::digits;
for (size_t i = 0; i < bits; i++) {
INT v1 = static_cast<UINT>(1) << i;
EXPECT_EQ(i + 1, findLastSet(v1));
INT v2 = (static_cast<UINT>(1) << i) - 1;
EXPECT_EQ(i, findLastSet(v2));
}
}
} // namespace
TEST(Bits, FindFirstSet) {
testFFS<char>();
testFFS<signed char>();
testFFS<unsigned char>();
testFFS<short>();
testFFS<unsigned short>();
testFFS<int>();
testFFS<unsigned int>();
testFFS<long>();
testFFS<unsigned long>();
testFFS<long long>();
testFFS<unsigned long long>();
}
TEST(Bits, FindLastSet) {
testFLS<char>();
testFLS<signed char>();
testFLS<unsigned char>();
testFLS<short>();
testFLS<unsigned short>();
testFLS<int>();
testFLS<unsigned int>();
testFLS<long>();
testFLS<unsigned long>();
testFLS<long long>();
testFLS<unsigned long long>();
}
#define testPowTwo(nextPowTwoFunc) { \
EXPECT_EQ(1, nextPowTwoFunc(0u)); \
EXPECT_EQ(1, nextPowTwoFunc(1u)); \
EXPECT_EQ(2, nextPowTwoFunc(2u)); \
EXPECT_EQ(4, nextPowTwoFunc(3u)); \
EXPECT_EQ(4, nextPowTwoFunc(4u)); \
EXPECT_EQ(8, nextPowTwoFunc(5u)); \
EXPECT_EQ(8, nextPowTwoFunc(6u)); \
EXPECT_EQ(8, nextPowTwoFunc(7u)); \
EXPECT_EQ(8, nextPowTwoFunc(8u)); \
EXPECT_EQ(16, nextPowTwoFunc(9u)); \
EXPECT_EQ(16, nextPowTwoFunc(13u)); \
EXPECT_EQ(16, nextPowTwoFunc(16u)); \
EXPECT_EQ(512, nextPowTwoFunc(510u)); \
EXPECT_EQ(512, nextPowTwoFunc(511u)); \
EXPECT_EQ(512, nextPowTwoFunc(512u)); \
EXPECT_EQ(1024, nextPowTwoFunc(513u)); \
EXPECT_EQ(1024, nextPowTwoFunc(777u)); \
EXPECT_EQ(1ul << 31, nextPowTwoFunc((1ul << 31) - 1)); \
EXPECT_EQ(1ul << 32, nextPowTwoFunc((1ul << 32) - 1)); \
EXPECT_EQ(1ull << 63, nextPowTwoFunc((1ull << 62) + 1)); \
}
TEST(Bits, nextPowTwoClz) {
testPowTwo(nextPowTwo);
}
BENCHMARK(nextPowTwoClz, 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) {
EXPECT_EQ(0, popcount(0U));
EXPECT_EQ(1, popcount(1U));
EXPECT_EQ(32, popcount(uint32_t(-1)));
EXPECT_EQ(64, popcount(uint64_t(-1)));
}
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true);
auto ret = RUN_ALL_TESTS();
if (!ret && FLAGS_benchmark) {
folly::runBenchmarks();
}
return ret;
}
/*
Benchmarks run on dual Xeon X5650's @ 2.67GHz w/hyperthreading enabled
(12 physical cores, 12 MB cache, 72 GB RAM)
Benchmark Iters Total t t/iter iter/sec
------------------------------------------------------------------------------
* nextPowTwoClz 1000000 1.659 ms 1.659 ns 574.8 M
*/