qb  2.0.0.0
C++17 Actor Framework
qb Issue Watch Star Fork Follow @isndev
Loading...
Searching...
No Matches
ring_buffer.h
Go to the documentation of this file.
1
24
25#ifndef QB_RINGBUFFER_H
26#define QB_RINGBUFFER_H
27
28#include <algorithm>
29#include <cstring>
30#include <iostream>
31#include <type_traits>
32#include <vector>
33
34namespace qb {
35
44template <typename T, size_t N, bool Overwrite = true>
45class ring_buffer;
46
47namespace detail {
56template <typename T, size_t N, bool C, bool Overwrite>
58 using buffer_t =
59 typename std::conditional<!C, ring_buffer<T, N, Overwrite> *,
61
62public:
64 using value_type = T;
65 using reference = T &;
66 using const_reference = T const &;
67 using pointer = T *;
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;
72
76 ring_buffer_iterator() noexcept = default;
77
85 ring_buffer_iterator(buffer_t source, size_type index, size_type count) noexcept
86 : source_{source}
87 , index_{index}
88 , count_{count} {}
89
93 ring_buffer_iterator(ring_buffer_iterator const &) noexcept = default;
94
99
105 template <bool Z = C, typename std::enable_if<(!Z), int>::type * = nullptr>
106 [[nodiscard]] reference
107 operator*() noexcept {
108 return (*source_)[index_];
109 }
110
116 template <bool Z = C, typename std::enable_if<(Z), int>::type * = nullptr>
117 [[nodiscard]] const_reference
118 operator*() const noexcept {
119 return (*source_)[index_];
120 }
121
127 template <bool Z = C, typename std::enable_if<(!Z), int>::type * = nullptr>
128 [[nodiscard]] reference
129 operator->() noexcept {
130 return &((*source_)[index_]);
131 }
132
138 template <bool Z = C, typename std::enable_if<(Z), int>::type * = nullptr>
139 [[nodiscard]] const_reference
140 operator->() const noexcept {
141 return &((*source_)[index_]);
142 }
143
149 self_type &
150 operator++() noexcept {
151 index_ = ++index_ % N;
152 ++count_;
153 return *this;
154 }
155
161 [[nodiscard]] self_type
162 operator++(int) noexcept {
163 auto result = *this;
164 this->operator++();
165 return result;
166 }
167
173 [[nodiscard]] size_type
174 index() const noexcept {
175 return index_;
176 }
177
183 [[nodiscard]] size_type
184 count() const noexcept {
185 return count_;
186 }
187
192
193private:
194 buffer_t source_{};
195 size_type index_{};
196 size_type count_{};
197};
198
210template <typename T, size_t N, bool C, bool Overwrite>
211bool
214 return l.count() == r.count();
215}
216
228template <typename T, size_t N, bool C, bool Overwrite>
229bool
232 return l.count() != r.count();
233}
234} // namespace detail
235
249template <typename T, size_t N, bool Overwrite>
251 using self_type = ring_buffer<T, N, Overwrite>;
252
253public:
254 static_assert(N > 0, "ring buffer must have a size greater than zero.");
255
256 using value_type = T;
257 using reference = T &;
258 using const_reference = T const &;
259 using pointer = T *;
260 using const_pointer = T const *;
261 using size_type = size_t;
264
268 ring_buffer() noexcept = default;
269
275 ring_buffer(ring_buffer const &rhs) noexcept(
276 std::is_nothrow_copy_constructible_v<value_type>) {
277 copy_impl(rhs, std::bool_constant<std::is_trivially_copyable_v<T>>{});
278 }
279
287 operator=(ring_buffer const &rhs) noexcept(
288 std::is_nothrow_copy_constructible_v<value_type>) {
289 if (this == &rhs)
290 return *this;
291
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>>{});
294
295 return *this;
296 }
297
308 template <typename U>
309 void
310 push_back(U &&value) {
311 push_back(std::forward<U>(value), std::bool_constant<Overwrite>{});
312 }
313
317 void
318 pop_front() noexcept {
319 if (empty())
320 return;
321
322 destroy(tail_,
323 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
324
325 --size_;
326 tail_ = ++tail_ % N;
327 }
328
334 [[nodiscard]] reference
335 back() noexcept {
336 return reinterpret_cast<reference>(
337 elements_[std::clamp<size_type>(head_ - 1, 0UL, N - 1)]);
338 }
339
345 [[nodiscard]] const_reference
346 back() const noexcept {
347 return const_cast<self_type *>(this)->back();
348 }
349
355 [[nodiscard]] reference
356 front() noexcept {
357 return reinterpret_cast<reference>(elements_[tail_]);
358 }
359
365 [[nodiscard]] const_reference
366 front() const noexcept {
367 return const_cast<self_type *>(this)->front();
368 }
369
376 [[nodiscard]] reference
377 operator[](size_type index) noexcept {
378 return reinterpret_cast<reference>(elements_[index]);
379 }
380
387 [[nodiscard]] const_reference
388 operator[](size_type index) const noexcept {
389 return const_cast<self_type *>(this)->operator[](index);
390 }
391
397 [[nodiscard]] iterator
398 begin() noexcept {
399 return iterator{this, tail_, 0};
400 }
401
407 [[nodiscard]] iterator
408 end() noexcept {
409 return iterator{this, head_, size_};
410 }
411
417 [[nodiscard]] const_iterator
418 cbegin() const noexcept {
419 return const_iterator{this, tail_, 0};
420 }
421
427 [[nodiscard]] const_iterator
428 cend() const noexcept {
429 return const_iterator{this, head_, size_};
430 }
431
437 [[nodiscard]] bool
438 empty() const noexcept {
439 return size_ == 0;
440 }
441
447 [[nodiscard]] bool
448 full() const noexcept {
449 return size_ == N;
450 }
451
457 [[nodiscard]] size_type
458 capacity() const noexcept {
459 return N;
460 }
461
465 void
466 clear() noexcept {
467 destroy_all(std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
468 }
469
474 clear();
475 };
476
477private:
485 void
486 destroy_all(std::true_type) {}
487
495 void
496 destroy_all(std::false_type) {
497 while (!empty()) {
498 destroy(tail_,
499 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
500 tail_ = ++tail_ % N;
501 --size_;
502 }
503 }
504
513 void
514 copy_impl(self_type const &rhs, std::true_type) {
515 std::memcpy(elements_, rhs.elements_, rhs.size_ * sizeof(T));
516 size_ = rhs.size_;
517 tail_ = rhs.tail_;
518 head_ = rhs.head_;
519 }
520
529 void
530 copy_impl(self_type const &rhs, std::false_type) {
531 tail_ = rhs.tail_;
532 head_ = rhs.head_;
533 size_ = rhs.size_;
534
535 try {
536 for (auto i = 0; i < size_; ++i)
537 new (elements_ + ((tail_ + i) % N)) T(rhs[tail_ + ((tail_ + i) % N)]);
538 } catch (...) {
539 while (!empty()) {
540 destroy(
541 tail_,
542 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
543 tail_ = ++tail_ % N;
544 --size_;
545 }
546 throw;
547 }
548 }
549
557 template <typename U>
558 void
559 push_back(U &&value, std::true_type) {
560 push_back_impl(std::forward<U>(value));
561 }
562
570 template <typename U>
571 void
572 push_back(U &&value, std::false_type) {
573 if (full() && !Overwrite)
574 return;
575 push_back_impl(std::forward<U>(value));
576 }
577
584 template <typename U>
585 void
586 push_back_impl(U &&value) {
587 if (full())
588 destroy(head_,
589 std::bool_constant<std::is_trivially_destructible_v<value_type>>{});
590
591 new (elements_ + head_) T{std::forward<U>(value)};
592 head_ = ++head_ % N;
593
594 if (full())
595 tail_ = ++tail_ % N;
596
597 if (!full())
598 ++size_;
599 }
600
609 void
610 destroy(size_type index, std::true_type) noexcept {}
611
620 void
621 destroy(size_type index, std::false_type) noexcept {
622 reinterpret_cast<pointer>(&elements_[index])->~T();
623 }
624
626 typename std::aligned_storage<sizeof(T), alignof(T)>::type elements_[N]{};
627 size_type head_{};
628 size_type tail_{};
629 size_type size_{};
630};
631
632} // namespace qb
633
634#endif // QB_RINGBUFFER_H
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