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/stl/unique_ptr.h"
4#include "fl/stl/int.h"
5
6#include "fl/math/math.h"
7#include "fl/stl/cstring.h"
9#include "fl/stl/noexcept.h"
10
11namespace fl {
12
13class string;
14
15namespace detail {
16void to_string(const fl::u16 *bit_data, fl::u32 bit_count, string* dst) FL_NOEXCEPT;
17}
18
21 private:
22 static constexpr fl::u32 bits_per_block = 8 * sizeof(fl::u16);
23 using block_type = fl::u16;
24
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) FL_NOEXCEPT { // okay static in header
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) FL_NOEXCEPT { resize(size); }
40
41 // Copy constructor
43 if (other._size > 0) {
44 resize(other._size);
45 fl::memcpy(_blocks.get(), other._blocks.get(), _block_count * sizeof(block_type));
46 }
47 }
48
49 // Move constructor
51 : _blocks(fl::move(other._blocks)), _block_count(other._block_count),
52 _size(other._size) {
53 other._block_count = 0;
54 other._size = 0;
55 }
56
57 // Copy assignment
59 if (this != &other) {
60 if (other._size > 0) {
61 resize(other._size);
62 fl::memcpy(_blocks.get(), other._blocks.get(),
63 _block_count * sizeof(block_type));
64 } else {
65 clear();
66 }
67 }
68 return *this;
69 }
70
71 // Move assignment
73 if (this != &other) {
74 _blocks = fl::move(other._blocks);
75 _block_count = other._block_count;
76 _size = other._size;
77 other._block_count = 0;
78 other._size = 0;
79 }
80 return *this;
81 }
82
83 // Destructor
84 ~bitset_dynamic() = default;
85
86 // Assign n bits to the value specified
89 void assign(fl::u32 n, bool value) FL_NOEXCEPT {
90 if (n > _size) {
91 resize(n);
92 }
93 if (value) {
94 // Set all bits to 1
95 if (_blocks && _block_count > 0) {
96 for (fl::u32 i = 0; i < _block_count; ++i) {
97 _blocks[i] = static_cast<block_type>(~block_type(0));
98 }
99 // Clear any bits beyond the actual size
100 if (_size % bits_per_block != 0) {
101 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
102 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
103 block_type mask = static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
104 _blocks[last_block_idx] &= mask;
105 }
106 }
107 } else {
108 // Set all bits to 0
109 reset();
110 }
111 }
113
114 // Resize the bitset
117 void resize(fl::u32 new_size) FL_NOEXCEPT {
118 if (new_size == _size)
119 return;
120
121 fl::u32 new_block_count = (new_size + bits_per_block - 1) / bits_per_block;
122
123 if (new_block_count != _block_count) {
124 block_type *new_blocks = new block_type[new_block_count]; // ok bare allocation (array new for unique_ptr)
125 fl::memset(new_blocks, 0, new_block_count * sizeof(block_type));
126
127 if (_blocks) {
128 fl::u32 copy_blocks = fl::min(_block_count, new_block_count);
129 fl::memcpy(new_blocks, _blocks.get(), copy_blocks * sizeof(block_type));
130 }
131
132 _blocks.reset(new_blocks);
133 _block_count = new_block_count;
134 }
135
136 _size = new_size;
137
138 // Clear any bits beyond the new size
139 if (_blocks && _block_count > 0 && _size % bits_per_block != 0) {
140 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
141 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
142 block_type mask =
143 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
144 _blocks[last_block_idx] &= mask;
145 }
146 }
148
149 // Clear the bitset (reset to empty)
151 _blocks.reset();
152 _block_count = 0;
153 _size = 0;
154 }
155
156 // Add a bit to the end (initialized to 0)
158 resize(_size + 1);
159 }
160
161 // Remove the last bit
163 if (_size > 0) {
164 resize(_size - 1);
165 }
166 }
167
168 // Reset all bits to 0
172 if (_blocks && _block_count > 0) {
173 fl::memset(_blocks.get(), 0, _block_count * sizeof(block_type));
174 }
175 }
177
178 // Reset a specific bit to 0
181 void reset(fl::u32 pos) FL_NOEXCEPT {
182 if (_blocks && pos < _size) {
183 const fl::u32 idx = pos / bits_per_block;
184 const fl::u32 off = pos % bits_per_block;
185 _blocks[idx] &= ~(static_cast<block_type>(1) << off);
186 }
187 }
189
190 // Set a specific bit to 1
193 void set(fl::u32 pos) FL_NOEXCEPT {
194 if (_blocks && pos < _size) {
195 const fl::u32 idx = pos / bits_per_block;
196 const fl::u32 off = pos % bits_per_block;
197 _blocks[idx] |= (static_cast<block_type>(1) << off);
198 }
199 }
201
202 // Set a specific bit to a given value
203 void set(fl::u32 pos, bool value) FL_NOEXCEPT {
204 if (value) {
205 set(pos);
206 } else {
207 reset(pos);
208 }
209 }
210
211 // Flip a specific bit
214 void flip(fl::u32 pos) FL_NOEXCEPT {
215 if (_blocks && pos < _size) {
216 const fl::u32 idx = pos / bits_per_block;
217 const fl::u32 off = pos % bits_per_block;
218 _blocks[idx] ^= (static_cast<block_type>(1) << off);
219 }
220 }
222
223 // Flip all bits
225 if (!_blocks) return;
226
227 for (fl::u32 i = 0; i < _block_count; ++i) {
228 _blocks[i] = ~_blocks[i];
229 }
230
231 // Clear any bits beyond size
232 if (_block_count > 0 && _size % bits_per_block != 0) {
233 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
234 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
235 block_type mask =
236 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
237 _blocks[last_block_idx] &= mask;
238 }
239 }
240
241 // Test if a bit is set
244 bool test(fl::u32 pos) const FL_NOEXCEPT {
245 if (_blocks && pos < _size) {
246 const fl::u32 idx = pos / bits_per_block;
247 const fl::u32 off = pos % bits_per_block;
248 return (_blocks[idx] >> off) & 1;
249 }
250 return false;
251 }
253
254 // Count the number of set bits
255 fl::u32 count() const FL_NOEXCEPT {
256 if (!_blocks) return 0;
257
258 fl::u32 result = 0;
259 for (fl::u32 i = 0; i < _block_count; ++i) {
260 result += static_cast<fl::u32>(__builtin_popcount(_blocks[i]));
261 }
262 return result;
263 }
264
265 // Check if any bit is set
266 bool any() const FL_NOEXCEPT {
267 if (!_blocks) return false;
268
269 for (fl::u32 i = 0; i < _block_count; ++i) {
270 if (_blocks[i] != 0)
271 return true;
272 }
273 return false;
274 }
275
276 // Check if no bit is set
277 bool none() const FL_NOEXCEPT { return !any(); }
278
279 // Check if all bits are set
280 bool all() const FL_NOEXCEPT {
281 if (_size == 0)
282 return true;
283
284 if (!_blocks) return false;
285
286 for (fl::u32 i = 0; i < _block_count - 1; ++i) {
287 if (_blocks[i] != static_cast<block_type>(~block_type(0)))
288 return false;
289 }
290
291 // Check last block with mask for valid bits
292 if (_block_count > 0) {
293 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
294 block_type mask =
295 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
296 return (_blocks[_block_count - 1] & mask) == mask;
297 }
298
299 return true;
300 }
301
302 // Get the size of the bitset
305 fl::u32 size() const FL_NOEXCEPT {
306 // Note: _size is a member variable, not a pointer, so this should be safe
307 // but we add this comment to clarify for static analysis
308 return _size;
309 }
311
312 // Convert bitset to string representation
313 void to_string(string* dst) const FL_NOEXCEPT;
314
315 // Access operator
316 bool operator[](fl::u32 pos) const FL_NOEXCEPT { return test(pos); }
317
322 fl::i32 find_first(bool test_value, fl::u32 offset = 0) const FL_NOEXCEPT {
323 // If offset is beyond our size, no match possible
324 if (offset >= _size) {
325 return -1;
326 }
327
328 // Calculate which block to start from
329 fl::u32 start_block = offset / bits_per_block;
330 fl::u32 start_bit = offset % bits_per_block;
331
332 for (fl::u32 block_idx = start_block; block_idx < _block_count; ++block_idx) {
333 block_type current_block = _blocks[block_idx];
334
335 // For the last block, we need to mask out unused bits
336 if (block_idx == _block_count - 1 && _size % bits_per_block != 0) {
337 const fl::u32 valid_bits = _size % bits_per_block;
338 block_type mask = (valid_bits == bits_per_block)
339 ? static_cast<block_type>(~block_type(0))
340 : static_cast<block_type>(((block_type(1) << valid_bits) - 1));
341 current_block &= mask;
342 }
343
344 // If looking for false bits, invert the block
345 if (!test_value) {
346 current_block = ~current_block;
347 }
348
349 // For the first block, mask out bits before the offset
350 if (block_idx == start_block && start_bit > 0) {
351 current_block &= ~static_cast<block_type>(((block_type(1) << start_bit) - 1));
352 }
353
354 // If there are any matching bits in this block
355 if (current_block != 0) {
356 // Find the first set bit
357 fl::u32 bit_pos = static_cast<fl::u32>(__builtin_ctz(current_block));
358 fl::u32 absolute_pos = block_idx * bits_per_block + bit_pos;
359
360 // Make sure we haven't gone past the end of the bitset
361 if (absolute_pos < _size) {
362 return static_cast<fl::i32>(absolute_pos);
363 }
364 }
365 }
366
367 return -1; // No matching bit found
368 }
369
370 // Bitwise AND operator
373
374 if (!_blocks || !other._blocks || !result._blocks) {
375 return result;
376 }
377
378 fl::u32 min_blocks = fl::min(_block_count, other._block_count);
379
380 for (fl::u32 i = 0; i < min_blocks; ++i) {
381 result._blocks[i] = _blocks[i] & other._blocks[i];
382 }
383
384 return result;
385 }
386
387 // Bitwise OR operator
390
391 if (!_blocks || !other._blocks || !result._blocks) {
392 return result;
393 }
394
395 fl::u32 min_blocks = fl::min(_block_count, other._block_count);
396
397 for (fl::u32 i = 0; i < min_blocks; ++i) {
398 result._blocks[i] = _blocks[i] | other._blocks[i];
399 }
400
401 // Copy remaining blocks from the larger bitset
402 if (_block_count > min_blocks) {
403 fl::memcpy(result._blocks.get() + min_blocks, _blocks.get() + min_blocks,
404 (_block_count - min_blocks) * sizeof(block_type));
405 }
406
407 return result;
408 }
409
410 // Bitwise XOR operator
413
414 if (!_blocks || !other._blocks || !result._blocks) {
415 return result;
416 }
417
418 fl::u32 min_blocks = fl::min(_block_count, other._block_count);
419
420 for (fl::u32 i = 0; i < min_blocks; ++i) {
421 result._blocks[i] = _blocks[i] ^ other._blocks[i];
422 }
423
424 // Copy remaining blocks from the larger bitset
425 if (_block_count > min_blocks) {
426 fl::memcpy(result._blocks.get() + min_blocks, _blocks.get() + min_blocks,
427 (_block_count - min_blocks) * sizeof(block_type));
428 }
429
430 return result;
431 }
432
433 // Bitwise NOT operator
436
437 if (!_blocks || !result._blocks) {
438 return result;
439 }
440
441 for (fl::u32 i = 0; i < _block_count; ++i) {
442 result._blocks[i] = ~_blocks[i];
443 }
444
445 // Clear any bits beyond size
446 if (_block_count > 0 && _size % bits_per_block != 0) {
447 fl::u32 last_block_idx = (_size - 1) / bits_per_block;
448 fl::u32 last_bit_pos = (_size - 1) % bits_per_block;
449 block_type mask =
450 static_cast<block_type>((static_cast<block_type>(1) << (last_bit_pos + 1)) - 1);
451 result._blocks[last_block_idx] &= mask;
452 }
453
454 return result;
455 }
456};
457
458} // namespace fl
uint8_t pos
Definition Blur.ino:11
bitset_dynamic & operator=(bitset_dynamic &&other) FL_NOEXCEPT
bitset_dynamic operator&(const bitset_dynamic &other) const FL_NOEXCEPT
bitset_dynamic operator|(const bitset_dynamic &other) const FL_NOEXCEPT
FL_DISABLE_WARNING_POP FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void reset(fl::u32 pos) FL_NOEXCEPT
FL_DISABLE_WARNING_POP FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void resize(fl::u32 new_size) FL_NOEXCEPT
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void flip(fl::u32 pos) FL_NOEXCEPT
fl::unique_ptr< block_type[]> _blocks
bitset_dynamic operator~() const FL_NOEXCEPT
bool none() const FL_NOEXCEPT
static fl::u32 calc_block_count(fl::u32 bit_count) FL_NOEXCEPT
FL_DISABLE_WARNING_POP void clear() FL_NOEXCEPT
bool operator[](fl::u32 pos) const FL_NOEXCEPT
bitset_dynamic(fl::u32 size) FL_NOEXCEPT
FL_DISABLE_WARNING_POP FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void set(fl::u32 pos) FL_NOEXCEPT
FL_DISABLE_WARNING_POP void to_string(string *dst) const FL_NOEXCEPT
void pop_back() FL_NOEXCEPT
FL_DISABLE_WARNING_POP void flip() FL_NOEXCEPT
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void reset() FL_NOEXCEPT
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE bool test(fl::u32 pos) const FL_NOEXCEPT
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE fl::u32 size() const FL_NOEXCEPT
~bitset_dynamic()=default
bitset_dynamic(bitset_dynamic &&other) FL_NOEXCEPT
bitset_dynamic operator^(const bitset_dynamic &other) const FL_NOEXCEPT
bitset_dynamic()=default
void push_back() FL_NOEXCEPT
bitset_dynamic & operator=(const bitset_dynamic &other) FL_NOEXCEPT
static constexpr fl::u32 bits_per_block
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void assign(fl::u32 n, bool value) FL_NOEXCEPT
fl::i32 find_first(bool test_value, fl::u32 offset=0) const FL_NOEXCEPT
Finds the first bit that matches the test value.
bool any() const FL_NOEXCEPT
bitset_dynamic(const bitset_dynamic &other) FL_NOEXCEPT
bool all() const FL_NOEXCEPT
FL_DISABLE_WARNING_POP void set(fl::u32 pos, bool value) FL_NOEXCEPT
FL_DISABLE_WARNING_POP fl::u32 count() const FL_NOEXCEPT
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
void to_string(const fl::u16 *bit_data, fl::u32 bit_count, string *dst)
Definition bitset.cpp.hpp:9
Compile-time linker keep-alive hook for a single fl::Bus.
Definition bus_traits.h:48
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NOEXCEPT
Definition math.h:71
void * memcpy(void *dest, const void *src, size_t n) FL_NOEXCEPT
constexpr int type_rank< T >::value
void * memset(void *s, int c, size_t n) FL_NOEXCEPT
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_NULL_DEREFERENCE
#define FL_DISABLE_WARNING_POP
#define FL_NOEXCEPT