circular_buffer.hpp
Go to the documentation of this file.
1 /*
2  * SocialLedge.com - Copyright (C) 2013
3  *
4  * This file is part of free software framework for embedded processors.
5  * You can use it and/or distribute it as long as this copyright header
6  * remains unmodified. The code is free for personal use and requires
7  * permission to use in a commercial product.
8  *
9  * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
10  * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
12  * I SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
13  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
14  *
15  * You can reach the author of this software at :
16  * p r e e t . w i k i @ g m a i l . c o m
17  */
18 
26 #ifndef CIRCULAR_BUFFER_HPP__
27 #define CIRCULAR_BUFFER_HPP__
28 
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <iterator>
32 
33 
34 
70 template <typename TYPE>
72 {
73 public:
74  CircularBuffer(uint32_t capacity);
75  CircularBuffer(const CircularBuffer& copy);
77  ~CircularBuffer();
78 
86  bool push_back(const TYPE data, bool forceWrite = false);
87 
88  TYPE pop_front(void);
89  bool pop_front(TYPE* dataPtr);
90  TYPE peek_front(void);
91  bool peek_front(TYPE* dataPtr);
92 
94  uint32_t size(void) const { return mCount; }
95 
97  uint32_t capacity(void) const { return mCapacity; }
98 
100  void clear(void) { mCount = mWriteIndex = mReadIndex = 0; }
101 
103  void operator+=(TYPE item) { push_back(item); }
104 
110  TYPE& operator [] (uint32_t index) const { return mpArray[ (index + mReadIndex) % mCapacity]; }
111 
112 
113  /****************************************************************/
114  /**** Iterators ****/
115  /****************************************************************/
116  typedef int size_type;
117 
118  class iterator
119  {
120  public:
122  typedef TYPE value_type;
123  typedef TYPE& reference;
124  typedef TYPE* pointer;
125  typedef std::forward_iterator_tag iterator_category;
126  typedef int difference_type;
127 
128  iterator(CircularBuffer<TYPE> *p) : mpCb(p), mIndex(0) { }
129 
131  self_type operator++() { self_type i = *this; mIndex++; return i; }
132 
134  self_type operator++(int unused) { mIndex++; self_type i = *this; return i; }
135 
137  reference operator*() { return mpCb->operator [] (mIndex); }
138 
140  pointer operator->() { return &( mpCb->operator [] (mIndex)); }
141 
143  bool operator!=(const self_type& rhs) { return (mpCb != rhs.mpCb) ? false : (mIndex < mpCb->size()); }
144 
146  bool operator==(const self_type& rhs) { return (mpCb != rhs.mpCb) ? false : (mIndex >= mpCb->size()); }
147 
148  private:
149  CircularBuffer<TYPE> *mpCb;
150  uint32_t mIndex;
151  };
152 
154  {
155  public:
157  typedef TYPE value_type;
158  typedef TYPE& reference;
159  typedef TYPE* pointer;
160  typedef std::forward_iterator_tag iterator_category;
161  typedef int difference_type;
162 
163  const_iterator(CircularBuffer<TYPE> *p) : mpCb(p), mIndex(0) { }
164 
166  self_type operator++() { self_type i = *this; mIndex++; return i; }
167 
169  self_type operator++(int unused) { mIndex++; self_type i = *this; return i; }
170 
172  reference operator*() { return mpCb->operator [] (mIndex); }
173 
175  pointer operator->() { return &( mpCb->operator [] (mIndex)); }
176 
178  bool operator!=(const self_type& rhs) { return (mpCb != rhs.mpCb) ? false : (mIndex < mpCb->size()); }
179 
181  bool operator==(const self_type& rhs) { return (mpCb != rhs.mpCb) ? false : (mIndex >= mpCb->size()); }
182 
183  private:
184  CircularBuffer<TYPE> *mpCb;
185  uint32_t mIndex;
186  };
187 
188 
189 
193  iterator begin() { return iterator(this); }
194  iterator end() { return iterator(this); }
196  const_iterator end() const { const_iterator(this); }
201 private:
203  CircularBuffer() : mCapacity(0), mWriteIndex(0), mReadIndex(0), mCount(0), mpArray(0) { }
204 
205  const uint32_t mCapacity;
206  uint32_t mWriteIndex;
207  uint32_t mReadIndex;
208  uint32_t mCount;
209  TYPE *mpArray;
210  friend class iterator;
211 
217  void init(void)
218  {
219  mWriteIndex = 0;
220  mReadIndex = 0;
221  mCount = 0;
222  mpArray = new TYPE[mCapacity];
223  }
224 };
225 
226 
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239 
240 
241 template <typename TYPE>
242 CircularBuffer<TYPE>::CircularBuffer(uint32_t cap) : mCapacity(cap)
243 {
244  init();
245 }
246 template <typename TYPE>
248 {
249  *this = copy; // Call = Operator below to copy vector contents
250 }
251 
252 template <typename TYPE>
254 {
255  if(this != &copy)
256  {
257  this->init(); // capacity is initialized by constructor
258 
259  // Now copy other contents into this object
260  for(unsigned int i = 0; i < copy.size(); i++)
261  {
262  this->push_back(copy[i]);
263  }
264  }
265  return *this;
266 }
267 template <typename TYPE>
269 {
270  delete [] mpArray;
271 }
272 
273 template <typename TYPE>
274 bool CircularBuffer<TYPE>::push_back(const TYPE data, bool forceWrite)
275 {
276  bool success = false;
277 
278  if (mCount < mCapacity || forceWrite)
279  {
284  if (++mCount > mCapacity) {
285  (void) pop_front();
286  }
287  success = true;
288 
289  mpArray[mWriteIndex] = data;
290  if (++mWriteIndex >= mCapacity) {
291  mWriteIndex = 0;
292  }
293  }
294 
295  return success;
296 }
297 
298 template <typename TYPE>
300 {
301  TYPE data = 0;
302 
303  if (mCount > 0) {
304  --mCount;
305  data = mpArray[mReadIndex];
306  if (++mReadIndex >= mCapacity) {
307  mReadIndex = 0;
308  }
309  }
310 
311  return data;
312 }
313 
314 template <typename TYPE>
316 {
317  bool success = (mCount > 0);
318  *dataPtr = pop_front();
319  return success;
320 }
321 
322 template <typename TYPE>
324 {
325  TYPE data = 0;
326  if (mCount > 0) {
327  data = mpArray[mReadIndex];
328  }
329  return data;
330 }
331 
332 template <typename TYPE>
334 {
335  bool success = (mCount > 0);
336  *dataPtr = peek_front();
337  return success;
338 }
339 
340 
341 
342 #ifdef TESTING
343 #include <assert.h>
344 static inline void test_CircularBuffer(void)
345 {
347 
348  assert(3 == b.capacity());
349  assert(0 == b.size());
350 
351  assert(b.push_back(1));
352  assert(b.push_back(2));
353  assert(b.push_back(3));
354  assert(3 == b.capacity());
355  assert(3 == b.size());
356  assert(1 == b[0]);
357  assert(2 == b[1]);
358  assert(3 == b[2]);
359  assert(!b.push_back(4));
360  assert(b.push_back(4, true));
361  assert(3 == b.capacity());
362  assert(3 == b.size());
363 
364  assert(2 == b[0]);
365  assert(3 == b[1]);
366  assert(4 == b[2]);
367  assert(2 == b.pop_front());
368  assert(3 == b.pop_front());
369  assert(4 == b.pop_front());
370 
371  int x;
372  assert(!b.pop_front(&x));
373 
374  b.clear();
375  b.push_back(1);
376  b.push_back(2);
377  b.push_back(3);
378 
386  do {
388  assert(*cb == 1); cb++;
389  assert(*cb == 2); cb++;
390  assert(*cb == 3); cb++;
391  } while(0);
392 
393  do {
395  assert(*(cb.operator->()) == 1); ++cb;
396  assert(*(cb.operator->()) == 2); ++cb;
397  assert(*(cb.operator->()) == 3); ++cb;
398  } while(0);
399 
400  b.clear();
401  b.push_back(1);
402  b.push_back(2);
403  b.push_back(3);
404 
405  // Copy constructor test
407  assert(1 == b2[0]);
408  assert(2 == b2[1]);
409  assert(3 == b2[2]);
410  b2.push_back(4, true); // Overwrite oldest data
411  assert(3 == b2.size());
412  assert(2 == b2.pop_front());
413  assert(3 == b2.pop_front());
414  assert(4 == b2.pop_front());
415 
416  // Write the elements without popping the data, access them using index operator
417  assert( b2.push_back(1));
418  assert( b2.push_back(2));
419  assert(1 == b2[0]);
420  assert(2 == b2[1]);
421 
423  assert(2 == b2.size());
424  assert(3 == b2.capacity());
425  assert(1 == *cb); cb++;
426  assert(2 == *cb); cb++;
427  assert(1 != *cb); cb++;
428 
429  assert( b2.push_back(3));
430  cb = b2.begin();
431  assert(1 == *cb); cb++;
432  assert(2 == *cb); cb++;
433  assert(3 == *cb); cb++;
434 
435  assert( !b2.push_back(4));
436  cb = b2.begin();
437  assert(1 == *cb); cb++;
438  assert(2 == *cb); cb++;
439  assert(3 == *cb); cb++;
440 
441  assert( b2.push_back(4, true));
442  cb = b2.begin();
443  assert(3 == b2.size());
444  assert(3 == b2.capacity());
445  assert(2 == *cb); cb++;
446  assert(3 == *cb); cb++;
447  assert(4 == *cb); cb++;
448 
449  do {
451  b.push_back(1);
452  b.push_back(2);
453  b.push_back(3);
454  b.push_back(4, true); // Overwrite oldest data
455  assert(3 == b.capacity());
456  assert(3 == b.size());
457 
458  // Write the elements without popping the data, access them using index operator
459  printf("\nContents using index operator: ");
460  // Should be "2 3 4"
461  for (uint32_t i = 0; i < b.size(); i++) {
462  printf("%i ", b[i]);
463  }
464 
465  // Use the iterator to read data without popping the data off the buffer
466  // Should be "2 3 4"
467  printf("\nContents using iterator: ");
468  for(CircularBuffer<int>::iterator cb = b.begin(); cb != b.end(); ++cb)
469  {
470  printf("%i ", *(cb));
471  }
472 
473  int i = 0;
474  while ((i = b.pop_front())) {
475  printf("\nPopped %i", i);
476  }
477  } while(0);
478 
479  puts("\nCircular Buffer Tests Successful!");
480 }
481 #endif /* #ifdef TESTING */
482 
483 
484 
485 #endif /* #ifndef CIRCULAR_BUFFER_HPP__ */
const_iterator self_type
Definition: circular_buffer.hpp:156
printf("Recorder started: %s\n", uiTraceStart()?"OK":"ERROR")
self_type operator++()
Preincrement operator ie: ++iterator.
Definition: circular_buffer.hpp:131
TYPE & reference
Definition: circular_buffer.hpp:123
int size_type
Definition: circular_buffer.hpp:116
self_type operator++(int unused)
Postincrement operator ie: iterator++.
Definition: circular_buffer.hpp:134
reference operator*()
Definition: circular_buffer.hpp:137
bool operator!=(const self_type &rhs)
!= operator between iterators
Definition: circular_buffer.hpp:178
bool operator==(const self_type &rhs)
== operator between iterators
Definition: circular_buffer.hpp:181
int difference_type
Definition: circular_buffer.hpp:126
TYPE value_type
Definition: circular_buffer.hpp:122
uint32_t capacity(void) const
Definition: circular_buffer.hpp:97
iterator end()
Definition: circular_buffer.hpp:194
bool push_back(const TYPE data, bool forceWrite=false)
Definition: circular_buffer.hpp:274
TYPE * pointer
Definition: circular_buffer.hpp:124
TYPE value_type
Definition: circular_buffer.hpp:157
Definition: circular_buffer.hpp:153
pointer operator->()
pointer operator to get the address ie: *(iterator.operator->())
Definition: circular_buffer.hpp:175
TYPE & reference
Definition: circular_buffer.hpp:158
~CircularBuffer()
Destructor of the buffer.
Definition: circular_buffer.hpp:268
self_type operator++(int unused)
Postincrement operator ie: iterator++.
Definition: circular_buffer.hpp:169
bool operator==(const self_type &rhs)
== operator between iterators
Definition: circular_buffer.hpp:146
Definition: circular_buffer.hpp:71
self_type operator++()
Preincrement operator ie: ++iterator.
Definition: circular_buffer.hpp:166
TYPE pop_front(void)
Definition: circular_buffer.hpp:299
iterator(CircularBuffer< TYPE > *p)
Definition: circular_buffer.hpp:128
bool operator!=(const self_type &rhs)
!= operator between iterators
Definition: circular_buffer.hpp:143
TYPE peek_front(void)
Definition: circular_buffer.hpp:323
uint32_t size(void) const
Definition: circular_buffer.hpp:94
iterator begin()
Definition: circular_buffer.hpp:193
const_iterator(CircularBuffer< TYPE > *p)
Definition: circular_buffer.hpp:163
TYPE & operator[](uint32_t index) const
Definition: circular_buffer.hpp:110
uint32_t b2
Definition: bit_manip.h:54
std::forward_iterator_tag iterator_category
Definition: circular_buffer.hpp:160
const_iterator begin() const
Definition: circular_buffer.hpp:195
reference operator*()
Definition: circular_buffer.hpp:172
void operator+=(TYPE item)
+= Operator which is same as push_back() of an item
Definition: circular_buffer.hpp:103
const_iterator end() const
Definition: circular_buffer.hpp:196
void clear(void)
Clears the contents of the buffer.
Definition: circular_buffer.hpp:100
std::forward_iterator_tag iterator_category
Definition: circular_buffer.hpp:125
int difference_type
Definition: circular_buffer.hpp:161
iterator self_type
Definition: circular_buffer.hpp:121
pointer operator->()
pointer operator to get the address ie: *(iterator.operator->())
Definition: circular_buffer.hpp:140
Definition: circular_buffer.hpp:118
TYPE * pointer
Definition: circular_buffer.hpp:159
CircularBuffer & operator=(const CircularBuffer &copy)
= Operator to copy the buffer
Definition: circular_buffer.hpp:253