| 12 | |
| 13 | template <typename T> |
| 14 | class deque { |
| 15 | private: |
| 16 | T* mData = nullptr; |
| 17 | fl::size mCapacity = 0; |
| 18 | fl::size mSize = 0; |
| 19 | fl::size mFront = 0; // Index of the front element |
| 20 | memory_resource* mResource = default_memory_resource(); |
| 21 | |
| 22 | static const fl::size kInitialCapacity = 8; |
| 23 | |
| 24 | void ensure_capacity(fl::size min_capacity) { |
| 25 | if (mCapacity >= min_capacity) { |
| 26 | return; |
| 27 | } |
| 28 | |
| 29 | fl::size new_capacity = mCapacity == 0 ? kInitialCapacity : mCapacity * 2; |
| 30 | while (new_capacity < min_capacity) { |
| 31 | new_capacity *= 2; |
| 32 | } |
| 33 | |
| 34 | T* new_data = static_cast<T*>(mResource->allocate(new_capacity * sizeof(T))); |
| 35 | if (!new_data) { |
| 36 | return; // Allocation failed |
| 37 | } |
| 38 | |
| 39 | // Copy existing elements to new buffer in linear order |
| 40 | for (fl::size i = 0; i < mSize; ++i) { |
| 41 | fl::size old_idx = (mFront + i) % mCapacity; |
| 42 | new (&new_data[i]) T(fl::move(mData[old_idx])); |
| 43 | mData[old_idx].~T(); |
| 44 | } |
| 45 | |
| 46 | if (mData) { |
| 47 | mResource->deallocate(mData, mCapacity * sizeof(T)); |
| 48 | } |
| 49 | |
| 50 | mData = new_data; |
| 51 | mCapacity = new_capacity; |
| 52 | mFront = 0; // Reset front to 0 after reallocation |
| 53 | } |
| 54 | |
| 55 | fl::size get_index(fl::size logical_index) const { |
| 56 | return (mFront + logical_index) % mCapacity; |
| 57 | } |
| 58 | |
| 59 | public: |
| 60 | // Iterator implementation (RandomAccessIterator) |
| 61 | class iterator { |
| 62 | public: |
| 63 | typedef T value_type; |
| 64 | typedef T& reference; |
| 65 | typedef T* pointer; |
| 66 | typedef fl::size difference_type; |
| 67 | typedef fl::random_access_iterator_tag iterator_category; |
| 68 | |
| 69 | private: |
| 70 | deque* mDeque; |
| 71 | fl::size mIndex; |