22#ifndef LIBSEMIGROUPS_BITSET_HPP_
23#define LIBSEMIGROUPS_BITSET_HPP_
35#include "exception.hpp"
37#include "detail/string.hpp"
43#if LIBSEMIGROUPS_USE_POPCNT && defined(LIBSEMIGROUPS_HAVE___BUILTIN_POPCOUNTL)
45 static inline size_t COUNT_TRUES_BLOCK(T block) {
46 return __builtin_popcountl(block);
49#if LIBSEMIGROUPS_SIZEOF_VOID_P == 8
51 static inline auto COUNT_TRUES_BLOCK(T block)
52 -> std::enable_if_t<
sizeof(T) == 8,
size_t> {
54 = (block & 0x5555555555555555L) + ((block >> 1) & 0x5555555555555555L);
56 = (block & 0x3333333333333333L) + ((block >> 2) & 0x3333333333333333L);
57 block = (block + (block >> 4)) & 0x0f0f0f0f0f0f0f0fL;
58 block = (block + (block >> 8));
59 block = (block + (block >> 16));
60 block = (block + (block >> 32)) & 0x00000000000000ffL;
66 static inline auto COUNT_TRUES_BLOCK(T block)
67 -> std::enable_if_t<
sizeof(T) == 4,
size_t> {
68 block = (block & 0x55555555) + ((block >> 1) & 0x55555555);
69 block = (block & 0x33333333) + ((block >> 2) & 0x33333333);
70 block = (block + (block >> 4)) & 0x0f0f0f0f;
71 block = (block + (block >> 8));
72 block = (block + (block >> 16)) & 0x000000ff;
77 static inline auto COUNT_TRUES_BLOCK(T block)
78 -> std::enable_if_t<
sizeof(T) == 2,
size_t> {
79 block = (block & 0x5555) + ((block >> 1) & 0x5555);
80 block = (block & 0x3333) + ((block >> 2) & 0x3333);
81 block = (block + (block >> 4)) & 0x0f0f;
82 block = (block + (block >> 8)) & 0x00ff;
87 static inline auto COUNT_TRUES_BLOCK(T block)
88 -> std::enable_if_t<
sizeof(T) == 1,
size_t> {
89 static constexpr std::array<size_t, 256>
const lookup = {
90 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4,
91 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
92 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4,
93 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
94 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
95 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
96 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
97 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
98 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
99 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
100 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
101 return lookup[block];
107 static_assert(N > 0,
"BitSet does not support 0 entries");
108#if LIBSEMIGROUPS_SIZEOF_VOID_P == 8
109 static_assert(N <= 64,
"BitSet does not support more than 64 entries");
111 static_assert(N <= 32,
"BitSet does not support more than 32 entries");
115 using block_type = std::conditional_t<
121 std::conditional_t<N <= 32, uint_fast32_t, uint64_t>>>;
123 explicit constexpr BitSet(block_type block) noexcept : _block(block) {}
124 constexpr BitSet() noexcept : BitSet(0) {}
125 constexpr BitSet(BitSet
const&)
noexcept =
default;
126 constexpr BitSet(BitSet&&) noexcept = default;
127 BitSet& operator=(BitSet const&) noexcept = default;
128 BitSet& operator=(BitSet&&) noexcept = default;
130 template <typename T>
131 BitSet(T first, T last) : BitSet() {
132 LIBSEMIGROUPS_ASSERT(first <= last);
136 "initialize with {} items",
141 for (
size_t i = 0; i < K; ++i, ++it) {
149 constexpr size_t size() const noexcept {
153 static constexpr size_t max_size() noexcept {
154#if LIBSEMIGROUPS_SIZEOF_VOID_P == 8
161 bool operator<(BitSet
const& that)
const noexcept {
163 that.clear_hi_bits();
164 return _block < that._block;
167 bool operator==(BitSet
const& that)
const noexcept {
169 that.clear_hi_bits();
170 return _block == that._block;
173 bool operator!=(BitSet
const& that)
const noexcept {
174 return !(*
this == that);
177 void operator&=(BitSet
const& that)
const noexcept {
178 _block &= that._block;
181 BitSet<N> operator&(BitSet
const& that)
const noexcept {
182 return BitSet(_block & that._block);
185 void operator|=(BitSet
const& that)
const noexcept {
186 _block |= that._block;
189 bool test(
size_t pos)
const noexcept {
190 LIBSEMIGROUPS_ASSERT(pos < N);
191 return _block & mask(pos);
194 bool operator[](
size_t pos)
const noexcept {
198 BitSet& set() noexcept {
203 BitSet& set(
size_t pos,
bool value =
true) noexcept {
204 LIBSEMIGROUPS_ASSERT(pos < N);
208 _block &= ~mask(pos);
213 BitSet& set(
size_t first,
size_t last,
bool value)
noexcept {
214 LIBSEMIGROUPS_ASSERT(first < N);
215 LIBSEMIGROUPS_ASSERT(last <= N);
216 LIBSEMIGROUPS_ASSERT(first < last);
219 m = (m << (first + (block_count() - last)));
220 m = (m >> (block_count() - last));
229 BitSet& reset() noexcept {
234 BitSet& reset(
size_t pos)
noexcept {
235 LIBSEMIGROUPS_ASSERT(pos < N);
236 _block &= ~mask(pos);
240 BitSet& reset(
size_t first,
size_t last) {
241 LIBSEMIGROUPS_ASSERT(first < N);
242 LIBSEMIGROUPS_ASSERT(last <= N);
243 LIBSEMIGROUPS_ASSERT(first < last);
244 return set(first, last,
false);
247 size_t count() const noexcept {
249 return COUNT_TRUES_BLOCK(_block);
252 template <
typename S>
253 void apply(S&& func)
const {
254#if LIBSEMIGROUPS_USE_CLZLL && defined(LIBSEMIGROUPS_HAVE___BUILTIN_CLZLL)
255 block_type block = _block;
257 block_type t = block & -block;
258 size_t i =
static_cast<size_t>(__builtin_ctzll(block));
266 for (
size_t i = 0; i < size(); ++i) {
274 block_type to_int() const noexcept {
279 friend std::ostringstream& operator<<(std::ostringstream& os,
280 BitSet<N>
const& bs) {
281 for (
size_t i = 0; i < N; ++i) {
287 friend std::ostream& operator<<(std::ostream& os, BitSet<N>
const& bs) {
288 os << detail::to_string(bs);
293 void clear_hi_bits() const noexcept {
294 size_t s = block_count() - N;
295 _block = _block << s;
296 _block = _block >> s;
299 constexpr size_t block_count() const noexcept {
300 return sizeof(block_type) * CHAR_BIT;
303 constexpr block_type mask(
size_t i)
const noexcept {
305 return static_cast<block_type
>(MASK[i]);
308 static constexpr uint64_t MASK[64] = {0x1,
372 mutable block_type _block;
376 constexpr uint64_t BitSet<N>::MASK[64];
379 template <
typename T>
380 struct IsBitSetHelper : std::false_type {};
383 struct IsBitSetHelper<BitSet<N>> : std::true_type {};
386 template <
typename T>
387 static constexpr bool IsBitSet = detail::IsBitSetHelper<T>::value;
395 bool operator()(std::bitset<N>
const& x, std::bitset<N>
const& y)
const {
400 bool operator()(BitSet<N>
const& x, BitSet<N>
const& y)
const noexcept {
409 struct hash<libsemigroups::BitSet<N>> {
410 using block_type =
typename libsemigroups::BitSet<N>::block_type;
411 size_t operator()(libsemigroups::BitSet<N>
const& bs)
const noexcept(
412 std::is_nothrow_default_constructible<hash<block_type>>::value) {
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:95
Namespace for everything in the libsemigroups library.
Definition action.hpp:44