gz-cpp-util 1.3
A c++20 library containing various utilities
ringbuffer.hpp
1#pragma once
2
3/* #include "log.hpp" */
4#include "../util/util.hpp"
5
6#include <vector>
7#include <iterator>
8#include <algorithm>
9#include <concepts>
10
11namespace gz {
42 template<std::swappable T>
43 class RingBuffer {
44 public:
45 RingBuffer(size_t size=10);
46
51 struct Iterator {
52 public:
53 Iterator(const RingBuffer<T>& b, size_t index) : b(b), ptr(const_cast<T*>(&b.buffer.at(index))) {}
54 Iterator(const Iterator& other) : b(other.b), ptr(other.ptr) {}
55 // Needed for std::input_iterator
56 using value_type = T;
57 T& operator*() const { return *ptr; }
58 Iterator& operator=(const Iterator& other) {
59 b = other.b;
60 ptr = other.ptr;
61 return this;
62 }
63 Iterator& operator++() {
64 if (ptr == &*b.buffer.begin()) { ptr = const_cast<T*>(&*b.buffer.rbegin()); }
65 else { ptr--; }
66 return *this;
67 }
68 Iterator operator++(int) {
69 auto copy = *this;
70 if (ptr == &*b.buffer.begin()) { ptr = const_cast<T*>(&*b.buffer.rbegin()); }
71 else { ptr--; }
72 return copy;
73 }
74 friend int operator-(Iterator lhs, Iterator rhs) {
75 return lhs.getCurrentIndex() - rhs.getCurrentIndex();
76 }
77 // Needed for std::forward_iterator
79 Iterator() : ptr(nullptr) {};
80 bool operator==(const Iterator& other) const {
81 return this->ptr == other.ptr;
82 }
83 // Needed for std::bidirectional_iterator
84 Iterator& operator--() {
85 if (ptr == &*b.buffer.rbegin()) { ptr = const_cast<T*>(&*b.buffer.begin()); }
86 else { ptr++; }
87 return *this;
88 }
89 Iterator operator--(int) {
90 auto copy = *this;
91 if (ptr == &*b.buffer.rbegin()) { ptr = const_cast<T*>(&*b.buffer.begin()); }
92 else { ptr++; }
93 return copy;
94 }
95 // Not needed )
96 /* friend Iterator operator+(Iterator lhs, int i) { */
97 /* return Iterator(lhs.b, &lhs.b.buffer[lhs.getValidIndex(lhs.getCurrentIndex() + i)]); */
98 /* } */
99 /* friend Iterator operator-(Iterator lhs, int i) { */
100 /* return Iterator(lhs.b, &lhs.b.buffer[lhs.getValidIndex(lhs.getCurrentIndex() - i)]); */
101 /* } */
102 /* friend Iterator operator+(int i, Iterator rhs) { */
103 /* return Iterator(rhs.b, &rhs.b.buffer[rhs.getValidIndex(rhs.getCurrentIndex() + i)]); */
104 /* } */
105 /* Iterator& operator+=(int i) { */
106 /* ptr = &b.buffer[getValidIndex(getCurrentIndex() + i)]; */
107 /* return this; */
108 /* } */
109 /* Iterator& operator-=(int i) { */
110 /* ptr = &b.buffer[getValidIndex(getCurrentIndex() - i)]; */
111 /* return this; */
112
113 /* } */
114 /* bool operator!=(const Iterator& other) const { */
115 /* return this->ptr != other.ptr; */
116 /* } */
118 std::string to_string() const {
119 return "Element: " + std::to_string(*ptr) + ", Index: " + std::to_string(getCurrentIndex()) + ", Pointer: " + std::to_string(reinterpret_cast<long>(ptr));
120 }
121 private:
122 size_t getCurrentIndex() const {
123 return reinterpret_cast<long>(ptr - &*b.buffer.begin());
124 }
125 T* ptr;
126 const RingBuffer<T>& b;
127 };
128 void push_back(T& t);
129 void push_back(T&& t) { push_back(t); };
130 void emplace_back(T&& t);
131
135 const Iterator cbegin() const { return Iterator(*this, writeIndex); }
139 const Iterator cend() const { return Iterator(*this, util::getIncrementedIndex(writeIndex, buffer.size())); }
143 const Iterator crbegin() const { return Iterator(*this, util::getIncrementedIndex(writeIndex + 1, buffer.size())); }
147 const Iterator crend() const { return Iterator(*this, util::getIncrementedIndex(writeIndex, buffer.size())); }
148
149 const Iterator begin() { return Iterator(*this, writeIndex); }
150 const Iterator end() { return Iterator(*this, util::getIncrementedIndex(writeIndex, buffer.size())); }
151 const Iterator rbegin() { return Iterator(*this, util::getIncrementedIndex(writeIndex + 1, buffer.size())); }
152 const Iterator rend() { return Iterator(*this, util::getIncrementedIndex(writeIndex, buffer.size())); }
153
160 void resize(const size_t size);
161
162 size_t capacity() const { return vectorCapacity - 1; }
163 size_t size() const { return buffer.size() - 1; }
164
165 private:
166 size_t writeIndex;
167 std::vector<T> buffer;
168 size_t vectorCapacity;
169 };
170
171 template<std::swappable T>
172 RingBuffer<T>::RingBuffer(size_t capacity) {
173 buffer.reserve(capacity + 1);
174 buffer.resize(1);
175 vectorCapacity = capacity + 1;
176
177 writeIndex = 0;
178 }
179
180 template<std::swappable T>
181 void RingBuffer<T>::resize(size_t size) {
182 if (size + 1 > buffer.capacity()) { // when growing
183 // point writeIndex to separator
184 util::incrementIndex(writeIndex, buffer.size());
185 // separator element becomes first element -> vector grows while inserting elements
186 std::rotate(buffer.begin(), buffer.begin() + writeIndex, buffer.end());
187 buffer.reserve(size + 1);
188 writeIndex = buffer.size() - 1;
189 }
190 else if (size + 1 < buffer.size()) { // when shrinking
191 // point writeIndex to separator
192 util::incrementIndex(writeIndex, buffer.size());
193 // separator becomes last element in smaller vector -> resize cuts oldest elements
194 std::rotate(buffer.begin(), buffer.begin() + util::getValidIndex(static_cast<int>(writeIndex - size), buffer.size()), buffer.end());
195 buffer.resize(size + 1);
196 writeIndex = util::getValidIndex(static_cast<int>(buffer.size() - 2), buffer.size());
197 }
198 vectorCapacity = size + 1;
199
200 }
201
202 template<std::swappable T>
203 void RingBuffer<T>::push_back(T& t) {
204 util::incrementIndex(writeIndex, vectorCapacity);
205 if (buffer.size() < vectorCapacity) {
206 buffer.push_back(t);
207 }
208 else {
209 buffer[writeIndex] = t;
210 }
211 }
212 template<std::swappable T>
213 void RingBuffer<T>::emplace_back(T&& t) {
214 util::incrementIndex(writeIndex, vectorCapacity);
215 if (buffer.size() < vectorCapacity) {
216 buffer.emplace_back(std::move(t));
217 }
218 else {
219 buffer[writeIndex] = std::move(t);
220 }
221 }
222}
A fixed size buffer that can store data continuously without needing to move data or reallocate memor...
Definition: ringbuffer.hpp:43
size_t writeIndex
Points to the element that was last written.
Definition: ringbuffer.hpp:166
const Iterator cend() const
Return an iterator poiting to the element preceeding the oldest element.
Definition: ringbuffer.hpp:139
void resize(const size_t size)
Resize the buffer to contain max size elements.
Definition: ringbuffer.hpp:181
const Iterator crend() const
Return an iterator pointing to the element following the newest element.
Definition: ringbuffer.hpp:147
const Iterator crbegin() const
Return an iterator pointing to the oldest object.
Definition: ringbuffer.hpp:143
const Iterator cbegin() const
Return an iterator pointing to the newest object.
Definition: ringbuffer.hpp:135
A generic iterator that satisfies std::forward_iterator.
Definition: iterator.hpp:9
Bidirectonal iterator for the RingBuffer.
Definition: ringbuffer.hpp:51
Iterator()
Definition: ringbuffer.hpp:79
std::string to_string() const
Get the index of the vector that ptr points to.
Definition: ringbuffer.hpp:118