#include <iostream>
#include <atomic>
#include <array>
#include <limits>
#include <cassert>
#include <cstddef>
template <size_t N>
class atomic_bit_set {
public:
atomic_bit_set() = default;
atomic_bit_set(const atomic_bit_set &) = delete;
atomic_bit_set & operator = (const atomic_bit_set &) = delete;
~atomic_bit_set() = default;
public:
constexpr size_t size() const {
return N;
}
static constexpr size_t block_index(size_t bit) {
return bit / bits_per_block;
}
static constexpr size_t block_offset(size_t bit) {
return bit % bits_per_block;
}
inline bool set(size_t index, std::memory_order order) {
if (index >= N * bits_per_block) {
return false;
}
block_type mask = ONE << block_offset(index);
return data_[block_index(index)].fetch_or(mask, order) & mask;
}
inline bool reset(size_t index, std::memory_order order) {
if (index >= N * bits_per_block) {
return false;
}
block_type mask = ONE << block_offset(index);
return data_[block_index(index)].fetch_and(~mask, order) & mask;
}
inline bool set(size_t index, bool value, std::memory_order order) {
return (true == value) ? set(index, order) : reset(index, order);
}
inline bool test(size_t index, std::memory_order order) const {
if (index >= N * bits_per_block) {
return false;
}
block_type mask = ONE << block_offset(index);
return data_[block_index(index)].load(order) & mask;
}
inline bool operator [] (size_t index) {
return test(index, std::memory_order::memory_order_acquire);
}
private:
#if (2 == ATOMIC_LLONG_LOCK_FREE)
using block_type = unsigned long long;
#elif (2 == ATOMIC_LONG_LOCK_FREE)
using block_type = unsigned long;
#else
using block_type = unsigned int;
#endif
using atomic_block_type = std::atomic<block_type>;
static constexpr size_t bits_per_block = std::numeric_limits<block_type>::digits;
static constexpr block_type ONE = 1;
std::array<atomic_block_type, N>data_;
};
int main() {
atomic_bit_set<8>bit_set;
bit_set.set(8, std::memory_order::memory_order_release);
std::cout << bit_set.set(256, std::memory_order::memory_order_release) << std::endl;
bit_set.set(0, std::memory_order::memory_order_release);
bit_set.set(1, std::memory_order::memory_order_release);
bit_set.set(2, std::memory_order::memory_order_release);
std::cout << bit_set[256] << std::endl;
std::cout << bit_set[0] << std::endl;
std::cout << bit_set[1] << std::endl;
std::cout << bit_set[2] << std::endl;
bit_set.reset(2, std::memory_order::memory_order_release);
std::cout << bit_set[2] << std::endl;
return 0;
}