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]))
205 if(cap == other.cap && sz == other.sz) {
206 for(
size_t i = 0; i < sz; i++) {
207 size_t idx1 = (front_idx + i) % cap;
208 size_t idx2 = (other.front_idx + i) % other.cap;
209 if(buf[idx1] != other.buf[idx2])
221 operator std::vector<T>()
const {
224 std::copy(std::begin(*
this), std::end(*
this), std::back_inserter(v));
231 throw std::length_error(
"ring_buffer: trying to add an element to a buffer of size 0");
232 if(sz && back_idx == front_idx)
233 throw std::overflow_error(
"ring_buffer: overflow error");
235 buf[back_idx] = item;
236 back_idx = (back_idx + 1) % cap;
241 throw std::length_error(
"ring_buffer: trying to add an element to a buffer of size 0");
242 if(sz && back_idx == front_idx)
243 throw std::overflow_error(
"ring_buffer: overflow error");
245 buf[back_idx] = std::move(item);
246 back_idx = (back_idx + 1) % cap;
250 iterator
begin() noexcept {
return iterator(
this, front_idx); }
253 const_iterator
begin() const noexcept {
return const_iterator(
this, front_idx); }
256 const_iterator
cbegin() const noexcept {
return const_iterator(
this, front_idx); }
259 iterator
end() noexcept {
return iterator(
this, (
size_t)(-1)); }
262 const_iterator
end() const noexcept {
return const_iterator(
this, (
size_t)(-1)); }
265 const_iterator
cend() const noexcept {
return const_iterator(
this, (
size_t)(-1)); }
270 throw std::underflow_error(
"ring_buffer: buffer is empty");
271 front_idx = (front_idx + 1) % cap;
278 throw std::underflow_error(
"ring_buffer: buffer is empty");
279 return buf[front_idx];
285 throw std::underflow_error(
"ring_buffer: buffer is empty");
286 return buf[front_idx];
292 throw std::underflow_error(
"ring_buffer: buffer is empty");
293 return buf[(back_idx + cap - 1) % cap];
299 throw std::underflow_error(
"ring_buffer: buffer is empty");
300 return buf[(back_idx + cap - 1) % cap];
305 for(
size_t i = 0; i < sz; i++) {
306 buf[(front_idx + i) % cap].~T();
309 front_idx = back_idx;
314 bool empty(
void)
const noexcept {
return (sz == 0); }
317 bool full(
void)
const noexcept {
return (sz == cap); }
320 size_t capacity(
void)
const noexcept {
return cap; };
325 throw std::bad_array_new_length();
326 std::unique_ptr<T[]> newbuf(new_cap ?
new T[new_cap] :
nullptr);
328 for(
size_t i = 0; i < sz; i++) {
329 newbuf[i] = std::move(buf[(front_idx + i) % cap]);
336 back_idx = cap ? (front_idx + sz) % cap : 0;
340 size_t size() const noexcept {
return sz; }
344 size_t increment(
size_t pos)
const noexcept {
345 if(cap && pos != (
size_t)-1)
346 pos = (pos + 1) % cap;
353 size_t decrement(
size_t pos)
const noexcept {
355 if(pos == (
size_t)-1)
356 pos = (back_idx + cap - 1) % cap;
357 else if(pos != front_idx)
358 pos = (pos + cap - 1) % cap;
364 size_t add(
size_t oldpos,
size_t delta)
const noexcept {
365 if(cap && oldpos != -1) {
366 size_t np = oldpos + (delta % cap);
367 if(np >= cap && np >= back_idx + cap)
377 size_t subtract(
size_t oldpos,
size_t delta)
const noexcept {
379 size_t np = (oldpos == (size_t)-1 ? back_idx : oldpos) - (delta % cap) + cap;
389 std::unique_ptr<T[]> buf;
390 size_t front_idx, back_idx, cap, sz;
iterator_type< C_ > & operator--()
Decrement operator (prefix).
iterator_type< C_ > operator++(int)
Increment operator (postfix).
iterator_type< C_ > & operator++()
Increment operator (prefix).
iterator_type< C_ > operator--(int)
Decrement operator (postfix).
iterator_type< C_ > & operator+=(size_t inc)
Addition assignment operator.
ptrdiff_t operator-(iterator_type< C_ > const &other) const
Difference operator.
bool operator==(iterator_type< C_ > const &it) const
Equality comparison.
iterator_type< C_ > & operator=(iterator_type< C_ > const &rhs)
Assignment operator.
const reference operator*() const
Dereference operator (const version).
iterator_type< C_ > & operator-=(size_t dec)
Subtraction assignment operator.
iterator_type< C_ > operator+(size_t inc) const
Addition operator.
iterator_type()
Default constructor.
iterator_type< C_ > operator-(size_t dec) const
Subtraction operator.
reference operator*()
Dereference operator.
const pointer operator->() const
Object pointer (const version).
bool operator!=(iterator_type< C_ > const &it) const
Inequality comparison.
pointer operator->()
Object pointer.
bool operator!=(ring_buffer< T > const &other) const noexcept
Inequality operator.
T & front()
Return a reference to first (oldest) element in buffer.
bool full(void) const noexcept
Return true if buffer is full.
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.
T const & back() const
Return reference to last (newest) element in 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 & back()
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.
void pop_front()
Remove oldest element from buffer.
ring_buffer()
Default constructor.
iterator begin() noexcept
Return an iterator pointing to first (oldest) 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.
T const & front() const
Return a reference to first (oldest) element in buffer.
ring_buffer & operator=(ring_buffer const &rhs)=delete
Assignment operator.
void push_back(T const &item)
Inserts new element in buffer.
size_t capacity(void) const noexcept
Return maximum buffer size.
bool empty(void) const noexcept
Return true if buffer is empty.