Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
sringbuffer.h
1#pragma once
2#include <cstddef>
3#include <type_traits>
4#include <utility>
5
6#include "gaia/core/iterator.h"
7#include "gaia/mem/data_layout_policy.h"
8#include "gaia/mem/mem_utils.h"
9
10namespace gaia {
11 namespace cnt {
13 namespace sringbuffer_detail {
14 using difference_type = uint32_t;
15 using size_type = uint32_t;
16 } // namespace sringbuffer_detail
18
22 template <typename T, sringbuffer_detail::size_type N>
25 using value_type = T;
27 using pointer = T*;
29 using reference = T&;
31 using difference_type = sringbuffer_detail::difference_type;
33 using size_type = sringbuffer_detail::size_type;
34
39
40 private:
41 pointer m_ptr;
42 sringbuffer_detail::size_type m_tail;
43 sringbuffer_detail::size_type m_size;
44 sringbuffer_detail::size_type m_index;
45
46 public:
53 // Buffer address
54 pointer ptr,
55 // Ringbuffer tail
56 sringbuffer_detail::size_type tail,
57 // Ringbuffer size
58 sringbuffer_detail::size_type size,
59 // Current index
60 sringbuffer_detail::size_type index): m_ptr(ptr), m_tail(tail), m_size(size), m_index(index) {}
61
64 T& operator*() const {
65 return m_ptr[(m_tail + m_index) % N];
66 }
69 T* operator->() const {
70 return &m_ptr[(m_tail + m_index) % N];
71 }
76 return m_ptr[(m_tail + m_index + offset) % N];
77 }
78
83 m_index += diff;
84 return *this;
85 }
90 m_index -= diff;
91 return *this;
92 }
96 ++m_index;
97 return *this;
98 }
102 iterator temp(*this);
103 ++*this;
104 return temp;
105 }
109 --m_index;
110 return *this;
111 }
115 iterator temp(*this);
116 --*this;
117 return temp;
118 }
123 return {m_index + offset};
124 }
129 return {m_index - offset};
130 }
134 difference_type operator-(const iterator& other) const {
135 GAIA_ASSERT(m_ptr == other.m_ptr);
136 return (difference_type)(m_index - other.m_index);
137 }
141 GAIA_NODISCARD bool operator==(const iterator& other) const {
142 GAIA_ASSERT(m_ptr == other.m_ptr);
143 return m_index == other.m_index;
144 }
148 GAIA_NODISCARD bool operator!=(const iterator& other) const {
149 GAIA_ASSERT(m_ptr == other.m_ptr);
150 return m_index != other.m_index;
151 }
155 GAIA_NODISCARD bool operator>(const iterator& other) const {
156 GAIA_ASSERT(m_ptr == other.m_ptr);
157 return m_index > other.m_index;
158 }
162 GAIA_NODISCARD bool operator>=(const iterator& other) const {
163 GAIA_ASSERT(m_ptr == other.m_ptr);
164 return m_index >= other.m_index;
165 }
169 GAIA_NODISCARD bool operator<(const iterator& other) const {
170 GAIA_ASSERT(m_ptr == other.m_ptr);
171 return m_index < other.m_index;
172 }
176 GAIA_NODISCARD bool operator<=(const iterator& other) const {
177 GAIA_ASSERT(m_ptr == other.m_ptr);
178 return m_index <= other.m_index;
179 }
180 };
181
186 template <typename T, sringbuffer_detail::size_type N>
188 public:
189 static_assert(N > 1);
190
192 using value_type = T;
194 using reference = T&;
196 using const_reference = const T&;
198 using pointer = T*;
200 using const_pointer = const T*;
202 using difference_type = sringbuffer_detail::size_type;
204 using size_type = sringbuffer_detail::size_type;
205
212
214 static constexpr size_type extent = N;
215
222
223 constexpr sringbuffer() noexcept = default;
224
231 const auto count = (size_type)core::distance(first, last);
232 GAIA_ASSERT(count <= max_size());
233 if (count < 1)
234 return;
235
236 m_size = count;
237 m_tail = 0;
238
239 if constexpr (std::is_pointer_v<InputIt>) {
240 for (size_type i = 0; i < count; ++i)
241 m_data[i] = first[i];
242 } else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
243 for (size_type i = 0; i < count; ++i)
244 m_data[i] = *(first[i]);
245 } else {
246 size_type i = 0;
247 for (auto it = first; it != last; ++it)
248 m_data[i++] = *it;
249 }
250 }
251
254 constexpr sringbuffer(std::initializer_list<T> il) noexcept: sringbuffer(il.begin(), il.end()) {}
255
258 constexpr sringbuffer(const sringbuffer& other) noexcept: m_tail(other.m_tail), m_size(other.m_size) {
259 mem::copy_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
260 }
261
264 constexpr sringbuffer(sringbuffer&& other) noexcept: m_tail(other.m_tail), m_size(other.m_size) {
265 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
266
267 other.m_tail = size_type(0);
268 other.m_size = size_type(0);
269 }
270
274 constexpr sringbuffer& operator=(std::initializer_list<T> il) noexcept {
275 *this = sringbuffer(il.begin(), il.end());
276 return *this;
277 }
278
282 constexpr sringbuffer& operator=(const sringbuffer& other) {
283 GAIA_ASSERT(core::addressof(other) != this);
284
285 mem::copy_elements<T, false>(&m_data[0], other.m_data, other.size(), 0, extent, other.extent);
286
287 m_tail = other.m_tail;
288 m_size = other.m_size;
289
290 return *this;
291 }
292
296 constexpr sringbuffer& operator=(sringbuffer&& other) noexcept {
297 GAIA_ASSERT(core::addressof(other) != this);
298
299 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
300
301 m_tail = other.m_tail;
302 m_size = other.m_size;
303
304 other.m_tail = size_type(0);
305 other.m_size = size_type(0);
306
307 return *this;
308 }
309
311
315 GAIA_ASSERT(m_size < N);
316 const auto head = (m_tail + m_size) % N;
317 m_data[head] = arg;
318 ++m_size;
319 }
320
323 constexpr void push_back(T&& arg) {
324 GAIA_ASSERT(m_size < N);
325 const auto head = (m_tail + m_size) % N;
326 m_data[head] = GAIA_MOV(arg);
327 ++m_size;
328 }
329
332 constexpr void pop_front(T& out) {
333 GAIA_ASSERT(!empty());
334 out = m_data[m_tail];
335 m_tail = (m_tail + 1) % N;
336 --m_size;
337 }
338
341 constexpr void pop_front(T&& out) {
342 GAIA_ASSERT(!empty());
343 out = GAIA_MOV(m_data[m_tail]);
344 m_tail = (m_tail + 1) % N;
345 --m_size;
346 }
347
350 constexpr void pop_back(T& out) {
351 GAIA_ASSERT(m_size < N);
352 const auto head = (m_tail + m_size - 1) % N;
353 out = m_data[head];
354 --m_size;
355 }
356
359 constexpr void pop_back(T&& out) {
360 GAIA_ASSERT(m_size < N);
361 const auto head = (m_tail + m_size - 1) % N;
362 out = GAIA_MOV(m_data[head]);
363 --m_size;
364 }
365
368 GAIA_NODISCARD constexpr size_type size() const noexcept {
369 return m_size;
370 }
371
374 GAIA_NODISCARD constexpr bool empty() const noexcept {
375 return size() == 0;
376 }
377
380 GAIA_NODISCARD constexpr size_type capacity() const noexcept {
381 return N;
382 }
383
386 GAIA_NODISCARD constexpr size_type max_size() const noexcept {
387 return N;
388 }
389
392 GAIA_NODISCARD constexpr reference front() noexcept {
393 GAIA_ASSERT(!empty());
394 return m_data[m_tail];
395 }
396
399 GAIA_NODISCARD constexpr const_reference front() const noexcept {
400 GAIA_ASSERT(!empty());
401 return m_data[m_tail];
402 }
403
406 GAIA_NODISCARD constexpr reference back() noexcept {
407 GAIA_ASSERT(!empty());
408 const auto head = (m_tail + m_size - 1) % N;
409 return m_data[head];
410 }
411
414 GAIA_NODISCARD constexpr const_reference back() const noexcept {
415 GAIA_ASSERT(!empty());
416 const auto head = (m_tail + m_size - 1) % N;
417 return m_data[head];
418 }
419
422 GAIA_NODISCARD constexpr auto begin() noexcept {
423 return iterator((T*)&m_data[0], m_tail, m_size, 0);
424 }
425
428 GAIA_NODISCARD constexpr auto begin() const noexcept {
429 return const_iterator((T*)&m_data[0], m_tail, m_size, 0);
430 }
431
434 GAIA_NODISCARD constexpr auto cbegin() const noexcept {
435 return const_iterator((T*)&m_data[0], m_tail, m_size, 0);
436 }
437
440 GAIA_NODISCARD constexpr auto end() noexcept {
441 return iterator((T*)&m_data[0], m_tail, m_size, m_size);
442 }
443
446 GAIA_NODISCARD constexpr auto end() const noexcept {
447 return const_iterator((T*)&m_data[0], m_tail, m_size, m_size);
448 }
449
452 GAIA_NODISCARD constexpr auto cend() const noexcept {
453 return const_iterator((T*)&m_data[0], m_tail, m_size, m_size);
454 }
455
459 GAIA_NODISCARD constexpr bool operator==(const sringbuffer& other) const {
460 for (size_type i = 0; i < N; ++i) {
461 if (m_data[i] == other.m_data[i])
462 return false;
463 }
464 return true;
465 }
466 };
467
469 namespace detail {
470 template <typename T, uint32_t N, uint32_t... I>
471 constexpr sringbuffer<std::remove_cv_t<T>, N>
472 to_sringbuffer_impl(T (&a)[N], std::index_sequence<I...> /*no_name*/) {
473 return {{a[I]...}};
474 }
475 } // namespace detail
477
483 template <typename T, uint32_t N>
484 constexpr sringbuffer<std::remove_cv_t<T>, N> to_sringbuffer(T (&a)[N]) {
485 return detail::to_sringbuffer_impl(a, std::make_index_sequence<N>{});
486 }
487
491 template <typename T, typename... U>
492 sringbuffer(T, U...) -> sringbuffer<T, 1 + sizeof...(U)>;
493
494 } // namespace cnt
495
496} // namespace gaia
Array with variable size of elements of type.
Definition darray_impl.h:27
darr_detail::size_type size_type
Unsigned type used for sizes and indices.
Definition darray_impl.h:44
GAIA_NODISCARD size_type size() const noexcept
Returns the number of elements.
Definition darray_impl.h:504
GAIA_NODISCARD auto begin() noexcept
Returns an iterator to the first element.
Definition darray_impl.h:556
darr_detail::difference_type difference_type
Type used for iterator differences.
Definition darray_impl.h:42
GAIA_NODISCARD auto end() noexcept
Returns an iterator one past the last element.
Definition darray_impl.h:592
Array of elements of type.
Definition sringbuffer.h:187
GAIA_NODISCARD constexpr reference front() noexcept
Returns the front element.
Definition sringbuffer.h:392
static constexpr size_type extent
Compile-time buffer capacity.
Definition sringbuffer.h:214
size_type m_tail
Physical index of the logical front element.
Definition sringbuffer.h:217
GAIA_NODISCARD constexpr auto cend() const noexcept
Returns the immutable end sentinel.
Definition sringbuffer.h:452
GAIA_NODISCARD constexpr auto end() noexcept
Returns the mutable end sentinel.
Definition sringbuffer.h:440
sringbuffer_detail::size_type difference_type
Type used for iterator distances.
Definition sringbuffer.h:202
sringbuffer_detail::size_type size_type
Type used for sizes and indices.
Definition sringbuffer.h:204
size_type m_size
Number of live elements.
Definition sringbuffer.h:219
GAIA_NODISCARD constexpr auto begin() noexcept
Returns an iterator to the logical front.
Definition sringbuffer.h:422
GAIA_NODISCARD constexpr const_reference back() const noexcept
Returns the back element.
Definition sringbuffer.h:414
constexpr sringbuffer(std::initializer_list< T > il) noexcept
Constructs a ring buffer from an initializer list.
Definition sringbuffer.h:254
GAIA_NODISCARD constexpr auto begin() const noexcept
Returns an iterator to the logical front.
Definition sringbuffer.h:428
constexpr sringbuffer(sringbuffer &&other) noexcept
Move-constructs a ring buffer and leaves the source empty.
Definition sringbuffer.h:264
GAIA_NODISCARD constexpr bool empty() const noexcept
Checks whether the buffer is empty.
Definition sringbuffer.h:374
constexpr void pop_front(T &out)
Removes and copies the front element.
Definition sringbuffer.h:332
GAIA_NODISCARD constexpr const_reference front() const noexcept
Returns the front element.
Definition sringbuffer.h:399
GAIA_NODISCARD constexpr auto end() const noexcept
Returns the immutable end sentinel.
Definition sringbuffer.h:446
constexpr sringbuffer & operator=(std::initializer_list< T > il) noexcept
Assigns elements from an initializer list.
Definition sringbuffer.h:274
constexpr void push_back(const T &arg)
Appends a copied element.
Definition sringbuffer.h:314
sringbuffer_iterator< T, N > iterator
Mutable random-access iterator.
Definition sringbuffer.h:207
GAIA_NODISCARD constexpr size_type max_size() const noexcept
Returns the maximum element count.
Definition sringbuffer.h:386
constexpr sringbuffer(const sringbuffer &other) noexcept
Copy-constructs a ring buffer.
Definition sringbuffer.h:258
GAIA_NODISCARD constexpr auto cbegin() const noexcept
Returns an iterator to the logical front.
Definition sringbuffer.h:434
GAIA_NODISCARD constexpr size_type capacity() const noexcept
Returns the fixed capacity.
Definition sringbuffer.h:380
constexpr sringbuffer & operator=(sringbuffer &&other) noexcept
Move-assigns a ring buffer and leaves the source empty.
Definition sringbuffer.h:296
constexpr void pop_back(T &out)
Removes and copies the back element.
Definition sringbuffer.h:350
constexpr sringbuffer & operator=(const sringbuffer &other)
Copy-assigns a ring buffer.
Definition sringbuffer.h:282
sringbuffer_iterator< const T, N > const_iterator
Immutable random-access iterator.
Definition sringbuffer.h:209
T m_data[N]
Physical element storage.
Definition sringbuffer.h:221
constexpr void pop_back(T &&out)
Removes and moves the back element.
Definition sringbuffer.h:359
constexpr void pop_front(T &&out)
Removes and moves the front element.
Definition sringbuffer.h:341
constexpr void push_back(T &&arg)
Appends a moved element.
Definition sringbuffer.h:323
GAIA_NODISCARD constexpr bool operator==(const sringbuffer &other) const
Compares corresponding physical storage positions.
Definition sringbuffer.h:459
GAIA_NODISCARD constexpr size_type size() const noexcept
Returns the number of live elements.
Definition sringbuffer.h:368
GAIA_NODISCARD constexpr reference back() noexcept
Returns the back element.
Definition sringbuffer.h:406
Random-access iterator over the logical sequence stored in a sringbuffer.
Definition sringbuffer.h:23
T & operator*() const
Dereferences the current logical element.
Definition sringbuffer.h:64
iterator operator+(size_type offset) const
Returns an iterator advanced by an offset.
Definition sringbuffer.h:122
GAIA_NODISCARD bool operator>(const iterator &other) const
Compares logical iterator positions.
Definition sringbuffer.h:155
iterator & operator++()
Advances by one logical position.
Definition sringbuffer.h:95
iterator operator++(int)
Advances by one logical position.
Definition sringbuffer.h:101
iterator operator--(int)
Moves backward by one logical position.
Definition sringbuffer.h:114
iterator operator[](size_type offset) const
Accesses storage at a logical offset using the declared iterator result type.
Definition sringbuffer.h:75
sringbuffer_iterator(pointer ptr, sringbuffer_detail::size_type tail, sringbuffer_detail::size_type size, sringbuffer_detail::size_type index)
Constructs an iterator over a ring-buffer sequence.
Definition sringbuffer.h:52
iterator & operator--()
Moves backward by one logical position.
Definition sringbuffer.h:108
GAIA_NODISCARD bool operator>=(const iterator &other) const
Compares logical iterator positions.
Definition sringbuffer.h:162
difference_type operator-(const iterator &other) const
Calculates the logical distance between iterators from the same buffer.
Definition sringbuffer.h:134
sringbuffer_detail::difference_type difference_type
Type used for iterator distances.
Definition sringbuffer.h:31
iterator & operator+=(size_type diff)
Advances by a logical offset.
Definition sringbuffer.h:82
iterator operator-(size_type offset) const
Returns an iterator moved backward by an offset.
Definition sringbuffer.h:128
sringbuffer_detail::size_type size_type
Type used for indices and offsets.
Definition sringbuffer.h:33
iterator & operator-=(size_type diff)
Moves backward by a logical offset.
Definition sringbuffer.h:89
GAIA_NODISCARD bool operator==(const iterator &other) const
Compares logical iterator positions.
Definition sringbuffer.h:141
GAIA_NODISCARD bool operator<=(const iterator &other) const
Compares logical iterator positions.
Definition sringbuffer.h:176
GAIA_NODISCARD bool operator<(const iterator &other) const
Compares logical iterator positions.
Definition sringbuffer.h:169
T * operator->() const
Accesses the current logical element.
Definition sringbuffer.h:69
GAIA_NODISCARD bool operator!=(const iterator &other) const
Compares logical iterator positions.
Definition sringbuffer.h:148