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 = int32_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_size, (size_type)((difference_type)m_index + offset)};
77 }
78
83 m_index = (size_type)((difference_type)m_index + diff);
84 return *this;
85 }
90 m_index = (size_type)((difference_type)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_ptr, m_tail, m_size, (size_type)((difference_type)m_index + offset)};
124 }
129 return {m_ptr, m_tail, m_size, (size_type)((difference_type)m_index - offset)};
130 }
135 GAIA_ASSERT(m_ptr == other.m_ptr);
136 return (difference_type)m_index - (difference_type)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::difference_type;
204 using size_type = sringbuffer_detail::size_type;
205
212
214 static constexpr size_type extent = N;
215
222
223 private:
226 constexpr void copy_live_data(const sringbuffer& other) {
227 const auto countFirst = (m_size < N - m_tail) ? m_size : N - m_tail;
228 mem::copy_elements<T, false>(
230 if (countFirst < m_size) {
231 mem::copy_elements<T, false>(
232 (uint8_t*)m_data, (const uint8_t*)other.m_data, m_size - countFirst, 0, extent, other.extent);
233 }
234 }
235
238 constexpr void move_live_data(sringbuffer& other) {
239 const auto countFirst = (m_size < N - m_tail) ? m_size : N - m_tail;
240 mem::move_elements<T, false>(
242 if (countFirst < m_size) {
243 mem::move_elements<T, false>(
245 }
246 }
247
248 public:
249
250 constexpr sringbuffer() noexcept = default;
251
256 template <typename InputIt>
258 const auto count = (size_type)core::distance(first, last);
259 GAIA_ASSERT(count <= max_size());
260 if (count < 1)
261 return;
262
263 m_size = count;
264 m_tail = 0;
265
266 if constexpr (std::is_pointer_v<InputIt>) {
267 for (size_type i = 0; i < count; ++i)
268 m_data[i] = first[i];
269 } else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
270 for (size_type i = 0; i < count; ++i)
271 m_data[i] = *(first[i]);
272 } else {
273 size_type i = 0;
274 for (auto it = first; it != last; ++it)
275 m_data[i++] = *it;
276 }
277 }
278
281 constexpr sringbuffer(std::initializer_list<T> il) noexcept: sringbuffer(il.begin(), il.end()) {}
282
285 constexpr sringbuffer(const sringbuffer& other) noexcept: m_tail(other.m_tail), m_size(other.m_size) {
286 copy_live_data(other);
287 }
288
291 constexpr sringbuffer(sringbuffer&& other) noexcept: m_tail(other.m_tail), m_size(other.m_size) {
292 move_live_data(other);
293
294 other.m_tail = size_type(0);
295 other.m_size = size_type(0);
296 }
297
301 constexpr sringbuffer& operator=(std::initializer_list<T> il) noexcept {
302 *this = sringbuffer(il.begin(), il.end());
303 return *this;
304 }
305
310 GAIA_ASSERT(core::addressof(other) != this);
311
312 m_tail = other.m_tail;
313 m_size = other.m_size;
314 copy_live_data(other);
315
316 return *this;
317 }
318
322 constexpr sringbuffer& operator=(sringbuffer&& other) noexcept {
323 GAIA_ASSERT(core::addressof(other) != this);
324
325 m_tail = other.m_tail;
326 m_size = other.m_size;
327 move_live_data(other);
328
329 other.m_tail = size_type(0);
330 other.m_size = size_type(0);
331
332 return *this;
333 }
334
336
340 GAIA_ASSERT(m_size < N);
341 const auto head = (m_tail + m_size) % N;
342 m_data[head] = arg;
343 ++m_size;
344 }
345
348 constexpr void push_back(T&& arg) {
349 GAIA_ASSERT(m_size < N);
350 const auto head = (m_tail + m_size) % N;
351 m_data[head] = GAIA_MOV(arg);
352 ++m_size;
353 }
354
357 constexpr void pop_front(T& out) {
358 GAIA_ASSERT(!empty());
359 out = m_data[m_tail];
360 m_tail = (m_tail + 1) % N;
361 --m_size;
362 }
363
366 constexpr void pop_front(T&& out) {
367 GAIA_ASSERT(!empty());
368 out = GAIA_MOV(m_data[m_tail]);
369 m_tail = (m_tail + 1) % N;
370 --m_size;
371 }
372
375 constexpr void pop_back(T& out) {
376 GAIA_ASSERT(!empty());
377 const auto head = (m_tail + m_size - 1) % N;
378 out = m_data[head];
379 --m_size;
380 }
381
384 constexpr void pop_back(T&& out) {
385 GAIA_ASSERT(!empty());
386 const auto head = (m_tail + m_size - 1) % N;
387 out = GAIA_MOV(m_data[head]);
388 --m_size;
389 }
390
393 GAIA_NODISCARD constexpr size_type size() const noexcept {
394 return m_size;
395 }
396
399 GAIA_NODISCARD constexpr bool empty() const noexcept {
400 return size() == 0;
401 }
402
405 GAIA_NODISCARD constexpr size_type capacity() const noexcept {
406 return N;
407 }
408
411 GAIA_NODISCARD constexpr size_type max_size() const noexcept {
412 return N;
413 }
414
417 GAIA_NODISCARD constexpr reference front() noexcept {
418 GAIA_ASSERT(!empty());
419 return m_data[m_tail];
420 }
421
424 GAIA_NODISCARD constexpr const_reference front() const noexcept {
425 GAIA_ASSERT(!empty());
426 return m_data[m_tail];
427 }
428
431 GAIA_NODISCARD constexpr reference back() noexcept {
432 GAIA_ASSERT(!empty());
433 const auto head = (m_tail + m_size - 1) % N;
434 return m_data[head];
435 }
436
439 GAIA_NODISCARD constexpr const_reference back() const noexcept {
440 GAIA_ASSERT(!empty());
441 const auto head = (m_tail + m_size - 1) % N;
442 return m_data[head];
443 }
444
447 GAIA_NODISCARD constexpr auto begin() noexcept {
448 return iterator((T*)&m_data[0], m_tail, m_size, 0);
449 }
450
453 GAIA_NODISCARD constexpr auto begin() const noexcept {
454 return const_iterator((T*)&m_data[0], m_tail, m_size, 0);
455 }
456
459 GAIA_NODISCARD constexpr auto cbegin() const noexcept {
460 return const_iterator((T*)&m_data[0], m_tail, m_size, 0);
461 }
462
465 GAIA_NODISCARD constexpr auto end() noexcept {
466 return iterator((T*)&m_data[0], m_tail, m_size, m_size);
467 }
468
471 GAIA_NODISCARD constexpr auto end() const noexcept {
472 return const_iterator((T*)&m_data[0], m_tail, m_size, m_size);
473 }
474
477 GAIA_NODISCARD constexpr auto cend() const noexcept {
478 return const_iterator((T*)&m_data[0], m_tail, m_size, m_size);
479 }
480
484 GAIA_NODISCARD constexpr bool operator==(const sringbuffer& other) const {
485 if (m_size != other.m_size)
486 return false;
487
488 for (size_type i = 0; i < m_size; ++i) {
489 if (!(m_data[(m_tail + i) % N] == other.m_data[(other.m_tail + i) % N]))
490 return false;
491 }
492 return true;
493 }
494
498 GAIA_NODISCARD constexpr bool operator!=(const sringbuffer& other) const {
499 return !operator==(other);
500 }
501 };
502
504 namespace detail {
505 template <typename T, uint32_t N, uint32_t... I>
506 constexpr sringbuffer<std::remove_cv_t<T>, N>
507 to_sringbuffer_impl(T (&a)[N], std::index_sequence<I...> /*no_name*/) {
508 return {{a[I]...}};
509 }
510 } // namespace detail
512
518 template <typename T, uint32_t N>
519 constexpr sringbuffer<std::remove_cv_t<T>, N> to_sringbuffer(T (&a)[N]) {
520 return detail::to_sringbuffer_impl(a, std::make_index_sequence<N>{});
521 }
522
526 template <typename T, typename... U>
527 sringbuffer(T, U...) -> sringbuffer<T, 1 + sizeof...(U)>;
528
529 } // namespace cnt
530
531} // namespace gaia
Array of elements of type.
Definition darray_ext_impl.h:31
GAIA_NODISCARD auto begin() noexcept
Returns an iterator to the first element.
Definition darray_ext_impl.h:613
GAIA_NODISCARD auto end() noexcept
Returns an iterator one past the last element.
Definition darray_ext_impl.h:649
darr_ext_detail::size_type size_type
Unsigned type used for sizes and indices.
Definition darray_ext_impl.h:50
static constexpr size_type extent
Fixed capacity of the container.
Definition darray_ext_impl.h:66
darr_ext_detail::difference_type difference_type
Type used for iterator differences.
Definition darray_ext_impl.h:48
Array of elements of type.
Definition sringbuffer.h:187
GAIA_NODISCARD constexpr reference front() noexcept
Returns the front element.
Definition sringbuffer.h:417
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:477
GAIA_NODISCARD constexpr auto end() noexcept
Returns the mutable end sentinel.
Definition sringbuffer.h:465
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:447
GAIA_NODISCARD constexpr const_reference back() const noexcept
Returns the back element.
Definition sringbuffer.h:439
constexpr sringbuffer(std::initializer_list< T > il) noexcept
Constructs a ring buffer from an initializer list.
Definition sringbuffer.h:281
GAIA_NODISCARD constexpr auto begin() const noexcept
Returns an iterator to the logical front.
Definition sringbuffer.h:453
constexpr sringbuffer(sringbuffer &&other) noexcept
Move-constructs a ring buffer and leaves the source empty.
Definition sringbuffer.h:291
GAIA_NODISCARD constexpr bool empty() const noexcept
Checks whether the buffer is empty.
Definition sringbuffer.h:399
constexpr void pop_front(T &out)
Removes and copies the front element.
Definition sringbuffer.h:357
GAIA_NODISCARD constexpr const_reference front() const noexcept
Returns the front element.
Definition sringbuffer.h:424
GAIA_NODISCARD constexpr bool operator!=(const sringbuffer &other) const
Checks whether live logical sequences differ.
Definition sringbuffer.h:498
GAIA_NODISCARD constexpr auto end() const noexcept
Returns the immutable end sentinel.
Definition sringbuffer.h:471
constexpr sringbuffer & operator=(std::initializer_list< T > il) noexcept
Assigns elements from an initializer list.
Definition sringbuffer.h:301
constexpr void push_back(const T &arg)
Appends a copied element.
Definition sringbuffer.h:339
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:411
constexpr sringbuffer(const sringbuffer &other) noexcept
Copy-constructs a ring buffer.
Definition sringbuffer.h:285
GAIA_NODISCARD constexpr auto cbegin() const noexcept
Returns an iterator to the logical front.
Definition sringbuffer.h:459
GAIA_NODISCARD constexpr size_type capacity() const noexcept
Returns the fixed capacity.
Definition sringbuffer.h:405
constexpr sringbuffer & operator=(sringbuffer &&other) noexcept
Move-assigns a ring buffer and leaves the source empty.
Definition sringbuffer.h:322
constexpr void pop_back(T &out)
Removes and copies the back element.
Definition sringbuffer.h:375
constexpr sringbuffer & operator=(const sringbuffer &other)
Copy-assigns a ring buffer.
Definition sringbuffer.h:309
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:384
sringbuffer_detail::difference_type difference_type
Type used for iterator distances.
Definition sringbuffer.h:202
constexpr void pop_front(T &&out)
Removes and moves the front element.
Definition sringbuffer.h:366
constexpr void push_back(T &&arg)
Appends a moved element.
Definition sringbuffer.h:348
GAIA_NODISCARD constexpr bool operator==(const sringbuffer &other) const
Compares live elements in logical order.
Definition sringbuffer.h:484
GAIA_NODISCARD constexpr size_type size() const noexcept
Returns the number of live elements.
Definition sringbuffer.h:393
GAIA_NODISCARD constexpr reference back() noexcept
Returns the back element.
Definition sringbuffer.h:431
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
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+(difference_type offset) const
Returns an iterator advanced by an offset.
Definition sringbuffer.h:122
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
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-=(difference_type diff)
Moves backward by a logical offset.
Definition sringbuffer.h:89
sringbuffer_detail::size_type size_type
Type used for indices and offsets.
Definition sringbuffer.h:33
iterator operator[](difference_type offset) const
Returns an iterator at a logical offset from the current position.
Definition sringbuffer.h:75
iterator & operator+=(difference_type diff)
Advances by a logical offset.
Definition sringbuffer.h:82
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
iterator operator-(difference_type offset) const
Returns an iterator moved backward by an offset.
Definition sringbuffer.h:128
GAIA_NODISCARD bool operator!=(const iterator &other) const
Compares logical iterator positions.
Definition sringbuffer.h:148