FastLED 3.9.15
Loading...
Searching...
No Matches
bitset_dynamic.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stdint.h"
4#include "fl/int.h"
5#include <string.h> // for memcpy
6
7#include "fl/math_macros.h"
8#include "fl/memfill.h"
10
11namespace fl {
12
13class string;
14
15namespace detail {
16void to_string(const fl::u16 *bit_data, fl::u32 bit_count, string* dst);
17}
18
21 private:
22 static constexpr fl::u32 bits_per_block = 8 * sizeof(fl::u16);
23 using block_type = fl::u16;
24
25 block_type *_blocks = nullptr;
26 fl::u32 _block_count = 0;
27 fl::u32 _size = 0;
28
29 // Helper to calculate block count from bit count
30 static fl::u32 calc_block_count(fl::u32 bit_count) {
31 return (bit_count + bits_per_block - 1) / bits_per_block;
32 }
33
34 public:
35 // Default constructor
36 bitset_dynamic() = default;
37
38 // Constructor with initial size
39 explicit bitset_dynamic(fl::u32 size) { resize(size); }
40
41 // Copy constructor
43 if (other._size > 0) {
44 resize(other._size);
45 memcpy(_blocks, other._blocks, _block_count * sizeof(block_type));
46 }
47 }
48
49 // Move constructor
51 : _blocks(other._blocks), _block_count(other._block_count),
52 _size(other._size) {
53 other._blocks = nullptr;
54 other._block_count = 0;
55 other._size = 0;
56 }
57
58 // Copy assignment
60 if (this != &other) {
61 if (other._size > 0) {
62 resize(other._size);
63 memcpy(_blocks, other._blocks,
64 _block_count * sizeof(block_type));
65 } else {
66 clear();
67 }
68 }
69 return *this;
70 }
71
72 // Move assignment
74 if (this != &other) {
75 delete[] _blocks;
76 _blocks = other._blocks;
77 _block_count = other._block_count;
78 _size = other._size;
79 other._blocks = nullptr;
80 other._block_count = 0;
81 other._size = 0;
82 }
83 return *this;
84 }
85
86 // Destructor
87 ~bitset_dynamic() { delete[] _blocks; }
88
89 // Assign n bits to the value specified
92 void assign(fl::u32 n, bool value) {
93 if (n > _size) {
94 resize(n);
95 }
96 if (value) {
97 // Set all bits to 1
98 if (_blocks && _block_count > 0) {
99 for (fl::u32 i = 0; i < _block_count; ++i) {
100 _blocks[i] = static_cast<block_type>(~block_type(0));
101 }
102 // Clear any bits beyond the actual size
103 if (_size % bits_per_block != 0) {
104 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
105 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
106 block_type mask = static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
107 _blocks[last_block_idx] &= mask;
108 }
109 }
110 } else {
111 // Set all bits to 0
112 reset();
113 }
114 }
116
117 // Resize the bitset
120 void resize(fl::u32 new_size) {
121 if (new_size == _size)
122 return;
123
124 fl::u32 new_block_count = (new_size + bits_per_block - 1) / bits_per_block;
125
126 if (new_block_count != _block_count) {
127 block_type *new_blocks = new block_type[new_block_count];
128 fl::memfill(new_blocks, 0, new_block_count * sizeof(block_type));
129
130 if (_blocks) {
131 fl::u32 copy_blocks = MIN(_block_count, new_block_count);
132 memcpy(new_blocks, _blocks, copy_blocks * sizeof(block_type));
133 }
134
135 delete[] _blocks;
136 _blocks = new_blocks;
137 _block_count = new_block_count;
138 }
139
140 _size = new_size;
141
142 // Clear any bits beyond the new size
143 if (_blocks && _block_count > 0 && _size % bits_per_block != 0) {
144 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
145 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
146 block_type mask =
147 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
148 _blocks[last_block_idx] &= mask;
149 }
150 }
152
153 // Clear the bitset (reset to empty)
154 void clear() {
155 delete[] _blocks;
156 _blocks = nullptr;
157 _block_count = 0;
158 _size = 0;
159 }
160
161 // Reset all bits to 0
164 void reset() noexcept {
165 if (_blocks && _block_count > 0) {
167 }
168 }
170
171 // Reset a specific bit to 0
174 void reset(fl::u32 pos) noexcept {
175 if (_blocks && pos < _size) {
176 const fl::u32 idx = pos / bits_per_block;
177 const fl::u32 off = pos % bits_per_block;
178 _blocks[idx] &= ~(static_cast<block_type>(1) << off);
179 }
180 }
182
183 // Set a specific bit to 1
186 void set(fl::u32 pos) noexcept {
187 if (_blocks && pos < _size) {
188 const fl::u32 idx = pos / bits_per_block;
189 const fl::u32 off = pos % bits_per_block;
190 _blocks[idx] |= (static_cast<block_type>(1) << off);
191 }
192 }
194
195 // Set a specific bit to a given value
196 void set(fl::u32 pos, bool value) noexcept {
197 if (value) {
198 set(pos);
199 } else {
200 reset(pos);
201 }
202 }
203
204 // Flip a specific bit
207 void flip(fl::u32 pos) noexcept {
208 if (_blocks && pos < _size) {
209 const fl::u32 idx = pos / bits_per_block;
210 const fl::u32 off = pos % bits_per_block;
211 _blocks[idx] ^= (static_cast<block_type>(1) << off);
212 }
213 }
215
216 // Flip all bits
217 void flip() noexcept {
218 if (!_blocks) return;
219
220 for (fl::u32 i = 0; i < _block_count; ++i) {
221 _blocks[i] = ~_blocks[i];
222 }
223
224 // Clear any bits beyond size
225 if (_block_count > 0 && _size % bits_per_block != 0) {
226 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
227 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
228 block_type mask =
229 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
230 _blocks[last_block_idx] &= mask;
231 }
232 }
233
234 // Test if a bit is set
237 bool test(fl::u32 pos) const noexcept {
238 if (_blocks && pos < _size) {
239 const fl::u32 idx = pos / bits_per_block;
240 const fl::u32 off = pos % bits_per_block;
241 return (_blocks[idx] >> off) & 1;
242 }
243 return false;
244 }
246
247 // Count the number of set bits
248 fl::u32 count() const noexcept {
249 if (!_blocks) return 0;
250
251 fl::u32 result = 0;
252 for (fl::u32 i = 0; i < _block_count; ++i) {
253 result += static_cast<fl::u32>(__builtin_popcount(_blocks[i]));
254 }
255 return result;
256 }
257
258 // Check if any bit is set
259 bool any() const noexcept {
260 if (!_blocks) return false;
261
262 for (fl::u32 i = 0; i < _block_count; ++i) {
263 if (_blocks[i] != 0)
264 return true;
265 }
266 return false;
267 }
268
269 // Check if no bit is set
270 bool none() const noexcept { return !any(); }
271
272 // Check if all bits are set
273 bool all() const noexcept {
274 if (_size == 0)
275 return true;
276
277 if (!_blocks) return false;
278
279 for (fl::u32 i = 0; i < _block_count - 1; ++i) {
280 if (_blocks[i] != static_cast<block_type>(~block_type(0)))
281 return false;
282 }
283
284 // Check last block with mask for valid bits
285 if (_block_count > 0) {
286 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
287 block_type mask =
288 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
289 return (_blocks[_block_count - 1] & mask) == mask;
290 }
291
292 return true;
293 }
294
295 // Get the size of the bitset
298 fl::u32 size() const noexcept {
299 // Note: _size is a member variable, not a pointer, so this should be safe
300 // but we add this comment to clarify for static analysis
301 return _size;
302 }
304
305 // Convert bitset to string representation
306 void to_string(string* dst) const;
307
308 // Access operator
309 bool operator[](fl::u32 pos) const noexcept { return test(pos); }
310
315 fl::i32 find_first(bool test_value, fl::u32 offset = 0) const noexcept {
316 // If offset is beyond our size, no match possible
317 if (offset >= _size) {
318 return -1;
319 }
320
321 // Calculate which block to start from
322 fl::u32 start_block = offset / bits_per_block;
323 fl::u32 start_bit = offset % bits_per_block;
324
325 for (fl::u32 block_idx = start_block; block_idx < _block_count; ++block_idx) {
326 block_type current_block = _blocks[block_idx];
327
328 // For the last block, we need to mask out unused bits
329 if (block_idx == _block_count - 1 && _size % bits_per_block != 0) {
330 const fl::u32 valid_bits = _size % bits_per_block;
331 block_type mask = (valid_bits == bits_per_block)
332 ? static_cast<block_type>(~block_type(0))
333 : static_cast<block_type>(((block_type(1) << valid_bits) - 1));
334 current_block &= mask;
335 }
336
337 // If looking for false bits, invert the block
338 if (!test_value) {
339 current_block = ~current_block;
340 }
341
342 // For the first block, mask out bits before the offset
343 if (block_idx == start_block && start_bit > 0) {
344 current_block &= ~static_cast<block_type>(((block_type(1) << start_bit) - 1));
345 }
346
347 // If there are any matching bits in this block
348 if (current_block != 0) {
349 // Find the first set bit
350 fl::u32 bit_pos = static_cast<fl::u32>(__builtin_ctz(current_block));
351 fl::u32 absolute_pos = block_idx * bits_per_block + bit_pos;
352
353 // Make sure we haven't gone past the end of the bitset
354 if (absolute_pos < _size) {
355 return static_cast<fl::i32>(absolute_pos);
356 }
357 }
358 }
359
360 return -1; // No matching bit found
361 }
362
363 // Bitwise AND operator
366
367 if (!_blocks || !other._blocks || !result._blocks) {
368 return result;
369 }
370
371 fl::u32 min_blocks = MIN(_block_count, other._block_count);
372
373 for (fl::u32 i = 0; i < min_blocks; ++i) {
374 result._blocks[i] = _blocks[i] & other._blocks[i];
375 }
376
377 return result;
378 }
379
380 // Bitwise OR operator
383
384 if (!_blocks || !other._blocks || !result._blocks) {
385 return result;
386 }
387
388 fl::u32 min_blocks = MIN(_block_count, other._block_count);
389
390 for (fl::u32 i = 0; i < min_blocks; ++i) {
391 result._blocks[i] = _blocks[i] | other._blocks[i];
392 }
393
394 // Copy remaining blocks from the larger bitset
395 if (_block_count > min_blocks) {
396 memcpy(result._blocks + min_blocks, _blocks + min_blocks,
397 (_block_count - min_blocks) * sizeof(block_type));
398 }
399
400 return result;
401 }
402
403 // Bitwise XOR operator
406
407 if (!_blocks || !other._blocks || !result._blocks) {
408 return result;
409 }
410
411 fl::u32 min_blocks = MIN(_block_count, other._block_count);
412
413 for (fl::u32 i = 0; i < min_blocks; ++i) {
414 result._blocks[i] = _blocks[i] ^ other._blocks[i];
415 }
416
417 // Copy remaining blocks from the larger bitset
418 if (_block_count > min_blocks) {
419 memcpy(result._blocks + min_blocks, _blocks + min_blocks,
420 (_block_count - min_blocks) * sizeof(block_type));
421 }
422
423 return result;
424 }
425
426 // Bitwise NOT operator
429
430 if (!_blocks || !result._blocks) {
431 return result;
432 }
433
434 for (fl::u32 i = 0; i < _block_count; ++i) {
435 result._blocks[i] = ~_blocks[i];
436 }
437
438 // Clear any bits beyond size
439 if (_block_count > 0 && _size % bits_per_block != 0) {
440 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
441 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
442 block_type mask =
443 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
444 result._blocks[last_block_idx] &= mask;
445 }
446
447 return result;
448 }
449};
450
451} // namespace fl
uint8_t pos
Definition Blur.ino:11
bool all() const noexcept
bitset_dynamic & operator=(const bitset_dynamic &other)
bool operator[](fl::u32 pos) const noexcept
FL_DISABLE_WARNING_POP void clear()
bool none() const noexcept
FL_DISABLE_WARNING_POP FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void set(fl::u32 pos) noexcept
bitset_dynamic operator&(const bitset_dynamic &other) const
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE fl::u32 size() const noexcept
FL_DISABLE_WARNING_POP fl::u32 count() const noexcept
bitset_dynamic operator|(const bitset_dynamic &other) const
bitset_dynamic(const bitset_dynamic &other)
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void flip(fl::u32 pos) noexcept
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void assign(fl::u32 n, bool value)
FL_DISABLE_WARNING_POP void flip() noexcept
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE bool test(fl::u32 pos) const noexcept
static fl::u32 calc_block_count(fl::u32 bit_count)
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void reset() noexcept
FL_DISABLE_WARNING_POP FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void resize(fl::u32 new_size)
bitset_dynamic operator~() const
FL_DISABLE_WARNING_POP FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void reset(fl::u32 pos) noexcept
block_type * _blocks
fl::i32 find_first(bool test_value, fl::u32 offset=0) const noexcept
Finds the first bit that matches the test value.
bitset_dynamic()=default
FL_DISABLE_WARNING_POP void set(fl::u32 pos, bool value) noexcept
static constexpr fl::u32 bits_per_block
bool any() const noexcept
bitset_dynamic operator^(const bitset_dynamic &other) const
bitset_dynamic(bitset_dynamic &&other) noexcept
bitset_dynamic & operator=(bitset_dynamic &&other) noexcept
FL_DISABLE_WARNING_POP void to_string(string *dst) const
Definition bitset.cpp:24
bitset_dynamic(fl::u32 size)
Result type for promise operations.
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_NULL_DEREFERENCE
#define FL_DISABLE_WARNING_POP
UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
#define MIN(a, b)
Definition math_macros.h:41
void to_string(const fl::u16 *bit_data, fl::u32 bit_count, string *dst)
Definition bitset.cpp:8
void * memfill(void *ptr, int value, fl::size num)
Definition memfill.h:11
IMPORTANT!
Definition crgb.h:20