jaulib v1.3.6
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
bitfield.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2022 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24#ifndef JAU_BITFIELD_HPP_
25#define JAU_BITFIELD_HPP_
26
27#include <array>
28
29#include <cstdint>
30#include <limits>
31#include <unistd.h>
32#include <jau/int_math_ct.hpp>
33
34namespace jau {
35 /**
36 * Simple bitfield template for efficient bit storage access in O(1).
37 *
38 * Implementations utilizes an in-memory `std::array<uint32_t, (BitSize+31)/5>`.
39 */
40 template <size_t BitSize>
41 class bitfield {
42 public:
43 static constexpr size_t unit_shift = 5;
44 static constexpr size_t unit_bit_size = 32;
45 static constexpr size_t bit_size = BitSize;
46
47 private:
48 static constexpr size_t storage_size = std::max<size_t>(1, ( bit_size + unit_bit_size - 1 ) >> unit_shift);
49 typedef std::array<uint32_t, storage_size> storage_t;
50 storage_t storage;
51
52 static constexpr bool in_range(size_t bit_size_, size_t bitnum) { return bitnum < bit_size_; }
53
54 /// Returns the 32 bit mask of n-bits, i.e. n low order 1’s
55 static constexpr uint32_t bit_mask(size_t n) noexcept {
56 if( unit_bit_size > n ) {
57 return ( 1 << n ) - 1;
58 } else if ( unit_bit_size == n ) {
59 return std::numeric_limits<uint32_t>::max();
60 } else {
61 return 0;
62 }
63 }
64
65 public:
66 static constexpr bool in_range(size_t bitnum) { return bitnum < bit_size; }
67
68 constexpr bitfield() noexcept { clear(); }
69
70 /*** Clears whole bitfield, i.e. sets all bits to zero. */
71 constexpr void clear() noexcept {
72 for(size_t i=0; i<storage_size; ++i) {
73 storage[i] = 0;
74 }
75 }
76
77 /*** Reads the bit value at position `bitnum`. */
78 constexpr bool get(size_t bitnum) const noexcept {
79 if( !in_range(bitnum) ) {
80 return false;
81 }
82 const size_t u = bitnum >> unit_shift;
83 const size_t b = bitnum - ( u << unit_shift );
84 return 0 != ( storage[u] & ( 1U << b ) ) ;
85 }
86 /*** Writes the bit value `v` to position `bitnum` into this storage. */
87 constexpr void put(size_t bitnum, bool v) noexcept {
88 if( !in_range(bitnum) ) {
89 return;
90 }
91 const size_t u = bitnum >> unit_shift;
92 const size_t b = bitnum - ( u << unit_shift );
93 const uint32_t m = 1 << b;
94 if( v ) {
95 storage[u] |= m;
96 } else {
97 storage[u] &= ~m;
98 }
99 }
100 /*** Sets the bit at position `bitnum` of this storage. */
101 constexpr void set(size_t bitnum) noexcept { put(bitnum, true); }
102 /*** Clear the bit at position `bitnum` of this storage. */
103 constexpr void clr(size_t bitnum) noexcept { put(bitnum, false); }
104
105 /*** Copies the bit at position `srcBitnum` to position `dstBitnum`, returning the copied bit-value. */
106 bool copy(size_t srcBitnum, size_t dstBitnum) noexcept {
107 const bool bit = get(srcBitnum);
108 put(dstBitnum, bit);
109 return bit;
110 }
111
112 /*** Reads `length` bits from this storage, starting with the lowest bit from the storage position `lowBitnum`.*/
113 uint32_t getu32(size_t lowBitnum, size_t length) const noexcept {
114 if( 0 == length || length > unit_bit_size || !in_range(bit_size-length+1, lowBitnum) ) {
115 return 0;
116 }
117 const size_t u = lowBitnum >> unit_shift;
118 const size_t left = unit_bit_size - ( lowBitnum - ( u << unit_shift ) ); // remaining bits of first chunk storage
119 if( unit_bit_size == left ) {
120 // fast path
121 const uint32_t m = bit_mask(length); // mask of chunk
122 return m & storage[u];
123 } else {
124 // slow path
125 const size_t l1 = std::min(length, left); // length of first chunk < 32
126 const uint32_t m1 = ( 1 << l1 ) - 1; // mask of first chunk
127 const uint32_t d1 = m1 & ( storage[u] >> lowBitnum ); // data of first chunk
128 const size_t l2 = length - l1; // length of second chunk < 32
129 if( l2 > 0 ) {
130 const uint32_t m2 = ( 1 << l2 ) - 1; // mask of second chunk
131 return d1 | ( ( m2 & storage[u+1] ) << l1 ); // data combined chunk 1+2
132 } else {
133 return d1; // data of chunk 1 only
134 }
135 }
136 }
137
138 /*** Writes `length` bits of given `data` into this storage, starting with the lowest bit from the storage position `lowBitnum`.*/
139 void putu32(size_t lowBitnum, size_t length, uint32_t data) noexcept {
140 if( 0 == length || length > unit_bit_size || !in_range(bit_size-length+1, lowBitnum) ) {
141 return;
142 }
143 const size_t u = lowBitnum >> unit_shift;
144 const size_t left = unit_bit_size - ( lowBitnum - ( u << unit_shift ) ); // remaining bits of first chunk storage
145 if( unit_bit_size == left ) {
146 // fast path
147 const uint32_t m = bit_mask(length); // mask of chunk
148 storage[u] = ( ( ~m ) & storage[u] ) // keep non-written storage bits
149 | ( m & data ); // overwrite storage w/ used data bits
150 } else {
151 // slow path
152 const size_t l1 = std::min(length, left); // length of first chunk < 32
153 const uint32_t m1 = ( 1 << l1 ) - 1; // mask of first chunk
154 storage[u] = ( (~( m1 << lowBitnum ) ) & storage[u]) // keep non-written storage bits
155 | ( ( m1 & data ) << lowBitnum); // overwrite storage w/ used data bits
156 const size_t l2 = length - l1; // length of second chunk < 32
157 if( l2 > 0 ) {
158 const uint32_t m2 = ( 1 << l2 ) - 1; // mask of second chunk
159 storage[u+1] = ( ( ~m2 ) & storage[u+1] ) // keep non-written storage bits
160 | ( m2 & ( data >> l1 ) ); // overwrite storage w/ used data bits
161 }
162 }
163 }
164
165 /*** Copies `length` bits at position `srcLowBitnum` to position `dstLowBitnum`, returning the copied bits.*/
166 uint32_t copyu32(size_t srcBitnum, size_t dstBitnum, size_t length) noexcept {
167 const uint32_t data = getu32(srcBitnum, length);
168 putu32(dstBitnum, length, data);
169 return data;
170 }
171
172 /*** Returns the number of set bits within this bitfield. */
173 size_t bitCount() const noexcept {
174 size_t c = 0;
175 for(size_t i=0; i<storage_size; ++i) {
176 c += jau::ct_bit_count(storage[i]);
177 }
178 return c;
179 }
180 };
181}
182
183#endif /* JAU_BITFIELD_HPP_ */
184
constexpr void put(size_t bitnum, bool v) noexcept
Definition bitfield.hpp:87
uint32_t getu32(size_t lowBitnum, size_t length) const noexcept
Definition bitfield.hpp:113
static constexpr size_t unit_shift
Definition bitfield.hpp:43
size_t bitCount() const noexcept
Definition bitfield.hpp:173
constexpr void clr(size_t bitnum) noexcept
Definition bitfield.hpp:103
constexpr bool get(size_t bitnum) const noexcept
Definition bitfield.hpp:78
static constexpr size_t bit_size
Definition bitfield.hpp:45
static constexpr size_t unit_bit_size
Definition bitfield.hpp:44
constexpr bitfield() noexcept
Definition bitfield.hpp:68
void putu32(size_t lowBitnum, size_t length, uint32_t data) noexcept
Definition bitfield.hpp:139
static constexpr bool in_range(size_t bitnum)
Definition bitfield.hpp:66
uint32_t copyu32(size_t srcBitnum, size_t dstBitnum, size_t length) noexcept
Definition bitfield.hpp:166
bool copy(size_t srcBitnum, size_t dstBitnum) noexcept
Definition bitfield.hpp:106
constexpr void set(size_t bitnum) noexcept
Definition bitfield.hpp:101
constexpr void clear() noexcept
Definition bitfield.hpp:71
constexpr uint32_t ct_bit_count(uint32_t n) noexcept
Returns the number of set bits within given 32bit integer (w/o branching) in O(1) and constant time (...
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
static const Mat4f m1(m1_0)
static const Mat4f m2(m2_0)