47 using difference_type = std::ptrdiff_t;
49 using reference =
typename std::conditional_t<C_, T const&, T&>;
50 using pointer =
typename std::conditional_t<C_, T const*, T*>;
51 using iterator_category = std::bidirectional_iterator_tag;
60 if(pos == (
size_t)(-1))
61 throw std::range_error(
"Ring buffer iterator at end!");
62 return ring->buf[pos];
67 if(pos == (
size_t)(-1))
68 throw std::range_error(
"Ring buffer iterator at end!");
69 return ring->buf[pos];
74 if(pos == (
size_t)(-1))
75 throw std::range_error(
"Ring buffer iterator at end!");
76 return &ring->buf[pos];
81 if(pos == (
size_t)(-1))
82 throw std::range_error(
"Ring buffer iterator at end!");
83 return &ring->buf[pos];
89 pos = ring->increment(pos);
95 pos = ring->increment(pos);
102 pos = ring->decrement(pos);
108 pos = ring->decrement(pos);
130 tmp.pos = ring->add(pos, inc);
136 pos = ring->add(pos, inc);
143 tmp.pos = ring->subtract(pos, dec);
149 pos = ring->subtract(pos, dec);
155 assert(ring == other.ring);
156 size_t p1 = (pos != -1) ? pos : (ring->back_idx == ring->front_idx) ? ring->sz : ring->back_idx;
157 size_t p2 = (other.pos != -1) ? other.pos : (ring->back_idx == ring->front_idx) ? ring->sz : ring->back_idx;
161 return ring->cap - p2 + p1;
174 typedef iterator_type<false> iterator;
175 typedef iterator_type<true> const_iterator;
179 : buf(std::unique_ptr<T[]>(new T[
size]))
200 : buf(std::unique_ptr<T[]>(new T[il.
size()]))
206 for(
const auto v : il)
207 buf[i++] = std::move(v);
217 if(cap == other.cap && sz == other.sz) {
218 for(
size_t i = 0; i < sz; i++) {
219 size_t idx1 = (front_idx + i) % cap;
220 size_t idx2 = (other.front_idx + i) % other.cap;
221 if(buf[idx1] != other.buf[idx2])
233 operator std::vector<T>()
const {
236 std::copy(std::begin(*
this), std::end(*
this), std::back_inserter(v));
244 throw std::length_error(
"ring_buffer: trying to add an element to a buffer of size 0");
245 if(sz && back_idx == front_idx)
246 throw std::overflow_error(
"ring_buffer: overflow error");
248 buf[back_idx] = item;
249 back_idx = (back_idx + 1) % cap;
255 throw std::length_error(
"ring_buffer: trying to add an element to a buffer of size 0");
256 if(sz && back_idx == front_idx)
257 throw std::overflow_error(
"ring_buffer: overflow error");
259 buf[back_idx] = std::move(item);
260 back_idx = (back_idx + 1) % cap;
284 throw std::underflow_error(
"ring_buffer: buffer is empty");
285 front_idx = (front_idx + 1) % cap;
292 throw std::underflow_error(
"ring_buffer: buffer is empty");
293 return buf[front_idx];
299 throw std::underflow_error(
"ring_buffer: buffer is empty");
300 return buf[front_idx];
306 throw std::underflow_error(
"ring_buffer: buffer is empty");
307 return buf[(back_idx + cap - 1) % cap];
313 throw std::underflow_error(
"ring_buffer: buffer is empty");
314 return buf[(back_idx + cap - 1) % cap];
319 for(
size_t i = 0; i < sz; i++) {
320 buf[(front_idx + i) % cap].~T();
323 front_idx = back_idx;
328 bool empty(
void)
const noexcept {
return (sz == 0); }
331 bool full(
void)
const noexcept {
return (sz == cap); }
334 size_t capacity(
void)
const noexcept {
return cap; };
339 throw std::bad_array_new_length();
340 std::unique_ptr<T[]> newbuf(new_cap ?
new T[new_cap] :
nullptr);
342 for(
size_t i = 0; i < sz; i++) {
343 newbuf[i] = std::move(buf[(front_idx + i) % cap]);
350 back_idx = cap ? (front_idx + sz) % cap : 0;
354 size_t size() const noexcept {
return sz; }
358 size_t increment(
size_t pos)
const noexcept {
359 if(cap && pos != (
size_t)-1)
360 pos = (pos + 1) % cap;
367 size_t decrement(
size_t pos)
const noexcept {
369 if(pos == (
size_t)-1)
370 pos = (back_idx + cap - 1) % cap;
371 else if(pos != front_idx)
372 pos = (pos + cap - 1) % cap;
378 size_t add(
size_t oldpos,
size_t delta)
const noexcept {
379 if(cap && oldpos != -1) {
380 size_t np = oldpos + (delta % cap);
381 if(np >= cap && np >= back_idx + cap)
391 size_t subtract(
size_t oldpos,
size_t delta)
const noexcept {
393 size_t np = (oldpos == (size_t)-1 ? back_idx : oldpos) - (delta % cap) + cap;
403 std::unique_ptr<T[]> buf;
404 size_t front_idx, back_idx, cap, sz;
Iterator through the circular buffer.
iterator_type< C_ > & operator+=(size_t inc)
Addition assignment operator.
ptrdiff_t operator-(iterator_type< C_ > const &other) const
Difference operator.
iterator_type< C_ > & operator++()
Increment operator (prefix)
bool operator==(iterator_type< C_ > const &it) const
Equality comparison.
const reference operator*() const
Dereference operator (const version)
iterator_type< C_ > operator++(int)
Increment operator (postfix)
iterator_type< C_ > operator-(size_t dec) const
Subtraction operator.
iterator_type()
Default constructor.
iterator_type< C_ > operator+(size_t inc) const
Addition operator.
iterator_type< C_ > operator--(int)
Decrement operator (postfix)
iterator_type< C_ > & operator=(iterator_type< C_ > const &rhs)
Assignment operator.
iterator_type< C_ > & operator-=(size_t dec)
Subtraction assignment operator.
reference operator*()
Dereference operator.
const pointer operator->() const
Object pointer (const version)
bool operator!=(iterator_type< C_ > const &it) const
Inequality comparison.
iterator_type< C_ > & operator--()
Decrement operator (prefix)
pointer operator->()
Object pointer.
bool operator!=(ring_buffer< T > const &other) const noexcept
Inequality operator.
bool full(void) const noexcept
Return true if buffer is full.
ring_buffer(std::initializer_list< T > il)
Initializer list constructor.
const_iterator cend() const noexcept
Return an iterator pointing past the last (newest) element in buffer.
ring_buffer(size_t size)
Constructor.
void clear(void)
Remove all elements from buffer.
void resize(size_t new_cap)
(Re)allocate buffer with a different capacity
const_iterator cbegin() const noexcept
Return a const iterator pointing to first (oldest) element in buffer.
size_t size() const noexcept
Return number of elements in buffer.
T const & back() const
Return reference to last (newest) element in buffer.
iterator end() noexcept
Return an iterator pointing past the last (newest) element in buffer.
const_iterator end() const noexcept
Return a const iterator pointing past the last (newest) element in buffer.
ring_buffer(ring_buffer &&other)=delete
Copy constructor.
T & front()
Return a reference to first (oldest) element in buffer.
void pop_front()
Remove oldest element from buffer.
ring_buffer & operator=(ring_buffer const &rhs)=delete
Assignment operator.
ring_buffer()
Default constructor.
iterator begin() noexcept
Return an iterator pointing to first (oldest) element in buffer.
T & back()
Return reference to last (newest) element in buffer.
bool operator==(ring_buffer< T > const &other) const noexcept
Equality operator.
const_iterator begin() const noexcept
Return a const iterator pointing to first (oldest) element in buffer.
ring_buffer(ring_buffer const &other)=delete
Copy constructor.
void push_back(T const &item)
Inserts new element in buffer.
size_t capacity(void) const noexcept
Return maximum buffer size.
T const & front() const
Return a reference to first (oldest) element in buffer.
bool empty(void) const noexcept
Return true if buffer is empty.