MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
mtcore::RingBuffer< T > Struct Template Reference

Represents a ring buffer with dynamically allocated memory Can be used as a FIFO or LIFO queue Allows memory reuse rather than continuous memory allocations as it is used May be dynamically resized. More...

#include <ring_buffer.hpp>

Public Types

using Elem = T
 

Public Member Functions

decltype(auto) ptr_iter () noexcept
 Gets iterator over pointers to elements.
 
decltype(auto) ptr_iter () const noexcept
 Gets iterator over const pointers to elements.
 
decltype(auto) iter () noexcept
 Gets iterator over values.
 
Result< void, AllocationErrorinit (Allocator &alloc, size_t initCapacity=10) noexcept
 Initializes an empty ArrayList with an initial capacity.
 
Result< void, AllocationErrorinit (Allocator &alloc, std::initializer_list< T > init, size_t capacity=0) noexcept
 Initializes an ring buffer with specified elements.
 
void deinit (Allocator &alloc)
 Cleans up any memory held by ring buffer.
 
const T & operator[] (size_t i) const noexcept
 Access element.
 
T & operator[] (size_t i) noexcept
 Access element.
 
size_t size () const noexcept
 Get size.
 
size_t capacity () const noexcept
 Get capacity.
 
const T & at (size_t i) const noexcept
 Access element.
 
T & at (size_t i) noexcept
 Access element.
 
Result< void, AllocationErrorpush_back (Allocator &alloc, const T &elem)
 Add element to back of buffer.
 
Result< void, AllocationErrorpush_front (Allocator &alloc, const T &elem)
 Add element to front of buffer.
 
Result< void, CollectionAddNoAllocationErrorpush_back (const T &elem)
 Add element to back of buffer.
 
Result< void, AllocationErrorshrink_to_fit (Allocator &alloc)
 
Result< void, CollectionAddNoAllocationErrorpush_front (const T &elem)
 Add element to front of buffer.
 
Optional< T > pop_front ()
 Removes and returns element from front.
 
Optional< T > pop_back ()
 Removes and returns element from back.
 

Detailed Description

template<typename T>
struct mtcore::RingBuffer< T >

Represents a ring buffer with dynamically allocated memory Can be used as a FIFO or LIFO queue Allows memory reuse rather than continuous memory allocations as it is used May be dynamically resized.

Accessing elements is \(O(1)\) Adding elements is worst case \(O(N)\), but generally is \(O(1)\) Removing elements is \(O(1)\)

Template Parameters
TType of element stored

Definition at line 42 of file ring_buffer.hpp.

Member Typedef Documentation

◆ Elem

template<typename T>
using mtcore::RingBuffer< T >::Elem = T

Definition at line 50 of file ring_buffer.hpp.

Member Function Documentation

◆ at() [1/2]

template<typename T>
const T & mtcore::RingBuffer< T >::at ( size_t i) const
inlinenodiscardnoexcept

Access element.

Definition at line 156 of file ring_buffer.hpp.

156 {
157 ensure(elements.head, "NOT INITIALIZED");
158 ensure(i < count, "OUT OF BOUNDS ACCESS");
159 auto index = i + head;
160 if (index >= elements.size()) {
161 index -= elements.size();
162 }
163 return elements[index];
164 }
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Represents a ring buffer with dynamically allocated memory Can be used as a FIFO or LIFO queue Allows...
size_t size() const noexcept
Get size.
Here is the caller graph for this function:

◆ at() [2/2]

template<typename T>
T & mtcore::RingBuffer< T >::at ( size_t i)
inlinenoexcept

Access element.

Definition at line 167 of file ring_buffer.hpp.

167 {
168 ensure(elements.head, "NOT INITIALIZED");
169 ensure(i < count, "OUT OF BOUNDS ACCESS");
170 auto index = i + head;
171 if (index >= elements.size()) {
172 index -= elements.size();
173 }
174 return elements[index];
175 }

◆ capacity()

template<typename T>
size_t mtcore::RingBuffer< T >::capacity ( ) const
inlinenodiscardnoexcept

Get capacity.

Definition at line 153 of file ring_buffer.hpp.

153{ return elements.size(); }
Here is the caller graph for this function:

◆ deinit()

template<typename T>
void mtcore::RingBuffer< T >::deinit ( Allocator & alloc)
inline

Cleans up any memory held by ring buffer.

Parameters
allocAllocator to use for cleanup

Definition at line 128 of file ring_buffer.hpp.

128 {
129 if (elements.head) {
130 alloc.destroy_many(elements);
131 elements.head = nullptr;
132 }
133 elements.len = 0;
134 head = 0;
135 tail = 0;
136 count = 0;
137 }
Here is the call graph for this function:

◆ init() [1/2]

template<typename T>
Result< void, AllocationError > mtcore::RingBuffer< T >::init ( Allocator & alloc,
size_t initCapacity = 10 )
inlinenoexcept

