22 using size_type = std::uint64_t;
23 using block_type = std::uint64_t;
24 static constexpr size_type bits_per_block =
25 std::numeric_limits<block_type>::digits;
27 dynamic_bitset() =
default;
33 explicit dynamic_bitset(size_type value) {
36 m_blocks.resize(1, 0);
39 m_num_bits = std::numeric_limits<size_type>::digits - clzll(value);
40 m_blocks.resize((m_num_bits + bits_per_block - 1) / bits_per_block);
46 size_type size()
const {
51 std::fill(m_blocks.begin(), m_blocks.end(), 0);
54 void resize(size_type nbits) {
56 m_blocks.resize((nbits + bits_per_block - 1) / bits_per_block);
60 dynamic_bitset& masked_and_not(dynamic_bitset& exclude_mask) {
61 if (exclude_mask.size() > size()) {
62 resize(exclude_mask.size());
63 }
else if (size() > exclude_mask.size()) {
64 exclude_mask.resize(size());
67 for (size_type i = 0; i < m_blocks.size(); ++i) {
68 m_blocks[i] &= ~exclude_mask.m_blocks[i];
75 dynamic_bitset& operator&=(
const dynamic_bitset& rhs) {
79 size_type min_blocks = (m_blocks.size() < rhs.m_blocks.size())
81 : rhs.m_blocks.size();
83 for (size_type i = 0; i < min_blocks; ++i) {
84 m_blocks[i] &= rhs.m_blocks[i];
87 if (m_blocks.size() > rhs.m_blocks.size()) {
88 std::fill(m_blocks.begin() + min_blocks, m_blocks.end(), 0);
95 dynamic_bitset& operator|=(
const dynamic_bitset& rhs) {
96 if (rhs.m_num_bits > m_num_bits) {
97 resize(rhs.m_num_bits);
99 for (size_type i = 0; i < rhs.m_blocks.size(); ++i) {
100 m_blocks[i] |= rhs.m_blocks[i];
107 dynamic_bitset& operator^=(
const dynamic_bitset& rhs) {
108 if (rhs.m_num_bits > m_num_bits) {
109 resize(rhs.m_num_bits);
111 for (size_type i = 0; i < rhs.m_blocks.size(); ++i) {
112 m_blocks[i] ^= rhs.m_blocks[i];
119 dynamic_bitset operator~()
const {
120 dynamic_bitset result(*
this);
121 for (
auto& block : result.m_blocks) {
124 result.zero_unused_bits();
129 dynamic_bitset& operator<<=(size_type shift) {
130 if (shift >= m_num_bits) {
132 std::fill(m_blocks.begin(), m_blocks.end(), 0);
136 size_type block_shift = shift / bits_per_block;
137 size_type bit_shift = shift % bits_per_block;
138 size_type inv_bit_shift = bits_per_block - bit_shift;
140 if (block_shift != 0) {
141 for (size_type i = m_blocks.size(); i-- > block_shift;) {
142 m_blocks[i] = m_blocks[i - block_shift];
144 std::fill(m_blocks.begin(), m_blocks.begin() + block_shift, 0);
147 if (bit_shift != 0) {
148 block_type carry = 0;
149 for (size_type i = block_shift; i < m_blocks.size(); ++i) {
150 block_type temp = m_blocks[i];
151 m_blocks[i] = (temp << bit_shift) | carry;
152 carry = temp >> inv_bit_shift;
160 dynamic_bitset& operator>>=(size_type shift) {
161 if (shift >= m_num_bits) {
163 std::fill(m_blocks.begin(), m_blocks.end(), 0);
167 size_type block_shift = shift / bits_per_block;
168 size_type bit_shift = shift % bits_per_block;
169 size_type inv_bit_shift = bits_per_block - bit_shift;
171 if (block_shift != 0) {
172 for (size_type i = 0; i < m_blocks.size() - block_shift; ++i) {
173 m_blocks[i] = m_blocks[i + block_shift];
175 std::fill(m_blocks.end() - block_shift, m_blocks.end(), 0);
178 if (bit_shift != 0) {
179 block_type carry = 0;
180 for (size_type i = m_blocks.size(); i-- > 0;) {
181 block_type temp = m_blocks[i];
182 m_blocks[i] = (temp >> bit_shift) | carry;
183 carry = temp << inv_bit_shift;
191 friend dynamic_bitset
192 operator&(dynamic_bitset lhs,
const dynamic_bitset& rhs) {
197 friend dynamic_bitset
198 operator|(dynamic_bitset lhs,
const dynamic_bitset& rhs) {
203 friend dynamic_bitset
204 operator^(dynamic_bitset lhs,
const dynamic_bitset& rhs) {
209 friend dynamic_bitset operator<<(dynamic_bitset lhs, size_type shift) {
214 friend dynamic_bitset operator>>(dynamic_bitset lhs, size_type shift) {
220 bool operator[](size_type pos)
const {
221 if (pos >= m_num_bits) {
224 size_type block_index = pos / bits_per_block;
225 size_type bit_index = pos % bits_per_block;
226 return (m_blocks[block_index] & (block_type(1) << bit_index)) != 0;
230 void set(size_type pos,
bool value =
true) {
231 if (pos >= m_num_bits) {
234 size_type block_index = pos / bits_per_block;
235 size_type bit_index = pos % bits_per_block;
237 m_blocks[block_index] |= (block_type(1) << bit_index);
239 m_blocks[block_index] &= ~(block_type(1) << bit_index);
244 void reset(size_type pos) {
249 void flip(size_type pos) {
250 if (pos >= m_num_bits) {
253 size_type block_index = pos / bits_per_block;
254 size_type bit_index = pos % bits_per_block;
255 m_blocks[block_index] ^= (block_type(1) << bit_index);
259 bool operator==(
const dynamic_bitset& rhs)
const {
260 if (m_num_bits != rhs.m_num_bits) {
263 return m_blocks == rhs.m_blocks;
266 bool operator!=(
const dynamic_bitset& rhs)
const {
267 return !(*
this == rhs);
271 size_type count()
const {
273 for (
const auto& block : m_blocks) {
274 cnt += popcount(block);
281 for (
const auto& m_block : m_blocks) {
294 bool contains(
const dynamic_bitset& other)
const {
296 for (
size_t i = 0; i < other.size(); ++i) {
297 if (other.test(i) && !this->test(i)) {
305 bool test(size_type pos)
const {
306 return operator[](pos);
309 std::string to_string()
const {
310 std::string result(m_num_bits,
'0');
312 for (size_type i = 0; i < m_num_bits; ++i) {
314 result[m_num_bits - 1 - i] =
'1';
321 std::vector<block_type> m_blocks;
322 size_t m_num_bits {0};
324 void zero_unused_bits() {
327 size_type unused_bits = bits_per_block - (m_num_bits % bits_per_block);
328 if (unused_bits != bits_per_block) {
329 m_blocks.back() &= (block_type(~0) >> unused_bits);
334 inline static int clzll(
unsigned long long value) {
336 return _BitScanReverse64(&index, value) ? (63 - index) : 64;
339 inline static int clzll(
unsigned long long value) {
340 return value == 0 ? 64 : __builtin_clzll(value);
344 static size_type popcount(block_type x) {
345#if defined(__GNUC__) || defined(__clang__)
346 if constexpr (
sizeof(block_type) <=
sizeof(
unsigned int))
347 return __builtin_popcount(x);
348 else if constexpr (
sizeof(block_type) <=
sizeof(
unsigned long))
349 return __builtin_popcountl(x);
350 else if constexpr (
sizeof(block_type) <=
sizeof(
unsigned long long))
351 return __builtin_popcountll(x);
361#elif defined(_MSC_VER)
362 if constexpr (
sizeof(block_type) ==
sizeof(
unsigned int))
363 return __popcnt(
static_cast<unsigned int>(x));
364 else if constexpr (
sizeof(block_type) ==
sizeof(
unsigned long long))
365 return __popcnt64(
static_cast<unsigned long long>(x));
385 friend struct std::hash<dynamic_bitset>;