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
110template<Unsigned Word>
111constexpr Word
112with_set_bits(u8 begin, u8 end) {
113 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
114 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
115 return (MAX<Word> << begin) & (MAX<Word> >> (BITS<Word> - end));
116}
117
131template<Unsigned Word>
132constexpr Word
133with_unset_bits(u8 begin, u8 end) {
134 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
135 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
136 auto result = with_set_bits<Word>(begin, end);
137 return static_cast<Word>(~result);
138}
139
143
155template<Unsigned Word>
156constexpr void
157set_bits(Word& word, u8 begin, u8 end) {
158 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
159 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
160 if (begin != end) word |= with_set_bits<Word>(begin, end);
161}
162
174template<Unsigned Word>
175constexpr void
176reset_bits(Word& word, u8 begin, u8 end) {
177 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
178 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
179 if (begin != end) {
180 auto mask = with_set_bits<Word>(begin, end);
181 mask = static_cast<Word>(~mask);
182 word &= mask;
183 }
184}
185
197template<Unsigned Word>
198constexpr void
199set_except_bits(Word& word, u8 begin, u8 end) {
200 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
201 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
202 if (begin != end) {
203 auto mask = with_set_bits<Word>(begin, end);
204 mask = static_cast<Word>(~mask);
205 word |= mask;
206 }
207}
208
220template<Unsigned Word>
221constexpr void
222reset_except_bits(Word& word, u8 begin, u8 end) {
223 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
224 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
225 if (begin != end) {
226 auto mask = with_set_bits<Word>(begin, end);
227 word &= mask;
228 }
229}
230
247template<Unsigned Word>
248constexpr Word
249reverse_bits(Word word) {
250 Word result = 0;
251 for (u8 i = 0; i < BITS<Word>; ++i, word >>= 1) { result = static_cast<Word>((result << 1) | (word & 1)); }
252 return result;
253}
254
270template<Unsigned Word, typename Other>
271constexpr void
272replace_bits(Word& word, u8 begin, u8 end, Other other)
273 requires std::convertible_to<Other, Word>
274{
275 gf2_debug_assert(end <= BITS<Word>, "End of range `{}` should be at most `{}`.", end, BITS<Word>);
276 gf2_debug_assert(begin <= end, "Mis-ordered range: [{}, {})", begin, end);
277 if (begin != end) {
278 auto other_mask = with_set_bits<Word>(begin, end);
279 auto word_mask = static_cast<Word>(~other_mask);
280 word = (word & word_mask) | (static_cast<Word>(other) & other_mask);
281 }
282}
283
287
300template<Unsigned Word>
301constexpr std::pair<Word, Word>
302riffle(Word word) {
303 auto half_bits = BITS<Word> / 2;
304 Word lo = word & (MAX<Word> >> half_bits);
305 Word hi = word >> half_bits;
306
307 // Some magic to interleave the respective halves with zeros starting with half the bits in each half.
308 Word one = 1;
309 auto shift = BITS<Word> / 4;
310 while (shift > 0) {
311 Word div = Word(one << shift) | one;
312 Word mask = MAX<Word> / div;
313 lo = (lo ^ (lo << shift)) & mask;
314 hi = (hi ^ (hi << shift)) & mask;
315 shift /= 2;
316 }
317 return std::pair{lo, hi};
318}
319
323
333template<Unsigned Word>
334constexpr u8
335count_ones(Word word) {
336 return static_cast<u8>(std::popcount(word));
337}
338
348template<Unsigned Word>
349constexpr u8
350count_zeros(Word word) {
351 return BITS<Word> - count_ones(word);
352}
353
363template<Unsigned Word>
364constexpr u8
365trailing_zeros(Word word) {
366 return static_cast<u8>(std::countr_zero(word));
367}
368
378template<Unsigned Word>
379constexpr u8
380leading_zeros(Word word) {
381 return static_cast<u8>(std::countl_zero(word));
382}
383
393template<Unsigned Word>
394constexpr u8
395trailing_ones(Word word) {
396 return static_cast<u8>(std::countr_one(word));
397}
398
408template<Unsigned Word>
409constexpr u8
410leading_ones(Word word) {
411 return static_cast<u8>(std::countl_one(word));
412}
413
423template<Unsigned Word>
424constexpr std::optional<u8>
425lowest_set_bit(Word word) {
426 if (word != 0) return trailing_zeros(word);
427 return {};
428}
429
433
443template<Unsigned Word>
444constexpr std::optional<u8>
445highest_set_bit(Word word) {
446 if (word != 0) return BITS<Word> - leading_zeros(word) - 1;
447 return {};
448}
449
459template<Unsigned Word>
460constexpr std::optional<u8>
462 if (word != MAX<Word>) return trailing_ones(word);
463 return {};
464}
465
475template<Unsigned Word>
476constexpr std::optional<u8>
478 if (word != MAX<Word>) return BITS<Word> - leading_ones(word) - 1;
479 return {};
480}
481
485
495template<Unsigned Word>
496static inline std::string
498 return std::format("{:0{}b}", word, BITS<Word>);
499}
500
510template<Unsigned Word>
511static inline std::string
512to_hex_string(Word word) {
513 return std::format("{:0{}X}", word, BITS<Word> / 4);
514}
515
519
528template<Unsigned Word>
529constexpr usize
531 // Usually divide returns *both* the quotient & remainder & the compiler will optimise the next line.
532 return n_bits / BITS<Word> + (n_bits % BITS<Word> != 0);
533}
534
545template<Unsigned Word>
546constexpr usize
548 return i / BITS<Word>;
549}
550
561template<Unsigned Word>
562constexpr u8
564 return i % BITS<Word>;
565}
566
578template<Unsigned Word>
579constexpr std::pair<usize, u8>
581 return std::pair{word_index<Word>(i), bit_offset<Word>(i)};
582}
583
595template<Unsigned Word>
596constexpr std::pair<usize, Word>
598 return std::pair{word_index<Word>(i), static_cast<Word>(ONE<Word> << bit_offset<Word>(i))};
599}
600
602
603} // 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:272
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:580
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:199
constexpr u8 bit_offset(usize i)
Returns the bit position within the containing word for bit element i.
Definition Unsigned.h:563
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:249
constexpr usize count_zeros(Store const &store)
Returns the number of unset bits in the store.
Definition BitStore.h:762
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:133
constexpr auto set_bits(Store const &store)
Returns an iterator over the indices of any set bits in the bit-store.
Definition BitStore.h:1170
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:176
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:1642
constexpr usize count_ones(Store const &store)
Returns the number of set bits in the store.
Definition BitStore.h:745
constexpr usize leading_zeros(Store const &store)
Returns the number of leading zeros in the store.
Definition BitStore.h:779
constexpr usize word_index(usize i)
Returns the index of the Unsigned word holding bit element i.
Definition Unsigned.h:547
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:597
constexpr usize trailing_zeros(Store const &store)
Returns the number of trailing zeros in the store.
Definition BitStore.h:800
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:112
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:461
constexpr void riffle(Store const &store, BitVector< 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:1468
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:445
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:410
constexpr usize words_needed(usize n_bits)
Returns the number of Unsigneds needed to store n_bits bits.
Definition Unsigned.h:530
constexpr u8 trailing_ones(Word word)
Returns the number of trailing ones in an Unsigned.
Definition Unsigned.h:395
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:222
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:425
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:1537
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:477