GF2++
Loading...
Searching...
No Matches
unsigned_word.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
11#include <bit>
12#include <concepts>
13#include <cstdint>
14#include <format>
15#include <optional>
16#include <utility>
17#include <type_traits>
18
19namespace gf2 {
20
21// Our `unsigned_word` concept is the same as `std::unsigned_integral`
22template<typename T>
23concept unsigned_word = std::unsigned_integral<T>;
24
27
29using u8 = std::uint8_t;
30
32using u16 = std::uint16_t;
33
35using u32 = std::uint32_t;
36
38using u64 = std::uint64_t;
39
41using usize = std::size_t;
42
46
53template<unsigned_word Word>
54constexpr u8 BITS = std::numeric_limits<Word>::digits;
55
62template<unsigned_word Word>
63constexpr Word ZERO = Word{0};
64
71template<unsigned_word Word>
72constexpr Word ONE = Word{1};
73
80template<unsigned_word Word>
81constexpr Word MAX = std::numeric_limits<Word>::max();
82
89template<unsigned_word Word>
90constexpr Word ALTERNATING = MAX<Word> / 3;
91
95
108template<unsigned_word Word>
109constexpr Word
110with_set_bits(u8 begin, u8 end) {
111 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
112 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
113 return (MAX<Word> << begin) & (MAX<Word> >> (BITS<Word> - end));
114}
115
128template<unsigned_word Word>
129constexpr Word
130with_unset_bits(u8 begin, u8 end) {
131 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
132 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
133 auto result = with_set_bits<Word>(begin, end);
134 return static_cast<Word>(~result);
135}
136
140
151template<unsigned_word Word>
152constexpr void
153set_bits(Word& word, u8 begin, u8 end) {
154 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
155 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
156 if (begin != end) word |= with_set_bits<Word>(begin, end);
157}
158
169template<unsigned_word Word>
170constexpr void
171reset_bits(Word& word, u8 begin, u8 end) {
172 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
173 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
174 if (begin != end) {
175 auto mask = with_set_bits<Word>(begin, end);
176 mask = static_cast<Word>(~mask);
177 word &= mask;
178 }
179}
180
191template<unsigned_word Word>
192constexpr void
193set_except_bits(Word& word, u8 begin, u8 end) {
194 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
195 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
196 if (begin != end) {
197 auto mask = with_set_bits<Word>(begin, end);
198 mask = static_cast<Word>(~mask);
199 word |= mask;
200 }
201}
202
213template<unsigned_word Word>
214constexpr void
215reset_except_bits(Word& word, u8 begin, u8 end) {
216 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
217 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
218 if (begin != end) {
219 auto mask = with_set_bits<Word>(begin, end);
220 word &= mask;
221 }
222}
223
240template<unsigned_word Word>
241constexpr Word
242reverse_bits(Word word) {
243 Word result = 0;
244 for (u8 i = 0; i < BITS<Word>; ++i, word >>= 1) { result = static_cast<Word>((result << 1) | (word & 1)); }
245 return result;
246}
247
262template<unsigned_word Word, typename Other>
263constexpr void
264replace_bits(Word& word, u8 begin, u8 end, Other other)
265 requires std::convertible_to<Other, Word>
266{
267 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
268 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
269 if (begin != end) {
270 auto other_mask = with_set_bits<Word>(begin, end);
271 auto word_mask = static_cast<Word>(~other_mask);
272 word = (word & word_mask) | (static_cast<Word>(other) & other_mask);
273 }
274}
275
279
292template<unsigned_word Word>
293constexpr std::pair<Word, Word>
294riffle(Word word) {
295 auto half_bits = BITS<Word> / 2;
296 Word lo = word & (MAX<Word> >> half_bits);
297 Word hi = word >> half_bits;
298
299 // Some magic to interleave the respective halves with zeros starting with half the bits in each half.
300 Word one = 1;
301 auto shift = BITS<Word> / 4;
302 while (shift > 0) {
303 Word div = Word(one << shift) | one;
304 Word mask = MAX<Word> / div;
305 lo = (lo ^ (lo << shift)) & mask;
306 hi = (hi ^ (hi << shift)) & mask;
307 shift /= 2;
308 }
309 return std::pair{lo, hi};
310}
311
315
325template<unsigned_word Word>
326constexpr u8
327count_ones(Word word) {
328 return static_cast<u8>(std::popcount(word));
329}
330
340template<unsigned_word Word>
341constexpr u8
342count_zeros(Word word) {
343 return BITS<Word> - count_ones(word);
344}
345
355template<unsigned_word Word>
356constexpr u8
357trailing_zeros(Word word) {
358 return static_cast<u8>(std::countr_zero(word));
359}
360
370template<unsigned_word Word>
371constexpr u8
372leading_zeros(Word word) {
373 return static_cast<u8>(std::countl_zero(word));
374}
375
385template<unsigned_word Word>
386constexpr u8
387trailing_ones(Word word) {
388 return static_cast<u8>(std::countr_one(word));
389}
390
400template<unsigned_word Word>
401constexpr u8
402leading_ones(Word word) {
403 return static_cast<u8>(std::countl_one(word));
404}
405
415template<unsigned_word Word>
416constexpr std::optional<u8>
417lowest_set_bit(Word word) {
418 if (word != 0) return trailing_zeros(word);
419 return {};
420}
421
425
435template<unsigned_word Word>
436constexpr std::optional<u8>
437highest_set_bit(Word word) {
438 if (word != 0) return BITS<Word> - leading_zeros(word) - 1;
439 return {};
440}
441
451template<unsigned_word Word>
452constexpr std::optional<u8>
454 if (word != MAX<Word>) return trailing_ones(word);
455 return {};
456}
457
467template<unsigned_word Word>
468constexpr std::optional<u8>
470 if (word != MAX<Word>) return BITS<Word> - leading_ones(word) - 1;
471 return {};
472}
473
477
487template<unsigned_word Word>
488static inline std::string
490 return std::format("{:0{}b}", word, BITS<Word>);
491}
492
502template<unsigned_word Word>
503static inline std::string
504to_hex_string(Word word) {
505 return std::format("{:0{}X}", word, BITS<Word> / 4);
506}
507
511
520template<unsigned_word Word>
521constexpr usize
523 // Usually divide returns *both* the quotient & remainder & the compiler will optimise the next line.
524 return n_bits / BITS<Word> + (n_bits % BITS<Word> != 0);
525}
526
537template<unsigned_word Word>
538constexpr usize
540 return i / BITS<Word>;
541}
542
553template<unsigned_word Word>
554constexpr u8
556 return i % BITS<Word>;
557}
558
570template<unsigned_word Word>
571constexpr std::pair<usize, u8>
573 return std::pair{word_index<Word>(i), bit_offset<Word>(i)};
574}
575
587template<unsigned_word Word>
588constexpr std::pair<usize, Word>
590 return std::pair{word_index<Word>(i), static_cast<Word>(ONE<Word> << bit_offset<Word>(i))};
591}
592
594
595} // namespace gf2
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
The namespace for the gf2 library.
Definition assert.h:119
constexpr std::pair< Word, Word > riffle(Word word)
Riffles an unsigned_word into a pair of others containing the bits in the original word interleaved w...
Definition unsigned_word.h:294
constexpr Word ZERO
The zero value for an unsigned_word type.
Definition unsigned_word.h:63
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
constexpr Word ALTERNATING
The unsigned_word instance with alternating bits set to 0 and 1.
Definition unsigned_word.h:90
constexpr std::pair< usize, u8 > index_and_offset(usize i)
Returns a pair of the index of the word and the bit position within the word for bit element i.
Definition unsigned_word.h:572
constexpr void set_except_bits(Word &word, u8 begin, u8 end)
Sets the bits of word to 1 except for those in the half-open range [begin, end) which are unchanged.
Definition unsigned_word.h:193
constexpr u8 bit_offset(usize i)
Returns the bit position within the containing word for bit element i.
Definition unsigned_word.h:555
constexpr void set_bits(Word &word, u8 begin, u8 end)
Sets the bits in the half-open range [begin, end) of word to one, leaving the others unchanged.
Definition unsigned_word.h:153
constexpr Word ONE
The one value for an unsigned_word type.
Definition unsigned_word.h:72
constexpr Word reverse_bits(Word word)
Returns a copy of word with all its bits reversed.
Definition unsigned_word.h:242
constexpr Word with_unset_bits(u8 begin, u8 end)
Returns an unsigned_word with the bits in the half-open range [begin, end) set to 0 and the others se...
Definition unsigned_word.h:130
constexpr u8 count_zeros(Word word)
Returns the number of unset bits in an unsigned_word.
Definition unsigned_word.h:342
constexpr u8 leading_zeros(Word word)
Returns the number of leading zeros in an unsigned_word.
Definition unsigned_word.h:372
std::uint64_t u64
Word type alias for a 64-bit unsigned integer.
Definition unsigned_word.h:38
constexpr void reset_bits(Word &word, u8 begin, u8 end)
Resets the bits in the half-open range [begin, end) of word to zero, leaving the others unchanged.
Definition unsigned_word.h:171
std::uint8_t u8
Word type alias for an 8-bit unsigned integer.
Definition unsigned_word.h:29
static std::string to_binary_string(Word word)
Returns the binary string representation of an unsigned_word showing all the bits.
Definition unsigned_word.h:489
constexpr usize word_index(usize i)
Returns the index of the unsigned_word word holding bit element i.
Definition unsigned_word.h:539
constexpr std::pair< usize, Word > index_and_mask(usize i)
Returns a pair of the index of the word and a mask isolating bit element i.
Definition unsigned_word.h:589
constexpr u8 count_ones(Word word)
Returns the number of set bits in an unsigned_word.
Definition unsigned_word.h:327
constexpr u8 trailing_zeros(Word word)
Returns the number of trailing zeros in an unsigned_word.
Definition unsigned_word.h:357
std::size_t usize
Word type alias for the platform's "native"-sized unsigned integer.
Definition unsigned_word.h:41
constexpr Word with_set_bits(u8 begin, u8 end)
Returns an unsigned_word with the bits in the half-open range [begin, end) set to 1 and the others se...
Definition unsigned_word.h:110
constexpr std::optional< u8 > lowest_unset_bit(Word word)
Returns the index of the lowest unset bit in an unsigned_word or std::nullopt if there are no unset b...
Definition unsigned_word.h:453
constexpr std::optional< u8 > highest_set_bit(Word word)
Returns the index of the highest set bit in an unsigned_word or std::nullopt if no bits are set.
Definition unsigned_word.h:437
constexpr Word MAX
The unsigned_word instance with all its bits set to 1.
Definition unsigned_word.h:81
constexpr u8 BITS
The number of bits in an unsigned_word returned as a u8.
Definition unsigned_word.h:54
std::uint32_t u32
Word type alias for a 32-bit unsigned integer.
Definition unsigned_word.h:35
constexpr u8 leading_ones(Word word)
Returns the number of leading ones in an unsigned_word.
Definition unsigned_word.h:402
constexpr usize words_needed(usize n_bits)
Returns the number of unsigned_words needed to store n_bits bits.
Definition unsigned_word.h:522
constexpr u8 trailing_ones(Word word)
Returns the number of trailing ones in an unsigned_word.
Definition unsigned_word.h:387
constexpr void reset_except_bits(Word &word, u8 begin, u8 end)
Sets the bits of word to 0 except for those in the half-open range [begin, end) which are unchanged.
Definition unsigned_word.h:215
std::uint16_t u16
Word type alias for a 16-bit unsigned integer.
Definition unsigned_word.h:32
constexpr std::optional< u8 > lowest_set_bit(Word word)
Returns the index of the lowest set bit in an unsigned_word or std::nullopt if no bits are set.
Definition unsigned_word.h:417
static std::string to_hex_string(Word word)
Returns the hex string representation of an unsigned_word showing all the bits.
Definition unsigned_word.h:504
constexpr std::optional< u8 > highest_unset_bit(Word word)
Returns the index of the highest unset bit in an unsigned_word or std::nullopt if there are none.
Definition unsigned_word.h:469