ringbuffer.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #ifndef RINGBUFFER__HPP
  2. #define RINGBUFFER__HPP
  3. #include <stdlib.h>
  4. #include <iostream>
  5. #include <string.h>
  6. using namespace std;
  7. /** @brief A ring buffer template class
  8. *
  9. * using the "Always Keep One Byte Open" principle \n
  10. * http://en.wikipedia.org/wiki/Circular_buffer \n
  11. * but here it is not bytes but slots for storing type T \n
  12. * buffer has size+1, empty buffer: first==last, full buffer: first == last+2 \n
  13. * @author Frank Michler
  14. * @date 28.10.2009
  15. */
  16. template <class T> class RingBuffer
  17. {
  18. public:
  19. /**
  20. @brief nested iterator template class for access to ring buffer
  21. */
  22. class iterator
  23. {
  24. private:
  25. T* mElmPtr; //!< pointer to ring buffer element
  26. RingBuffer* mContainerPtr; //!< pointer to the container (ring buffer)
  27. public:
  28. //! @brief default constructor
  29. iterator():mElmPtr(0), mContainerPtr(0){};
  30. /** @brief copy constructor, taking const reference as parameter
  31. initializes element pointer and container pointer with values of given iterator
  32. */
  33. iterator(const iterator& it) {
  34. mElmPtr = it.mElmPtr;
  35. mContainerPtr = it.mContainerPtr;
  36. }
  37. /** @brief constructor with explicite values as parameters */
  38. iterator(T* ElmPtr, RingBuffer* ContainerPtr): mElmPtr(ElmPtr), mContainerPtr(ContainerPtr){};
  39. /** @brief prefix ++ operator */
  40. iterator& operator++()
  41. {
  42. mContainerPtr->IncRngPtr(mElmPtr);
  43. return *this;
  44. };
  45. //! @brief postfix ++ operator
  46. iterator operator++(int)
  47. {
  48. iterator prev(*this);
  49. mContainerPtr->IncRngPtr(mElmPtr);
  50. return prev;
  51. };
  52. /** @brief Increment operator. Calls the prefix ++ operator delta times.
  53. @param delta number of desired increments
  54. */
  55. iterator operator+(unsigned int delta) const
  56. {
  57. iterator it(*this);
  58. for (int i=0;i<delta;++i) {
  59. ++it;
  60. }
  61. return it;
  62. }
  63. /** @brief Dereferencing operator. Returns a reference to a stored element.
  64. */
  65. T& operator*() {return *mElmPtr;};
  66. /** @brief IsEqual operator.
  67. @return True if iterator points to same element in the same container. False otherwises
  68. */
  69. bool operator==(const iterator& lvalue) const
  70. {
  71. return (bool)((mContainerPtr==lvalue.mContainerPtr) && (mElmPtr==lvalue.mElmPtr));
  72. };
  73. /** @brief IsNotEqual operator.
  74. @return True if element pointer or container pointer are different. False otherwise.
  75. */
  76. bool operator!=(const iterator& lvalue) const
  77. {
  78. return (bool)((mContainerPtr!=lvalue.mContainerPtr) || (mElmPtr!=lvalue.mElmPtr));
  79. };
  80. };
  81. RingBuffer(const size_t& BufferSize); //!< constructor specifying the size of the ring buffer
  82. RingBuffer(const RingBuffer& _rngbuff); //!< copy constructor
  83. ~RingBuffer(); //!< destructor
  84. void write(const T& value); //!< write a value to the end of the buffer
  85. bool push_back(const T& value);
  86. iterator begin() {return iterator(mBegin, this);};
  87. iterator end() {return iterator(mEnd, this);};
  88. //! @brief get last entry in buffer
  89. //! @return last element
  90. T& last() {T* h=mEnd; DecRngPtr(h); return *h;};
  91. //! @brief get pointer to last entry in buffer
  92. //! @return last element
  93. T* plast() {T* h=mEnd; DecRngPtr(h); return h;};
  94. //! @brief get first entry in buffer
  95. //! @return first element
  96. T& first() {return *mBegin;};
  97. //! @brief get pointer to first entry in buffer
  98. //! @return first element
  99. T* pfirst() {return mBegin;};
  100. //! @brief check if buffer is empty
  101. //! @return true if empty, false otherwise
  102. bool isEmpty() {return mBegin==mEnd;};
  103. //! @brief check if buffer is full
  104. //! @return true if buffer is full, false otherwise
  105. //bool isFull() {T* h=mEnd; IncRngPtr(h);return h==mBegin;};
  106. bool isFull() {return mIsFull;};
  107. void clear() {mEnd=mBegin; mIsFull=false;};
  108. //! @brief print content of ring buffer from first to last element to stdout
  109. void print();
  110. //! @brief dump the raw content of the buffer
  111. //! the buffer is one element larger than size of the ring buffer
  112. //! to distinguish full and empty buffer
  113. void dump();
  114. private:
  115. size_t mSize; //!< Größe des Ringpuffers
  116. size_t mBuffSize; //!< Tatsächliche Größe des internen Puffers. mBuffSize == mSize+1
  117. T* mBuffEnd; //!< zeigt hinter den Puffer
  118. T* mBuffer;
  119. /** mEnd zeigt hinter den letzten Eintrag.
  120. D.h. die pos, wo der nächste Eintrag geschrieben wird. */
  121. T* mEnd;
  122. T* mBegin; //!< erster Eintrag
  123. /** @brief Increase buffer pointer.
  124. If end of the buffer is reached, pointer is set to the beginning. (wraped around)
  125. @param ptr reference to the pointer to be increased.
  126. */
  127. void IncRngPtr(T* & ptr) {if (++ptr==mBuffEnd) {ptr=mBuffer;}};
  128. /** @brief Decrease buffer pointer.
  129. If beginning of buffer is reached, pointer is set to the last element.
  130. Note that mBuffEnd points behind the last buffer element.
  131. @param ptr Reference to pointer to be decreased.
  132. */
  133. void DecRngPtr(T* & ptr) {if (--ptr<mBuffer) {ptr=mBuffEnd-1;}};
  134. /**
  135. @brief Check if ring buffer is full.
  136. Note that mEnd points behind the last element.
  137. In case of a full ring buffer there is only one free element between last and first.
  138. @return True if buffer is full. False otherwise.
  139. */
  140. bool CheckIsFull() {T* h=mEnd; IncRngPtr(h);return h==mBegin;};
  141. /**
  142. @brief Update the internal status variable mIsFull by checking if buffer is actually full.
  143. To increase performance, the status of being full is stored in a bool variable.
  144. Not yet used.
  145. */
  146. void SetIsFull() {T* h=mEnd; IncRngPtr(h); mIsFull=(h==mBegin);};
  147. bool mIsFull;
  148. };
  149. /** @brief Constructor.
  150. @param RngBufferSize is the maximum number of elements that can be stored in the ring buffer.
  151. */
  152. template <class T>
  153. RingBuffer<T>::RingBuffer(const size_t& RngBufferSize)
  154. {
  155. mSize=RngBufferSize;
  156. mBuffSize=mSize+1;
  157. mBuffer = new T [mBuffSize];
  158. mBegin=mEnd=mBuffer;
  159. mBuffEnd = mBuffer+mBuffSize;
  160. mIsFull=false;
  161. }
  162. /** copy constructor
  163. *
  164. * @param in
  165. */
  166. template <class T>
  167. RingBuffer<T>::RingBuffer(const RingBuffer& in)
  168. {
  169. // cout << "copy constructor\n";
  170. mSize=in.mSize;
  171. mBuffSize=in.mBuffSize;
  172. // cout << "mBuffSize=" << mBuffSize << "\n";
  173. mBuffer = new T [mBuffSize];
  174. memcpy(mBuffer, in.mBuffer, mBuffSize*sizeof(T));
  175. mBegin=mBuffer+(in.mBegin-in.mBuffer);
  176. mEnd=mBuffer+(in.mEnd-in.mBuffer);
  177. mBuffEnd=mBuffer+(in.mBuffEnd-in.mBuffer);
  178. mIsFull=in.mIsFull;
  179. }
  180. template <class T>
  181. RingBuffer<T>::~RingBuffer()
  182. {
  183. if (mBuffer) {
  184. delete[] mBuffer;
  185. }
  186. }
  187. /** @brief Writes new value to the end of the buffer and returns true if buffer is full.
  188. If buffer is already full when push_back is called, first value is deleted.
  189. Actually this function does the same as write().
  190. */
  191. template <class T>
  192. bool RingBuffer<T>::push_back(const T& value)
  193. {
  194. *mEnd=value;
  195. IncRngPtr(mEnd);
  196. if (mIsFull) {
  197. IncRngPtr(mBegin);
  198. } else {
  199. mIsFull=CheckIsFull();
  200. }
  201. return mIsFull;
  202. }
  203. /** @brief Writes new value to the end of the buffer. If buffer is full, first value is deleted.
  204. The internal status variable mIsFull is updated on every write call.
  205. */
  206. template <class T>
  207. void RingBuffer<T>::write(const T& value)
  208. {
  209. *mEnd=value;
  210. IncRngPtr(mEnd);
  211. if (mIsFull) {
  212. IncRngPtr(mBegin);
  213. } else {
  214. mIsFull=CheckIsFull();
  215. }
  216. /* // weg-optimiert durch mIsFull
  217. if (mEnd==mBegin) {
  218. IncRngPtr(mBegin);
  219. }
  220. */
  221. }
  222. template <class T>
  223. void RingBuffer<T>::print()
  224. {
  225. cout << "RingBuffer content: ";
  226. T* h=mBegin;
  227. while(h!=mEnd) {
  228. std::cout << *h << " ";
  229. IncRngPtr(h);
  230. }
  231. cout << "\n";
  232. }
  233. template <class T>
  234. void RingBuffer<T>::dump()
  235. {
  236. T* h=mBuffer;
  237. while(h!=mBuffEnd) {
  238. std::cout << *h << " ";
  239. ++h;
  240. }
  241. cout << "\n";
  242. }
  243. #endif // #ifndef RINGBUFFER__HPP