FastLED 3.9.12
Loading...
Searching...
No Matches
vector.h
1#pragma once
2
3#include <stdint.h>
4#include <stddef.h>
5
6#include "inplacenew.h"
7#include "fl/namespace.h"
8#include "fl/scoped_ptr.h"
9#include "fl/insert_result.h"
10
11namespace fl {
12
13
14// A fixed sized vector. The user is responsible for making sure that the
15// inserts do not exceed the capacity of the vector, otherwise they will fail.
16// Because of this limitation, this vector is not a drop in replacement for
17// std::vector.
18template<typename T, size_t N>
20private:
21 union {
22 char mRaw[N * sizeof(T)];
23 T mData[N];
24 };
25 size_t current_size = 0;
26
27public:
28 typedef T* iterator;
29 typedef const T* const_iterator;
30 // Constructor
31 constexpr FixedVector() : current_size(0) {}
32
33 FixedVector(const T (&values)[N]) : current_size(N) {
34 assign(values, N);
35 }
36
37 template<size_t M>
38 FixedVector(const T (&values)[M]) : current_size(M) {
39 static_assert(M <= N, "Too many elements for FixedVector");
40 assign(values, M);
41 }
42
43 // Destructor
44 ~FixedVector() {
45 clear();
46 }
47
48 // Array subscript operator
49 T& operator[](size_t index) {
50 return mData[index];
51 }
52
53 // Const array subscript operator
54 const T& operator[](size_t index) const {
55 if (index >= current_size) {
56 const T* out = nullptr;
57 return *out; // Cause a nullptr dereference
58 }
59 return mData[index];
60 }
61
62 // Get the current size of the vector
63 constexpr size_t size() const {
64 return current_size;
65 }
66
67 constexpr bool empty() const {
68 return current_size == 0;
69 }
70
71 // Get the capacity of the vector
72 constexpr size_t capacity() const {
73 return N;
74 }
75
76 // Add an element to the end of the vector
77 void push_back(const T& value) {
78 if (current_size < N) {
79 void* mem = &mData[current_size];
80 new (mem) T(value);
81 ++current_size;
82 }
83 }
84
85 void assign(const T* values, size_t count) {
86 clear();
87 for (size_t i = 0; i < count; ++i) {
88 push_back(values[i]);
89 }
90 }
91
92 void assign(const_iterator begin, const_iterator end) {
93 clear();
94 for (const_iterator it = begin; it != end; ++it) {
95 push_back(*it);
96 }
97 }
98
99 // Remove the last element from the vector
100 void pop_back() {
101 if (current_size > 0) {
102 --current_size;
103 mData[current_size].~T();
104 }
105 }
106
107 // Clear the vector
108 void clear() {
109 while (current_size > 0) {
110 pop_back();
111 }
112 }
113
114 // Erase the element at the given iterator position
115 iterator erase(iterator pos) {
116 if (pos != end()) {
117 pos->~T();
118 // shift all elements to the left
119 for (iterator p = pos; p != end() - 1; ++p) {
120 new (p) T(*(p + 1)); // Use copy constructor instead of std::move
121 (p + 1)->~T();
122 }
123 --current_size;
124 }
125 return pos;
126 }
127
128 iterator erase(const T& value) {
129 iterator it = find(value);
130 if (it != end()) {
131 erase(it);
132 }
133 return it;
134 }
135
136 iterator find(const T& value) {
137 for (iterator it = begin(); it != end(); ++it) {
138 if (*it == value) {
139 return it;
140 }
141 }
142 return end();
143 }
144
145 template<typename Predicate>
146 iterator find_if(Predicate pred) {
147 for (iterator it = begin(); it != end(); ++it) {
148 if (pred(*it)) {
149 return it;
150 }
151 }
152 return end();
153 }
154
155 bool insert(iterator pos, const T& value) {
156 if (current_size < N) {
157 // shift all elements to the right
158 for (iterator p = end(); p != pos; --p) {
159 new (p) T(*(p - 1)); // Use copy constructor instead of std::move
160 (p - 1)->~T();
161 }
162 new (pos) T(value);
163 ++current_size;
164 return true;
165 }
166 return false;
167 }
168
169 const_iterator find(const T& value) const {
170 for (const_iterator it = begin(); it != end(); ++it) {
171 if (*it == value) {
172 return it;
173 }
174 }
175 return end();
176 }
177
178 iterator data() {
179 return begin();
180 }
181
182 const_iterator data() const {
183 return begin();
184 }
185
186 bool has(const T& value) const {
187 return find(value) != end();
188 }
189
190 // Access to first and last elements
191 T& front() {
192 return mData[0];
193 }
194
195 const T& front() const {
196 return mData[0];
197 }
198
199 T& back() {
200 return mData[current_size - 1];
201 }
202
203 const T& back() const {
204 return mData[current_size - 1];
205 }
206
207 // Iterator support
208 iterator begin() { return &mData[0]; }
209 const_iterator begin() const { return &mData[0]; }
210 iterator end() { return &mData[current_size]; }
211 const_iterator end() const { return &mData[current_size]; }
212};
213
214
215template<typename T>
217private:
218 fl::scoped_array<T> mArray;
219
220 size_t mCapacity = 0;
221 size_t mSize = 0;
222
223 public:
224 typedef T* iterator;
225 typedef const T* const_iterator;
226
227 // Constructor
228 HeapVector(size_t size = 0, const T& value = T()): mCapacity(size) {
229 mArray.reset(new T[mCapacity]);
230 for (size_t i = 0; i < size; ++i) {
231 mArray[i] = value;
232 }
233 mSize = size;
234 }
235 HeapVector(const HeapVector<T>& other): mSize(other.size()) {
236 assign(other.begin(), other.end());
237 }
238 HeapVector& operator=(const HeapVector<T>& other) { // cppcheck-suppress operatorEqVarError
239 if (this != &other) {
240 assign(other.begin(), other.end());
241 }
242 return *this;
243 }
244
245 // Destructor
246 ~HeapVector() {
247 clear();
248 }
249
250 void ensure_size(size_t n) {
251 if (n > mCapacity) {
252 size_t new_capacity = (3*mCapacity) / 2;
253 if (new_capacity < n) {
254 new_capacity = n;
255 }
256 fl::scoped_array<T> new_array(new T[new_capacity]);
257 for (size_t i = 0; i < mSize; ++i) {
258 new_array[i] = mArray[i];
259 }
260 // mArray = std::move(new_array);
261 mArray.reset();
262 mArray.reset(new_array.release());
263 mCapacity = new_capacity;
264 }
265 }
266
267 void reserve(size_t n) {
268 if (n > mCapacity) {
269 ensure_size(n);
270 }
271 }
272
273 void resize(size_t n) {
274 if (mSize == n) {
275 return;
276 }
277 HeapVector<T> temp(n);
278 for (size_t i = 0; i < n && i < mSize; ++i) {
279 temp.mArray[i] = mArray[i];
280 }
281 swap(temp);
282 }
283
284 void resize(size_t n, const T& value) {
285 mArray.reset();
286 mArray.reset(new T[n]);
287 for (size_t i = 0; i < n; ++i) {
288 mArray[i] = value;
289 }
290 mCapacity = n;
291 }
292
293 // Array access operators
294 T& operator[](size_t index) {
295 return mArray[index];
296 }
297
298 const T& operator[](size_t index) const {
299 return mArray[index];
300 }
301
302 // Capacity and size methods
303 size_t size() const {
304 return mSize;
305 }
306
307 bool empty() const {
308 return mSize == 0;
309 }
310
311 size_t capacity() const {
312 return mCapacity;
313 }
314
315 // Element addition/removal
316 void push_back(const T& value) {
317 ensure_size(mSize + 1);
318 if (mSize < mCapacity) {
319 mArray[mSize] = value;
320 ++mSize;
321 }
322 }
323
324 void pop_back() {
325 if (mSize > 0) {
326 --mSize;
327 mArray[mSize] = T();
328 }
329 }
330
331 void clear() {
332 while (mSize > 0) {
333 pop_back();
334 }
335 }
336
337 // Iterator methods
338 iterator begin() { return &mArray[0]; }
339 const_iterator begin() const { return &mArray[0]; }
340 iterator end() { return &mArray[mSize]; }
341 const_iterator end() const { return &mArray[mSize]; }
342
343 // Element access
344 T& front() {
345 return mArray[0];
346 }
347
348 const T& front() const {
349 return mArray[0];
350 }
351
352 T& back() {
353 return mArray[mSize - 1];
354 }
355
356 const T& back() const {
357 return mArray[mSize - 1];
358 }
359
360 // Search and modification
361 iterator find(const T& value) {
362 for (iterator it = begin(); it != end(); ++it) {
363 if (*it == value) {
364 return it;
365 }
366 }
367 return end();
368 }
369
370 const_iterator find(const T& value) const {
371 for (const_iterator it = begin(); it != end(); ++it) {
372 if (*it == value) {
373 return it;
374 }
375 }
376 return end();
377 }
378
379 template<typename Predicate>
380 iterator find_if(Predicate pred) {
381 for (iterator it = begin(); it != end(); ++it) {
382 if (pred(*it)) {
383 return it;
384 }
385 }
386 return end();
387 }
388
389 bool has(const T& value) const {
390 return find(value) != end();
391 }
392
393 bool erase(iterator pos, T* out_value = nullptr) {
394 if (pos == end() || empty()) {
395 return false;
396 }
397 if (out_value) {
398 *out_value = *pos;
399 }
400 while (pos != end() - 1) {
401 *pos = *(pos + 1);
402 ++pos;
403 }
404 back() = T();
405 --mSize;
406 return true;
407 }
408
409 void erase(const T& value) {
410 iterator it = find(value);
411 if (it != end()) {
412 erase(it);
413 }
414 }
415
416 void swap(HeapVector<T>& other) {
417 T* temp = mArray.release();
418 size_t temp_size = mSize;
419 size_t temp_capacity = mCapacity;
420 T* temp2 = other.mArray.release();
421 mArray.reset(temp2);
422 other.mArray.reset(temp);
423 mSize = other.mSize;
424 mCapacity = other.mCapacity;
425 other.mSize = temp_size;
426 other.mCapacity = temp_capacity;
427 }
428
429 void swap(iterator a, iterator b) {
430 T temp = *a;
431 *a = *b;
432 *b = temp;
433 }
434
435 bool full() const {
436 return mSize >= mCapacity;
437 }
438
439 bool insert(iterator pos, const T& value) {
440 // TODO: Introduce mMaxSize (and move it from SortedVector to here)
441 // push back and swap into place.
442 size_t target_idx = pos - begin();
443 push_back(value);
444 auto last = end() - 1;
445 for (size_t curr_idx = last - begin(); curr_idx > target_idx; --curr_idx) {
446 auto first = begin() + curr_idx - 1;
447 auto second = begin() + curr_idx;
448 swap(first, second);
449 }
450 return true;
451 }
452
453 void assign(const T* values, size_t count) {
454 assign(values, values + count);
455 }
456
457 void assign(const_iterator begin, const_iterator end) {
458 clear();
459 reserve(end - begin);
460 for (const_iterator it = begin; it != end; ++it) {
461 push_back(*it);
462 }
463 }
464
465 T* data() {
466 return mArray.get();
467 }
468
469 const T* data() const {
470 return mArray.get();
471 }
472
473 bool operator==(const HeapVector<T>& other) const {
474 if (size() != other.size()) {
475 return false;
476 }
477 for (size_t i = 0; i < size(); ++i) {
478 if (mArray[i] != other.mArray[i]) {
479 return false;
480 }
481 }
482 return true;
483 }
484
485 bool operator!=(const HeapVector<T>& other) const {
486 return !(*this == other);
487 }
488};
489
490
491template <typename T, typename LessThan>
493private:
494 HeapVector<T> mArray;
495 LessThan mLess;
496 size_t mMaxSize = size_t(-1);
497
498public:
499 typedef typename HeapVector<T>::iterator iterator;
501
502 SortedHeapVector(LessThan less=LessThan()): mLess(less) {}
503
504 void setMaxSize(size_t n) {
505 if (mMaxSize == n) {
506 return;
507 }
508 mMaxSize = n;
509 const bool needs_adjustment = mArray.size() > mMaxSize;
510 if (needs_adjustment) {
511 mArray.resize(n);
512 } else {
513 mArray.reserve(n);
514 }
515 }
516
518 mArray.clear();
519 }
520
521 void reserve(size_t n) {
522 mArray.reserve(n);
523 }
524
525 // Insert while maintaining sort order
526 bool insert(const T& value, InsertResult* result = nullptr) {
527 // Find insertion point using binary search
528 iterator pos = lower_bound(value);
529 if (pos != end() && !mLess(value, *pos) && !mLess(*pos, value)) {
530 // return false; // Already inserted.
531 if (result) {
532 // *result = kExists;
533 *result = InsertResult::kExists;
534 }
535
536 return false;
537 }
538 if (mArray.size() >= mMaxSize) {
539 // return false; // Too full
540 if (result) {
541 *result = InsertResult::kMaxSize;
542 }
543 return false;
544 }
545 mArray.insert(pos, value);
546 if (result) {
547 *result = kInserted;
548 }
549
550 return true;
551 }
552
553 // Find the first position where we should insert value to maintain sort order
554 iterator lower_bound(const T& value) {
555 iterator first = mArray.begin();
556 iterator last = mArray.end();
557
558 while (first != last) {
559 iterator mid = first + (last - first) / 2;
560
561 if (mLess(*mid, value)) {
562 first = mid + 1;
563 } else {
564 last = mid;
565 }
566 }
567 return first;
568 }
569
570 const_iterator lower_bound(const T& value) const {
571 return const_cast<SortedHeapVector*>(this)->lower_bound(value);
572 }
573
574 // Lookup operations
575 iterator find(const T& value) {
576 iterator pos = lower_bound(value);
577 if (pos != end() && !mLess(value, *pos) && !mLess(*pos, value)) {
578 return pos;
579 }
580 return end();
581 }
582
583 void swap(SortedHeapVector& other) {
584 mArray.swap(other.mArray);
585 }
586
587 const_iterator find(const T& value) const {
588 return const_cast<SortedHeapVector*>(this)->find(value);
589 }
590
591 bool has(const T& value) const {
592 return find(value) != end();
593 }
594
595 // Removal operations
596 bool erase(const T& value) {
597 iterator it = find(value);
598 if (it != end()) {
599 return mArray.erase(it);
600 }
601 return false;
602 }
603
604 bool erase(iterator pos) {
605 return mArray.erase(pos);
606 }
607
608 // Basic container operations
609 size_t size() const { return mArray.size(); }
610 bool empty() const { return mArray.empty(); }
611 size_t capacity() const { return mArray.capacity(); }
612 void clear() { mArray.clear(); }
613 bool full() const {
614 if (mArray.size() >= mMaxSize) {
615 return true;
616 }
617 return mArray.full();
618 }
619
620 // Element access
621 T& operator[](size_t index) { return mArray[index]; }
622 const T& operator[](size_t index) const { return mArray[index]; }
623
624 T& front() { return mArray.front(); }
625 const T& front() const { return mArray.front(); }
626
627 T& back() { return mArray.back(); }
628 const T& back() const { return mArray.back(); }
629
630 // Iterators
631 iterator begin() { return mArray.begin(); }
632 const_iterator begin() const { return mArray.begin(); }
633 iterator end() { return mArray.end(); }
634 const_iterator end() const { return mArray.end(); }
635
636 // Raw data access
637 T* data() { return mArray.data(); }
638 const T* data() const { return mArray.data(); }
639};
640
641
642} // namespace fl
Implements the FastLED namespace macros.
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
Definition pair.h:6