67 template <
typename B, null_count_policy NCP = tracking_null_count<>>
68 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
77 std::remove_cvref_t<storage_type>>;
78 using block_type =
typename storage_type_without_cvrefpointer::value_type;
83 using size_type =
typename storage_type_without_cvrefpointer::size_type;
85 using difference_type =
typename storage_type_without_cvrefpointer::difference_type;
123 [[nodiscard]] constexpr
bool empty() const noexcept;
312 if constexpr (std::is_pointer_v<storage_type>)
329 if constexpr (std::is_pointer_v<storage_type>)
358 return std::move(m_buffer);
398 requires(NCP::track_null_count);
464 template <
std::input_iterator InputIt>
534 static constexpr
std::
size_t s_bits_per_block = sizeof(
block_type) * CHAR_BIT;
562 [[nodiscard]] constexpr
size_type count_extra_bits() const noexcept;
590 requires
std::
ranges::random_access_range<
std::remove_pointer_t<B>>
596 template <
typename B, null_count_policy NCP>
597 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
603 template <
typename B, null_count_policy NCP>
604 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
610 template <
typename B, null_count_policy NCP>
611 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
617 template <
typename B, null_count_policy NCP>
618 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
624 template <
typename B, null_count_policy NCP>
625 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
629 return NCP::null_count();
632 template <
typename B, null_count_policy NCP>
633 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
640 template <
typename B, null_count_policy NCP>
641 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
647 template <
typename B, null_count_policy NCP>
648 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
652 if constexpr (std::is_pointer_v<storage_type>)
654 if (m_buffer ==
nullptr)
659 if (
data() ==
nullptr)
663 const size_type actual_pos = m_offset + pos;
666 return buffer().data()[block_index(actual_pos)] & bit_mask(actual_pos);
669 template <
typename B, null_count_policy NCP>
670 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
674 const size_type actual_pos = m_offset + pos;
675 const size_type target_block = block_index(actual_pos);
677 if (
data() ==
nullptr)
694 throw std::runtime_error(
"Cannot set a bit in a null buffer.");
704 buffer().resize(target_block + 1, true_value);
714 const bool old_value = block & bit_mask(actual_pos);
717 block |= bit_mask(actual_pos);
726 template <
typename B, null_count_policy NCP>
727 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
730 if constexpr (std::is_pointer_v<storage_type>)
732 if (m_buffer ==
nullptr)
740 template <
typename B, null_count_policy NCP>
741 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
747 template <
typename B, null_count_policy NCP>
748 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
754 template <
typename B, null_count_policy NCP>
755 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
759 swap(m_buffer, rhs.m_buffer);
760 swap(m_size, rhs.m_size);
761 swap(m_offset, rhs.m_offset);
765 template <
typename B, null_count_policy NCP>
766 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
772 template <
typename B, null_count_policy NCP>
773 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
779 template <
typename B, null_count_policy NCP>
780 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
786 template <
typename B, null_count_policy NCP>
787 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
793 template <
typename B, null_count_policy NCP>
794 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
800 template <
typename B, null_count_policy NCP>
801 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
807 template <
typename B, null_count_policy NCP>
808 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
813 throw std::out_of_range(
814 "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size"
815 + std::to_string(
size()) +
" at index " + std::to_string(pos)
821 template <
typename B, null_count_policy NCP>
822 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
827 throw std::out_of_range(
828 "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size"
829 + std::to_string(
size()) +
" at index " + std::to_string(pos)
835 template <
typename B, null_count_policy NCP>
836 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
843 template <
typename B, null_count_policy NCP>
844 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
848 if (
data() ==
nullptr)
855 template <
typename B, null_count_policy NCP>
856 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
860 return (*
this)[
size() - 1];
863 template <
typename B, null_count_policy NCP>
864 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
868 if (
data() ==
nullptr)
872 return (*
this)[
size() - 1];
875 template <
typename B, null_count_policy NCP>
876 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
878 : m_buffer(
std::move(buf))
885 template <
typename B, null_count_policy NCP>
886 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
888 : m_buffer(
std::move(buf))
895 template <
typename B, null_count_policy NCP>
896 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
903 requires(NCP::track_null_count)
904 : m_buffer(
std::move(buf))
911 template <
typename B, null_count_policy NCP>
912 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
915 return bits_count / s_bits_per_block +
static_cast<size_type>(bits_count % s_bits_per_block != 0);
918 template <
typename B, null_count_policy NCP>
919 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
920 constexpr auto dynamic_bitset_base<B, NCP>::block_index(size_type pos)
noexcept -> size_type
922 return pos / s_bits_per_block;
925 template <
typename B, null_count_policy NCP>
926 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
927 constexpr auto dynamic_bitset_base<B, NCP>::bit_index(size_type pos)
noexcept -> size_type
929 return pos % s_bits_per_block;
932 template <
typename B, null_count_policy NCP>
933 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
934 constexpr auto dynamic_bitset_base<B, NCP>::bit_mask(size_type pos)
noexcept -> block_type
936 const size_type bit = bit_index(pos);
937 return static_cast<block_type
>(block_type(1) << bit);
940 template <
typename B, null_count_policy NCP>
941 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
942 constexpr auto dynamic_bitset_base<B, NCP>::count_extra_bits() const noexcept -> size_type
944 return bit_index(
size() + m_offset);
947 template <
typename B, null_count_policy NCP>
948 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
951 if (
data() ==
nullptr)
955 const size_type extra_bits = count_extra_bits();
962 template <
typename B, null_count_policy NCP>
963 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
966 if ((
data() ==
nullptr) && b)
977 if (new_block_count != old_block_count)
979 if (
data() ==
nullptr)
983 buffer.resize(old_block_count, true_value);
985 const size_type old_extra_bits = bit_index(old_size + m_offset);
986 if (old_extra_bits != 0)
991 buffer.resize(new_block_count, value);
997 const size_type old_extra_bits = bit_index(old_size + m_offset);
998 if (old_extra_bits > 0)
1001 auto& last_block =
buffer.data()[old_last_block_idx];
1005 const auto mask =
static_cast<block_type>(value << old_extra_bits);
1022 template <
typename B, null_count_policy NCP>
1023 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1031 template <
typename B, null_count_policy NCP>
1032 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1036 return insert(pos, 1, value);
1039 template <
typename B, null_count_policy NCP>
1040 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1046 const auto index =
static_cast<size_type>(std::distance(
cbegin(), pos));
1047 if (
data() ==
nullptr && value)
1054 const size_type new_size = old_size + count;
1059 const size_type bits_to_shift = old_size - index;
1060 if (bits_to_shift > 0)
1062 shift_bits_right(index + m_offset, bits_to_shift, count);
1066 fill_bits(index + m_offset, count, value);
1075 template <
typename B, null_count_policy NCP>
1076 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1077 template <std::input_iterator InputIt>
1081 const auto index =
static_cast<size_type>(std::distance(
cbegin(), pos));
1082 const auto count =
static_cast<size_type>(std::distance(first, last));
1083 if (
data() ==
nullptr)
1102 const size_type new_size = old_size + count;
1107 const size_type bits_to_shift = old_size - index;
1108 if (bits_to_shift > 0)
1110 shift_bits_right(index + m_offset, bits_to_shift, count);
1116 set(index + i, *first++);
1125 template <
typename B, null_count_policy NCP>
1126 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1130 return insert(pos, value);
1133 template <
typename B, null_count_policy NCP>
1134 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1140 return erase(pos, pos + 1);
1143 template <
typename B, null_count_policy NCP>
1144 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1152 const auto first_index =
static_cast<size_type>(std::distance(
cbegin(), first));
1153 const auto last_index =
static_cast<size_type>(std::distance(
cbegin(), last));
1154 const size_type count = last_index - first_index;
1156 if (
data() ==
nullptr)
1170 if (bits_to_move > 0)
1173 for (
size_type i = 0; i < bits_to_move; ++i)
1175 const bool bit_value =
test(last_index + i);
1176 set(first_index + i, bit_value);
1182 return iterator(
this, first_index);
1185 template <
typename B, null_count_policy NCP>
1186 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1192 template <
typename B, null_count_policy NCP>
1193 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1203 template <
typename B, null_count_policy NCP>
1204 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1206 dynamic_bitset_base<B, NCP>::shift_bits_right(size_type start, size_type length, size_type shift_amount)
1208 if (length == 0 || shift_amount == 0)
1213 auto* blocks = data();
1214 const size_type src_start_bit = start;
1215 const size_type dst_start_bit = start + shift_amount;
1219 size_type remaining = length;
1221 while (remaining > 0)
1224 const size_type current_offset = remaining - 1;
1225 const size_type src_bit = src_start_bit + current_offset;
1226 const size_type dst_bit = dst_start_bit + current_offset;
1228 const size_type src_block_idx = block_index(src_bit);
1229 const size_type dst_block_idx = block_index(dst_bit);
1230 const size_type src_bit_offset = bit_index(src_bit);
1231 const size_type dst_bit_offset = bit_index(dst_bit);
1235 const size_type bits_available_in_src_block = src_bit_offset + 1;
1236 const size_type bits_available_in_dst_block = dst_bit_offset + 1;
1237 const size_type bits_this_iter = std::min(
1238 {remaining, bits_available_in_src_block, bits_available_in_dst_block}
1242 const size_type extract_start_offset = src_bit_offset - (bits_this_iter - 1);
1243 const block_type mask =
static_cast<block_type
>(
1244 ((block_type(1) << bits_this_iter) - 1) << extract_start_offset
1246 const block_type src_bits =
static_cast<block_type
>(
1247 (blocks[src_block_idx] & mask) >> extract_start_offset
1251 const size_type write_start_offset = dst_bit_offset - (bits_this_iter - 1);
1252 const block_type dst_mask =
static_cast<block_type
>(
1253 ((block_type(1) << bits_this_iter) - 1) << write_start_offset
1255 blocks[dst_block_idx] =
static_cast<block_type
>(
1256 (blocks[dst_block_idx] & ~dst_mask) | ((src_bits << write_start_offset) & dst_mask)
1259 remaining -= bits_this_iter;
1263 template <
typename B, null_count_policy NCP>
1264 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1265 constexpr void dynamic_bitset_base<B, NCP>::fill_bits(size_type start, size_type count, value_type value)
1272 auto* blocks = data();
1273 const block_type fill_pattern = value ?
static_cast<block_type
>(~block_type(0)) : block_type(0);
1275 size_type current_bit = start;
1276 size_type remaining =
count;
1279 const size_type first_bit_offset = bit_index(current_bit);
1280 if (first_bit_offset != 0)
1282 const size_type bits_in_first = std::min(remaining, s_bits_per_block - first_bit_offset);
1283 const block_type mask =
static_cast<block_type
>(
1284 ((block_type(1) << bits_in_first) - 1) << first_bit_offset
1287 const size_type block_idx = block_index(current_bit);
1290 blocks[block_idx] |= mask;
1294 blocks[block_idx] &= ~mask;
1297 current_bit += bits_in_first;
1298 remaining -= bits_in_first;
1302 while (remaining >= s_bits_per_block)
1304 blocks[block_index(current_bit)] = fill_pattern;
1305 current_bit += s_bits_per_block;
1306 remaining -= s_bits_per_block;
1312 const block_type mask =
static_cast<block_type
>((block_type(1) << remaining) - 1);
1313 const size_type block_idx = block_index(current_bit);
1316 blocks[block_idx] |= mask;
1320 blocks[block_idx] &= ~mask;
Iterator used to iterate over the bits of a dynamic bitset as if they were addressable values.
A proxy reference class that provides mutable access to individual bits in a bitset.
constexpr const_reference at(size_type pos) const
constexpr reference operator[](size_type i)
Accesses a bit without bounds checking.
constexpr reference front()
constexpr size_type block_count() const noexcept
typename storage_type_without_cvrefpointer::value_type block_type
constexpr dynamic_bitset_base(const dynamic_bitset_base &)=default
constexpr block_type * data() noexcept
constexpr void set(size_type pos, value_type value)
constexpr void set_size(size_type new_size) noexcept
static constexpr size_type compute_block_count(size_type bits_count) noexcept
Computes the number of blocks needed to store the specified number of bits.
constexpr const_iterator cbegin() const
constexpr iterator insert(const_iterator pos, value_type value)
constexpr storage_type_without_cvrefpointer & buffer() noexcept
Returns a mutable reference to the underlying buffer.
bitset_reference< self_type > reference
constexpr iterator erase(const_iterator pos)
constexpr bool test(size_type pos) const
constexpr iterator emplace(const_iterator pos, value_type value)
constexpr void resize(size_type n, value_type b=false)
bitset_iterator< self_type, true > const_iterator
constexpr void clear() noexcept
constexpr size_type size() const noexcept
Returns the number of bits in the bitset.
bitset_iterator< self_type, false > iterator
constexpr const storage_type_without_cvrefpointer & buffer() const noexcept
typename storage_type_without_cvrefpointer::size_type size_type
constexpr const_iterator cend() const
constexpr bool empty() const noexcept
constexpr dynamic_bitset_base(storage_type buffer, size_type size)
Constructs a bitset with the given storage and size.
storage_type extract_storage() noexcept
Extracts the underlying storage (move operation).
std::remove_pointer_t< std::remove_cvref_t< storage_type > > storage_type_without_cvrefpointer
constexpr ~dynamic_bitset_base()=default
tracking_null_count<> null_count_policy_type
constexpr size_type null_count() const noexcept
constexpr dynamic_bitset_base(dynamic_bitset_base &&) noexcept=default
constexpr reference back()
constexpr size_type offset() const noexcept
constexpr dynamic_bitset_base(storage_type buffer, size_type size, size_type offset)
Constructs a bitset with the given storage, size, and null count.
constexpr void push_back(value_type value)
constexpr void swap(self_type &rhs) noexcept
constexpr iterator begin()
constexpr dynamic_bitset_base(storage_type buffer, size_type size, size_type offset, size_type null_count)
Constructs a bitset with the given storage, size, offset, and null count.
constexpr void set_offset(size_type offset) noexcept
constexpr void zero_unused_bits()
constexpr void pop_back()
dynamic_bitset_base< buffer< T >, tracking_null_count<> > self_type
typename storage_type_without_cvrefpointer::difference_type difference_type
void initialize_null_count(const BlockType *data, size_type bit_size, size_type block_count, size_type offset=0) noexcept
Initializes the null count by counting bits in the buffer.
constexpr void set_null_count(size_type count) noexcept
constexpr void swap_null_count(tracking_null_count &other) noexcept
void recompute_null_count(const BlockType *data, size_type bit_size, size_type block_count, size_type offset=0) noexcept
Recomputes the null count from the buffer.
constexpr void clear_null_count() noexcept
constexpr void update_null_count(bool old_value, bool new_value) noexcept
static constexpr bool track_null_count
Concept that checks if a type is a valid null count policy.
#define SPARROW_ASSERT_TRUE(expr__)
SPARROW_API int count(const std::string &key, int disabled_value=0)
constexpr std::size_t size(typelist< T... >={})
Gets the count of types contained in a typelist.
Extensions to the C++ standard library.