28 static constexpr bool is_const = std::is_const_v<integer_type>;
30 bit_view() noexcept = default;
31 bit_view(std::span<
integer_type> span) noexcept : m_integers(span) {}
38 template <typename INTEGER>
42 using difference_type = ptrdiff_t;
44 [[nodiscard]]
constexpr value_type operator*()
const
50 [[nodiscard]]
constexpr difference_type operator-(base_iterator<U> other)
const
52 return bit_number - other.bit_number;
54 constexpr base_iterator& operator++()
56 if (bit_number < bit_view(integers).size())
60 constexpr base_iterator operator++(
int)
66 constexpr base_iterator& operator--()
72 constexpr base_iterator operator--(
int)
78 constexpr base_iterator& operator+=(difference_type n)
80 bit_number = std::clamp(bit_number + n, 0, bit_view(integers).size());
83 constexpr base_iterator& operator-=(difference_type n)
85 bit_number = std::clamp(bit_number + n, 0, bit_view(integers).size());
89 [[nodiscard]]
constexpr base_iterator operator+(difference_type n)
const;
90 friend constexpr base_iterator operator+(difference_type, base_iterator);
92 [[nodiscard]]
constexpr base_iterator operator-(difference_type)
const;
93 [[nodiscard]]
constexpr value_type operator[](difference_type)
const;
96 [[nodiscard]]
constexpr bool operator==(base_iterator<U>
const& other)
const noexcept
98 return integers.data() == other.integers.data() && integers.size() == other.integers.size() && bit_number == other.bit_number;
101 template <
typename U>
102 [[nodiscard]]
constexpr std::strong_ordering operator<=>(base_iterator<U>
const& other)
const noexcept
104 return std::tie(integers.data(), integers.size(), bit_number) <=> std::tie(other.integers.data(), other.integers.size(), other.bit_number);
107 base_iterator() noexcept = default;
109 base_iterator(base_iterator const&) noexcept = default;
110 base_iterator(base_iterator&&) noexcept = default;
111 base_iterator& operator=(base_iterator const&) noexcept = default;
112 base_iterator& operator=(base_iterator&&) noexcept = default;
116 base_iterator(std::span<INTEGER> span,
size_t num) noexcept : integers(span), bit_number(num) {}
117 friend struct bit_view;
119 [[nodiscard]]
constexpr INTEGER& integer_at_bit(
size_t bit)
const { return ::ghassanpl::at(integers, bit / integer_type_bit_count); }
120 [[nodiscard]]
static constexpr size_t real_bit_at_bit(
size_t bit) {
return bit % integer_type_bit_count; }
122 std::span<INTEGER> integers;
126 using iterator = base_iterator<INTEGER_TYPE>;
127 using const_iterator = base_iterator<INTEGER_TYPE const>;
129 static_assert(std::random_access_iterator<iterator>);
131 [[nodiscard]]
constexpr const_iterator begin()
const {
return const_iterator{ m_integers, 0 }; }
132 [[nodiscard]]
constexpr const_iterator end()
const {
return const_iterator{ m_integers, size() }; }
133 [[nodiscard]]
constexpr iterator begin() {
return iterator{ m_integers, 0 }; }
134 [[nodiscard]]
constexpr iterator end() {
return iterator{ m_integers, size() }; }
135 [[nodiscard]]
constexpr const_iterator cbegin();
136 [[nodiscard]]
constexpr const_iterator cend();
138 [[nodiscard]]
constexpr element_type at(
size_t index)
requires (!is_const)
140 return bit_reference<integer_type>{ integer_at_bit(index), real_bit_at_bit(index) };
143 [[nodiscard]]
constexpr element_type at(
size_t index)
const
145 return bit_reference<integer_type const>{ integer_at_bit(index), real_bit_at_bit(index) };
148 [[nodiscard]]
constexpr element_type operator[](
size_t index)
requires (!is_const)
150 return bit_reference<integer_type>{ integer_at_bit_unsafe(index), real_bit_at_bit(index) };
153 [[nodiscard]]
constexpr element_type operator[](
size_t index)
const
155 return bit_reference<integer_type const>{ integer_at_bit_unsafe(index), real_bit_at_bit(index) };
158 constexpr void set(
size_t index)
requires (!is_const);
159 constexpr void clear(
size_t index)
requires (!is_const);
160 [[nodiscard]]
constexpr bool is_set(
size_t index)
const;
162 constexpr void set_all()
requires (!is_const);
163 constexpr void clear_all()
requires (!is_const);
164 constexpr void toggle_all()
requires (!is_const);
166 [[nodiscard]]
constexpr bool are_all_set()
const;
168 template <
typename U>
169 [[nodiscard]]
constexpr bool are_all_set(bit_view<U>
const& bit_set)
const;
171 [[nodiscard]]
constexpr bool are_any_set()
const;
173 template <
typename U>
174 [[nodiscard]]
constexpr bool are_any_set(bit_view<U>
const& bit_set)
const;
176 [[nodiscard]]
constexpr inline size_t size() const noexcept {
return size_t(m_integers.size() * integer_type_bit_count); }
178 [[nodiscard]]
constexpr integer_type& integer_at_bit(
size_t bit) { return ::ghassanpl::at(m_integers, bit / integer_type_bit_count); }
179 [[nodiscard]]
constexpr integer_type const& integer_at_bit(
size_t bit)
const { return ::ghassanpl::at(m_integers, bit / integer_type_bit_count); }
181 [[nodiscard]]
static constexpr size_t real_bit_at_bit(
size_t bit) {
return bit % integer_type_bit_count; }
183 [[nodiscard]]
constexpr auto integers() const noexcept {
return m_integers; }
187 template <
typename U>
188 constexpr void copy_to(bit_view<U>& target)
const requires (!std::is_const_v<U>);
189 template <
typename U>
190 constexpr void and_with(bit_view<U>& target)
const requires (!std::is_const_v<U>);
191 template <
typename U>
192 constexpr void or_with(bit_view<U>& target)
const requires (!std::is_const_v<U>);
193 template <
typename U>
194 constexpr void xor_with(bit_view<U>& target)
const requires (!std::is_const_v<U>);
196 [[nodiscard]]
constexpr size_t find_first_bit(
bool that_is)
const noexcept;
197 [[nodiscard]]
constexpr size_t find_last_bit(
bool that_is)
const noexcept;
198 [[nodiscard]]
constexpr size_t count_bits(
bool that_are)
const noexcept;
202 [[nodiscard]]
constexpr integer_type& integer_at_bit_unsafe(
size_t bit) {
return m_integers[bit / integer_type_bit_count]; }
203 [[nodiscard]]
constexpr integer_type const& integer_at_bit_unsafe(
size_t bit)
const {
return m_integers[bit / integer_type_bit_count]; }
205 std::span<integer_type> m_integers;