MLIB
Loading...
Searching...
No Matches
ringbuf.h
Go to the documentation of this file.
1
8#pragma once
9
10#include <memory>
11#include <vector>
12#include <stdexcept>
13#include <assert.h>
14
15#if __has_include("defs.h")
16#include "defs.h"
17#endif
18
19namespace mlib {
20
22template <class T>
24{
25public:
27 template <bool C_>
29 {
30 public:
31 // Following typedefs must exist to allow instantiation of std::iterator_traits
32 using difference_type = std::ptrdiff_t;
33 using value_type = T;
34 using reference = typename std::conditional_t<C_, T const&, T&>;
35 using pointer = typename std::conditional_t<C_, T const*, T*>;
36 using iterator_category = std::bidirectional_iterator_tag;
37
40 : ring (nullptr)
41 , pos (0)
42 {}
43
44 // Implicit forms of copy constructor, destructor and assignment operator are OK
45
47 reference operator* ()
48 {
49 if (pos == (size_t)(-1))
50 throw std::range_error ("Ring buffer iterator at end!");
51 return ring->buf[pos];
52 }
53
55 const reference operator* () const
56 {
57 if (pos == (size_t)(-1))
58 throw std::range_error ("Ring buffer iterator at end!");
59 return ring->buf[pos];
60 }
61
63 pointer operator->()
64 {
65 if (pos == (size_t)(-1))
66 throw std::range_error ("Ring buffer iterator at end!");
67 return &ring->buf[pos];
68 }
69
71 const pointer operator->() const
72 {
73 if (pos == (size_t)(-1))
74 throw std::range_error ("Ring buffer iterator at end!");
75 return &ring->buf[pos];
76 }
77
80 {
81 iterator_type<C_> tmp = *this;
82 pos = ring->increment (pos);
83 return tmp;
84 }
85
88 {
89 pos = ring->increment (pos);
90 return *this;
91 }
92
95 {
96 iterator_type<C_> tmp = *this;
97 pos = ring->decrement (pos);
98 return tmp;
99 }
100
103 {
104 pos = ring->decrement (pos);
105 return *this;
106 }
107
110 {
111 return (ring == it.ring) && (pos == it.pos);
112 }
113
116 {
117 return !operator== (it);
118 }
119
122 {
123 if (this != &rhs)
124 {
125 ring = rhs.ring;
126 pos = rhs.pos;
127 }
128 return *this;
129 }
130
133 {
134 iterator_type<C_> tmp = *this;
135 tmp.pos = ring->add (pos, inc);
136 return tmp;
137 }
138
141 {
142 pos = ring->add (pos, inc);
143 return *this;
144 }
145
148 {
149 iterator_type<C_> tmp = *this;
150 tmp.pos = ring->subtract (pos, dec);
151 return tmp;
152 }
153
156 {
157 pos = ring->subtract (pos, dec);
158 return *this;
159 }
160
163 {
164 assert (ring == other.ring);
165 size_t p1 = (pos != -1) ? pos
166 : (ring->back_idx == ring->front_idx) ? ring->sz
167 : ring->back_idx;
168 size_t p2 = (other.pos != -1) ? other.pos
169 : (ring->back_idx == ring->front_idx) ? ring->sz
170 : ring->back_idx;
171 if (p1 >= p2)
172 return p1 - p2;
173 else
174 return ring->cap - p2 + p1;
175 }
176
177 private:
178 iterator_type (const ring_buffer* ring_, size_t pos_)
179 : ring (ring_)
180 , pos (pos_)
181 {}
182
183 const ring_buffer* ring;
184 size_t pos;
185 friend class ring_buffer;
186 };
187
188 typedef iterator_type<false> iterator;
189 typedef iterator_type<true> const_iterator;
190
193 : buf (std::unique_ptr<T[]> (new T[size]))
194 , cap (size)
195 , front_idx (0)
196 , back_idx (0)
197 , sz (0)
198 {}
199
202 : cap (0)
203 , front_idx (0)
204 , back_idx (0)
205 , sz (0)
206 {}
207
210 : front_idx (other.front_idx)
211 , back_idx (other.back_idx)
212 , cap (other.cap)
213 , sz (other.sz)
214 {
215 if (other.cap)
216 {
217 buf = std::unique_ptr<T[]> (new T[other.cap]);
218 for (size_t i = 0; i < sz; i++)
219 {
220 size_t idx = (front_idx + i) % cap;
221 buf[idx] = other.buf[idx];
222 }
223 }
224 }
225
227 ring_buffer (std::initializer_list<T> il)
228 : buf (std::unique_ptr<T[]> (new T[il.size ()]))
229 , cap (il.size ())
230 , front_idx (0)
231 , back_idx (0)
232 , sz (il.size ())
233 {
234 size_t i = 0;
235 for (const auto v : il)
236 buf[i++] = std::move (v);
237 }
238
241 {
242 if (&rhs != this)
243 {
244 front_idx = rhs.front_idx;
245 back_idx = rhs.back_idx;
246 cap = rhs.cap;
247 sz = rhs.sz;
248 if (rhs.cap)
249 {
250 buf.reset (new T[rhs.cap]);
251 for (size_t i = 0; i < sz; i++)
252 {
253 size_t idx = (front_idx + i) % cap;
254 buf[idx] = rhs.buf[idx];
255 }
256 }
257 else
258 buf.reset ();
259 }
260 return *this;
261 }
262
265 {
266 if (cap == other.cap && sz == other.sz)
267 {
268 for (size_t i = 0; i < sz; i++)
269 {
270 size_t idx1 = (front_idx + i) % cap;
271 size_t idx2 = (other.front_idx + i) % other.cap;
272 if (buf[idx1] != other.buf[idx2])
273 return false;
274 }
275 return true;
276 }
277 return false;
278 }
279
282 {
283 return !operator== (other);
284 }
285
287 operator std::vector<T> () const
288 {
289 std::vector<T> v (sz);
290 for (size_t i = 0; i < sz; i++)
291 v[i] = buf[(front_idx + i) % cap];
292
293 return v;
294 }
295
297 void push_back (const T& item)
298 {
299 if (!cap)
300 return; // container not allocated
301
302 if (sz && back_idx == front_idx)
303 front_idx = (front_idx + 1) % cap;
304 else
305 sz++;
306 buf[back_idx] = item;
307 back_idx = (back_idx + 1) % cap;
308 }
309
312 {
313 return iterator (this, front_idx);
314 }
315
318 {
319 return const_iterator (this, front_idx);
320 }
321
324 {
325 return const_iterator (this, front_idx);
326 }
327
330 {
331 return iterator (this, (size_t)(-1));
332 }
333
336 {
337 return const_iterator (this, (size_t)(-1));
338 }
339
342 {
343 return const_iterator (this, (size_t)(-1));
344 }
345
347 void pop_front ()
348 {
349 if (sz)
350 {
351 front_idx = (front_idx + 1) % cap;
352 sz--;
353 }
354 }
355
358 {
359 return buf[front_idx];
360 }
361
363 const T& front () const
364 {
365 return buf[front_idx];
366 }
367
369 T& back ()
370 {
371 return buf[(back_idx + cap - 1) % cap];
372 }
373
375 const T& back () const
376 {
377 return buf[(back_idx + cap - 1) % cap];
378 }
379
381 void clear (void)
382 {
383 front_idx = back_idx;
384 sz = 0;
385 }
386
388 bool empty (void)
389 {
390 return (sz == 0);
391 }
392
394 bool full (void) const
395 {
396 return (sz == cap);
397 }
398
400 size_t capacity (void) const
401 {
402 return cap;
403 };
404
406 void resize (size_t new_cap)
407 {
408 std::unique_ptr<T[]> newbuf (new_cap ? new T[new_cap] : nullptr);
409 if (new_cap)
410 {
411 if (sz >= new_cap)
412 sz = new_cap;
413 for (size_t i = 0; i < sz; i++)
414 newbuf[i] = buf[(front_idx + i) % cap];
415 }
416 else
417 sz = 0;
418 cap = new_cap;
419 buf.swap (newbuf);
420 front_idx = 0;
421 back_idx = cap ? (front_idx + sz) % cap : 0;
422 }
423
425 size_t size () const
426 {
427 return sz;
428 }
429
430private:
432 size_t increment (size_t pos) const
433 {
434 if (cap && pos != (size_t)-1)
435 pos = (pos + 1) % cap;
436 if (pos == back_idx)
437 pos = (size_t)-1;
438 return pos;
439 }
440
442 size_t decrement (size_t pos) const
443 {
444 if (cap)
445 {
446 if (pos == (size_t)-1)
447 pos = (back_idx + cap - 1) % cap;
448 else if (pos != front_idx)
449 pos = (pos + cap - 1) % cap;
450 }
451 return pos;
452 }
453
455 size_t add (size_t oldpos, size_t delta) const
456 {
457 if (cap && oldpos != -1)
458 {
459 size_t np = oldpos + (delta % cap);
460 if (np >= cap && np >= back_idx + cap)
461 np = (size_t)(-1);
462 else
463 np %= cap;
464 return np;
465 }
466 return oldpos;
467 }
468
470 size_t subtract (size_t oldpos, size_t delta) const
471 {
472 if (cap)
473 {
474 size_t np = (oldpos == (size_t)-1 ? back_idx : oldpos) - (delta % cap) + cap;
475 if (np < front_idx)
476 np = front_idx;
477 else
478 np %= cap;
479 return np;
480 }
481 return oldpos;
482 }
483
484 std::unique_ptr<T[]> buf;
485 size_t front_idx, back_idx, cap, sz;
486};
487
488} // namespace mlib
Iterator through the circular buffer.
Definition ringbuf.h:29
iterator_type< C_ > & operator+=(size_t inc)
Addition assignment operator.
Definition ringbuf.h:140
pointer operator->()
Object pointer.
Definition ringbuf.h:63
iterator_type< C_ > & operator--()
Decrement operator (prefix)
Definition ringbuf.h:102
iterator_type< C_ > operator+(size_t inc) const
Addition operator.
Definition ringbuf.h:132
iterator_type< C_ > & operator++()
Increment operator (prefix)
Definition ringbuf.h:87
iterator_type()
Default constructor.
Definition ringbuf.h:39
iterator_type< C_ > & operator=(const iterator_type< C_ > &rhs)
Assignment operator.
Definition ringbuf.h:121
reference operator*()
Dereference operator.
Definition ringbuf.h:47
iterator_type< C_ > operator-(size_t dec) const
Subtraction operator.
Definition ringbuf.h:147
bool operator!=(const iterator_type< C_ > &it) const
Inequality comparison.
Definition ringbuf.h:115
const pointer operator->() const
Object pointer (const version)
Definition ringbuf.h:71
iterator_type< C_ > & operator-=(size_t dec)
Subtraction assignment operator.
Definition ringbuf.h:155
bool operator==(const iterator_type< C_ > &it) const
Equality comparison.
Definition ringbuf.h:109
Circular buffer.
Definition ringbuf.h:24
void pop_front()
Remove oldest element from buffer.
Definition ringbuf.h:347
void clear(void)
Remove all elements from buffer.
Definition ringbuf.h:381
size_t size() const
Return number of elements in buffer.
Definition ringbuf.h:425
ring_buffer(const ring_buffer &other)
Copy constructor.
Definition ringbuf.h:209
T & front()
Return a reference to first (oldest) element in buffer.
Definition ringbuf.h:357
void push_back(const T &item)
Inserts new element in buffer.
Definition ringbuf.h:297
ring_buffer()
Default constructor.
Definition ringbuf.h:201
bool empty(void)
Return true if buffer is empty.
Definition ringbuf.h:388
const T & front() const
Return a reference to first (oldest) element in buffer.
Definition ringbuf.h:363
ring_buffer(std::initializer_list< T > il)
Initializer list constructor.
Definition ringbuf.h:227
bool full(void) const
Return true if buffer is full.
Definition ringbuf.h:394
bool operator==(const ring_buffer< T > &other) const
Equality operator.
Definition ringbuf.h:264
bool operator!=(const ring_buffer< T > &other) const
Inequality operator.
Definition ringbuf.h:281
const_iterator begin() const
Return a const iterator pointing to first (oldest) element in buffer.
Definition ringbuf.h:317
void resize(size_t new_cap)
(Re)allocate buffer with a different capacity
Definition ringbuf.h:406
size_t capacity(void) const
Return maximum buffer size.
Definition ringbuf.h:400
const T & back() const
Return reference to last (newest) element in buffer.
Definition ringbuf.h:375
const_iterator cbegin()
Return a const iterator pointing to first (oldest) element in buffer.
Definition ringbuf.h:323
ring_buffer & operator=(const ring_buffer &rhs)
Assignment operator.
Definition ringbuf.h:240
iterator end()
Return an iterator pointing past the last (newest) element in buffer.
Definition ringbuf.h:329
T & back()
Return reference to last (newest) element in buffer.
Definition ringbuf.h:369
const_iterator end() const
Return a const iterator pointing past the last (newest) element in buffer.
Definition ringbuf.h:335
ring_buffer(size_t size)
Constructor.
Definition ringbuf.h:192
const_iterator cend()
Return an iterator pointing past the last (newest) element in buffer.
Definition ringbuf.h:341
iterator begin()
Return an iterator pointing to first (oldest) element in buffer.
Definition ringbuf.h:311