Skip to content

Commit

Permalink
bitvec::atomic_set (#227)
Browse files Browse the repository at this point in the history
  • Loading branch information
felixguendling authored Aug 22, 2024
1 parent f52a62c commit f5c8baf
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
26 changes: 26 additions & 0 deletions include/cista/containers/bitvec.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,32 @@ struct basic_bitvec {
}
}

#if __has_cpp_attribute(__cpp_lib_atomic_ref)
constexpr void atomic_set(
Key const i, bool const val = true,
memory_order succ = std::memory_order::memory_order_seq_cst,
memory_order fail = std::memory_order::memory_order_seq_cst) noexcept {
assert(i < size_);
assert((to_idx(i) / bits_per_block) < blocks_.size());
auto const block = std::atomic_ref{
blocks_[static_cast<size_type>(to_idx(i)) / bits_per_block]};
auto const bit = to_idx(i) % bits_per_block;

auto const update_block = [&](block_t const b) -> block_t {
if (val) {
return block | (block_t{1U} << bit);
} else {
return block & (~block_t{0U} ^ (block_t{1U} << bit));
}
};

auto expected = block.load();
while (std::atomic_compare_exchange_weak(
&block, &expected, update_block(expected), succ, fail)) {
}
}
#endif

void reset() noexcept { blocks_ = {}; }

bool operator[](Key const i) const noexcept { return test(i); }
Expand Down
31 changes: 31 additions & 0 deletions test/bitvec_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,37 @@ unsigned long get_random_number() { // period 2^96-1
return z;
}

#if __has_cpp_attribute(__cpp_lib_atomic_ref)
TEST_CASE("bitvec atomic set") {
constexpr auto const kBits = 100'000U;
constexpr auto const kWorkers = 100U;

auto start = std::atomic_bool{};
auto b = cista::raw::bitvec{};
b.resize(kBits);
auto workers = std::vector<std::thread>(kWorkers);
for (auto i = 0U; i != kWorkers; ++i) {
workers[i] = std::thread{[&, i]() {
while (!start) {
// wait for synchronized start
}

for (auto j = i; j < kBits; j += kBits / kWorkers) {
b.atomic_set(j);
}
}};
}

start.store(true);

for (auto& w : workers) {
w.join();
}

CHECK(b.count() == kBits);
}
#endif

TEST_CASE("bitvec parallel") {
constexpr auto const kBits = 1'000'000U;
constexpr auto const kWorkers = 100U;
Expand Down

0 comments on commit f5c8baf

Please sign in to comment.