12#ifndef __BOXES_LINKED_VECTOR_HPP__
13#define __BOXES_LINKED_VECTOR_HPP__
15#include "compiler.hpp"
47 using reference = T &;
48 using const_reference =
const T &;
49 using size_type = std::size_t;
50 using difference_type = std::ptrdiff_t;
52 static constexpr std::size_t ChunkSize = ChunkSizeV;
57 using reference = T &;
59 using difference_type = std::ptrdiff_t;
60 using iterator_category = std::random_access_iterator_tag;
63 : cnt{cnt}, pos{pos} {}
65 iterator &operator++() {
66 if (pos != cnt->
size()) {
72 iterator operator++(
int) {
78 iterator &operator--() {
85 iterator operator--(
int) {
91 reference operator*() {
return cnt->
at(pos); }
93 pointer operator->() {
return &cnt->
at(pos); }
96 return cnt == other.cnt && pos == other.pos;
99 bool operator!=(
const iterator &other)
const {
return !(*
this == other); }
122 : chunks{std::move(other.chunks)},
123 discardedChunks{std::move(other.discardedChunks)},
124 frontChunk{other.frontChunk}, backChunk{other.backChunk} {
125 other.frontChunk =
nullptr;
126 other.backChunk =
nullptr;
139 if (
this != &other) {
154 std::swap(chunks, other.chunks);
155 std::swap(discardedChunks, other.discardedChunks);
156 std::swap(frontChunk, other.frontChunk);
157 std::swap(backChunk, other.backChunk);
175 frontChunk->
push_front(std::forward<Arg>(value));
193 backChunk->
push_back(std::forward<Arg>(value));
205 if (frontChunk == backChunk && frontChunk->
empty()) {
222 if (frontChunk == backChunk && backChunk->
empty()) {
239 if (frontChunk->
empty()) {
240 throw std::out_of_range(
"LinkedVector::front");
243 return frontChunk->
front();
265 if (backChunk->
empty()) {
266 throw std::out_of_range(
"LinkedVector::back");
269 return backChunk->
back();
288 if (
const auto &fs = frontChunk->
size(); pos < fs) {
289 return frontChunk->operator[](pos);
292 auto chunkIndex = pos / ChunkSizeV + 1;
293 auto chunkOffset = pos % ChunkSizeV;
295 auto it = chunks.begin();
296 std::advance(it, chunkIndex);
297 return it->get()->operator[](chunkOffset);
312 return const_cast<LinkedVector *
>(
this)->
operator[](pos);
324 T &
at(size_type pos) {
326 throw std::out_of_range(
"LinkedVector::at");
340 const T &
at(size_type pos)
const {
349 iterator
begin() {
return iterator(
this, 0); }
358 iterator
end() {
return iterator(
this,
size()); }
389 for (
auto it = chunks.cbegin(), otherIt = other.chunks.cbegin();
390 it != chunks.cend(); ++it, ++otherIt) {
391 if (**it != **otherIt) {
406 return !(*
this == other);
414 std::size_t
size() const BOXES_NOTHROW {
415 switch (chunks.size()) {
419 return frontChunk->
size();
421 return frontChunk->
size() + backChunk->
size();
423 return frontChunk->
size() + backChunk->
size() +
424 (chunks.size() - 2) * ChunkSizeV;
445 return chunks.size() * ChunkSizeV;
453 discardedChunks.clear();
462 bool empty() const BOXES_NOTHROW {
return size() == 0; }
466 std::list<std::unique_ptr<Chunk>> chunks;
467 std::list<std::unique_ptr<Chunk>> discardedChunks;
468 Chunk *frontChunk{
nullptr};
469 Chunk *backChunk{
nullptr};
472 if (frontChunk != backChunk && frontChunk->
empty()) {
473 discardedChunks.
push_back(std::move(chunks.front()));
475 frontChunk = chunks.
front().get();
480 if (frontChunk != backChunk && backChunk->
empty()) {
481 discardedChunks.push_back(std::move(chunks.back()));
483 backChunk = chunks.
back().get();
488 if (frontChunk->
full()) {
490 frontChunk = c.get();
496 if (backChunk->
full()) {
503 std::unique_ptr<Chunk> getChunk() {
504 if (discardedChunks.empty()) {
505 return std::make_unique<Chunk>();
508 auto c = std::move(discardedChunks.front());
510 discardedChunks.pop_front();
515 chunks.push_back(getChunk());
516 frontChunk = chunks.
front().get();
517 backChunk = chunks.
back().get();
Implements a vector-like container that uses a linked list of fixed-size chunks to store its elements...
const T & operator[](size_type pos) const
Returns a const reference to the element at the specified position.
bool operator!=(const LinkedVector< T, ChunkSizeV > &other) const
Returns true if the two containers are not equal.
T & front()
Returns a reference to the first element in the container.
iterator cbegin() const
Returns a const iterator to the first element of the container.
const T & front() const
Returns a const reference to the first element in the container.
LinkedVector(LinkedVector< T, ChunkSizeV > &&other)
Move constructor.
std::size_t size() const BOXES_NOTHROW
Returns the number of elements in the container.
std::size_t capacity() const BOXES_NOTHROW
Returns the maximum number of elements the container can hold without additional memory allocation.
T & back()
Returns a reference to the last element in the container.
bool operator==(const LinkedVector< T, ChunkSizeV > &other) const
Returns true if the two containers are equal.
void swap(LinkedVector< T, ChunkSizeV > &other)
Swaps the contents of this LinkedVector with another.
const T & back() const
Returns a const reference to the last element in the container.
void pop_front()
Removes the first element from the container.
void clear()
Removes all elements from the container.
LinkedVector< T, ChunkSizeV > & operator=(LinkedVector< T, ChunkSizeV > &&other)
Move assignment operator.
T & at(size_type pos)
Returns a reference to the element at the specified position.
iterator end()
Returns an iterator to the element following the last element of the container.
void pop_back()
Removes the last element from the container.
LinkedVector()
Constructs an empty container.
T & operator[](size_type pos)
Provides access to the element at the specified position.
iterator begin()
Returns an iterator to the first element of the container.
void push_front(Arg &&value)
Pushes a new element to the front of the container.
bool empty() const BOXES_NOTHROW
Returns true if the container is empty.
iterator cend() const
Returns a const iterator to the element following the last element.
void push_back(Arg &&value)
Pushes a new element to the back of the container.
const T & at(size_type pos) const
Returns a const reference to the element at the specified position.
Implements a fixed-size double ended queue.
bool pop_front()
Removes the first element from the RingBuffer.
bool push_back(Arg &&value)
Inserts a new element at the end of the RingBuffer.
bool full() const BOXES_NOTHROW
Returns true if the RingBuffer is full.
bool pop_back()
Removes the last element from the RingBuffer.
T & front()
Returns the first element in the queue.
T & back()
Returns the last element in the queue.
size_type size() const BOXES_NOTHROW
Returns the number of elements in the RingBuffer.
bool empty() const BOXES_NOTHROW
Returns true if the RingBuffer is empty.
bool push_front(Arg &&value)
Inserts a new element at the front of the RingBuffer.
Implements a fixed-size double-ended queue.