GF2++
Loading...
Searching...
No Matches
Unsigned.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
23template<typename T>
24concept Unsigned = std::unsigned_integral<T>;
25
28
30using u8 = std::uint8_t;
31
33using u16 = std::uint16_t;
34
36using u32 = std::uint32_t;
37
39using u64 = std::uint64_t;
40
42using usize = std::size_t;
43
47
54template<Unsigned Word>
55constexpr u8 BITS = std::numeric_limits<Word>::digits;
56
63template<Unsigned Word>
64constexpr Word ZERO = Word{0};
65
72template<Unsigned Word>
73constexpr Word ONE = Word{1};
74
81template<Unsigned Word>
82constexpr Word MAX = std::numeric_limits<Word>::max();
83
90template<Unsigned Word>
91constexpr Word ALTERNATING = MAX<Word> / 3;
92
96
109template<Unsigned Word>
110constexpr Word
111with_set_bits(u8 begin, u8 end) {
112 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
113 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
114 return (MAX<Word> << begin) & (MAX<Word> >> (BITS<Word> - end));
115}
116
129template<Unsigned Word>
130constexpr Word
131with_unset_bits(u8 begin, u8 end) {
132 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
133 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
134 auto result = with_set_bits<Word>(begin, end);
135 return static_cast<Word>(~result);
136}
137
141
152template<Unsigned Word>
153constexpr void
154set_bits(Word& word, u8 begin, u8 end) {
155 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
156 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
157 if (begin != end) word |= with_set_bits<Word>(begin, end);
158}
159
170template<Unsigned Word>
171constexpr void
172reset_bits(Word& word, u8 begin, u8 end) {
173 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
174 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
175 if (begin != end) {
176 auto mask = with_set_bits<Word>(begin, end);
177 mask = static_cast<Word>(~mask);
178 word &= mask;
179 }
180}
181
192template<Unsigned Word>
193constexpr void
194set_except_bits(Word& word, u8 begin, u8 end) {
195 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
196 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
197 if (begin != end) {
198 auto mask = with_set_bits<Word>(begin, end);
199 mask = static_cast<Word>(~mask);
200 word |= mask;
201 }
202}
203
214template<Unsigned Word>
215constexpr void
216reset_except_bits(Word& word, u8 begin, u8 end) {
217 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
218 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
219 if (begin != end) {
220 auto mask = with_set_bits<Word>(begin, end);
221 word &= mask;
222 }
223}
224
241template<Unsigned Word>
242constexpr Word
243reverse_bits(Word word) {
244 Word result = 0;
245 for (u8 i = 0; i < BITS<Word>; ++i, word >>= 1) { result = static_cast<Word>((result << 1) | (word & 1)); }
246 return result;
247}
248
263template<Unsigned Word, typename Other>
264constexpr void
265replace_bits(Word& word, u8 begin, u8 end, Other other)
266 requires std::convertible_to<Other, Word>
267{
268 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
269 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
270 if (begin != end) {
271 auto other_mask = with_set_bits<Word>(begin, end);
272 auto word_mask = static_cast<Word>(~other_mask);
273 word = (word & word_mask) | (static_cast<Word>(other) & other_mask);
274 }
275}
276
280
293template<Unsigned Word>
294constexpr std::pair<Word, Word>
295riffle(Word word) {
296 auto half_bits = BITS<Word> / 2;
297 Word lo = word & (MAX<Word> >> half_bits);
298 Word hi = word >> half_bits;
299
300 // Some magic to interleave the respective halves with zeros starting with half the bits in each half.
301 Word one = 1;
302 auto shift = BITS<Word> / 4;
303 while (shift > 0) {
304 Word div = Word(one << shift) | one;
305 Word mask = MAX<Word> / div;
306 lo = (lo ^ (lo << shift)) & mask;
307 hi = (hi ^ (hi << shift)) & mask;
308 shift /= 2;
309 }
310 return std::pair{lo, hi};
311}
312
316
326template<Unsigned Word>
327constexpr u8
328count_ones(Word word) {
329 return static_cast<u8>(std::popcount(word));
330}
331
341template<Unsigned Word>
342constexpr u8
343count_zeros(Word word) {
344 return BITS<Word> - count_ones(word);
345}
346
356template<Unsigned Word>
357constexpr u8
358trailing_zeros(Word word) {
359 return static_cast<u8>(std::countr_zero(word));
360}
361
371template<Unsigned Word>
372constexpr u8
373leading_zeros(Word word) {
374 return static_cast<u8>(std::countl_zero(word));
375}
376
386template<Unsigned Word>
387constexpr u8
388trailing_ones(Word word) {
389 return static_cast<u8>(std::countr_one(word));
390}
391
401template<Unsigned Word>
402constexpr u8
403leading_ones(Word word) {
404 return static_cast<u8>(std::countl_one(word));
405}
406
416template<Unsigned Word>
417constexpr std::optional<u8>
418lowest_set_bit(Word word) {
419 if (word != 0) return trailing_zeros(word);
420 return {};
421}
422
426
436template<Unsigned Word>
437constexpr std::optional<u8>
438highest_set_bit(Word word) {
439 if (word != 0) return BITS<Word> - leading_zeros(word) - 1;
440 return {};
441}
442
452template<Unsigned Word>
453constexpr std::optional<u8>
455 if (word != MAX<Word>) return trailing_ones(word);
456 return {};
457}
458
468template<Unsigned Word>
469constexpr std::optional<u8>
471 if (word != MAX<Word>) return BITS<Word> - leading_ones(word) - 1;
472 return {};
473}
474
478
488template<Unsigned Word>
489static inline std::string
491 return std::format("{:0{}b}", word, BITS<Word>);
492}
493
503template<Unsigned Word>
504static inline std::string
505to_hex_string(Word word) {
506 return std::format("{:0{}X}", word, BITS<Word> / 4);
507}
508
512
521template<Unsigned Word>
522constexpr usize
524 // Usually divide returns *both* the quotient & remainder & the compiler will optimise the next line.
525 return n_bits / BITS<Word> + (n_bits % BITS<Word> != 0);
526}
527
538template<Unsigned Word>
539constexpr usize
541 return i / BITS<Word>;
542}
543
554template<Unsigned Word>
555constexpr u8
557 return i % BITS<Word>;
558}
559
571template<Unsigned Word>
572constexpr std::pair<usize, u8>
574 return std::pair{word_index<Word>(i), bit_offset<Word>(i)};
575}
576
588template<Unsigned Word>
589constexpr std::pair<usize, Word>
591 return std::pair{word_index<Word>(i), static_cast<Word>(ONE<Word> << bit_offset<Word>(i))};
592}
593
595
596} // 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 Unsigned concept is the same as std::unsigned_integral. It is satisfied by all primitive unsigned...
Definition Unsigned.h:24
The namespace for the gf2 library.
Definition assert.h:119
constexpr Word ZERO
The zero value for an Unsigned type.
Definition Unsigned.h:64
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.h:265
constexpr Word ALTERNATING
The Unsigned instance with alternating bits set to 0 and 1.
Definition Unsigned.h:91
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.h:573
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.h:194
constexpr u8 bit_offset(usize i)
Returns the bit position within the containing word for bit element i.
Definition Unsigned.h:556
constexpr Word ONE
The one value for an Unsigned type.
Definition Unsigned.h:73
constexpr Word reverse_bits(Word word)
Returns a copy of word with all its bits reversed.
Definition Unsigned.h:243
constexpr usize count_zeros(Store const &store)
Returns the number of unset bits in the store.
Definition BitStore.h:691
constexpr Word with_unset_bits(u8 begin, u8 end)
Returns an Unsigned with the bits in the half-open range [begin, end) set to 0 and the others set to ...
Definition Unsigned.h:131
constexpr auto set_bits(Store const &store)
Returns an iterator over the indices of any set bits in the bit-store.
Definition BitStore.h:1097
std::uint64_t u64
Word type alias for a 64-bit unsigned integer.
Definition Unsigned.h:39
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.h:172
std::uint8_t u8
Word type alias for an 8-bit unsigned integer.
Definition Unsigned.h:30
static std::string to_hex_string(Store const &store)
Returns the "hex" string representation of the bits in the bit-store.
Definition BitStore.h:1536
constexpr usize count_ones(Store const &store)
Returns the number of set bits in the store.
Definition BitStore.h:674
constexpr usize leading_zeros(Store const &store)
Returns the number of leading zeros in the store.
Definition BitStore.h:708
constexpr usize word_index(usize i)
Returns the index of the Unsigned word holding bit element i.
Definition Unsigned.h:540
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.h:590
constexpr usize trailing_zeros(Store const &store)
Returns the number of trailing zeros in the store.
Definition BitStore.h:729
std::size_t usize
Word type alias for the platform's "native"-sized unsigned integer.
Definition Unsigned.h:42
constexpr Word with_set_bits(u8 begin, u8 end)
Returns an Unsigned with the bits in the half-open range [begin, end) set to 1 and the others set to ...
Definition Unsigned.h:111
constexpr std::optional< u8 > lowest_unset_bit(Word word)
Returns the index of the lowest unset bit in an Unsigned or std::nullopt if there are no unset bits.
Definition Unsigned.h:454
constexpr std::optional< u8 > highest_set_bit(Word word)
Returns the index of the highest set bit in an Unsigned or std::nullopt if no bits are set.
Definition Unsigned.h:438
constexpr Word MAX
The Unsigned instance with all its bits set to 1.
Definition Unsigned.h:82
constexpr u8 BITS
The number of bits in an Unsigned returned as a u8.
Definition Unsigned.h:55
std::uint32_t u32
Word type alias for a 32-bit unsigned integer.
Definition Unsigned.h:36
constexpr u8 leading_ones(Word word)
Returns the number of leading ones in an Unsigned.
Definition Unsigned.h:403
constexpr usize words_needed(usize n_bits)
Returns the number of Unsigneds needed to store n_bits bits.
Definition Unsigned.h:523
constexpr u8 trailing_ones(Word word)
Returns the number of trailing ones in an Unsigned.
Definition Unsigned.h:388
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.h:216
constexpr void riffle(Store const &store, BitVec< typename Store::word_type > &dst)
Interleaves the bits of a bit-store with zeros storing the result into the passed bit-vector dst.
Definition BitStore.h:1362
std::uint16_t u16
Word type alias for a 16-bit unsigned integer.
Definition Unsigned.h:33
constexpr std::optional< u8 > lowest_set_bit(Word word)
Returns the index of the lowest set bit in an Unsigned or std::nullopt if no bits are set.
Definition Unsigned.h:418
static std::string to_binary_string(Store const &store, std::string_view sep="", std::string_view pre="", std::string_view post="")
Returns a binary string representation of a store.
Definition BitStore.h:1431
constexpr std::optional< u8 > highest_unset_bit(Word word)
Returns the index of the highest unset bit in an Unsigned or std::nullopt if there are none.
Definition Unsigned.h:470