#pragma once #include "types.h" // Small bitset for enum class types with available values [0, BitSize). // T must be either enum type or convertible to (registered with via simple_t). // Internal representation is single value of type T. template struct bitset_t { using type = simple_t; using under = std::underlying_type_t; enum class raw_type : under {}; static constexpr auto bitsize = BitSize; bitset_t() = default; constexpr bitset_t(type _enum_const) : m_value(static_cast(shift(_enum_const))) { } constexpr bitset_t(raw_type raw_value) : m_value(static_cast(static_cast(raw_value))) { } // Get underlying value constexpr under _value() const { return static_cast(m_value); } explicit constexpr operator bool() const { return _value() ? true : false; } bitset_t& operator +=(bitset_t rhs) { return *this = static_cast(_value() | rhs._value()); } bitset_t& operator -=(bitset_t rhs) { return *this = static_cast(_value() & ~rhs._value()); } bitset_t& operator &=(bitset_t rhs) { return *this = static_cast(_value() & rhs._value()); } bitset_t& operator ^=(bitset_t rhs) { return *this = static_cast(_value() ^ rhs._value()); } friend constexpr bitset_t operator +(bitset_t lhs, bitset_t rhs) { return static_cast(lhs._value() | rhs._value()); } friend constexpr bitset_t operator -(bitset_t lhs, bitset_t rhs) { return static_cast(lhs._value() & ~rhs._value()); } friend constexpr bitset_t operator &(bitset_t lhs, bitset_t rhs) { return static_cast(lhs._value() & rhs._value()); } friend constexpr bitset_t operator ^(bitset_t lhs, bitset_t rhs) { return static_cast(lhs._value() ^ rhs._value()); } bool test(bitset_t rhs) const { const under v = _value(); const under s = rhs._value(); return (v & s) != 0; } bool test_and_set(bitset_t rhs) { const under v = _value(); const under s = rhs._value(); *this = static_cast(v | s); return (v & s) != 0; } bool test_and_reset(bitset_t rhs) { const under v = _value(); const under s = rhs._value(); *this = static_cast(v & ~s); return (v & s) != 0; } bool test_and_complement(bitset_t rhs) { const under v = _value(); const under s = rhs._value(); *this = static_cast(v ^ s); return (v & s) != 0; } private: static constexpr under shift(const T& value) { return static_cast(value) < BitSize ? static_cast(1) << static_cast(value) : throw value; } T m_value; }; template constexpr RT make_bitset() { return RT{}; } // Fold enum constants into bitset_t<> (must be implemented with constexpr initializer_list constructor instead) template::value, bitset_t, T>> constexpr RT make_bitset(Arg&& _enum_const, Args&&... args) { return RT{ std::forward(_enum_const) } + make_bitset(std::forward(args)...); } template struct atomic_add, CT, std::enable_if_t::value>> { using under = typename bitset_t::under; using raw_type = typename bitset_t::raw_type; static inline bitset_t op1(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::fetch_or(reinterpret_cast(left), right._value())); } static constexpr auto fetch_op = &op1; static inline bitset_t op2(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::or_fetch(reinterpret_cast(left), right._value())); } static constexpr auto op_fetch = &op2; static constexpr auto atomic_op = &op2; }; template struct atomic_sub, CT, std::enable_if_t::value>> { using under = typename bitset_t::under; using raw_type = typename bitset_t::raw_type; static inline bitset_t op1(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::fetch_and(reinterpret_cast(left), ~right._value())); } static constexpr auto fetch_op = &op1; static inline bitset_t op2(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::and_fetch(reinterpret_cast(left), ~right._value())); } static constexpr auto op_fetch = &op2; static constexpr auto atomic_op = &op2; }; template struct atomic_and, CT, std::enable_if_t::value>> { using under = typename bitset_t::under; using raw_type = typename bitset_t::raw_type; static inline bitset_t op1(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::fetch_and(reinterpret_cast(left), right._value())); } static constexpr auto fetch_op = &op1; static inline bitset_t op2(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::and_fetch(reinterpret_cast(left), right._value())); } static constexpr auto op_fetch = &op2; static constexpr auto atomic_op = &op2; }; template struct atomic_xor, CT, std::enable_if_t::value>> { using under = typename bitset_t::under; using raw_type = typename bitset_t::raw_type; static inline bitset_t op1(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::fetch_xor(reinterpret_cast(left), right._value())); } static constexpr auto fetch_op = &op1; static inline bitset_t op2(bitset_t& left, bitset_t right) { return static_cast(atomic_storage::xor_fetch(reinterpret_cast(left), right._value())); } static constexpr auto op_fetch = &op2; static constexpr auto atomic_op = &op2; }; template struct atomic_test_and_set, T, std::enable_if_t::value>> { using under = typename bitset_t::under; static inline bool _op(bitset_t& left, const T& value) { return atomic_storage::bts(reinterpret_cast(left), static_cast(value)); } static constexpr auto atomic_op = &_op; }; template struct atomic_test_and_reset, T, std::enable_if_t::value>> { using under = typename bitset_t::under; static inline bool _op(bitset_t& left, const T& value) { return atomic_storage::btr(reinterpret_cast(left), static_cast(value)); } static constexpr auto atomic_op = &_op; }; template struct atomic_test_and_complement, T, std::enable_if_t::value>> { using under = typename bitset_t::under; static inline bool _op(bitset_t& left, const T& value) { return atomic_storage::btc(reinterpret_cast(left), static_cast(value)); } static constexpr auto atomic_op = &_op; };