66 template <
typename B, null_count_policy NCP = tracking_null_count<>>
67 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
76 std::remove_cvref_t<storage_type>>;
77 using block_type =
typename storage_type_without_cvrefpointer::value_type;
82 using size_type =
typename storage_type_without_cvrefpointer::size_type;
84 using difference_type =
typename storage_type_without_cvrefpointer::difference_type;
122 [[nodiscard]] constexpr
bool empty() const noexcept;
311 if constexpr (std::is_pointer_v<storage_type>)
328 if constexpr (std::is_pointer_v<storage_type>)
357 return std::move(m_buffer);
397 requires(NCP::track_null_count);
463 template <
std::input_iterator InputIt>
533 static constexpr
std::
size_t s_bits_per_block = sizeof(
block_type) * CHAR_BIT;
561 [[nodiscard]] constexpr
size_type count_extra_bits() const noexcept;
589 requires
std::
ranges::random_access_range<
std::remove_pointer_t<B>>
595 template <
typename B, null_count_policy NCP>
596 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
602 template <
typename B, null_count_policy NCP>
603 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
609 template <
typename B, null_count_policy NCP>
610 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
616 template <
typename B, null_count_policy NCP>
617 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
623 template <
typename B, null_count_policy NCP>
624 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
628 return NCP::null_count();
631 template <
typename B, null_count_policy NCP>
632 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
639 template <
typename B, null_count_policy NCP>
640 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
646 template <
typename B, null_count_policy NCP>
647 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
651 if constexpr (std::is_pointer_v<storage_type>)
653 if (m_buffer ==
nullptr)
658 if (
data() ==
nullptr)
662 const size_type actual_pos = m_offset + pos;
665 return buffer().data()[block_index(actual_pos)] & bit_mask(actual_pos);
668 template <
typename B, null_count_policy NCP>
669 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
673 const size_type actual_pos = m_offset + pos;
674 const size_type target_block = block_index(actual_pos);
676 if (
data() ==
nullptr)
693 throw std::runtime_error(
"Cannot set a bit in a null buffer.");
703 buffer().resize(target_block + 1, true_value);
713 const bool old_value = block & bit_mask(actual_pos);
716 block |= bit_mask(actual_pos);
725 template <
typename B, null_count_policy NCP>
726 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
729 if constexpr (std::is_pointer_v<storage_type>)
731 if (m_buffer ==
nullptr)
739 template <
typename B, null_count_policy NCP>
740 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
746 template <
typename B, null_count_policy NCP>
747 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
753 template <
typename B, null_count_policy NCP>
754 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
758 swap(m_buffer, rhs.m_buffer);
759 swap(m_size, rhs.m_size);
760 swap(m_offset, rhs.m_offset);
764 template <
typename B, null_count_policy NCP>
765 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
771 template <
typename B, null_count_policy NCP>
772 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
778 template <
typename B, null_count_policy NCP>
779 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
785 template <
typename B, null_count_policy NCP>
786 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
792 template <
typename B, null_count_policy NCP>
793 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
799 template <
typename B, null_count_policy NCP>
800 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
806 template <
typename B, null_count_policy NCP>
807 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
812 throw std::out_of_range(
813 "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size"
814 + std::to_string(
size()) +
" at index " + std::to_string(pos)
820 template <
typename B, null_count_policy NCP>
821 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
826 throw std::out_of_range(
827 "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size"
828 + std::to_string(
size()) +
" at index " + std::to_string(pos)
834 template <
typename B, null_count_policy NCP>
835 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
842 template <
typename B, null_count_policy NCP>
843 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
847 if (
data() ==
nullptr)
854 template <
typename B, null_count_policy NCP>
855 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
859 return (*
this)[
size() - 1];
862 template <
typename B, null_count_policy NCP>
863 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
867 if (
data() ==
nullptr)
871 return (*
this)[
size() - 1];
874 template <
typename B, null_count_policy NCP>
875 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
877 : m_buffer(
std::move(buf))
884 template <
typename B, null_count_policy NCP>
885 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
887 : m_buffer(
std::move(buf))
894 template <
typename B, null_count_policy NCP>
895 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
902 requires(NCP::track_null_count)
903 : m_buffer(
std::move(buf))
910 template <
typename B, null_count_policy NCP>
911 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
914 return bits_count / s_bits_per_block +
static_cast<size_type>(bits_count % s_bits_per_block != 0);
917 template <
typename B, null_count_policy NCP>
918 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
919 constexpr auto dynamic_bitset_base<B, NCP>::block_index(size_type pos)
noexcept -> size_type
921 return pos / s_bits_per_block;
924 template <
typename B, null_count_policy NCP>
925 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
926 constexpr auto dynamic_bitset_base<B, NCP>::bit_index(size_type pos)
noexcept -> size_type
928 return pos % s_bits_per_block;
931 template <
typename B, null_count_policy NCP>
932 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
933 constexpr auto dynamic_bitset_base<B, NCP>::bit_mask(size_type pos)
noexcept -> block_type
935 const size_type bit = bit_index(pos);
936 return static_cast<block_type
>(block_type(1) << bit);
939 template <
typename B, null_count_policy NCP>
940 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
941 constexpr auto dynamic_bitset_base<B, NCP>::count_extra_bits() const noexcept -> size_type
943 return bit_index(
size() + m_offset);
946 template <
typename B, null_count_policy NCP>
947 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
950 if (
data() ==
nullptr)
954 const size_type extra_bits = count_extra_bits();
961 template <
typename B, null_count_policy NCP>
962 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
965 if ((
data() ==
nullptr) && b)
976 if (new_block_count != old_block_count)
978 if (
data() ==
nullptr)
982 buffer.resize(old_block_count, true_value);
984 const size_type old_extra_bits = bit_index(old_size + m_offset);
985 if (old_extra_bits != 0)
990 buffer.resize(new_block_count, value);
996 const size_type old_extra_bits = bit_index(old_size + m_offset);
997 if (old_extra_bits > 0)
1000 auto& last_block =
buffer.data()[old_last_block_idx];
1004 const auto mask =
static_cast<block_type>(value << old_extra_bits);
1021 template <
typename B, null_count_policy NCP>
1022 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1030 template <
typename B, null_count_policy NCP>
1031 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1035 return insert(pos, 1, value);
1038 template <
typename B, null_count_policy NCP>
1039 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1045 const auto index =
static_cast<size_type>(std::distance(
cbegin(), pos));
1046 if (
data() ==
nullptr && value)
1053 const size_type new_size = old_size + count;
1058 const size_type bits_to_shift = old_size - index;
1059 if (bits_to_shift > 0)
1061 shift_bits_right(index + m_offset, bits_to_shift, count);
1065 fill_bits(index + m_offset, count, value);
1074 template <
typename B, null_count_policy NCP>
1075 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1076 template <std::input_iterator InputIt>
1080 const auto index =
static_cast<size_type>(std::distance(
cbegin(), pos));
1081 const auto count =
static_cast<size_type>(std::distance(first, last));
1082 if (
data() ==
nullptr)
1101 const size_type new_size = old_size + count;
1106 const size_type bits_to_shift = old_size - index;
1107 if (bits_to_shift > 0)
1109 shift_bits_right(index + m_offset, bits_to_shift, count);
1115 set(index + i, *first++);
1124 template <
typename B, null_count_policy NCP>
1125 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1129 return insert(pos, value);
1132 template <
typename B, null_count_policy NCP>
1133 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1139 return erase(pos, pos + 1);
1142 template <
typename B, null_count_policy NCP>
1143 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1151 const auto first_index =
static_cast<size_type>(std::distance(
cbegin(), first));
1152 const auto last_index =
static_cast<size_type>(std::distance(
cbegin(), last));
1153 const size_type count = last_index - first_index;
1155 if (
data() ==
nullptr)
1169 if (bits_to_move > 0)
1172 for (
size_type i = 0; i < bits_to_move; ++i)
1174 const bool bit_value =
test(last_index + i);
1175 set(first_index + i, bit_value);
1181 return iterator(
this, first_index);
1184 template <
typename B, null_count_policy NCP>
1185 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1191 template <
typename B, null_count_policy NCP>
1192 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1202 template <
typename B, null_count_policy NCP>
1203 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1205 dynamic_bitset_base<B, NCP>::shift_bits_right(size_type start, size_type length, size_type shift_amount)
1207 if (length == 0 || shift_amount == 0)
1212 auto* blocks = data();
1213 const size_type src_start_bit = start;
1214 const size_type dst_start_bit = start + shift_amount;
1218 size_type remaining = length;
1220 while (remaining > 0)
1223 const size_type current_offset = remaining - 1;
1224 const size_type src_bit = src_start_bit + current_offset;
1225 const size_type dst_bit = dst_start_bit + current_offset;
1227 const size_type src_block_idx = block_index(src_bit);
1228 const size_type dst_block_idx = block_index(dst_bit);
1229 const size_type src_bit_offset = bit_index(src_bit);
1230 const size_type dst_bit_offset = bit_index(dst_bit);
1234 const size_type bits_available_in_src_block = src_bit_offset + 1;
1235 const size_type bits_available_in_dst_block = dst_bit_offset + 1;
1236 const size_type bits_this_iter = std::min(
1237 {remaining, bits_available_in_src_block, bits_available_in_dst_block}
1241 const size_type extract_start_offset = src_bit_offset - (bits_this_iter - 1);
1242 const block_type mask =
static_cast<block_type
>(
1243 ((block_type(1) << bits_this_iter) - 1) << extract_start_offset
1245 const block_type src_bits =
static_cast<block_type
>(
1246 (blocks[src_block_idx] & mask) >> extract_start_offset
1250 const size_type write_start_offset = dst_bit_offset - (bits_this_iter - 1);
1251 const block_type dst_mask =
static_cast<block_type
>(
1252 ((block_type(1) << bits_this_iter) - 1) << write_start_offset
1254 blocks[dst_block_idx] =
static_cast<block_type
>(
1255 (blocks[dst_block_idx] & ~dst_mask) | ((src_bits << write_start_offset) & dst_mask)
1258 remaining -= bits_this_iter;
1262 template <
typename B, null_count_policy NCP>
1263 requires std::ranges::random_access_range<std::remove_pointer_t<B>>
1264 constexpr void dynamic_bitset_base<B, NCP>::fill_bits(size_type start, size_type count, value_type value)
1271 auto* blocks = data();
1272 const block_type fill_pattern = value ?
static_cast<block_type
>(~block_type(0)) : block_type(0);
1274 size_type current_bit = start;
1275 size_type remaining =
count;
1278 const size_type first_bit_offset = bit_index(current_bit);
1279 if (first_bit_offset != 0)
1281 const size_type bits_in_first = std::min(remaining, s_bits_per_block - first_bit_offset);
1282 const block_type mask =
static_cast<block_type
>(
1283 ((block_type(1) << bits_in_first) - 1) << first_bit_offset
1286 const size_type block_idx = block_index(current_bit);
1289 blocks[block_idx] |= mask;
1293 blocks[block_idx] &= ~mask;
1296 current_bit += bits_in_first;
1297 remaining -= bits_in_first;
1301 while (remaining >= s_bits_per_block)
1303 blocks[block_index(current_bit)] = fill_pattern;
1304 current_bit += s_bits_per_block;
1305 remaining -= s_bits_per_block;
1311 const block_type mask =
static_cast<block_type
>((block_type(1) << remaining) - 1);
1312 const size_type block_idx = block_index(current_bit);
1315 blocks[block_idx] |= mask;
1319 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.