Initializes an empty ArrayList with an initial capacity.

Parameters
allocAllocator to use for initial allocation
initCapacity(Optional) Initial capacity to have (defaults to 10)
Returns
success or failure

Definition at line 83 of file ring_buffer.hpp.

83 {
84 ensure(!head && !tail && !count, "ALREADY INITIALIZED");
85 ensure(elements.head == nullptr && elements.size() == 0, "ALREADY INITIALIZED!");
87 auto allocRes = alloc.create_many<T>(initCapacity);
88 if (allocRes.is_error()) {
89 return allocRes.error();
90 }
91
92 elements = *allocRes;
93 return success();
94 }
Success< void > success()
Creates a successful void Result object.
Definition result.hpp:398
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init() [2/2]

template<typename T>
Result< void, AllocationError > mtcore::RingBuffer< T >::init ( Allocator & alloc,
std::initializer_list< T > init,
size_t capacity = 0 )
inlinenoexcept

Initializes an ring buffer with specified elements.

Parameters
allocAllocator to use for initial allocation
initInitial value list
capacity(Optional) initial capacity (if bigger than the initial value list)
Returns
success or failure

Definition at line 104 of file ring_buffer.hpp.

104 {
105 ensure(!head && !tail && !count, "ALREADY INITIALIZED");
106 ensure(elements.head == nullptr && elements.size() == 0, "ALREADY INITIALIZED!");
107 if (capacity < init.size()) {
108 capacity = init.size();
109 }
110 capacity = capacity ? capacity : 10;
111 auto allocRes = alloc.create_many<T>(init.size());
112 if (allocRes.is_error()) {
113 return allocRes.error();
114 }
115
116 elements = *allocRes;
117 for (const auto &elem: init) {
119 }
120
121 return success();
122 }
size_t capacity() const noexcept
Get capacity.
Result< void, AllocationError > push_back(Allocator &alloc, const T &elem)
Add element to back of buffer.
Result< void, AllocationError > init(Allocator &alloc, size_t initCapacity=10) noexcept
Initializes an empty ArrayList with an initial capacity.
Here is the call graph for this function:

◆ iter()

template<typename T>
decltype(auto) mtcore::RingBuffer< T >::iter ( )
inlinenoexcept

Gets iterator over values.

Returns
Iterator

Definition at line 72 of file ring_buffer.hpp.

72 {
73 ensure(elements.head, "NOT INITIALIZED");
74 return iter::val(*this);
75 }
ValIter< T > val(const T &r)
Generic value iterator that uses the operator[] and incrementing indexes to iterate over a collection...
Definition iter.hpp:114
Here is the call graph for this function:

◆ operator[]() [1/2]

template<typename T>
const T & mtcore::RingBuffer< T >::operator[] ( size_t i) const
inlinenoexcept

Access element.

Definition at line 140 of file ring_buffer.hpp.

140 {
141 ensure(elements.head, "NOT INITIALIZED");
142 return at(i);
143 }
const T & at(size_t i) const noexcept
Access element.
Here is the call graph for this function:

◆ operator[]() [2/2]

template<typename T>
T & mtcore::RingBuffer< T >::operator[] ( size_t i)
inlinenoexcept

Access element.

Definition at line 145 of file ring_buffer.hpp.

145 {
146 ensure(elements.head, "NOT INITIALIZED");
147 return at(i);
148 }
Here is the call graph for this function:

◆ pop_back()

template<typename T>
Optional< T > mtcore::RingBuffer< T >::pop_back ( )
inline

Removes and returns element from back.

Returns nullopt if empty

Definition at line 284 of file ring_buffer.hpp.

284 {
285 ensure(elements.head, "NOT INITIALIZED");
286 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
287 if (count == 0) {
288 return nullopt;
289 }
290
291 auto new_tail = tail;
292 if (new_tail == 0) {
293 new_tail = elements.size() - 1;
294 }
295 else {
296 new_tail--;
297 }
298
299 auto res = elements[tail];
300 --count;
301 tail = new_tail;
302 return res;
303 }
Here is the call graph for this function:

◆ pop_front()

template<typename T>
Optional< T > mtcore::RingBuffer< T >::pop_front ( )
inline

Removes and returns element from front.

Returns nullopt if empty

Definition at line 267 of file ring_buffer.hpp.

267 {
268 ensure(elements.head, "NOT INITIALIZED");
269 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
270 if (count == 0) {
271 return nullopt;
272 }
273
274 auto &res = elements[head++];
275
276 count--;
277 if (head == elements.size()) {
278 head = 0;
279 }
280 return Optional{std::move(res)};
281 }
Here is the call graph for this function:

◆ ptr_iter() [1/2]

template<typename T>
decltype(auto) mtcore::RingBuffer< T >::ptr_iter ( ) const
inlinenoexcept

Gets iterator over const pointers to elements.

Returns
Iterator

