25#ifndef QB_RINGBUFFER_H
26#define QB_RINGBUFFER_H
44template <
typename T,
size_t N,
bool Overwrite = true>
56template <
typename T,
size_t N,
bool C,
bool Overwrite>
59 typename std::conditional<!C, ring_buffer<T, N, Overwrite> *,
65 using reference = T &;
66 using const_reference = T
const &;
68 using const_pointer = T
const *;
69 using size_type = size_t;
70 using difference_type = ptrdiff_t;
71 using iterator_category = std::forward_iterator_tag;
105 template <
bool Z = C,
typename std::enable_if<(!Z),
int>::type * =
nullptr>
106 [[nodiscard]] reference
108 return (*source_)[index_];
116 template <
bool Z = C,
typename std::enable_if<(Z),
int>::type * =
nullptr>
117 [[nodiscard]] const_reference
119 return (*source_)[index_];
127 template <
bool Z = C,
typename std::enable_if<(!Z),
int>::type * =
nullptr>
128 [[nodiscard]] reference
130 return &((*source_)[index_]);
138 template <
bool Z = C,
typename std::enable_if<(Z),
int>::type * =
nullptr>
139 [[nodiscard]] const_reference
141 return &((*source_)[index_]);
151 index_ = ++index_ % N;
161 [[nodiscard]] self_type
173 [[nodiscard]] size_type
183 [[nodiscard]] size_type
210template <
typename T,
size_t N,
bool C,
bool Overwrite>
214 return l.count() == r.count();
228template <
typename T,
size_t N,
bool C,
bool Overwrite>
232 return l.count() != r.count();
249template <
typename T,
size_t N,
bool Overwrite>
254 static_assert(N > 0,
"ring buffer must have a size greater than zero.");
256 using value_type = T;
257 using reference = T &;
258 using const_reference = T
const &;
260 using const_pointer = T
const *;
261 using size_type = size_t;
276 std::is_nothrow_copy_constructible_v<value_type>) {
277 copy_impl(rhs, std::bool_constant<std::is_trivially_copyable_v<T>>{});
288 std::is_nothrow_copy_constructible_v<value_type>) {
292 destroy_all(std::bool_constant<std::is_trivially_copyable_v<T>>{});
293 copy_impl(rhs, std::bool_constant<std::is_trivially_copyable_v<T>>{});
308 template <
typename U>
311 push_back(std::forward<U>(value), std::bool_constant<Overwrite>{});
323 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
334 [[nodiscard]] reference
336 return reinterpret_cast<reference
>(
337 elements_[std::clamp<size_type>(head_ - 1, 0UL, N - 1)]);
345 [[nodiscard]] const_reference
347 return const_cast<self_type *
>(
this)->
back();
355 [[nodiscard]] reference
357 return reinterpret_cast<reference
>(elements_[tail_]);
365 [[nodiscard]] const_reference
367 return const_cast<self_type *
>(
this)->
front();
376 [[nodiscard]] reference
378 return reinterpret_cast<reference
>(elements_[index]);
387 [[nodiscard]] const_reference
389 return const_cast<self_type *
>(
this)->
operator[](index);
397 [[nodiscard]] iterator
399 return iterator{
this, tail_, 0};
407 [[nodiscard]] iterator
409 return iterator{
this, head_, size_};
417 [[nodiscard]] const_iterator
419 return const_iterator{
this, tail_, 0};
427 [[nodiscard]] const_iterator
429 return const_iterator{
this, head_, size_};
457 [[nodiscard]] size_type
467 destroy_all(std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
486 destroy_all(std::true_type) {}
496 destroy_all(std::false_type) {
499 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
514 copy_impl(self_type
const &rhs, std::true_type) {
515 std::memcpy(elements_, rhs.elements_, rhs.size_ *
sizeof(T));
530 copy_impl(self_type
const &rhs, std::false_type) {
536 for (
auto i = 0; i < size_; ++i)
537 new (elements_ + ((tail_ + i) % N)) T(rhs[tail_ + ((tail_ + i) % N)]);
542 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
557 template <
typename U>
560 push_back_impl(std::forward<U>(value));
570 template <
typename U>
573 if (
full() && !Overwrite)
575 push_back_impl(std::forward<U>(value));
584 template <
typename U>
586 push_back_impl(U &&value) {
589 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
591 new (elements_ + head_) T{std::forward<U>(value)};
610 destroy(size_type index, std::true_type)
noexcept {}
621 destroy(size_type index, std::false_type)
noexcept {
622 reinterpret_cast<pointer
>(&elements_[index])->~T();
626 typename std::aligned_storage<
sizeof(T),
alignof(T)>::type elements_[N]{};
Iterator for ring_buffer.
Definition ring_buffer.h:57
ring_buffer_iterator & operator=(ring_buffer_iterator const &) noexcept=default
Copy assignment operator.
const_reference operator*() const noexcept
Dereference operator (const version)
Definition ring_buffer.h:118
reference operator*() noexcept
Dereference operator (non-const version)
Definition ring_buffer.h:107
self_type operator++(int) noexcept
Post-increment operator.
Definition ring_buffer.h:162
const_reference operator->() const noexcept
Arrow operator (const version)
Definition ring_buffer.h:140
size_type count() const noexcept
Definition ring_buffer.h:184
size_type index() const noexcept
Definition ring_buffer.h:174
~ring_buffer_iterator()=default
Destructor.
self_type & operator++() noexcept
Pre-increment operator.
Definition ring_buffer.h:150
reference operator->() noexcept
Arrow operator (non-const version)
Definition ring_buffer.h:129
ring_buffer_iterator(ring_buffer_iterator const &) noexcept=default
Copy constructor.
ring_buffer_iterator() noexcept=default
Default constructor.
A fixed-size ring buffer (circular buffer) implementation.
Definition ring_buffer.h:250
reference back() noexcept
Access the newest element in the buffer.
Definition ring_buffer.h:335
void pop_front() noexcept
Remove the oldest element from the buffer.
Definition ring_buffer.h:318
void clear() noexcept
Clear all elements from the buffer.
Definition ring_buffer.h:466
const_iterator cbegin() const noexcept
Get a const iterator to the first element.
Definition ring_buffer.h:418
ring_buffer() noexcept=default
Default constructor.
const_reference back() const noexcept
Access the newest element in the buffer (const version)
Definition ring_buffer.h:346
~ring_buffer()
Destructor.
Definition ring_buffer.h:473
bool empty() const noexcept
Check if the buffer is empty.
Definition ring_buffer.h:438
const_reference front() const noexcept
Access the oldest element in the buffer (const version)
Definition ring_buffer.h:366
iterator end() noexcept
Get an iterator to the end of the buffer.
Definition ring_buffer.h:408
iterator begin() noexcept
Get an iterator to the first element.
Definition ring_buffer.h:398
reference front() noexcept
Access the oldest element in the buffer.
Definition ring_buffer.h:356
const_reference operator[](size_type index) const noexcept
Access an element by index (const version)
Definition ring_buffer.h:388
ring_buffer & operator=(ring_buffer const &rhs) noexcept(std::is_nothrow_copy_constructible_v< value_type >)
Copy assignment operator.
Definition ring_buffer.h:287
bool full() const noexcept
Check if the buffer is full.
Definition ring_buffer.h:448
void push_back(U &&value)
Add an element to the back of the buffer.
Definition ring_buffer.h:310
const_iterator cend() const noexcept
Get a const iterator to the end of the buffer.
Definition ring_buffer.h:428
reference operator[](size_type index) noexcept
Access an element by index.
Definition ring_buffer.h:377
size_type capacity() const noexcept
Get the capacity of the buffer.
Definition ring_buffer.h:458
bool operator==(ring_buffer_iterator< T, N, C, Overwrite > const &l, ring_buffer_iterator< T, N, C, Overwrite > const &r) noexcept
Equality comparison operator for ring buffer iterators.
Definition ring_buffer.h:212
bool operator!=(ring_buffer_iterator< T, N, C, Overwrite > const &l, ring_buffer_iterator< T, N, C, Overwrite > const &r) noexcept
Inequality comparison operator for ring buffer iterators.
Definition ring_buffer.h:230
Template struct used for type identification in the event system.
Definition Event.h:53