FastLED 3.10.6
Loading...
Searching...
No Matches
deque.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/stdint.h"
4
5#include "fl/stl/deque_basic.h" // detail::deque_grow_map_capacity (#3270)
6#include "fl/stl/move.h"
7#include "fl/stl/iterator.h"
9#include "fl/stl/new.h" // IWYU pragma: keep
10#include "fl/stl/noexcept.h"
11#include "fl/system/sketch_macros.h" // FL_PLATFORM_HAS_LARGE_MEMORY
12
13namespace fl {
14
15// Per-type chunk-size trait. Specialize to override the default chunk size
16// for a particular T (e.g. when the typical deque<T> sliding window has a
17// known fixed extent that should match the chunk size). See FastLED #3270.
18template <typename T>
20 static constexpr fl::size chunk_size =
21#if FL_PLATFORM_HAS_LARGE_MEMORY
22 64u;
23#else
24 16u;
25#endif
26};
27
28template <typename T>
29class deque {
30private:
31 // Map-of-fixed-size-chunks layout. Existing elements are NEVER moved on
32 // grow; only the chunk-pointer map is reallocated when one side runs out
33 // of room. push_back / push_front allocate a new chunk at the active
34 // end as needed; intermediate chunks (between front and back) are
35 // always allocated. See FastLED #3270.
36 static constexpr fl::size kChunkSize = deque_traits<T>::chunk_size;
37
38 T** mMap = nullptr; // array of T* chunk pointers, length mMapCapacity
39 fl::size mMapCapacity = 0; // number of chunk slots in mMap
40 fl::size mFrontMapIdx = 0; // index in mMap of the chunk holding the front element
41 fl::size mFrontOffset = 0; // offset within front chunk of the front element [0, kChunkSize)
42 fl::size mSize = 0; // total elements
44
46 return static_cast<T*>(mResource->allocate(kChunkSize * sizeof(T)));
47 }
48
50 if (chunk) {
51 mResource->deallocate(chunk, kChunkSize * sizeof(T));
52 }
53 }
54
56 T** m = static_cast<T**>(mResource->allocate(capacity * sizeof(T*)));
57 if (m) {
58 for (fl::size i = 0; i < capacity; ++i) {
59 m[i] = nullptr;
60 }
61 }
62 return m;
63 }
64
66 if (map) {
67 mResource->deallocate(map, capacity * sizeof(T*));
68 }
69 }
70
71 // Translate logical index -> (chunk_idx in mMap, offset within chunk).
72 // Caller validates `logical_idx < mSize` (or == mSize for end-position).
73 void locate(fl::size logical_idx, fl::size& chunk_idx, fl::size& offset) const FL_NO_EXCEPT {
74 fl::size global = mFrontOffset + logical_idx;
75 chunk_idx = mFrontMapIdx + global / kChunkSize;
76 offset = global % kChunkSize;
77 }
78
79 // Number of currently-used chunk slots [mFrontMapIdx .. back_chunk_idx].
80 fl::size used_chunks() const FL_NO_EXCEPT {
81 if (mSize == 0) return 0;
82 fl::size last_global = mFrontOffset + mSize - 1;
83 fl::size last_chunk = mFrontMapIdx + last_global / kChunkSize;
84 return last_chunk - mFrontMapIdx + 1;
85 }
86
87 // Grow the chunk-pointer map. After return:
88 // - mMap has at least `extra_front` empty slots before mFrontMapIdx
89 // - mMap has at least `extra_back` empty slots after the back chunk
90 // Live chunk pointers in [mFrontMapIdx, mFrontMapIdx+used) are preserved
91 // (chunks themselves are never moved). Orphaned chunks outside that range
92 // (left behind by prior pop_front / pop_back when a chunk emptied without
93 // being released) are FREED here -- otherwise the old `mMap` is
94 // deallocated below and those chunk pointers are lost forever, leaking
95 // their backing storage. See FastLED #3286.
96 // mFrontMapIdx may shift to a new position within the new map.
97 void grow_map(fl::size extra_front, fl::size extra_back) FL_NO_EXCEPT {
98 fl::size used = used_chunks();
99 fl::size needed = used + extra_front + extra_back;
100 fl::size new_cap = detail::deque_grow_map_capacity(mMapCapacity, needed);
101 // Center the existing chunks within the new map, biased to leave the
102 // requested extra room on each side.
103 fl::size new_front = extra_front + (new_cap - needed) / 2;
104 T** new_map = allocate_map(new_cap);
105 if (!new_map) {
106 // Allocation failure: match the silent-fail behavior of the prior
107 // vector-style ensure_capacity. Callers must defensively check
108 // capacity / size after push_*.
109 return;
110 }
111 // Free any chunk pointers in the OLD map that live outside the
112 // [mFrontMapIdx, mFrontMapIdx+used) live range; those are orphans
113 // and would otherwise leak when the old map is deallocated.
114 fl::size live_end = mFrontMapIdx + used;
115 for (fl::size i = 0; i < mMapCapacity; ++i) {
116 if (i < mFrontMapIdx || i >= live_end) {
118 mMap[i] = nullptr;
119 }
120 }
121 for (fl::size i = 0; i < used; ++i) {
122 new_map[new_front + i] = mMap[mFrontMapIdx + i];
123 }
125 mMap = new_map;
126 mMapCapacity = new_cap;
127 mFrontMapIdx = new_front;
128 }
129
130 // Ensure the chunk that will hold the next push_back exists. May grow
131 // the map if the back chunk lies past mMapCapacity.
133 fl::size global = mFrontOffset + mSize;
134 fl::size need_chunk_idx = mFrontMapIdx + global / kChunkSize;
135 if (need_chunk_idx >= mMapCapacity) {
136 grow_map(0, 1);
137 global = mFrontOffset + mSize;
138 need_chunk_idx = mFrontMapIdx + global / kChunkSize;
139 if (need_chunk_idx >= mMapCapacity) return; // grow failed
140 }
141 if (mMap[need_chunk_idx] == nullptr) {
142 mMap[need_chunk_idx] = allocate_chunk();
143 }
144 }
145
146 // Ensure the chunk that will hold the next push_front exists. May grow
147 // the map if push_front would step before mMap[0].
149 if (mFrontOffset > 0) {
150 // Stays within current front chunk; that chunk is guaranteed
151 // allocated when mSize > 0, and allocated below for empty deque.
152 if (mMapCapacity == 0) {
153 grow_map(1, 0);
154 if (mMapCapacity == 0) return;
155 }
156 if (mMap[mFrontMapIdx] == nullptr) {
158 }
159 return;
160 }
161 // mFrontOffset == 0: need the previous chunk.
162 if (mFrontMapIdx == 0) {
163 grow_map(1, 0);
164 if (mFrontMapIdx == 0) return; // grow failed
165 }
166 if (mMap[mFrontMapIdx - 1] == nullptr) {
168 }
169 }
170
171public:
172 // Iterator implementation (RandomAccessIterator). The iterator carries
173 // only `(deque*, logical_index)` and resolves to a chunk pointer at
174 // dereference time. Pointer stability for T* taken at insertion time is
175 // provided by chunks themselves never being moved; iterator stability
176 // is preserved across push at either end (logical_index of pre-existing
177 // elements doesn't change for push_back, and is adjusted internally by
178 // mFrontOffset / mFrontMapIdx for push_front).
179 class iterator {
180 public:
181 typedef T value_type;
182 typedef T& reference;
183 typedef T* pointer;
184 typedef fl::size difference_type;
186
187 private:
189 fl::size mIndex;
190
191 friend class deque;
192
193 public:
194 iterator(deque* dq, fl::size index) : mDeque(dq), mIndex(index) {}
195
196 T& operator*() const {
197 return (*mDeque)[mIndex];
198 }
199
200 T* operator->() const {
201 return &(*mDeque)[mIndex];
202 }
203
205 ++mIndex;
206 return *this;
207 }
208
210 iterator temp = *this;
211 ++mIndex;
212 return temp;
213 }
214
216 --mIndex;
217 return *this;
218 }
219
221 iterator temp = *this;
222 --mIndex;
223 return temp;
224 }
225
226 iterator& operator+=(fl::size n) {
227 mIndex += n;
228 return *this;
229 }
230
231 iterator operator+(fl::size n) const {
232 iterator temp = *this;
233 return temp += n;
234 }
235
236 iterator& operator-=(fl::size n) {
237 mIndex -= n;
238 return *this;
239 }
240
241 iterator operator-(fl::size n) const {
242 iterator temp = *this;
243 return temp -= n;
244 }
245
246 fl::size operator-(const iterator& other) const {
247 return mIndex - other.mIndex;
248 }
249
250 T& operator[](fl::size n) const {
251 return (*mDeque)[mIndex + n];
252 }
253
254 bool operator==(const iterator& other) const {
255 return mDeque == other.mDeque && mIndex == other.mIndex;
256 }
257
258 bool operator!=(const iterator& other) const {
259 return !(*this == other);
260 }
261
262 bool operator<(const iterator& other) const {
263 return mIndex < other.mIndex;
264 }
265
266 bool operator<=(const iterator& other) const {
267 return mIndex <= other.mIndex;
268 }
269
270 bool operator>(const iterator& other) const {
271 return mIndex > other.mIndex;
272 }
273
274 bool operator>=(const iterator& other) const {
275 return mIndex >= other.mIndex;
276 }
277 };
278
280 public:
281 typedef T value_type;
282 typedef const T& reference;
283 typedef const T* pointer;
284 typedef fl::size difference_type;
286
287 private:
288 const deque* mDeque;
289 fl::size mIndex;
290
291 friend class deque;
292
293 public:
294 const_iterator(const deque* dq, fl::size index) : mDeque(dq), mIndex(index) {}
295
296 // Implicit conversion from iterator to const_iterator
298
299 const T& operator*() const {
300 return (*mDeque)[mIndex];
301 }
302
303 const T* operator->() const {
304 return &(*mDeque)[mIndex];
305 }
306
308 ++mIndex;
309 return *this;
310 }
311
313 const_iterator temp = *this;
314 ++mIndex;
315 return temp;
316 }
317
319 --mIndex;
320 return *this;
321 }
322
324 const_iterator temp = *this;
325 --mIndex;
326 return temp;
327 }
328
330 mIndex += n;
331 return *this;
332 }
333
334 const_iterator operator+(fl::size n) const {
335 const_iterator temp = *this;
336 return temp += n;
337 }
338
340 mIndex -= n;
341 return *this;
342 }
343
344 const_iterator operator-(fl::size n) const {
345 const_iterator temp = *this;
346 return temp -= n;
347 }
348
349 fl::size operator-(const const_iterator& other) const {
350 return mIndex - other.mIndex;
351 }
352
353 const T& operator[](fl::size n) const {
354 return (*mDeque)[mIndex + n];
355 }
356
357 bool operator==(const const_iterator& other) const {
358 return mDeque == other.mDeque && mIndex == other.mIndex;
359 }
360
361 bool operator!=(const const_iterator& other) const {
362 return !(*this == other);
363 }
364
365 bool operator<(const const_iterator& other) const {
366 return mIndex < other.mIndex;
367 }
368
369 bool operator<=(const const_iterator& other) const {
370 return mIndex <= other.mIndex;
371 }
372
373 bool operator>(const const_iterator& other) const {
374 return mIndex > other.mIndex;
375 }
376
377 bool operator>=(const const_iterator& other) const {
378 return mIndex >= other.mIndex;
379 }
380 };
381
384
385 // Constructors
387
388 explicit deque(memory_resource* resource) FL_NO_EXCEPT : mResource(resource) {}
389
390 explicit deque(fl::size count, const T& value = T()) : deque() {
391 resize(count, value);
392 }
393
394 deque(const deque& other) FL_NO_EXCEPT : deque() {
395 *this = other;
396 }
397
399 *this = fl::move(other);
400 }
401
402 deque(fl::initializer_list<T> init) : deque() {
403 for (const auto& value : init) {
405 }
406 }
407
409 clear();
410 // Deallocate any remaining chunk pointers (clear() releases element
411 // storage but may leave the map intact for reuse on a still-live deque;
412 // here we tear it down for good).
413 for (fl::size i = 0; i < mMapCapacity; ++i) {
415 }
417 }
418
420 if (this != &other) {
421 clear();
422 for (fl::size i = 0; i < other.size(); ++i) {
423 push_back(other[i]);
424 }
425 }
426 return *this;
427 }
428
430 if (this != &other) {
431 // Tear down current state.
432 clear();
433 for (fl::size i = 0; i < mMapCapacity; ++i) {
435 }
437
438 mMap = other.mMap;
439 mMapCapacity = other.mMapCapacity;
440 mFrontMapIdx = other.mFrontMapIdx;
441 mFrontOffset = other.mFrontOffset;
442 mSize = other.mSize;
443 mResource = other.mResource;
444
445 other.mMap = nullptr;
446 other.mMapCapacity = 0;
447 other.mFrontMapIdx = 0;
448 other.mFrontOffset = 0;
449 other.mSize = 0;
450 }
451 return *this;
452 }
453
454 // Element access
455 T& operator[](fl::size index) {
456 fl::size c, o; locate(index, c, o);
457 return mMap[c][o];
458 }
459
460 const T& operator[](fl::size index) const {
461 fl::size c, o; locate(index, c, o);
462 return mMap[c][o];
463 }
464
465 T& at(fl::size index) {
466 if (index >= mSize) {
467 // Bounds error: return front in embedded context (matching the
468 // pre-#3270 deque's documented fallback).
469 return front();
470 }
471 fl::size c, o; locate(index, c, o);
472 return mMap[c][o];
473 }
474
475 const T& at(fl::size index) const {
476 if (index >= mSize) {
477 return front();
478 }
479 fl::size c, o; locate(index, c, o);
480 return mMap[c][o];
481 }
482
483 T& front() {
485 }
486
487 const T& front() const {
489 }
490
491 T& back() {
492 fl::size c, o; locate(mSize - 1, c, o);
493 return mMap[c][o];
494 }
495
496 const T& back() const {
497 fl::size c, o; locate(mSize - 1, c, o);
498 return mMap[c][o];
499 }
500
501 iterator begin() FL_NO_EXCEPT { return iterator(this, 0); }
502 const_iterator begin() const FL_NO_EXCEPT { return const_iterator(this, 0); }
503 iterator end() FL_NO_EXCEPT { return iterator(this, mSize); }
504 const_iterator end() const FL_NO_EXCEPT { return const_iterator(this, mSize); }
505
510
511 const_iterator cbegin() const FL_NO_EXCEPT { return const_iterator(this, 0); }
512 const_iterator cend() const FL_NO_EXCEPT { return const_iterator(this, mSize); }
515
516 bool empty() const FL_NO_EXCEPT { return mSize == 0; }
517 fl::size size() const FL_NO_EXCEPT { return mSize; }
518
519 // Total addressable storage in the currently-allocated chunks. Returns
520 // a chunk-size-quantized value (multiple of kChunkSize). The old
521 // vector-style deque reported exact element capacity; chunked deques
522 // report whole-chunk capacity. See FastLED #3270 migration plan.
523 fl::size capacity() const {
524 fl::size allocated = 0;
525 for (fl::size i = 0; i < mMapCapacity; ++i) {
526 if (mMap[i] != nullptr) ++allocated;
527 }
528 return allocated * kChunkSize;
529 }
530
531 fl::size max_size() const {
532 return static_cast<fl::size>(-1) / sizeof(T);
533 }
534
535 // Ensure capacity for at least `n` elements from the current front.
536 // Chunked: pre-allocates ceil(n / kChunkSize) chunks at the back.
537 void reserve(fl::size n) FL_NO_EXCEPT {
538 if (n <= capacity()) return;
539 // Allocate enough chunks behind the current front-offset to hold n total.
540 fl::size needed_chunks = (mFrontOffset + n + kChunkSize - 1) / kChunkSize;
541 fl::size cur_chunks = used_chunks();
542 if (cur_chunks < needed_chunks) {
543 fl::size extra = needed_chunks - cur_chunks;
544 // Ensure mMap has room for `extra` more chunks past current back.
545 fl::size last_used_idx = (mSize == 0) ? mFrontMapIdx : (mFrontMapIdx + used_chunks() - 1);
546 if (last_used_idx + extra >= mMapCapacity) {
547 grow_map(0, extra);
548 }
549 // Allocate chunks at the back to cover [front .. front+n).
550 fl::size first_new = (mSize == 0) ? mFrontMapIdx : (mFrontMapIdx + cur_chunks);
551 for (fl::size i = 0; i < extra; ++i) {
552 if (first_new + i >= mMapCapacity) break;
553 if (mMap[first_new + i] == nullptr) {
554 mMap[first_new + i] = allocate_chunk();
555 }
556 }
557 }
558 }
559
560 // Release chunks that hold no live elements. After return, only the
561 // chunks spanning [front .. back] remain allocated. Capacity is
562 // quantized to kChunkSize and equals ceil(size / kChunkSize) * kChunkSize.
564 if (mSize == 0) {
565 // Release every chunk and the map itself.
566 for (fl::size i = 0; i < mMapCapacity; ++i) {
568 mMap[i] = nullptr;
569 }
571 mMap = nullptr;
572 mMapCapacity = 0;
573 mFrontMapIdx = 0;
574 mFrontOffset = 0;
575 return;
576 }
577 // Release chunks outside [front .. back].
578 fl::size last_used = mFrontMapIdx + used_chunks() - 1;
579 for (fl::size i = 0; i < mMapCapacity; ++i) {
580 if (i < mFrontMapIdx || i > last_used) {
582 mMap[i] = nullptr;
583 }
584 }
585 }
586
588
589 void clear() {
590 for (fl::size i = 0; i < mSize; ++i) {
591 fl::size c, o; locate(i, c, o);
592 mMap[c][o].~T();
593 }
594 mSize = 0;
595 // Reset front to the start of its current chunk so subsequent
596 // pushes don't waste leading-chunk space. Chunks themselves stay
597 // allocated for reuse; callers wanting deallocation should call
598 // shrink_to_fit() afterward.
599 mFrontOffset = 0;
600 }
601
602 void push_back(const T& value) {
604 fl::size global = mFrontOffset + mSize;
605 fl::size c = mFrontMapIdx + global / kChunkSize;
606 fl::size o = global % kChunkSize;
607 new (&mMap[c][o]) T(value);
608 ++mSize;
609 }
610
611 void push_back(T&& value) {
613 fl::size global = mFrontOffset + mSize;
614 fl::size c = mFrontMapIdx + global / kChunkSize;
615 fl::size o = global % kChunkSize;
616 new (&mMap[c][o]) T(fl::move(value));
617 ++mSize;
618 }
619
620 void push_front(const T& value) {
622 if (mFrontOffset == 0) {
623 --mFrontMapIdx;
625 } else {
626 --mFrontOffset;
627 }
629 ++mSize;
630 }
631
632 void push_front(T&& value) {
634 if (mFrontOffset == 0) {
635 --mFrontMapIdx;
637 } else {
638 --mFrontOffset;
639 }
641 ++mSize;
642 }
643
644 void pop_back() {
645 if (mSize == 0) return;
646 fl::size c, o; locate(mSize - 1, c, o);
647 mMap[c][o].~T();
648 --mSize;
649 }
650
651 void pop_front() {
652 if (mSize == 0) return;
654 ++mFrontOffset;
655 if (mFrontOffset == kChunkSize) {
656 mFrontOffset = 0;
657 ++mFrontMapIdx;
658 }
659 --mSize;
660 }
661
662 void resize(fl::size new_size) {
663 resize(new_size, T());
664 }
665
666 void resize(fl::size new_size, const T& value) {
667 while (mSize < new_size) push_back(value);
668 while (mSize > new_size) pop_back();
669 }
670
671 void swap(deque& other) {
672 if (this != &other) {
673 T** t_map = mMap;
674 fl::size t_cap = mMapCapacity;
675 fl::size t_idx = mFrontMapIdx;
676 fl::size t_off = mFrontOffset;
677 fl::size t_size = mSize;
678 memory_resource* t_res = mResource;
679
680 mMap = other.mMap;
684 mSize = other.mSize;
685 mResource = other.mResource;
686
687 other.mMap = t_map;
688 other.mMapCapacity = t_cap;
689 other.mFrontMapIdx = t_idx;
690 other.mFrontOffset = t_off;
691 other.mSize = t_size;
692 other.mResource = t_res;
693 }
694 }
695
696 // Insert / emplace / erase use a higher-level strategy than the
697 // vector-style deque: instead of manual ~T() + placement-new bookkeeping
698 // across un-allocated chunk slots, they (1) extend the deque by pushing
699 // a copy of the current back (or the new value when the deque is
700 // empty), which routes through push_back's chunk-allocation path, then
701 // (2) shift via operator[] assignment. Erase is symmetric: shift via
702 // assignment then pop_back. Requires CopyConstructible + CopyAssignable
703 // T, the same contract as std::deque::insert.
704
705 iterator insert(const_iterator pos, const T& value) {
706 fl::size idx = pos.mIndex;
707 if (idx == mSize) {
709 return iterator(this, idx);
710 }
711 // Push a copy of the current back to extend by one; chunk alloc
712 // is handled inside push_back.
713 push_back((*this)[mSize - 1]);
714 for (fl::size i = mSize - 1; i > idx + 1; --i) {
715 (*this)[i - 1] = fl::move((*this)[i - 2]);
716 }
717 (*this)[idx] = value;
718 return iterator(this, idx);
719 }
720
721 iterator insert(const_iterator pos, T&& value) {
722 fl::size idx = pos.mIndex;
723 if (idx == mSize) {
725 return iterator(this, idx);
726 }
727 // Move-extend at the back so move-only T works. The moved-from
728 // slot at old logical mSize-1 is overwritten by the shift loop.
729 push_back(fl::move((*this)[mSize - 1]));
730 for (fl::size i = mSize - 1; i > idx + 1; --i) {
731 (*this)[i - 1] = fl::move((*this)[i - 2]);
732 }
733 (*this)[idx] = fl::move(value);
734 return iterator(this, idx);
735 }
736
737 iterator insert(const_iterator pos, fl::size count, const T& value) {
738 fl::size idx = pos.mIndex;
739 if (count == 0) return iterator(this, idx);
740 fl::size old_size = mSize;
741 // Extend by `count` slots. First push uses `value` if the deque
742 // is empty, else copies the current back; subsequent pushes copy
743 // whatever's at the back now. All these copies will be overwritten
744 // by the shift + fill below.
745 for (fl::size k = 0; k < count; ++k) {
746 if (mSize == 0) push_back(value);
747 else push_back((*this)[mSize - 1]);
748 }
749 // Shift elements [idx .. old_size) right by `count` slots.
750 for (fl::size i = old_size; i > idx; --i) {
751 (*this)[i - 1 + count] = fl::move((*this)[i - 1]);
752 }
753 for (fl::size i = 0; i < count; ++i) {
754 (*this)[idx + i] = value;
755 }
756 return iterator(this, idx);
757 }
758
759 iterator erase(const_iterator pos) {
760 if (pos == end()) return end();
761 fl::size idx = pos.mIndex;
762 for (fl::size i = idx; i + 1 < mSize; ++i) {
763 (*this)[i] = fl::move((*this)[i + 1]);
764 }
765 pop_back();
766 return iterator(this, idx);
767 }
768
769 iterator erase(const_iterator first, const_iterator last) {
770 fl::size start_idx = first.mIndex;
771 if (first == last) return iterator(this, start_idx);
772 fl::size count = last.mIndex - first.mIndex;
773 for (fl::size i = start_idx; i + count < mSize; ++i) {
774 (*this)[i] = fl::move((*this)[i + count]);
775 }
776 for (fl::size k = 0; k < count; ++k) {
777 pop_back();
778 }
779 return iterator(this, start_idx);
780 }
781
782 template<typename... Args>
783 iterator emplace(const_iterator pos, Args&&... args) {
784 fl::size idx = pos.mIndex;
785 if (idx == mSize) {
787 return iterator(this, idx);
788 }
789 // Move-extend at the back so move-only T works. The moved-from
790 // slot at old logical mSize-1 is overwritten by the shift loop.
791 push_back(fl::move((*this)[mSize - 1]));
792 for (fl::size i = mSize - 1; i > idx + 1; --i) {
793 (*this)[i - 1] = fl::move((*this)[i - 2]);
794 }
795 (*this)[idx] = T(fl::forward<Args>(args)...);
796 return iterator(this, idx);
797 }
798
799 template<typename... Args>
800 T& emplace_back(Args&&... args) {
802 fl::size global = mFrontOffset + mSize;
803 fl::size c = mFrontMapIdx + global / kChunkSize;
804 fl::size o = global % kChunkSize;
805 new (&mMap[c][o]) T(fl::forward<Args>(args)...);
806 ++mSize;
807 return mMap[c][o];
808 }
809
810 template<typename... Args>
811 T& emplace_front(Args&&... args) {
813 if (mFrontOffset == 0) {
814 --mFrontMapIdx;
816 } else {
817 --mFrontOffset;
818 }
820 ++mSize;
822 }
823
824 void assign(fl::size count, const T& value) {
825 clear();
826 for (fl::size i = 0; i < count; ++i) {
828 }
829 }
830
831 bool operator==(const deque& other) const {
832 if (mSize != other.mSize) return false;
833 for (fl::size i = 0; i < mSize; ++i) {
834 if ((*this)[i] != other[i]) return false;
835 }
836 return true;
837 }
838
839 bool operator!=(const deque& other) const FL_NO_EXCEPT { return !(*this == other); }
840
841 bool operator<(const deque& other) const {
842 fl::size min_size = mSize < other.mSize ? mSize : other.mSize;
843 for (fl::size i = 0; i < min_size; ++i) {
844 if ((*this)[i] < other[i]) return true;
845 if ((*this)[i] > other[i]) return false;
846 }
847 return mSize < other.mSize;
848 }
849
850 bool operator<=(const deque& other) const FL_NO_EXCEPT { return *this < other || *this == other; }
851 bool operator>(const deque& other) const FL_NO_EXCEPT { return other < *this; }
852 bool operator>=(const deque& other) const FL_NO_EXCEPT { return *this > other || *this == other; }
853};
854
858
859} // namespace fl
uint8_t pos
Definition Blur.ino:11
const_iterator(const iterator &it)
Definition deque.h:297
const T & operator*() const
Definition deque.h:299
fl::size operator-(const const_iterator &other) const
Definition deque.h:349
const_iterator operator+(fl::size n) const
Definition deque.h:334
bool operator!=(const const_iterator &other) const
Definition deque.h:361
const_iterator & operator+=(fl::size n)
Definition deque.h:329
bool operator>(const const_iterator &other) const
Definition deque.h:373
const_iterator & operator--()
Definition deque.h:318
const T * operator->() const
Definition deque.h:303
bool operator<(const const_iterator &other) const
Definition deque.h:365
bool operator==(const const_iterator &other) const
Definition deque.h:357
const_iterator operator--(int)
Definition deque.h:323
const_iterator(const deque *dq, fl::size index)
Definition deque.h:294
bool operator<=(const const_iterator &other) const
Definition deque.h:369
const_iterator operator++(int)
Definition deque.h:312
const T & operator[](fl::size n) const
Definition deque.h:353
bool operator>=(const const_iterator &other) const
Definition deque.h:377
const_iterator & operator++()
Definition deque.h:307
const_iterator & operator-=(fl::size n)
Definition deque.h:339
friend class deque
Definition deque.h:291
const deque * mDeque
Definition deque.h:288
fl::random_access_iterator_tag iterator_category
Definition deque.h:285
const_iterator operator-(fl::size n) const
Definition deque.h:344
iterator(deque *dq, fl::size index)
Definition deque.h:194
bool operator>=(const iterator &other) const
Definition deque.h:274
fl::size mIndex
Definition deque.h:189
bool operator!=(const iterator &other) const
Definition deque.h:258
iterator & operator-=(fl::size n)
Definition deque.h:236
T & operator[](fl::size n) const
Definition deque.h:250
fl::random_access_iterator_tag iterator_category
Definition deque.h:185
T * operator->() const
Definition deque.h:200
bool operator<(const iterator &other) const
Definition deque.h:262
bool operator==(const iterator &other) const
Definition deque.h:254
bool operator>(const iterator &other) const
Definition deque.h:270
iterator & operator++()
Definition deque.h:204
iterator operator--(int)
Definition deque.h:220
T & operator*() const
Definition deque.h:196
iterator & operator+=(fl::size n)
Definition deque.h:226
iterator & operator--()
Definition deque.h:215
fl::size operator-(const iterator &other) const
Definition deque.h:246
fl::size difference_type
Definition deque.h:184
friend class deque
Definition deque.h:191
iterator operator-(fl::size n) const
Definition deque.h:241
iterator operator++(int)
Definition deque.h:209
iterator operator+(fl::size n) const
Definition deque.h:231
bool operator<=(const iterator &other) const
Definition deque.h:266
bool operator>=(const deque &other) const FL_NO_EXCEPT
Definition deque.h:852
deque(fl::size count, const T &value=T())
Definition deque.h:390
memory_resource * mResource
Definition deque.h:43
iterator begin() FL_NO_EXCEPT
Definition deque.h:501
T & operator[](fl::size index)
Definition deque.h:455
void push_back(T &&value)
Definition deque.h:611
const_reverse_iterator crend() const FL_NO_EXCEPT
Definition deque.h:514
void ensure_back_room() FL_NO_EXCEPT
Definition deque.h:132
const_reverse_iterator rbegin() const FL_NO_EXCEPT
Definition deque.h:507
void clear()
Definition deque.h:589
void deallocate_chunk(T *chunk) FL_NO_EXCEPT
Definition deque.h:49
void pop_front()
Definition deque.h:651
void locate(fl::size logical_idx, fl::size &chunk_idx, fl::size &offset) const FL_NO_EXCEPT
Definition deque.h:73
void push_front(const T &value)
Definition deque.h:620
void push_front(T &&value)
Definition deque.h:632
fl::reverse_iterator< const_iterator > const_reverse_iterator
Definition deque.h:383
fl::reverse_iterator< iterator > reverse_iterator
Definition deque.h:382
fl::size mMapCapacity
Definition deque.h:39
void resize(fl::size new_size, const T &value)
Definition deque.h:666
iterator emplace(const_iterator pos, Args &&... args)
Definition deque.h:783
bool operator<(const deque &other) const
Definition deque.h:841
T & emplace_back(Args &&... args)
Definition deque.h:800
deque & operator=(deque &&other) FL_NO_EXCEPT
Definition deque.h:429
fl::size capacity() const
Definition deque.h:523
const T & back() const
Definition deque.h:496
const T & front() const
Definition deque.h:487
void shrink_to_fit()
Definition deque.h:563
bool operator>(const deque &other) const FL_NO_EXCEPT
Definition deque.h:851
const_iterator end() const FL_NO_EXCEPT
Definition deque.h:504
reverse_iterator rbegin() FL_NO_EXCEPT
Definition deque.h:506
static constexpr fl::size kChunkSize
Definition deque.h:36
bool operator==(const deque &other) const
Definition deque.h:831
fl::size size() const FL_NO_EXCEPT
Definition deque.h:517
void deallocate_map(T **map, fl::size capacity) FL_NO_EXCEPT
Definition deque.h:65
bool operator<=(const deque &other) const FL_NO_EXCEPT
Definition deque.h:850
reverse_iterator rend() FL_NO_EXCEPT
Definition deque.h:508
deque() FL_NO_EXCEPT
Definition deque.h:386
void resize(fl::size new_size)
Definition deque.h:662
iterator end() FL_NO_EXCEPT
Definition deque.h:503
fl::size mSize
Definition deque.h:42
void reserve(fl::size n) FL_NO_EXCEPT
Definition deque.h:537
deque(memory_resource *resource) FL_NO_EXCEPT
Definition deque.h:388
T * allocate_chunk() FL_NO_EXCEPT
Definition deque.h:45
void ensure_front_room() FL_NO_EXCEPT
Definition deque.h:148
T & front()
Definition deque.h:483
iterator insert(const_iterator pos, T &&value)
Definition deque.h:721
deque(deque &&other) FL_NO_EXCEPT
Definition deque.h:398
iterator erase(const_iterator first, const_iterator last)
Definition deque.h:769
iterator insert(const_iterator pos, fl::size count, const T &value)
Definition deque.h:737
const_iterator begin() const FL_NO_EXCEPT
Definition deque.h:502
T ** allocate_map(fl::size capacity) FL_NO_EXCEPT
Definition deque.h:55
const_iterator cend() const FL_NO_EXCEPT
Definition deque.h:512
const T & at(fl::size index) const
Definition deque.h:475
const_reverse_iterator crbegin() const FL_NO_EXCEPT
Definition deque.h:513
memory_resource * get_memory_resource() const FL_NO_EXCEPT
Definition deque.h:587
T & at(fl::size index)
Definition deque.h:465
fl::size used_chunks() const FL_NO_EXCEPT
Definition deque.h:80
void pop_back()
Definition deque.h:644
fl::size max_size() const
Definition deque.h:531
T & emplace_front(Args &&... args)
Definition deque.h:811
const_iterator cbegin() const FL_NO_EXCEPT
Definition deque.h:511
fl::size mFrontOffset
Definition deque.h:41
bool empty() const FL_NO_EXCEPT
Definition deque.h:516
void grow_map(fl::size extra_front, fl::size extra_back) FL_NO_EXCEPT
Definition deque.h:97
deque(const deque &other) FL_NO_EXCEPT
Definition deque.h:394
~deque() FL_NO_EXCEPT
Definition deque.h:408
bool operator!=(const deque &other) const FL_NO_EXCEPT
Definition deque.h:839
int ** mMap
Definition deque.h:38
iterator insert(const_iterator pos, const T &value)
Definition deque.h:705
T & back()
Definition deque.h:491
void assign(fl::size count, const T &value)
Definition deque.h:824
iterator erase(const_iterator pos)
Definition deque.h:759
void push_back(const T &value)
Definition deque.h:602
fl::size mFrontMapIdx
Definition deque.h:40
const T & operator[](fl::size index) const
Definition deque.h:460
deque & operator=(const deque &other) FL_NO_EXCEPT
Definition deque.h:419
const_reverse_iterator rend() const FL_NO_EXCEPT
Definition deque.h:509
deque(fl::initializer_list< T > init)
Definition deque.h:402
void swap(deque &other)
Definition deque.h:671
Polymorphic memory resource base class (PMR-style).
Reverse iterator adapter - reverses the direction of a bidirectional iterator.
Definition iterator.h:160
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
PMR-style polymorphic memory resource for type-erased allocation.
FL_NO_INLINE fl::size deque_grow_map_capacity(fl::size current_map_capacity, fl::size min_required_chunks) FL_NO_EXCEPT
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:28
constexpr int type_rank< T >::value
void init(Context &ctx, int w, int h)
Definition engine.h:133
MapRedBlackTree< Key, T, Compare, fl::allocator_slab< char > > map
Definition map.h:283
deque< float > deque_float
Definition deque.h:856
memory_resource * default_memory_resource() FL_NO_EXCEPT
Get the default memory resource (wraps fl::Malloc / fl::Free / fl::realloc).
deque< double > deque_double
Definition deque.h:857
constexpr T && forward(typename remove_reference< T >::type &t) FL_NO_EXCEPT
InputGamut g FL_NO_EXCEPT
Definition rgbw.h:121
deque< int > deque_int
Definition deque.h:855
Base definition for an LED controller.
Definition crgb.hpp:179
corkscrew_args args
Definition old.h:149
static constexpr fl::size chunk_size
Definition deque.h:20