|
17 | 17 | #include <stdint.h> |
18 | 18 | #include <math.h> |
19 | 19 |
|
| 20 | +#include "Wlib.h" |
| 21 | + |
20 | 22 | namespace wlp { |
21 | | -#define NO_OF_BITS (8 * sizeof(unsigned int)) |
22 | 23 |
|
23 | | - template<uint8_t bits> |
| 24 | + /** |
| 25 | + * Computes the mask corresponding to the number of bits |
| 26 | + * or the exponent in the from 2^n - 1. |
| 27 | + * @tparam exp the number of bits, 32 or less |
| 28 | + */ |
| 29 | + template<uint8_t exp> |
| 30 | + struct pow_mask { |
| 31 | + static const uint32_t value = (uint32_t) ((1 << exp) - 1); |
| 32 | + }; |
| 33 | + |
| 34 | + /** |
| 35 | + * Template specialization for 32 bits to |
| 36 | + * prevent overflow. |
| 37 | + */ |
| 38 | + template<> struct pow_mask<32> { |
| 39 | + static const uint32_t value = 0xffffffff; |
| 40 | + }; |
| 41 | + |
| 42 | + /** |
| 43 | + * Compute the minimum number of integers |
| 44 | + * needed to store a certain number of bits. |
| 45 | + * @tparam nBits the bits to store |
| 46 | + */ |
| 47 | + template<uint8_t nBits> |
| 48 | + struct ceil_bits { |
| 49 | + static const uint32_t value = (nBits + INT_SIZE - 1) / INT_SIZE; |
| 50 | + }; |
| 51 | + |
| 52 | + template<uint8_t nBits> |
24 | 53 | class Bitset { |
25 | 54 | public: |
26 | 55 | /** |
27 | | - * Default Constructor creates an empty bitset |
| 56 | + * Default Constructor creates an empty bitset. |
28 | 57 | */ |
29 | 58 | Bitset() { |
30 | 59 | memset(m_array, 0, sizeof(m_array)); |
31 | 60 | } |
32 | 61 |
|
33 | 62 | /** |
34 | | - * Constructor creates a bitset from a number that can be of max |
35 | | - * 64 bit in size |
| 63 | + * Constructor creates a bitset from a number that |
| 64 | + * can be of max 64 bit in size. |
36 | 65 | * |
37 | | - * @param number the number to create bitset from |
| 66 | + * @param n the number to create bitset from |
38 | 67 | */ |
39 | | - explicit Bitset(uint64_t number){ |
40 | | - memset(m_array, 0, sizeof(m_array)); |
41 | | - |
42 | | - uint16_t size = sizeof(number) * 8; |
| 68 | + explicit Bitset(uint64_t n) { |
| 69 | + setFromNumber(n); |
| 70 | + } |
43 | 71 |
|
44 | | - if (size > bits) size = bits; |
| 72 | + /** |
| 73 | + * Copy constructor. |
| 74 | + * @param b Bitset to copy |
| 75 | + */ |
| 76 | + Bitset(Bitset<nBits>& b) { |
| 77 | + uint32_t end = ceil_bits<nBits>::value; |
| 78 | + for (uint16_t i = 0; i < end; i++) { |
| 79 | + m_array[i] = (m_array[i] & 0) | b.m_array[i]; |
| 80 | + } |
| 81 | + } |
45 | 82 |
|
46 | | - for (uint16_t index = 0; index < size; ++index) { |
47 | | - uint8_t remainder = (uint8_t) (number % 2); |
48 | | - number /= 2; |
| 83 | + /** |
| 84 | + * Copy constructor for const. |
| 85 | + * @param b Bitset to copy |
| 86 | + */ |
| 87 | + Bitset(const Bitset<nBits>& b) { |
| 88 | + uint32_t end = ceil_bits<nBits>::value; |
| 89 | + for (uint16_t i = 0; i < end; i++) { |
| 90 | + m_array[i] = (m_array[i] & 0) | b.m_array[i]; |
| 91 | + } |
| 92 | + } |
49 | 93 |
|
50 | | - if (remainder) set(index); |
51 | | - else reset(index); |
| 94 | + /** |
| 95 | + * Set the value of the Bitset from a number |
| 96 | + * of maximum 64 bit size. |
| 97 | + * @param n the number to set from |
| 98 | + */ |
| 99 | + void setFromNumber(uint64_t n) { |
| 100 | + memset(m_array, 0, sizeof(m_array)); |
| 101 | + constexpr uint32_t end = nBits / INT_SIZE; |
| 102 | + constexpr uint32_t extra = nBits - end * INT_SIZE; |
| 103 | + for (uint16_t i = 0; i < end; ++i) { |
| 104 | + m_array[i] = (uint32_t) n; |
| 105 | + n >>= INT_SIZE; |
| 106 | + } |
| 107 | + if (extra) { |
| 108 | + m_array[end] = ((uint32_t) n) & pow_mask<extra>::value; |
52 | 109 | } |
53 | 110 | } |
54 | 111 |
|
55 | 112 |
|
56 | 113 | /** |
57 | | - * Sets the bit at @code index to be true |
| 114 | + * Sets the bit at @code index to be true. |
58 | 115 | * |
59 | 116 | * @param index the index of the bit |
60 | 117 | */ |
61 | 118 | void set(uint16_t index) { |
62 | | - m_array[index / NO_OF_BITS] |= (1U << (index % NO_OF_BITS)); |
| 119 | + m_array[index / INT_SIZE] |= (1U << (index % INT_SIZE)); |
63 | 120 | } |
64 | 121 |
|
65 | 122 | /** |
66 | | - * Sets the bit at @code index to be false |
| 123 | + * Sets the bit at @code index to be false. |
67 | 124 | * |
68 | 125 | * @param index the index of the bit |
69 | 126 | */ |
70 | 127 | void reset(uint16_t index) { |
71 | | - m_array[index / NO_OF_BITS] &= ~(1U << (index % NO_OF_BITS)); |
| 128 | + m_array[index / INT_SIZE] &= ~(1U << (index % INT_SIZE)); |
72 | 129 | } |
73 | 130 |
|
74 | 131 | /** |
75 | | - * Toggles the but at @code index |
| 132 | + * Toggles the but at @code index. |
76 | 133 | * |
77 | 134 | * @param index the index of the bit |
78 | 135 | */ |
79 | 136 | void flip(uint16_t index) { |
80 | | - m_array[index / NO_OF_BITS] ^= (1U << (index % NO_OF_BITS)); |
| 137 | + m_array[index / INT_SIZE] ^= (1U << (index % INT_SIZE)); |
81 | 138 | } |
82 | 139 |
|
83 | 140 | /** |
84 | | - * Returns the value of bit at @code index |
| 141 | + * Returns the value of bit at @code index. |
85 | 142 | * |
86 | 143 | * @param index the index of the bit |
87 | 144 | * @return the bit value |
88 | 145 | */ |
89 | | - bool test(uint16_t index) { |
90 | | - return (m_array[index / NO_OF_BITS] & (1U << (index % NO_OF_BITS))) != 0; |
| 146 | + bool test(uint16_t index) const { |
| 147 | + return (m_array[index / INT_SIZE] & (1U << (index % INT_SIZE))) != 0; |
91 | 148 | } |
92 | 149 |
|
93 | 150 | /** |
94 | 151 | * Converts the bits into 64 bit unsigned integer |
95 | 152 | * |
96 | 153 | * @return unsigned 64 bit integer |
97 | 154 | */ |
98 | | - uint64_t to_uint64_t() { |
99 | | - uint64_t number = 0; |
100 | | - |
101 | | - for (uint8_t i = 0; i < 64; ++i) { |
102 | | - uint64_t powerVal = (uint64_t) ceil(pow(2, i)); |
103 | | - uint8_t bitVal = (uint8_t) test(i); |
104 | | - number += bitVal * powerVal; |
| 155 | + uint64_t to_uint64_t() const { |
| 156 | + if (nBits <= 32) { |
| 157 | + return to_uint32_t(); |
105 | 158 | } |
106 | | - |
107 | | - return number; |
| 159 | + return (((uint64_t) m_array[1]) << INT_SIZE) | ((uint32_t) m_array[0]); |
108 | 160 | } |
109 | 161 |
|
110 | 162 | /** |
111 | 163 | * Converts the bits into 32 bit unsigned integer |
112 | 164 | * |
113 | 165 | * @return unsigned 32 bit integer |
114 | 166 | */ |
115 | | - uint32_t to_uint32_t() { |
116 | | - uint32_t number = 0; |
117 | | - |
118 | | - for (uint8_t i = 0; i < 32; ++i) { |
119 | | - uint32_t powerVal = (uint32_t) ceil(pow(2, i)); |
120 | | - uint8_t bitVal = (uint8_t) test(i); |
121 | | - number += bitVal * powerVal; |
122 | | - } |
123 | | - |
124 | | - return number; |
| 167 | + uint32_t to_uint32_t() const { |
| 168 | + return (uint32_t) m_array[0]; |
125 | 169 | } |
126 | 170 |
|
127 | 171 | /** |
128 | 172 | * Converts the bits into 16 bit unsigned integer |
129 | 173 | * |
130 | 174 | * @return unsigned 16 bit integer |
131 | 175 | */ |
132 | | - uint16_t to_uint16_t() { |
133 | | - uint16_t number = 0; |
134 | | - |
135 | | - for (uint8_t i = 0; i < 16; ++i) { |
136 | | - uint16_t powerVal = (uint16_t) ceil(pow(2, i)); |
137 | | - uint8_t bitVal = (uint8_t) test(i); |
138 | | - number += bitVal * powerVal; |
139 | | - } |
140 | | - |
141 | | - return number; |
| 176 | + uint16_t to_uint16_t() const { |
| 177 | + return (uint16_t) (m_array[0] & pow_mask<16>::value); |
142 | 178 | } |
143 | 179 |
|
144 | 180 | /** |
145 | 181 | * Converts the bits into 8 bit unsigned integer |
146 | 182 | * |
147 | 183 | * @return unsigned 8 bit integer |
148 | 184 | */ |
149 | | - uint8_t to_uint8_t() { |
150 | | - uint8_t number = 0; |
| 185 | + uint8_t to_uint8_t() const { |
| 186 | + return (uint8_t) (m_array[0] & pow_mask<8>::value); |
| 187 | + } |
151 | 188 |
|
152 | | - for (uint8_t i = 0; i < 8; ++i) { |
153 | | - uint8_t powerVal = (uint8_t) ceil(pow(2, i)); |
154 | | - uint8_t bitVal = (uint8_t) test(i); |
155 | | - number += bitVal * powerVal; |
| 189 | + /** |
| 190 | + * Access operator returns the bit at the given position. |
| 191 | + * @param i the position of the bit to test |
| 192 | + * @return the value of the bit |
| 193 | + */ |
| 194 | + bool operator[](const uint16_t i) const { |
| 195 | + return test(i); |
| 196 | + } |
| 197 | + |
| 198 | + /** |
| 199 | + * Assignment operator copies the contents of the bitset. |
| 200 | + * @param b Bitset to assign |
| 201 | + */ |
| 202 | + Bitset<nBits>& operator=(Bitset<nBits>& b) { |
| 203 | + uint32_t end = ceil_bits<nBits>::value; |
| 204 | + for (uint16_t i = 0; i < end; i++) { |
| 205 | + m_array[i] = (m_array[i] & 0) | b.m_array[i]; |
156 | 206 | } |
| 207 | + return *this; |
| 208 | + } |
157 | 209 |
|
158 | | - return number; |
| 210 | + /** |
| 211 | + * Assignment operator copies the contents of the bitset. |
| 212 | + * @param b Bitset to assign |
| 213 | + */ |
| 214 | + Bitset<nBits>& operator=(const Bitset<nBits>& b) { |
| 215 | + uint32_t end = ceil_bits<nBits>::value; |
| 216 | + for (uint16_t i = 0; i < end; i++) { |
| 217 | + m_array[i] = (m_array[i] & 0) | b.m_array[i]; |
| 218 | + } |
| 219 | + return *this; |
159 | 220 | } |
160 | 221 |
|
161 | 222 | private: |
162 | | - int m_array[bits/ NO_OF_BITS]; |
| 223 | + /** |
| 224 | + * Backing array of integers that contain the bites. |
| 225 | + * Integer type arrays generally have the fastest access |
| 226 | + * times in C++. |
| 227 | + */ |
| 228 | + uint32_t m_array[ceil_bits<nBits>::value]; |
163 | 229 | }; |
164 | 230 | } |
165 | 231 |
|
|
0 commit comments