21#ifndef LIBSEMIGROUPS_BITSET_HPP_
22#define LIBSEMIGROUPS_BITSET_HPP_
36#include "exception.hpp"
38#include "detail/string.hpp"
44#if LIBSEMIGROUPS_USE_POPCNT && defined(LIBSEMIGROUPS_HAVE___BUILTIN_POPCOUNTL)
46 static inline size_t COUNT_TRUES_BLOCK(T block) {
47 return __builtin_popcountl(block);
50#if LIBSEMIGROUPS_SIZEOF_VOID_P == 8
52 static inline auto COUNT_TRUES_BLOCK(T block)
53 -> std::enable_if_t<
sizeof(T) == 8,
size_t> {
55 = (block & 0x5555555555555555L) + ((block >> 1) & 0x5555555555555555L);
57 = (block & 0x3333333333333333L) + ((block >> 2) & 0x3333333333333333L);
58 block = (block + (block >> 4)) & 0x0f0f0f0f0f0f0f0fL;
59 block = (block + (block >> 8));
60 block = (block + (block >> 16));
61 block = (block + (block >> 32)) & 0x00000000000000ffL;
67 static inline auto COUNT_TRUES_BLOCK(T block)
68 -> std::enable_if_t<
sizeof(T) == 4,
size_t> {
69 block = (block & 0x55555555) + ((block >> 1) & 0x55555555);
70 block = (block & 0x33333333) + ((block >> 2) & 0x33333333);
71 block = (block + (block >> 4)) & 0x0f0f0f0f;
72 block = (block + (block >> 8));
73 block = (block + (block >> 16)) & 0x000000ff;
78 static inline auto COUNT_TRUES_BLOCK(T block)
79 -> std::enable_if_t<
sizeof(T) == 2,
size_t> {
80 block = (block & 0x5555) + ((block >> 1) & 0x5555);
81 block = (block & 0x3333) + ((block >> 2) & 0x3333);
82 block = (block + (block >> 4)) & 0x0f0f;
83 block = (block + (block >> 8)) & 0x00ff;
88 static inline auto COUNT_TRUES_BLOCK(T block)
89 -> std::enable_if_t<
sizeof(T) == 1,
size_t> {
90 static constexpr std::array<size_t, 256>
const lookup = {
91 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4,
92 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
93 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4,
94 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
95 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
96 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
97 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
98 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
99 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
100 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
101 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
102 return lookup[block];
108 static_assert(N > 0,
"BitSet does not support 0 entries");
109#if LIBSEMIGROUPS_SIZEOF_VOID_P == 8
110 static_assert(N <= 64,
"BitSet does not support more than 64 entries");
112 static_assert(N <= 32,
"BitSet does not support more than 32 entries");
116 using block_type = std::conditional_t<
122 std::conditional_t<N <= 32, uint_fast32_t, uint64_t>>>;
124 explicit constexpr BitSet(block_type block) noexcept : _block(block) {}
125 constexpr BitSet() noexcept : BitSet(0) {}
126 constexpr BitSet(BitSet
const&)
noexcept =
default;
127 constexpr BitSet(BitSet&&) noexcept = default;
128 BitSet& operator=(BitSet const&) noexcept = default;
129 BitSet& operator=(BitSet&&) noexcept = default;
131 template <typename T>
132 BitSet(T first, T last);
137 constexpr
size_t size() const noexcept {
141 static constexpr size_t max_size() noexcept {
142#if LIBSEMIGROUPS_SIZEOF_VOID_P == 8
149 bool operator<(BitSet
const& that)
const noexcept {
151 that.clear_hi_bits();
152 return _block < that._block;
155 bool operator==(BitSet
const& that)
const noexcept {
157 that.clear_hi_bits();
158 return _block == that._block;
161 bool operator!=(BitSet
const& that)
const noexcept {
162 return !(*
this == that);
165 void operator&=(BitSet
const& that)
const noexcept {
166 _block &= that._block;
169 BitSet<N> operator&(BitSet
const& that)
const noexcept {
170 return BitSet(_block & that._block);
173 void operator|=(BitSet
const& that)
const noexcept {
174 _block |= that._block;
177 bool test(
size_t pos)
const noexcept {
178 LIBSEMIGROUPS_ASSERT(pos < N);
179 return _block & mask(pos);
182 bool operator[](
size_t pos)
const noexcept {
186 BitSet& set() noexcept {
191 BitSet& set(
size_t pos,
bool value =
true) noexcept;
193 BitSet& set(
size_t first,
size_t last,
bool value) noexcept;
195 BitSet& reset() noexcept {
200 BitSet& reset(
size_t pos)
noexcept {
201 LIBSEMIGROUPS_ASSERT(pos < N);
202 _block &= ~mask(pos);
206 BitSet& reset(
size_t first,
size_t last);
208 size_t count() const noexcept {
210 return COUNT_TRUES_BLOCK(_block);
213 template <
typename S>
214 void apply(S&& func)
const;
216 block_type to_int() const noexcept {
222 void clear_hi_bits() const noexcept {
223 size_t s = block_count() - N;
224 _block = _block << s;
225 _block = _block >> s;
228 constexpr size_t block_count() const noexcept {
229 return sizeof(block_type) * CHAR_BIT;
232 constexpr block_type mask(
size_t i)
const noexcept {
234 return static_cast<block_type
>(MASK[i]);
237 static constexpr uint64_t MASK[64] = {0x1,
301 mutable block_type _block;
305 constexpr uint64_t BitSet<N>::MASK[64];
308 template <
typename T>
309 struct IsBitSetHelper : std::false_type {};
312 struct IsBitSetHelper<BitSet<N>> : std::true_type {};
315 template <
typename T>
316 static constexpr bool IsBitSet = detail::IsBitSetHelper<T>::value;
319 std::ostringstream& operator<<(std::ostringstream& os, BitSet<N>
const& bs);
322 std::ostream& operator<<(std::ostream& os, BitSet<N>
const& bs) {
323 os << detail::to_string(bs);
333 bool operator()(std::bitset<N>
const& x, std::bitset<N>
const& y)
const {
338 bool operator()(BitSet<N>
const& x, BitSet<N>
const& y)
const noexcept {
347 struct hash<libsemigroups::BitSet<N>> {
348 using block_type =
typename libsemigroups::BitSet<N>::block_type;
349 size_t operator()(libsemigroups::BitSet<N>
const& bs)
const noexcept(
350 std::is_nothrow_default_constructible<hash<block_type>>::value) {
Namespace for everything in the libsemigroups library.
Definition action.hpp:44