PIDUINO
Loading...
Searching...
No Matches
ringbuffer.h
1/* Copyright © 2002-2012 Pete Goodliffe, All rights reserved.
2 *
3 * Copyright © 2018-2025 Pascal JEAN, All rights reserved.
4 * This file is part of the Piduino Library.
5 *
6 * The Piduino Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * The Piduino Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * This circular buffer is based on the STL-style circular buffer by
17 * Pete Goodliffe (circular.h). That code was subject of the following articles
18 * - Pete Goodliffe. STL-style circular buffers by example.
19 * Overload, 10(50), August 2002.
20 * http://accu.org/index.php/journals/389
21 * - Pete Goodliffe. STL-style circular buffers by example, part two.
22 * Overload, 10(51), October 2002.
23 * http://accu.org/index.php/journals/383
24 * - Project page C++ circular buffer library,
25 * http://www.goodliffe.net/circularbuffers
26 *
27 * In 2008, Pete wrote a series of 11 Blog articles on similar, but not
28 * completely identical circular buffer code:
29 * - Pete Goodliffe. An STL-like circular buffer (Part {n}),
30 * http://goodliffe.blogspot.com/2008/11/c-stl-like-circular-buffer-part-{n}.html
31 * where {n} is 1..11.
32 *
33 * The code in this file compiles with VC6, VC8, VC2010, GNUC 4.5.2.
34 * If compiling with VC6 is not a requirement, you may also be able to use
35 * boost::RingBuffer<>, see
36 * http://www.boost.org/doc/libs/1_48_0/libs/RingBuffer/
37 *
38 * Notable changes with respect to he original implementation are:
39 * - There's no policy to select between accept and reject on buffer full
40 * - Added non-member begin(cb) and end(cb).
41 * - The iterator class is defined inside the RingBuffer class
42 * (this may help to make the code more acceptable to VC6).
43 * - The iterator class is derived from std::iterator<> to supply the
44 * iterator traits.
45 * - The copy-swap idiom used for operator= uses a value parameter.
46 *
47 * Note 1: use template parameters names with a maximum length of two
48 * to prevent clashes with names defined via #define.
49 * Mathew Wilson. Imperfect C++ p.xxxxxx.
50 *
51 * 12 September 2012 - fixed computation of offset in reserve().
52 * 17 December 2011 - created.
53 */
54#pragma once
55
56#include <piduino/memory.h>
57#include <iterator>
58#include <stdexcept>
59
60namespace Piduino {
61
66 template <typename T, typename A = std::allocator<T>>
67 class RingBuffer {
68
69 public:
71 typedef A allocator_type;
72 typedef typename allocator_type::value_type value_type;
73 typedef typename allocator_type::pointer pointer;
74 typedef typename allocator_type::const_pointer const_pointer;
75 typedef typename allocator_type::reference reference;
76 typedef typename allocator_type::const_reference const_reference;
77 typedef typename allocator_type::size_type size_type;
78 typedef typename allocator_type::difference_type difference_type;
79
80 // Lifetime
81 // -----------------------------------------------------------------------
82
88 explicit RingBuffer (size_type const capacity = 1,
89 allocator_type const & allocator = allocator_type())
91 , m_allocator (allocator)
92 , m_array (m_allocator.allocate (capacity, (void *) 0))
93 , m_head (1)
94 , m_tail (0)
95 , m_contents_size (0) {}
96
104 RingBuffer (self_type const & other)
105 : m_capacity (other.m_capacity)
106 , m_allocator (other.m_allocator)
107 // VC6 requires (void *) 0:
108 , m_array (m_allocator.allocate (other.m_capacity, (void *) 0))
109 , m_head (other.m_head)
110 , m_tail (other.m_tail)
112
113 try {
114 assign_into (other.begin(), other.end());
115 }
116 catch (...) {
117 clear();
118 m_allocator.deallocate (m_array, m_capacity);
119 throw;
120 }
121 }
122
128 template <typename II>
129 RingBuffer (II const from, II const to)
130 : m_capacity (0)
132 , m_array (0)
133 , m_head (0)
134 , m_tail (0)
135 , m_contents_size (0) {
136
137 RingBuffer tmp (std::distance (from, to));
138 tmp.assign_into (from, to);
139 swap (tmp);
140 }
141
146 clear();
147 m_allocator.deallocate (m_array, m_capacity);
148 }
149
155 other.swap (*this);
156 return *this;
157 }
158
163 void swap (self_type & other) {
164 using std::swap;
165
166 swap (m_capacity, other.m_capacity);
167
168 // no need to swap the allocator object
169 // as RingBuffer types are identical:
170 // swap( m_allocator, other.m_allocator );
171
172 swap (m_array, other.m_array);
173 swap (m_head, other.m_head);
174 swap (m_tail, other.m_tail);
176 }
177
183
184 return m_allocator;
185 }
186
191 template<typename E, typename EN>
192 class iterator_ : public std::iterator<std::random_access_iterator_tag, EN> {
193
194 public:
195 typedef E elem_type;
196
197 // non-const element type
198 typedef EN elem_type_nc;
199
201
202 // VC6 requires <T,A>:
204
205 /*
206 * iterator lifetime:
207 */
208
209 iterator_ (RingBufferType * const buf, size_type const pos)
210 : m_buf (buf)
211 , m_pos (pos) {
212 }
213
214 iterator_ (RingBufferType const * const buf, size_type const pos)
215 : m_buf (const_cast<RingBufferType *> (buf))
216 , m_pos (pos) {
217 }
218
219 // Use compiler generated copy ctor and dtor
220
221 // convert from iterator to const_iterator:
222
223 friend class iterator_<const elem_type, elem_type_nc> ;
224
226 : m_buf (other.m_buf)
227 , m_pos (other.m_pos) {
228 }
229
230 self_type & operator= (self_type const & other) {
231 m_buf = other.m_buf;
232 m_pos = other.m_pos;
233 return *this;
234 }
235
236 /*
237 * iterator accessors:
238 */
239
241 return (*m_buf) [m_pos];
242 }
243
245 return & (operator*());
246 }
247
248 /*
249 * iterator modifiers:
250 */
251
253 m_pos += 1;
254 return *this;
255 }
256
258 self_type tmp (*this);
259 ++ (*this);
260 return tmp;
261 }
262
264 m_pos -= 1;
265 return *this;
266 }
267
269 self_type tmp (*this);
270 -- (*this);
271 return tmp;
272 }
273
275 self_type tmp (*this);
276 tmp.m_pos += n;
277 return tmp;
278 }
279
281 m_pos += n;
282 return *this;
283 }
284
286 self_type tmp (*this);
287 tmp.m_pos -= n;
288 return tmp;
289 }
290
292 m_pos -= n;
293 return *this;
294 }
295
297 return m_pos - c.m_pos;
298 }
299
300 bool operator== (self_type const & other) const {
301 return m_pos == other.m_pos && m_buf == other.m_buf;
302 }
303
304 bool operator!= (self_type const & other) const {
305 return m_pos != other.m_pos && m_buf == other.m_buf;
306 }
307
308 bool operator> (self_type const & other) const {
309 return m_pos > other.m_pos;
310 }
311
312 bool operator>= (self_type const & other) const {
313 return m_pos >= other.m_pos;
314 }
315
316 bool operator< (self_type const & other) const {
317 return m_pos < other.m_pos;
318 }
319
320 bool operator<= (self_type const & other) const {
321 return m_pos <= other.m_pos;
322 }
323
324 /*
325 * iterator free standing operator + and -, defined here as
326 * friends for brevity and to prevent probable difficulties with VC6:
327 */
328
330 typename self_type::difference_type const & lhs,
331 self_type const & rhs) {
332 return self_type (lhs) + rhs;
333 }
334
336 typename self_type::difference_type const & lhs,
337 self_type const & rhs) {
338 return self_type (lhs) - rhs;
339 }
340
341 private:
344 };
345
346 // Iterators
347 // -----------------------------------------------------------------------
348
351
352 typedef std::reverse_iterator<iterator> reverse_iterator;
353 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
354
360
361 return iterator (this, 0);
362 }
363
369
370 return iterator (this, size());
371 }
372
378
379 return const_iterator (this, 0);
380 }
381
387
388 return const_iterator (this, size());
389 }
390
396
397 return reverse_iterator (end());
398 }
399
405
406 return reverse_iterator (begin());
407 }
408
414
415 return const_reverse_iterator (end());
416 }
417
423
424 return const_reverse_iterator (begin());
425 }
426
427 // Size accessors
428 // -----------------------------------------------------------------------
429
434 bool empty() const {
435
436 return 0 == m_contents_size;
437 }
438
444
445 return m_capacity;
446 }
447
452 size_type size() const {
453
454 return m_contents_size;
455 }
456
462
463 return m_allocator.max_size();
464 }
465
466 // Size modifiers
467 // -----------------------------------------------------------------------
468
475 void reserve (size_type const new_size) {
476 if (new_size != capacity()) {
477 RingBuffer tmp (new_size);
478
479 // preferred:
480 // const size_type offset = std::max( 0, size() - new_size );
481 // however, VC6 may have defined max() as macro.
482 const size_type offset =
483 new_size < size() ? size() - new_size : 0;
484
485 tmp.assign_into (begin() + offset, end());
486 swap (tmp);
487 }
488 }
489
490 // Content accessors
491 // -----------------------------------------------------------------------
492
498
499 return m_array[m_head];
500 }
501
507
508 return m_array[m_tail];
509 }
510
516
517 return m_array[m_head];
518 }
519
525
526 return m_array[m_tail];
527 }
528
535
536 return at_unchecked (n);
537 }
538
544 const_reference at (size_type const n) const {
545
546 return at_checked (n);
547 }
548
549 // Content modifiers
550 // -----------------------------------------------------------------------
551
555 void clear() {
556
557 for (size_type n = 0; n < m_contents_size; ++n) {
558 m_allocator.destroy (m_array + index_to_subscript (n));
559 }
560
561 m_head = 1;
563 }
564
565
569 void push_back (value_type const & item) {
570
571 size_type next = next_tail();
572
574 m_array[next] = item;
576 }
577 else {
578 m_allocator.construct (m_array + next, item);
579 }
581 }
582
586 void push_front (value_type const & item) {
587
588 size_type previous = previous_head();
589
591 m_array[previous] = item; // buffer full, replace last element
592 }
593 else {
594 m_allocator.construct (m_array + previous, item);
595 }
597 }
598
599
603 void pop_front() {
604
605 if (m_contents_size) {
606
607 size_type destroy_pos = m_head;
609 m_allocator.destroy (m_array + destroy_pos);
610 }
611 }
612
616 void pop_back() {
617
618 if (m_contents_size) {
619
620 size_type destroy_pos = previous_tail();
622 m_allocator.destroy (m_array + destroy_pos);
623 }
624 }
625
630 void skip (size_type len) {
631
632 if (len >= m_contents_size) {
633 clear();
634 }
635 else {
636
637 while (len--) {
638 pop_front();
639 }
640 }
641 }
642
647 void chop (size_type len) {
648
649 if (len >= m_contents_size) {
650 clear();
651 }
652 else {
653
654 while (len--) {
655 pop_back();
656 }
657 }
658 }
659
666
667 return at_unchecked (n);
668 }
669
676
677 return at_checked (n);
678 }
679
685
686 return m_array;
687 }
688
689 private:
690 reference at_unchecked (size_type const index) const {
691 return m_array[index_to_subscript (index)];
692 }
693
694 reference at_checked (size_type const index) const {
695 if (index >= m_contents_size) {
696 throw std::out_of_range ("RingBuffer::at()");
697 }
698 return at_unchecked (index);
699 }
700
701 // Round an unbounded to an index into m_array
702 size_type normalise (size_type const n) const {
703 return n % m_capacity;
704 }
705
706 // Convert external index to an array subscript
708 return normalise (index + m_head);
709 }
710
713 m_tail = next_tail();
714 }
715
719 }
720
722 return (m_tail + 1 == m_capacity) ? 0 : m_tail + 1;
723 }
724
726 return (m_tail == 0) ? m_capacity - 1 : m_tail - 1;
727 }
728
730 return (m_head == 0) ? m_capacity - 1 : m_head - 1;
731 }
732
734 // precondition: !empty()
735 ++m_head;
737
738 if (m_head == m_capacity) {
739 m_head = 0;
740 }
741 }
742
744 if (m_head == 0) {
746 }
747
748 --m_head;
750 }
751
752 template <typename I>
753 void assign_into (I from, I const to) {
754 if (m_contents_size > 0) {
755 clear();
756 }
757
758 while (from != to) {
759 push_back (*from);
760 ++from;
761 }
762 }
763
764 private:
771 };
772
773 // Comparison operators
774 // ---------------------------------------------------------------------------
781 template <typename T, typename A>
783 RingBuffer<T, A> const & rhs) {
784 return lhs.size() == rhs.size()
785 && std::equal (lhs.begin(), lhs.end(), rhs.begin());
786 }
787
794 template <typename T, typename A>
796 RingBuffer<T, A> const & rhs) {
797 return ! (lhs == rhs);
798 }
799
806 template <typename T, typename A>
807 bool operator< (RingBuffer<T, A> const & lhs,
808 RingBuffer<T, A> const & rhs) {
809 return std::lexicographical_compare (
810 lhs.begin(), lhs.end(),
811 rhs.begin(), rhs.end());
812 }
813
819 template <typename T, typename A>
822 return cb.begin();
823 }
824
830 template <typename T, typename A>
833 return cb.end();
834 }
835
841 template <typename T, typename A>
844 return cb.begin();
845 }
846
852 template <typename T, typename A>
855 return cb.end();
856 }
857
858}
859/* ========================================================================== */
RingBuffer iterator class template.
Definition ringbuffer.h:192
self_type & operator+=(difference_type const n)
Definition ringbuffer.h:280
iterator_(RingBufferType *const buf, size_type const pos)
Definition ringbuffer.h:209
bool operator<(self_type const &other) const
Definition ringbuffer.h:316
self_type & operator=(self_type const &other)
Definition ringbuffer.h:230
friend self_type operator+(typename self_type::difference_type const &lhs, self_type const &rhs)
Definition ringbuffer.h:329
bool operator<=(self_type const &other) const
Definition ringbuffer.h:320
friend self_type operator-(typename self_type::difference_type const &lhs, self_type const &rhs)
Definition ringbuffer.h:335
bool operator>=(self_type const &other) const
Definition ringbuffer.h:312
bool operator!=(self_type const &other) const
Definition ringbuffer.h:304
iterator_< elem_type, elem_type_nc > self_type
Definition ringbuffer.h:200
iterator_(RingBufferType const *const buf, size_type const pos)
Definition ringbuffer.h:214
bool operator==(self_type const &other) const
Definition ringbuffer.h:300
iterator_(iterator_< elem_type_nc, elem_type_nc > const &other)
Definition ringbuffer.h:225
self_type & operator-=(difference_type const n)
Definition ringbuffer.h:291
RingBuffer< T, A > RingBufferType
Definition ringbuffer.h:203
bool operator>(self_type const &other) const
Definition ringbuffer.h:308
STL-style circular buffer.
Definition ringbuffer.h:67
size_type size() const
Definition ringbuffer.h:452
void swap(self_type &other)
Definition ringbuffer.h:163
size_type previous_tail()
Definition ringbuffer.h:725
size_type next_tail()
Definition ringbuffer.h:721
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition ringbuffer.h:353
reference at_unchecked(size_type const index) const
Definition ringbuffer.h:690
const_reference at(size_type const n) const
Definition ringbuffer.h:544
iterator_< value_type, value_type > iterator
Definition ringbuffer.h:349
size_type capacity() const
Definition ringbuffer.h:443
~RingBuffer()
Destructor.
Definition ringbuffer.h:145
allocator_type::const_pointer const_pointer
Definition ringbuffer.h:74
void skip(size_type len)
Definition ringbuffer.h:630
void push_back(value_type const &item)
Appends the given item to the end of the container.
Definition ringbuffer.h:569
const_reference operator[](size_type const n) const
Definition ringbuffer.h:534
reference back()
access the last element
Definition ringbuffer.h:506
void push_front(value_type const &item)
Insert a new element at the beginning of the container.
Definition ringbuffer.h:586
const_reference back() const
access the last element
Definition ringbuffer.h:524
reference front()
access the first element
Definition ringbuffer.h:497
std::reverse_iterator< iterator > reverse_iterator
Definition ringbuffer.h:352
allocator_type::difference_type difference_type
Definition ringbuffer.h:78
allocator_type::value_type value_type
Definition ringbuffer.h:72
reverse_iterator rend()
Definition ringbuffer.h:404
reference at(size_type const n)
Definition ringbuffer.h:675
RingBuffer(self_type const &other)
Copy constructor.
Definition ringbuffer.h:104
allocator_type::reference reference
Definition ringbuffer.h:75
allocator_type::size_type size_type
Definition ringbuffer.h:77
RingBuffer< T, A > self_type
Definition ringbuffer.h:70
void assign_into(I from, I const to)
Definition ringbuffer.h:753
void pop_back()
Remove the last element from the container.
Definition ringbuffer.h:616
const_iterator begin() const
Definition ringbuffer.h:377
void pop_front()
Removes the first element of the container.
Definition ringbuffer.h:603
size_type max_size() const
Definition ringbuffer.h:461
reference at_checked(size_type const index) const
Definition ringbuffer.h:694
void chop(size_type len)
Definition ringbuffer.h:647
allocator_type get_allocator() const
Definition ringbuffer.h:182
size_type m_contents_size
Definition ringbuffer.h:770
size_type index_to_subscript(size_type const index) const
Definition ringbuffer.h:707
const_reverse_iterator rend() const
Definition ringbuffer.h:422
allocator_type::pointer pointer
Definition ringbuffer.h:73
const_reference front() const
access the first element
Definition ringbuffer.h:515
iterator_< const value_type, value_type > const_iterator
Definition ringbuffer.h:350
void reserve(size_type const new_size)
reserve shrinks or expands the internal buffer to the size given
Definition ringbuffer.h:475
reverse_iterator rbegin()
Definition ringbuffer.h:395
const_reverse_iterator rbegin() const
Definition ringbuffer.h:413
RingBuffer(II const from, II const to)
??
Definition ringbuffer.h:129
allocator_type m_allocator
Definition ringbuffer.h:766
RingBuffer & operator=(self_type other)
copy-swap idiom using value parameter
Definition ringbuffer.h:154
size_type previous_head()
Definition ringbuffer.h:729
const_iterator end() const
Definition ringbuffer.h:386
size_type normalise(size_type const n) const
Definition ringbuffer.h:702
RingBuffer(size_type const capacity=1, allocator_type const &allocator=allocator_type())
Default constructor.
Definition ringbuffer.h:88
allocator_type::const_reference const_reference
Definition ringbuffer.h:76
bool empty() const
Definition ringbuffer.h:434
Global namespace for Piduino.
Definition board.h:28
RingBuffer< T, A >::iterator end(RingBuffer< T, A > &cb)
Definition ringbuffer.h:832
bool operator<(RingBuffer< T, A > const &lhs, RingBuffer< T, A > const &rhs)
Definition ringbuffer.h:807
bool operator==(RingBuffer< T, A > const &lhs, RingBuffer< T, A > const &rhs)
Definition ringbuffer.h:782
bool operator!=(RingBuffer< T, A > const &lhs, RingBuffer< T, A > const &rhs)
Definition ringbuffer.h:795
RingBuffer< T, A >::iterator begin(RingBuffer< T, A > &cb)
Definition ringbuffer.h:821