41 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
49 using block_type =
typename storage_type_without_cvrefpointer::value_type;
53 using size_type =
typename storage_type_without_cvrefpointer::size_type;
54 using difference_type =
typename storage_type_without_cvrefpointer::difference_type;
59 [[nodiscard]] constexpr
bool empty() const noexcept;
92 if constexpr (std::is_pointer_v<storage_type>)
104 if constexpr (std::is_pointer_v<storage_type>)
120 return std::move(m_buffer);
140 template <
std::input_iterator InputIt>
152 static constexpr
std::
size_t s_bits_per_block = sizeof(
block_type) * CHAR_BIT;
157 [[nodiscard]]
size_type count_non_null() const noexcept;
158 [[nodiscard]] constexpr
size_type count_extra_bits() const noexcept;
159 constexpr
void zero_unused_bits();
160 constexpr
void update_null_count(
bool old_value,
bool new_value);
171 template <typename B>
172 requires
std::ranges::random_access_range<
std::remove_pointer_t<B>>
178 template <
typename B>
179 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
185 template <
typename B>
186 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
192 template <
typename B>
193 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
201 template <
typename B>
202 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
208 template <
typename B>
209 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
213 if (
data() ==
nullptr)
217 return !m_null_count ||
buffer().data()[block_index(pos)] & bit_mask(pos);
220 template <
typename B>
221 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
227 const bool old_value = block & bit_mask(pos);
230 block |= bit_mask(pos);
236 update_null_count(old_value, value);
239 template <
typename B>
240 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
246 template <
typename B>
247 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
253 template <
typename B>
254 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
260 template <
typename B>
261 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
265 swap(m_buffer, rhs.m_buffer);
266 swap(m_size, rhs.m_size);
267 swap(m_null_count, rhs.m_null_count);
270 template <
typename B>
271 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
277 template <
typename B>
278 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
282 return iterator(
this, block,
size() % s_bits_per_block);
285 template <
typename B>
286 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
292 template <
typename B>
293 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
299 template <
typename B>
300 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
306 template <
typename B>
307 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
314 template <
typename B>
315 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
320 throw std::out_of_range(
321 "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size"
322 + std::to_string(
size()) +
" at index " + std::to_string(pos)
328 template <
typename B>
329 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
334 throw std::out_of_range(
335 "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size"
336 + std::to_string(
size()) +
" at index " + std::to_string(pos)
342 template <
typename B>
343 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
350 template <
typename B>
351 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
355 if (
data() ==
nullptr)
362 template <
typename B>
363 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
367 return (*
this)[
size() - 1];
370 template <
typename B>
371 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
375 if (
data() ==
nullptr)
379 return (*
this)[
size() - 1];
382 template <
typename B>
383 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
385 : m_buffer(
std::move(buf))
387 , m_null_count(m_size - count_non_null())
389 if constexpr (!std::is_const_v<block_type>)
395 template <
typename B>
396 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
398 : m_buffer(
std::move(buf))
402 if constexpr (!std::is_const_v<block_type>)
409 template <
typename B>
410 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
413 return bits_count / s_bits_per_block +
static_cast<size_type>(bits_count % s_bits_per_block != 0);
416 template <
typename B>
417 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
418 constexpr auto dynamic_bitset_base<B>::block_index(size_type pos)
noexcept -> size_type
420 return pos / s_bits_per_block;
423 template <
typename B>
424 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
425 constexpr auto dynamic_bitset_base<B>::bit_index(size_type pos)
noexcept -> size_type
427 return pos % s_bits_per_block;
430 template <
typename B>
431 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
432 constexpr auto dynamic_bitset_base<B>::bit_mask(size_type pos)
noexcept -> block_type
434 const size_type bit = bit_index(pos);
435 return static_cast<block_type
>(block_type(1) << bit);
438 template <
typename B>
439 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
440 auto dynamic_bitset_base<B>::count_non_null() const noexcept -> size_type
442 if (data() ==
nullptr)
452 size_t full_blocks = m_size / s_bits_per_block;
453 for (
size_t i = 0; i < full_blocks; ++i)
455 res += std::popcount(
buffer().data()[i]);
459 const size_t bits_count = m_size % s_bits_per_block;
460 const block_type mask = ~block_type(~block_type(0) << bits_count);
461 const block_type block =
buffer().
data()[full_blocks] & mask;
462 res += std::popcount(block);
465 return static_cast<size_t>(res);
468 template <
typename B>
469 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
470 constexpr auto dynamic_bitset_base<B>::count_extra_bits() const noexcept -> size_type
472 return bit_index(
size());
475 template <
typename B>
476 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
477 constexpr void dynamic_bitset_base<B>::zero_unused_bits()
479 if (data() ==
nullptr)
483 const size_type extra_bits = count_extra_bits();
486 buffer().
back() &= block_type(~(~block_type(0) << extra_bits));
490 template <
typename B>
491 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
492 constexpr void dynamic_bitset_base<B>::update_null_count(
bool old_value,
bool new_value)
494 if (new_value && !old_value)
498 else if (!new_value && old_value)
504 template <
typename B>
505 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
512 if (new_block_count != old_block_count)
514 buffer().resize(new_block_count, value);
519 const size_type extra_bits = count_extra_bits();
522 buffer().data()[old_block_count - 1] |=
static_cast<block_type>(value << extra_bits);
527 m_null_count = m_size - count_non_null();
531 template <
typename B>
532 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
540 template <
typename B>
541 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
545 return insert(pos, 1, value);
548 template <
typename B>
549 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
556 const auto index =
static_cast<size_type>(std::distance(
cbegin(), pos));
558 const size_type new_size = old_size + count;
564 for (
size_type i = old_size + count - 1; i >= index + count; --i)
571 set(index + i, value);
574 auto block =
data() + block_index(index);
575 return iterator(
this, block, bit_index(index));
578 template <
typename B>
579 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
580 template <std::input_iterator InputIt>
587 const auto index =
static_cast<size_type>(std::distance(
cbegin(), pos));
590 const size_type new_size = old_size + count;
596 for (
size_type i = old_size + count - 1; i >= index + count; --i)
603 set(index + i, *first++);
606 auto block =
data() + block_index(index);
607 return iterator(
this, block, bit_index(index));
610 template <
typename B>
611 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
615 return insert(pos, value);
618 template <
typename B>
619 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
625 return erase(pos, pos + 1);
628 template <
typename B>
629 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
638 const auto first_index =
static_cast<size_type>(std::distance(
cbegin(), first));
648 const auto last_index =
static_cast<size_type>(std::distance(
cbegin(), last));
649 const size_type count = last_index - first_index;
652 for (
size_type i = 0; i < bit_to_move; ++i)
654 set(first_index + i,
test(last_index + i));
659 auto block =
data() + block_index(first_index);
660 return iterator(
this, block, bit_index(first_index));
663 template <
typename B>
664 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
670 template <
typename B>
671 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
Iterator used to iterate over the bits of a dynamic bitset as if they were addressable values.
Reference proxy used by the bitset_iterator class to make it possible to assign a bit of a bitset as ...
Object that owns a piece of contiguous memory.
constexpr U * data() noexcept
constexpr reference back()
typename storage_type_without_cvrefpointer::value_type block_type
bitset_reference< self_type > reference
constexpr ~dynamic_bitset_base()=default
bitset_iterator< self_type, false > iterator
constexpr iterator insert(const_iterator pos, value_type value)
constexpr const_iterator cbegin() const
constexpr void clear() noexcept
constexpr void push_back(value_type value)
constexpr iterator erase(const_iterator pos)
constexpr reference front()
typename storage_type_without_cvrefpointer::size_type size_type
constexpr bool empty() const noexcept
constexpr reference back()
constexpr iterator emplace(const_iterator pos, value_type value)
dynamic_bitset_base< buffer< T > > self_type
storage_type extract_storage() noexcept
constexpr const_reference at(size_type pos) const
constexpr iterator begin()
constexpr bool test(size_type pos) const
constexpr void resize(size_type n, value_type b=false)
constexpr size_type null_count() const noexcept
bitset_iterator< self_type, true > const_iterator
std::remove_pointer_t< std::remove_cvref_t< storage_type > > storage_type_without_cvrefpointer
static constexpr size_type compute_block_count(size_type bits_count) noexcept
constexpr size_type size() const noexcept
constexpr void pop_back()
constexpr dynamic_bitset_base(dynamic_bitset_base &&) noexcept=default
constexpr void set(size_type pos, value_type value)
typename storage_type_without_cvrefpointer::difference_type difference_type
constexpr size_type block_count() const noexcept
constexpr const storage_type_without_cvrefpointer & buffer() const noexcept
constexpr reference operator[](size_type i)
constexpr dynamic_bitset_base(storage_type buffer, size_type size, size_type null_count)
constexpr dynamic_bitset_base(const dynamic_bitset_base &)=default
constexpr void swap(self_type &) noexcept
constexpr block_type * data() noexcept
constexpr dynamic_bitset_base(storage_type buffer, size_type size)
constexpr const_iterator cend() const
constexpr storage_type_without_cvrefpointer & buffer() noexcept
typename base_type::block_type block_type
#define SPARROW_ASSERT_TRUE(expr__)
constexpr std::size_t size(typelist< T... >={})