Definition at line 64 of file ring_buffer.hpp.

64 {
65 ensure(elements.head, "NOT INITIALIZED");
66 return iter::const_ptr(*this);
67 }
ConstPtrIter< T > const_ptr(const T &r)
Generic constant pointer iterator that uses the operator[] and incrementing indexes to iterate over a...
Definition iter.hpp:128
Here is the call graph for this function:

◆ ptr_iter() [2/2]

template<typename T>
decltype(auto) mtcore::RingBuffer< T >::ptr_iter ( )
inlinenoexcept

Gets iterator over pointers to elements.

Returns
Iterator

Definition at line 56 of file ring_buffer.hpp.

56 {
57 ensure(elements.head, "NOT INITIALIZED");
58 return iter::ptr(*this);
59 }
PtrIter< T > ptr(T &r)
Generic pointer iterator that uses the operator[] and incrementing indexes to iterate over a collecti...
Definition iter.hpp:101
Here is the call graph for this function:

◆ push_back() [1/2]

template<typename T>
Result< void, AllocationError > mtcore::RingBuffer< T >::push_back ( Allocator & alloc,
const T & elem )
inline

Add element to back of buffer.

Allocate more memory if needed

Definition at line 178 of file ring_buffer.hpp.

178 {
179 ensure(elements.head, "NOT INITIALIZED");
180 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
181 if (auto err = grow_if_needed(alloc); err.is_error()) {
182 return err;
183 }
184 if (push_back(elem).is_error()) {
186 }
187 return success();
188 }
Error< Underlying > error(Underlying err)
Creates an error.
Definition result.hpp:425
Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_back() [2/2]

template<typename T>
Result< void, CollectionAddNoAllocationError > mtcore::RingBuffer< T >::push_back ( const T & elem)
inline

Add element to back of buffer.

Errors if full

Definition at line 204 of file ring_buffer.hpp.

204 {
205 ensure(elements.head, "NOT INITIALIZED");
206 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
207 if (count >= elements.size()) {
209 }
210
211 elements[tail++] = elem;
212 count++;
213 if (tail == elements.size()) {
214 tail = 0;
215 }
216 return success();
217 }
Here is the call graph for this function:

◆ push_front() [1/2]

template<typename T>
Result< void, AllocationError > mtcore::RingBuffer< T >::push_front ( Allocator & alloc,
const T & elem )
inline

Add element to front of buffer.

Allocate more memory if needed

Definition at line 191 of file ring_buffer.hpp.

191 {
192 ensure(elements.head, "NOT INITIALIZED");
193 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
194 if (auto err = grow_if_needed(alloc); err.is_error()) {
195 return err;
196 }
197 if (push_front(elem).is_error()) {
199 }
200 return success();
201 }
Result< void, AllocationError > push_front(Allocator &alloc, const T &elem)
Add element to front of buffer.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_front() [2/2]

template<typename T>
Result< void, CollectionAddNoAllocationError > mtcore::RingBuffer< T >::push_front ( const T & elem)
inline

Add element to front of buffer.

Errors if full

Definition at line 246 of file ring_buffer.hpp.

246 {
247 ensure(elements.head, "NOT INITIALIZED");
248 mtdefer { ensure(size() <= capacity(), "SIZE MISMATCH"); };
249 if (count >= elements.size()) {
251 }
252
253 auto new_head = head;
254 if (new_head == 0) {
255 new_head = elements.size() - 1;
256 }
257 else {
258 new_head--;
259 }
260 elements[new_head] = elem;
261 count++;
262 head = new_head;
263 return success();
264 }
Here is the call graph for this function:

◆ shrink_to_fit()

template<typename T>
Result< void, AllocationError > mtcore::RingBuffer< T >::shrink_to_fit ( Allocator & alloc)
inline

Definition at line 219 of file ring_buffer.hpp.

219 {
220 const auto newSize = std::max(static_cast<size_t>(1), count);
221 auto newBufferRes = alloc.create_many<T>(newSize);
222 if (newBufferRes.is_error()) {
223 return newBufferRes.error();
224 }
225 auto newBuffer = *newBufferRes;
226
227 for (size_t i = 0, curHead = head; i < newBuffer.size() && i < count; ++i) {
228 mtdefer {
229 curHead += 1;
230 if (curHead == elements.size()) {
231 curHead = 0;
232 }
233 };
234 std::swap(newBuffer[i], elements[curHead]);
235 }
236 head = 0;
237 tail = elements.size();
238 count = tail - head;
239 alloc.destroy_many(elements);
240 elements = newBuffer;
241 head = 0;
242 return success();
243 }
Here is the call graph for this function:

◆ size()

template<typename T>
size_t mtcore::RingBuffer< T >::size ( ) const
inlinenodiscardnoexcept

Get size.

Definition at line 151 of file ring_buffer.hpp.

151{ return count; }
Here is the caller graph for this function:

The documentation for this struct was generated from the following file: