FastLED 3.9.15
Loading...
Searching...
No Matches
deque.h
Go to the documentation of this file.
1#pragma once
2
3
4#include "fl/stdint.h"
5#include <string.h>
6
7#include "fl/allocator.h"
9#include "fl/inplacenew.h"
10#include "fl/move.h"
11#include "fl/namespace.h"
12#include "fl/type_traits.h"
13
14namespace fl {
15
16template <typename T, typename Allocator = fl::allocator<T>>
17class deque {
18private:
19 T* mData = nullptr;
20 fl::size mCapacity = 0;
21 fl::size mSize = 0;
22 fl::size mFront = 0; // Index of the front element
23 Allocator mAlloc;
24
25 static const fl::size kInitialCapacity = 8;
26
27 void ensure_capacity(fl::size min_capacity) {
28 if (mCapacity >= min_capacity) {
29 return;
30 }
31
32 fl::size new_capacity = mCapacity == 0 ? kInitialCapacity : mCapacity * 2;
33 while (new_capacity < min_capacity) {
34 new_capacity *= 2;
35 }
36
37 T* new_data = mAlloc.allocate(new_capacity);
38 if (!new_data) {
39 return; // Allocation failed
40 }
41
42 // Copy existing elements to new buffer in linear order
43 for (fl::size i = 0; i < mSize; ++i) {
44 fl::size old_idx = (mFront + i) % mCapacity;
45 mAlloc.construct(&new_data[i], fl::move(mData[old_idx]));
46 mAlloc.destroy(&mData[old_idx]);
47 }
48
49 if (mData) {
50 mAlloc.deallocate(mData, mCapacity);
51 }
52
53 mData = new_data;
54 mCapacity = new_capacity;
55 mFront = 0; // Reset front to 0 after reallocation
56 }
57
58 fl::size get_index(fl::size logical_index) const {
59 return (mFront + logical_index) % mCapacity;
60 }
61
62public:
63 // Iterator implementation
64 class iterator {
65 private:
67 fl::size mIndex;
68
69 public:
70 iterator(deque* dq, fl::size index) : mDeque(dq), mIndex(index) {}
71
72 T& operator*() const {
73 return (*mDeque)[mIndex];
74 }
75
76 T* operator->() const {
77 return &(*mDeque)[mIndex];
78 }
79
81 ++mIndex;
82 return *this;
83 }
84
86 iterator temp = *this;
87 ++mIndex;
88 return temp;
89 }
90
92 --mIndex;
93 return *this;
94 }
95
97 iterator temp = *this;
98 --mIndex;
99 return temp;
100 }
101
102 bool operator==(const iterator& other) const {
103 return mDeque == other.mDeque && mIndex == other.mIndex;
104 }
105
106 bool operator!=(const iterator& other) const {
107 return !(*this == other);
108 }
109 };
110
112 private:
113 const deque* mDeque;
114 fl::size mIndex;
115
116 public:
117 const_iterator(const deque* dq, fl::size index) : mDeque(dq), mIndex(index) {}
118
119 const T& operator*() const {
120 return (*mDeque)[mIndex];
121 }
122
123 const T* operator->() const {
124 return &(*mDeque)[mIndex];
125 }
126
128 ++mIndex;
129 return *this;
130 }
131
133 const_iterator temp = *this;
134 ++mIndex;
135 return temp;
136 }
137
139 --mIndex;
140 return *this;
141 }
142
144 const_iterator temp = *this;
145 --mIndex;
146 return temp;
147 }
148
149 bool operator==(const const_iterator& other) const {
150 return mDeque == other.mDeque && mIndex == other.mIndex;
151 }
152
153 bool operator!=(const const_iterator& other) const {
154 return !(*this == other);
155 }
156 };
157
158 // Constructors
159 deque() : mData(nullptr), mCapacity(0), mSize(0), mFront(0) {}
160
161 explicit deque(fl::size count, const T& value = T()) : deque() {
162 resize(count, value);
163 }
164
165 deque(const deque& other) : deque() {
166 *this = other;
167 }
168
169 deque(deque&& other) : deque() {
170 *this = fl::move(other);
171 }
172
173 deque(fl::initializer_list<T> init) : deque() {
174 for (const auto& value : init) {
175 push_back(value);
176 }
177 }
178
179 // Destructor
181 clear();
182 if (mData) {
183 mAlloc.deallocate(mData, mCapacity);
184 }
185 }
186
187 // Assignment operators
188 deque& operator=(const deque& other) {
189 if (this != &other) {
190 clear();
191 for (fl::size i = 0; i < other.size(); ++i) {
192 push_back(other[i]);
193 }
194 }
195 return *this;
196 }
197
199 if (this != &other) {
200 clear();
201 if (mData) {
202 mAlloc.deallocate(mData, mCapacity);
203 }
204
205 mData = other.mData;
206 mCapacity = other.mCapacity;
207 mSize = other.mSize;
208 mFront = other.mFront;
209 mAlloc = other.mAlloc;
210
211 other.mData = nullptr;
212 other.mCapacity = 0;
213 other.mSize = 0;
214 other.mFront = 0;
215 }
216 return *this;
217 }
218
219 // Element access
220 T& operator[](fl::size index) {
221 return mData[get_index(index)];
222 }
223
224 const T& operator[](fl::size index) const {
225 return mData[get_index(index)];
226 }
227
228 T& at(fl::size index) {
229 if (index >= mSize) {
230 // Handle bounds error - in embedded context, we'll just return the first element
231 // In a real implementation, this might throw an exception
232 return mData[mFront];
233 }
234 return mData[get_index(index)];
235 }
236
237 const T& at(fl::size index) const {
238 if (index >= mSize) {
239 // Handle bounds error - in embedded context, we'll just return the first element
240 return mData[mFront];
241 }
242 return mData[get_index(index)];
243 }
244
245 T& front() {
246 return mData[mFront];
247 }
248
249 const T& front() const {
250 return mData[mFront];
251 }
252
253 T& back() {
254 return mData[get_index(mSize - 1)];
255 }
256
257 const T& back() const {
258 return mData[get_index(mSize - 1)];
259 }
260
261 // Iterators
262 iterator begin() {
263 return iterator(this, 0);
264 }
265
266 const_iterator begin() const {
267 return const_iterator(this, 0);
268 }
269
270 iterator end() {
271 return iterator(this, mSize);
272 }
273
274 const_iterator end() const {
275 return const_iterator(this, mSize);
276 }
277
278 // Capacity
279 bool empty() const {
280 return mSize == 0;
281 }
282
283 fl::size size() const {
284 return mSize;
285 }
286
287 fl::size capacity() const {
288 return mCapacity;
289 }
290
291 // Modifiers
292 void clear() {
293 while (!empty()) {
294 pop_back();
295 }
296 }
297
298 void push_back(const T& value) {
300 fl::size back_index = get_index(mSize);
301 mAlloc.construct(&mData[back_index], value);
302 ++mSize;
303 }
304
305 void push_back(T&& value) {
307 fl::size back_index = get_index(mSize);
308 mAlloc.construct(&mData[back_index], fl::move(value));
309 ++mSize;
310 }
311
312 void push_front(const T& value) {
314 mFront = (mFront - 1 + mCapacity) % mCapacity;
315 mAlloc.construct(&mData[mFront], value);
316 ++mSize;
317 }
318
319 void push_front(T&& value) {
321 mFront = (mFront - 1 + mCapacity) % mCapacity;
322 mAlloc.construct(&mData[mFront], fl::move(value));
323 ++mSize;
324 }
325
326 void pop_back() {
327 if (mSize > 0) {
328 fl::size back_index = get_index(mSize - 1);
329 mAlloc.destroy(&mData[back_index]);
330 --mSize;
331 }
332 }
333
334 void pop_front() {
335 if (mSize > 0) {
336 mAlloc.destroy(&mData[mFront]);
337 mFront = (mFront + 1) % mCapacity;
338 --mSize;
339 }
340 }
341
342 void resize(fl::size new_size) {
343 resize(new_size, T());
344 }
345
346 void resize(fl::size new_size, const T& value) {
347 if (new_size > mSize) {
348 // Add elements
349 ensure_capacity(new_size);
350 while (mSize < new_size) {
351 push_back(value);
352 }
353 } else if (new_size < mSize) {
354 // Remove elements
355 while (mSize > new_size) {
356 pop_back();
357 }
358 }
359 // If new_size == mSize, do nothing
360 }
361
362 void swap(deque& other) {
363 if (this != &other) {
364 T* temp_data = mData;
365 fl::size temp_capacity = mCapacity;
366 fl::size temp_size = mSize;
367 fl::size temp_front = mFront;
368 Allocator temp_alloc = mAlloc;
369
370 mData = other.mData;
371 mCapacity = other.mCapacity;
372 mSize = other.mSize;
373 mFront = other.mFront;
374 mAlloc = other.mAlloc;
375
376 other.mData = temp_data;
377 other.mCapacity = temp_capacity;
378 other.mSize = temp_size;
379 other.mFront = temp_front;
380 other.mAlloc = temp_alloc;
381 }
382 }
383};
384
385// Convenience typedef for the most common use case
389
390} // namespace fl
bool operator==(const const_iterator &other) const
Definition deque.h:149
const_iterator(const deque *dq, fl::size index)
Definition deque.h:117
bool operator!=(const const_iterator &other) const
Definition deque.h:153
const_iterator & operator--()
Definition deque.h:138
const deque * mDeque
Definition deque.h:113
const_iterator operator--(int)
Definition deque.h:143
const_iterator & operator++()
Definition deque.h:127
const T & operator*() const
Definition deque.h:119
const T * operator->() const
Definition deque.h:123
const_iterator operator++(int)
Definition deque.h:132
fl::size mIndex
Definition deque.h:67
iterator operator++(int)
Definition deque.h:85
iterator & operator--()
Definition deque.h:91
T * operator->() const
Definition deque.h:76
iterator(deque *dq, fl::size index)
Definition deque.h:70
T & operator*() const
Definition deque.h:72
bool operator==(const iterator &other) const
Definition deque.h:102
bool operator!=(const iterator &other) const
Definition deque.h:106
deque * mDeque
Definition deque.h:66
iterator operator--(int)
Definition deque.h:96
iterator & operator++()
Definition deque.h:80
void clear()
Definition deque.h:292
const_iterator begin() const
Definition deque.h:266
void ensure_capacity(fl::size min_capacity)
Definition deque.h:27
iterator end()
Definition deque.h:270
fl::size capacity() const
Definition deque.h:287
const_iterator end() const
Definition deque.h:274
int * mData
Definition deque.h:19
fl::size mFront
Definition deque.h:22
void resize(fl::size new_size, const T &value)
Definition deque.h:346
fl::size mCapacity
Definition deque.h:20
fl::size size() const
Definition deque.h:283
deque(const deque &other)
Definition deque.h:165
deque & operator=(const deque &other)
Definition deque.h:188
const T & operator[](fl::size index) const
Definition deque.h:224
const T & front() const
Definition deque.h:249
T & at(fl::size index)
Definition deque.h:228
deque()
Definition deque.h:159
void resize(fl::size new_size)
Definition deque.h:342
iterator begin()
Definition deque.h:262
bool empty() const
Definition deque.h:279
const T & back() const
Definition deque.h:257
fl::size get_index(fl::size logical_index) const
Definition deque.h:58
void push_front(T &&value)
Definition deque.h:319
T & back()
Definition deque.h:253
void pop_front()
Definition deque.h:334
void push_front(const T &value)
Definition deque.h:312
fl::size mSize
Definition deque.h:21
deque(deque &&other)
Definition deque.h:169
void pop_back()
Definition deque.h:326
void push_back(T &&value)
Definition deque.h:305
const T & at(fl::size index) const
Definition deque.h:237
fl::allocator< int > mAlloc
Definition deque.h:23
static const fl::size kInitialCapacity
Definition deque.h:25
void swap(deque &other)
Definition deque.h:362
deque & operator=(deque &&other)
Definition deque.h:198
T & operator[](fl::size index)
Definition deque.h:220
deque(fl::size count, const T &value=T())
Definition deque.h:161
~deque()
Definition deque.h:180
T & front()
Definition deque.h:245
void push_back(const T &value)
Definition deque.h:298
deque(fl::initializer_list< T > init)
Definition deque.h:173
Implements the FastLED namespace macros.
constexpr remove_reference< T >::type && move(T &&t) noexcept
Definition move.h:27
deque< float > deque_float
Definition deque.h:387
deque< double > deque_double
Definition deque.h:388
deque< int > deque_int
Definition deque.h:386
IMPORTANT!
Definition crgb.h:20