GF2++
Loading...
Searching...
No Matches
BitSpan.h
Go to the documentation of this file.
1#pragma once
2// SPDX-FileCopyrightText: 2025 Nessan Fitzmaurice <nzznfitz+gh@icloud.com>
3// SPDX-License-Identifier: MIT
4
8
9#include <gf2/assert.h>
10#include <gf2/BitStore.h>
11
12#include <print>
13
14namespace gf2 {
15
31template<unsigned_word Word>
32class BitSpan : public BitStore<BitSpan<Word>> {
33private:
34 Word* m_begin; // A pointer to the first word containing bits in the span (it may be partially occupied).
35 u8 m_offset; // The bit-span begins at this bit-offset inside `m_begin[0]`.
36 usize m_size; // The number of bits in the span..
37 usize m_words; // We cache the total number of synthesized words the span generates.
38
39public:
41 static constexpr usize bits_per_word = std::numeric_limits<Word>::digits;
42
43 // The underlying store really has words of this type (where we are remove any `const` qualifier).
44 using word_type = std::remove_const_t<Word>;
45
48
69 BitSpan(Word* begin, u8 offset, usize size) {
70
71 // Check that the span is non-empty and that the begin bit is valid.
72 gf2_debug_assert(size > 0, "We do not allow empty bit-spans.");
73 gf2_debug_assert(offset < bits_per_word, "Span begins at bit-offset {} > bits in a word ({})!", offset,
75
76 // Set the member variables.
77 m_begin = begin;
78 m_offset = offset;
79 m_size = size;
80
81 // Cache the total number of synthesized words needed to store all the bits in the span.
82 m_words = gf2::words_needed<Word>(m_size);
83 }
84
88
97 constexpr usize size() const { return m_size; }
98
113 constexpr usize words() const { return m_words; }
114
130 constexpr word_type word(usize i) const {
131 // Get the recipe for the "word" at index `i` (we may need two real words to synthesise it).
132 auto [w0_bits, w1_bits] = recipe_for_word(i);
133
134 // Our return value starts with all unset bits.
135 word_type result = 0;
136
137 // Replace `w0_bits` low-order bits in `result` with the same number of high-order bits from `w0`
138 Word w0 = m_begin[i];
139 gf2::replace_bits(result, 0, w0_bits, w0 >> m_offset);
140
141 // Perhaps our result spans two words.
142 if (w1_bits > 0) {
143 // Replace `w1_bits` high-order bits in result with the same number of low-order bits from `w1`
144 Word w1 = m_begin[i + 1];
145 gf2::replace_bits(result, w0_bits, w0_bits + w1_bits, w1 << w0_bits);
146 }
147 return result;
148 }
149
167 constexpr void set_word(usize i, word_type value) {
168 if constexpr (std::is_const_v<Word>) {
169 // This should never get called for const bit-spans.
170 throw std::logic_error("Cannot set a word in a const bit-span.");
171 } else {
172 // Get the recipe for the "word" at index `i` (it may be a synthesis of two real words).
173 auto [w0_bits, w1_bits] = recipe_for_word(i);
174
175 // Replace `w0_bits` low-order bits in `w0` with the same number of high-order bits from `value`
176 // Shift `value` to the left to align its bits with the start of `w0`.
177 gf2::replace_bits(m_begin[i], m_offset, m_offset + w0_bits, value << m_offset);
178
179 // Perhaps we also need to overwrite some bits in the second word.
180 if (w1_bits > 0) {
181 // Replace `w1_bits` low-order bits in `w1` with the same number of high-order bits from `value`
182 gf2::replace_bits(m_begin[i + 1], 0, w1_bits, value >> w0_bits);
183 }
184 }
185 }
186
188 constexpr const Word* data() const { return m_begin; }
189
191 constexpr Word* data() { return m_begin; }
192
194 constexpr u8 offset() const { return m_offset; }
195
197
198private:
214 constexpr auto recipe_for_word(usize i) const {
215 gf2_debug_assert(i < m_words, "Index {} should be less than {}", i, m_words);
216
217 // The default recipe (these sum to a whole word of bits).
218 u8 w0_bits = bits_per_word - m_offset;
219 u8 w1_bits = m_offset;
220
221 // The last word in the span may not be fully occupied so we need to adjust the bits accordingly.
222 if (i == m_words - 1) {
223 auto last_offset = static_cast<u8>((m_offset + m_size - 1) % bits_per_word);
224 if (last_offset < m_offset) {
225 // Still need to use two words but `w1-bits` may shrink.
226 w1_bits = static_cast<u8>(last_offset + 1);
227 } else {
228 // Only need to use one word so no need for `w1_bits`.
229 w0_bits = static_cast<u8>(last_offset - m_offset + 1);
230 w1_bits = 0;
231 }
232 }
233 return std::pair{w0_bits, w1_bits};
234 }
235};
236
237} // namespace gf2
238
239// --------------------------------------------------------------------------------------------------------------------
240// Specialises `std::formatter` for `BitSpan` -- defers to the version for `BitStore` ...
241// -------------------------------------------------------------------------------------------------------------------
242template<gf2::unsigned_word Word>
243struct std::formatter<gf2::BitSpan<Word>> : std::formatter<gf2::BitStore<gf2::BitSpan<Word>>> {
244 // Inherits all functionality from `BitStore` formatter
245};
The base class for the vector-like types in the gf2 library. See the BitStore page for more details...
Macros that improve on standard assert. See the Assertions page for all the details.
#define gf2_debug_assert(cond,...)
A confirmation macro that checks a boolean condition cond. On failure, the confirmation prints an e...
Definition assert.h:68
constexpr usize size() const
Returns the number of bits in the span.
Definition BitSpan.h:97
BitSpan(Word *begin, u8 offset, usize size)
Constructs a non-owning bit-span from a pointer to a contiguous span of unsigneds etc.
Definition BitSpan.h:69
constexpr word_type word(usize i) const
Returns a "word"'s worth of bits from the bit-span.
Definition BitSpan.h:130
constexpr Word * data()
Returns a pointer to the first span word in some underlying store of words (const version).
Definition BitSpan.h:191
static constexpr usize bits_per_word
A constant – the number of bits in a Word.
Definition BitSpan.h:41
constexpr void set_word(usize i, word_type value)
Sets a "word"'s worth of bits in the bit-span.
Definition BitSpan.h:167
constexpr u8 offset() const
Returns the offset (in bits) of the first bit in the span within the first span word.
Definition BitSpan.h:194
constexpr const Word * data() const
Returns a pointer to the first span word in some underlying store of words (const version).
Definition BitSpan.h:188
constexpr usize words() const
Returns the minimum number of words needed to store the bits in the span.
Definition BitSpan.h:113
The namespace for the gf2 library.
Definition assert.h:119
constexpr void replace_bits(Word &word, u8 begin, u8 end, Other other)
Replace the bits of word in the range [begin, end) with the bits from other leaving the rest unchange...
Definition unsigned_word.h:264
std::uint8_t u8
Word type alias for an 8-bit unsigned integer.
Definition unsigned_word.h:29
std::size_t usize
Word type alias for the platform's "native"-sized unsigned integer.
Definition unsigned_word.h:41
constexpr usize words_needed(usize n_bits)
Returns the number of unsigned_words needed to store n_bits bits.
Definition unsigned_word.h:522