Files
klubhaus-doorbell/libraries/FastLED/src/fl/deque.h
2026-02-12 00:45:31 -08:00

391 lines
9.1 KiB
C++

#pragma once
#include "fl/stdint.h"
#include <string.h>
#include "fl/allocator.h"
#include "fl/initializer_list.h"
#include "fl/inplacenew.h"
#include "fl/move.h"
#include "fl/namespace.h"
#include "fl/type_traits.h"
namespace fl {
template <typename T, typename Allocator = fl::allocator<T>>
class deque {
private:
T* mData = nullptr;
fl::size mCapacity = 0;
fl::size mSize = 0;
fl::size mFront = 0; // Index of the front element
Allocator mAlloc;
static const fl::size kInitialCapacity = 8;
void ensure_capacity(fl::size min_capacity) {
if (mCapacity >= min_capacity) {
return;
}
fl::size new_capacity = mCapacity == 0 ? kInitialCapacity : mCapacity * 2;
while (new_capacity < min_capacity) {
new_capacity *= 2;
}
T* new_data = mAlloc.allocate(new_capacity);
if (!new_data) {
return; // Allocation failed
}
// Copy existing elements to new buffer in linear order
for (fl::size i = 0; i < mSize; ++i) {
fl::size old_idx = (mFront + i) % mCapacity;
mAlloc.construct(&new_data[i], fl::move(mData[old_idx]));
mAlloc.destroy(&mData[old_idx]);
}
if (mData) {
mAlloc.deallocate(mData, mCapacity);
}
mData = new_data;
mCapacity = new_capacity;
mFront = 0; // Reset front to 0 after reallocation
}
fl::size get_index(fl::size logical_index) const {
return (mFront + logical_index) % mCapacity;
}
public:
// Iterator implementation
class iterator {
private:
deque* mDeque;
fl::size mIndex;
public:
iterator(deque* dq, fl::size index) : mDeque(dq), mIndex(index) {}
T& operator*() const {
return (*mDeque)[mIndex];
}
T* operator->() const {
return &(*mDeque)[mIndex];
}
iterator& operator++() {
++mIndex;
return *this;
}
iterator operator++(int) {
iterator temp = *this;
++mIndex;
return temp;
}
iterator& operator--() {
--mIndex;
return *this;
}
iterator operator--(int) {
iterator temp = *this;
--mIndex;
return temp;
}
bool operator==(const iterator& other) const {
return mDeque == other.mDeque && mIndex == other.mIndex;
}
bool operator!=(const iterator& other) const {
return !(*this == other);
}
};
class const_iterator {
private:
const deque* mDeque;
fl::size mIndex;
public:
const_iterator(const deque* dq, fl::size index) : mDeque(dq), mIndex(index) {}
const T& operator*() const {
return (*mDeque)[mIndex];
}
const T* operator->() const {
return &(*mDeque)[mIndex];
}
const_iterator& operator++() {
++mIndex;
return *this;
}
const_iterator operator++(int) {
const_iterator temp = *this;
++mIndex;
return temp;
}
const_iterator& operator--() {
--mIndex;
return *this;
}
const_iterator operator--(int) {
const_iterator temp = *this;
--mIndex;
return temp;
}
bool operator==(const const_iterator& other) const {
return mDeque == other.mDeque && mIndex == other.mIndex;
}
bool operator!=(const const_iterator& other) const {
return !(*this == other);
}
};
// Constructors
deque() : mData(nullptr), mCapacity(0), mSize(0), mFront(0) {}
explicit deque(fl::size count, const T& value = T()) : deque() {
resize(count, value);
}
deque(const deque& other) : deque() {
*this = other;
}
deque(deque&& other) : deque() {
*this = fl::move(other);
}
deque(fl::initializer_list<T> init) : deque() {
for (const auto& value : init) {
push_back(value);
}
}
// Destructor
~deque() {
clear();
if (mData) {
mAlloc.deallocate(mData, mCapacity);
}
}
// Assignment operators
deque& operator=(const deque& other) {
if (this != &other) {
clear();
for (fl::size i = 0; i < other.size(); ++i) {
push_back(other[i]);
}
}
return *this;
}
deque& operator=(deque&& other) {
if (this != &other) {
clear();
if (mData) {
mAlloc.deallocate(mData, mCapacity);
}
mData = other.mData;
mCapacity = other.mCapacity;
mSize = other.mSize;
mFront = other.mFront;
mAlloc = other.mAlloc;
other.mData = nullptr;
other.mCapacity = 0;
other.mSize = 0;
other.mFront = 0;
}
return *this;
}
// Element access
T& operator[](fl::size index) {
return mData[get_index(index)];
}
const T& operator[](fl::size index) const {
return mData[get_index(index)];
}
T& at(fl::size index) {
if (index >= mSize) {
// Handle bounds error - in embedded context, we'll just return the first element
// In a real implementation, this might throw an exception
return mData[mFront];
}
return mData[get_index(index)];
}
const T& at(fl::size index) const {
if (index >= mSize) {
// Handle bounds error - in embedded context, we'll just return the first element
return mData[mFront];
}
return mData[get_index(index)];
}
T& front() {
return mData[mFront];
}
const T& front() const {
return mData[mFront];
}
T& back() {
return mData[get_index(mSize - 1)];
}
const T& back() const {
return mData[get_index(mSize - 1)];
}
// Iterators
iterator begin() {
return iterator(this, 0);
}
const_iterator begin() const {
return const_iterator(this, 0);
}
iterator end() {
return iterator(this, mSize);
}
const_iterator end() const {
return const_iterator(this, mSize);
}
// Capacity
bool empty() const {
return mSize == 0;
}
fl::size size() const {
return mSize;
}
fl::size capacity() const {
return mCapacity;
}
// Modifiers
void clear() {
while (!empty()) {
pop_back();
}
}
void push_back(const T& value) {
ensure_capacity(mSize + 1);
fl::size back_index = get_index(mSize);
mAlloc.construct(&mData[back_index], value);
++mSize;
}
void push_back(T&& value) {
ensure_capacity(mSize + 1);
fl::size back_index = get_index(mSize);
mAlloc.construct(&mData[back_index], fl::move(value));
++mSize;
}
void push_front(const T& value) {
ensure_capacity(mSize + 1);
mFront = (mFront - 1 + mCapacity) % mCapacity;
mAlloc.construct(&mData[mFront], value);
++mSize;
}
void push_front(T&& value) {
ensure_capacity(mSize + 1);
mFront = (mFront - 1 + mCapacity) % mCapacity;
mAlloc.construct(&mData[mFront], fl::move(value));
++mSize;
}
void pop_back() {
if (mSize > 0) {
fl::size back_index = get_index(mSize - 1);
mAlloc.destroy(&mData[back_index]);
--mSize;
}
}
void pop_front() {
if (mSize > 0) {
mAlloc.destroy(&mData[mFront]);
mFront = (mFront + 1) % mCapacity;
--mSize;
}
}
void resize(fl::size new_size) {
resize(new_size, T());
}
void resize(fl::size new_size, const T& value) {
if (new_size > mSize) {
// Add elements
ensure_capacity(new_size);
while (mSize < new_size) {
push_back(value);
}
} else if (new_size < mSize) {
// Remove elements
while (mSize > new_size) {
pop_back();
}
}
// If new_size == mSize, do nothing
}
void swap(deque& other) {
if (this != &other) {
T* temp_data = mData;
fl::size temp_capacity = mCapacity;
fl::size temp_size = mSize;
fl::size temp_front = mFront;
Allocator temp_alloc = mAlloc;
mData = other.mData;
mCapacity = other.mCapacity;
mSize = other.mSize;
mFront = other.mFront;
mAlloc = other.mAlloc;
other.mData = temp_data;
other.mCapacity = temp_capacity;
other.mSize = temp_size;
other.mFront = temp_front;
other.mAlloc = temp_alloc;
}
}
};
// Convenience typedef for the most common use case
typedef deque<int> deque_int;
typedef deque<float> deque_float;
typedef deque<double> deque_double;
} // namespace fl