#include #include "catch.hpp" #include "data_structures/bitset/bitblock.hpp" #include "sync/spinlock.hpp" TEST_CASE("BitBlock should be empty on construction") { BitBlock<> bb; REQUIRE(bb.block.load(std::memory_order_relaxed) == 0); } template void test_sizes() { BitBlock bb; auto bits = bb.bits; auto size = bb.size; REQUIRE(bits == (8 * sizeof(block_t))); REQUIRE(size == (8 * sizeof(block_t) / N)); } template struct test_sizes_loop : test_sizes_loop { test_sizes_loop() { test_sizes(); } }; template struct test_sizes_loop { test_sizes_loop() { test_sizes(); } }; TEST_CASE("BitBlock bit sizes should be set correctly") { test_sizes_loop size_test8; test_sizes_loop size_test16; test_sizes_loop size_test32; test_sizes_loop size_test64; } TEST_CASE("Values load correctly from the BitBlock") { constexpr uint32_t k = 0xCA3F; SECTION("Block size = 1") { constexpr size_t N = 1; BitBlock bb; bb.block.store(k); for(size_t i = 0; i < bb.size; ++i) REQUIRE(bb.at(i) == ((k >> i) & 1)); } SECTION("Block size = 4") { constexpr size_t N = 4; BitBlock bb; bb.block.store(k); for(size_t i = 0; i < bb.size; ++i) REQUIRE(bb.at(i) == ((k >> (N * i)) & 0xF)); } } TEST_CASE("You can set a bit in a BitBlock and get the result") { SECTION("Block size = 1") { BitBlock bb; for(size_t i = 0; i < bb.bits; ++i) { bb.set(i, 1); for(size_t j = 0; j < bb.bits; ++j) { if(j <= i) REQUIRE(bb.at(j) == 1); else REQUIRE(bb.at(j) == 0); } } } SECTION("Block size = 2") { constexpr size_t N = 2; BitBlock bb; for(size_t i = 0; i < bb.size; ++i) { auto k = i % (1 << N); bb.set(i, k); for(size_t j = 0; j < bb.size; j++) { auto l = j % (1 << N); if(j <= i) REQUIRE(bb.at(j) == l); else REQUIRE(bb.at(j) == 0); } } } SECTION("Block size = 5") { constexpr size_t N = 5; BitBlock bb; for(size_t i = 0; i < bb.size; ++i) { auto k = i % (1 << N); bb.set(i, k); for(size_t j = 0; j < bb.size; j++) { auto l = j % (1 << N); if(j <= i) REQUIRE(bb.at(j) == l); else REQUIRE(bb.at(j) == 0); } } } } template void bitblock_thead_test(BitBlock* bb, size_t idx, size_t n) { static SpinLock lock; uint8_t x; uint64_t sum = 0, actual = 0; for(size_t i = 0; i < n; ++i) { int y = i % 2; actual += i * y; bb->set(idx, y); x = bb->at(idx); sum += i * x; bb->clear(idx); x = bb->at(idx); } auto guard = std::unique_lock(lock); REQUIRE(sum == actual); } TEST_CASE("(try to) Test multithreaded correctness") { BitBlock bb; constexpr int N = 2; constexpr int K = 500000; std::vector threads; for(int i = 0; i < N; ++i) threads.push_back(std::thread( bitblock_thead_test, &bb, i, K)); for(auto& thread : threads){ thread.join(); } }