Gaia-ECS v0.9.3
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 {
12 namespace sringbuffer_detail {
13 using difference_type = uint32_t;
14 using size_type = uint32_t;
15 } // namespace sringbuffer_detail
16
17 template <typename T, sringbuffer_detail::size_type N>
19 using value_type = T;
20 using pointer = T*;
21 using reference = T&;
22 using difference_type = sringbuffer_detail::difference_type;
23 using size_type = sringbuffer_detail::size_type;
24
27
28 private:
29 pointer m_ptr;
30 sringbuffer_detail::size_type m_tail;
31 sringbuffer_detail::size_type m_size;
32 sringbuffer_detail::size_type m_index;
33
34 public:
36 // Buffer address
37 pointer ptr,
38 // Ringbuffer tail
39 sringbuffer_detail::size_type tail,
40 // Ringbuffer size
41 sringbuffer_detail::size_type size,
42 // Current index
43 sringbuffer_detail::size_type index): m_ptr(ptr), m_tail(tail), m_size(size), m_index(index) {}
44
45 T& operator*() const {
46 return m_ptr[(m_tail + m_index) % N];
47 }
48 T* operator->() const {
49 return &m_ptr[(m_tail + m_index) % N];
50 }
51 iterator operator[](size_type offset) const {
52 return m_ptr[(m_tail + m_index + offset) % N];
53 }
54
55 iterator& operator+=(size_type diff) {
56 m_index += diff;
57 return *this;
58 }
59 iterator& operator-=(size_type diff) {
60 m_index -= diff;
61 return *this;
62 }
63 iterator& operator++() {
64 ++m_index;
65 return *this;
66 }
67 iterator operator++(int) {
68 iterator temp(*this);
69 ++*this;
70 return temp;
71 }
72 iterator& operator--() {
73 --m_index;
74 return *this;
75 }
76 iterator operator--(int) {
77 iterator temp(*this);
78 --*this;
79 return temp;
80 }
81 iterator operator+(size_type offset) const {
82 return {m_index + offset};
83 }
84 iterator operator-(size_type offset) const {
85 return {m_index - offset};
86 }
87 difference_type operator-(const iterator& other) const {
88 GAIA_ASSERT(m_ptr == other.m_ptr);
89 return (difference_type)(m_index - other.m_index);
90 }
91 GAIA_NODISCARD bool operator==(const iterator& other) const {
92 GAIA_ASSERT(m_ptr == other.m_ptr);
93 return m_index == other.m_index;
94 }
95 GAIA_NODISCARD bool operator!=(const iterator& other) const {
96 GAIA_ASSERT(m_ptr == other.m_ptr);
97 return m_index != other.m_index;
98 }
99 GAIA_NODISCARD bool operator>(const iterator& other) const {
100 GAIA_ASSERT(m_ptr == other.m_ptr);
101 return m_index > other.m_index;
102 }
103 GAIA_NODISCARD bool operator>=(const iterator& other) const {
104 GAIA_ASSERT(m_ptr == other.m_ptr);
105 return m_index >= other.m_index;
106 }
107 GAIA_NODISCARD bool operator<(const iterator& other) const {
108 GAIA_ASSERT(m_ptr == other.m_ptr);
109 return m_index < other.m_index;
110 }
111 GAIA_NODISCARD bool operator<=(const iterator& other) const {
112 GAIA_ASSERT(m_ptr == other.m_ptr);
113 return m_index <= other.m_index;
114 }
115 };
116
121 template <typename T, sringbuffer_detail::size_type N>
123 public:
124 static_assert(N > 1);
125
126 using value_type = T;
127 using reference = T&;
128 using const_reference = const T&;
129 using pointer = T*;
130 using const_pointer = const T*;
131 using difference_type = sringbuffer_detail::size_type;
132 using size_type = sringbuffer_detail::size_type;
133
137
138 static constexpr size_type extent = N;
139
140 size_type m_tail{};
141 size_type m_size{};
142 T m_data[N];
143
144 constexpr sringbuffer() noexcept = default;
145
146 template <typename InputIt>
147 constexpr sringbuffer(InputIt first, InputIt last) noexcept {
148 const auto count = (size_type)core::distance(first, last);
149 GAIA_ASSERT(count <= max_size());
150 if (count < 1)
151 return;
152
153 m_size = count;
154 m_tail = 0;
155
156 if constexpr (std::is_pointer_v<InputIt>) {
157 for (size_type i = 0; i < count; ++i)
158 m_data[i] = first[i];
159 } else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
160 for (size_type i = 0; i < count; ++i)
161 m_data[i] = *(first[i]);
162 } else {
163 size_type i = 0;
164 for (auto it = first; it != last; ++it)
165 m_data[i++] = *it;
166 }
167 }
168
169 constexpr sringbuffer(std::initializer_list<T> il) noexcept: sringbuffer(il.begin(), il.end()) {}
170
171 constexpr sringbuffer(const sringbuffer& other) noexcept: m_tail(other.m_tail), m_size(other.m_size) {
172 mem::copy_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
173 }
174
175 constexpr sringbuffer(sringbuffer&& other) noexcept: m_tail(other.m_tail), m_size(other.m_size) {
176 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
177
178 other.m_tail = size_type(0);
179 other.m_size = size_type(0);
180 }
181
182 constexpr sringbuffer& operator=(std::initializer_list<T> il) noexcept {
183 *this = sringbuffer(il.begin(), il.end());
184 return *this;
185 }
186
187 constexpr sringbuffer& operator=(const sringbuffer& other) {
188 GAIA_ASSERT(core::addressof(other) != this);
189
190 mem::copy_elements<T, false>(&m_data[0], other.m_data, other.size(), 0, extent, other.extent);
191
192 m_tail = other.m_tail;
193 m_size = other.m_size;
194
195 return *this;
196 }
197
198 constexpr sringbuffer& operator=(sringbuffer&& other) noexcept {
199 GAIA_ASSERT(core::addressof(other) != this);
200
201 mem::move_elements<T, false>(m_data, other.m_data, other.size(), 0, extent, other.extent);
202
203 m_tail = other.m_tail;
204 m_size = other.m_size;
205
206 other.m_tail = size_type(0);
207 other.m_size = size_type(0);
208
209 return *this;
210 }
211
212 ~sringbuffer() noexcept = default;
213
214 constexpr void push_back(const T& arg) {
215 GAIA_ASSERT(m_size < N);
216 const auto head = (m_tail + m_size) % N;
217 m_data[head] = arg;
218 ++m_size;
219 }
220
221 constexpr void push_back(T&& arg) {
222 GAIA_ASSERT(m_size < N);
223 const auto head = (m_tail + m_size) % N;
224 m_data[head] = GAIA_MOV(arg);
225 ++m_size;
226 }
227
228 constexpr void pop_front(T& out) {
229 GAIA_ASSERT(!empty());
230 out = m_data[m_tail];
231 m_tail = (m_tail + 1) % N;
232 --m_size;
233 }
234
235 constexpr void pop_front(T&& out) {
236 GAIA_ASSERT(!empty());
237 out = GAIA_MOV(m_data[m_tail]);
238 m_tail = (m_tail + 1) % N;
239 --m_size;
240 }
241
242 constexpr void pop_back(T& out) {
243 GAIA_ASSERT(m_size < N);
244 const auto head = (m_tail + m_size - 1) % N;
245 out = m_data[head];
246 --m_size;
247 }
248
249 constexpr void pop_back(T&& out) {
250 GAIA_ASSERT(m_size < N);
251 const auto head = (m_tail + m_size - 1) % N;
252 out = GAIA_MOV(m_data[head]);
253 --m_size;
254 }
255
256 GAIA_NODISCARD constexpr size_type size() const noexcept {
257 return m_size;
258 }
259
260 GAIA_NODISCARD constexpr bool empty() const noexcept {
261 return size() == 0;
262 }
263
264 GAIA_NODISCARD constexpr size_type capacity() const noexcept {
265 return N;
266 }
267
268 GAIA_NODISCARD constexpr size_type max_size() const noexcept {
269 return N;
270 }
271
272 GAIA_NODISCARD constexpr reference front() noexcept {
273 GAIA_ASSERT(!empty());
274 return m_data[m_tail];
275 }
276
277 GAIA_NODISCARD constexpr const_reference front() const noexcept {
278 GAIA_ASSERT(!empty());
279 return m_data[m_tail];
280 }
281
282 GAIA_NODISCARD constexpr reference back() noexcept {
283 GAIA_ASSERT(!empty());
284 const auto head = (m_tail + m_size - 1) % N;
285 return m_data[head];
286 }
287
288 GAIA_NODISCARD constexpr const_reference back() const noexcept {
289 GAIA_ASSERT(!empty());
290 const auto head = (m_tail + m_size - 1) % N;
291 return m_data[head];
292 }
293
294 GAIA_NODISCARD constexpr auto begin() noexcept {
295 return iterator((T*)&m_data[0], m_tail, m_size, 0);
296 }
297
298 GAIA_NODISCARD constexpr auto begin() const noexcept {
299 return const_iterator((T*)&m_data[0], m_tail, m_size, 0);
300 }
301
302 GAIA_NODISCARD constexpr auto cbegin() const noexcept {
303 return const_iterator((T*)&m_data[0], m_tail, m_size, 0);
304 }
305
306 GAIA_NODISCARD constexpr auto end() noexcept {
307 return iterator((T*)&m_data[0], m_tail, m_size, m_size);
308 }
309
310 GAIA_NODISCARD constexpr auto end() const noexcept {
311 return const_iterator((T*)&m_data[0], m_tail, m_size, m_size);
312 }
313
314 GAIA_NODISCARD constexpr auto cend() const noexcept {
315 return const_iterator((T*)&m_data[0], m_tail, m_size, m_size);
316 }
317
318 GAIA_NODISCARD constexpr bool operator==(const sringbuffer& other) const {
319 for (size_type i = 0; i < N; ++i) {
320 if (m_data[i] == other.m_data[i])
321 return false;
322 }
323 return true;
324 }
325 };
326
327 namespace detail {
328 template <typename T, uint32_t N, uint32_t... I>
330 to_sringbuffer_impl(T (&a)[N], std::index_sequence<I...> /*no_name*/) {
331 return {{a[I]...}};
332 }
333 } // namespace detail
334
335 template <typename T, uint32_t N>
336 constexpr sringbuffer<std::remove_cv_t<T>, N> to_sringbuffer(T (&a)[N]) {
337 return detail::to_sringbuffer_impl(a, std::make_index_sequence<N>{});
338 }
339
340 template <typename T, typename... U>
341 sringbuffer(T, U...) -> sringbuffer<T, 1 + sizeof...(U)>;
342
343 } // namespace cnt
344
345} // namespace gaia
Array of elements of type.
Definition sringbuffer.h:122
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition sringbuffer.h:18