RingBuffer.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #pragma once
  2. #include <atomic>
  3. #include <stdint.h>
  4. /*
  5. * Circular buffer of bytes.
  6. */
  7. class ByteBuffer {
  8. public:
  9. ByteBuffer(uint32_t size);
  10. ~ByteBuffer(void);
  11. // number of bytes available to be read
  12. uint32_t available(void) const;
  13. // Discards the buffer content, emptying it.
  14. void clear(void);
  15. // number of bytes space available to write
  16. uint32_t space(void) const;
  17. // true if available() is zero
  18. bool empty(void) const;
  19. // write bytes to ringbuffer. Returns number of bytes written
  20. uint32_t write(const uint8_t *data, uint32_t len);
  21. // read bytes from ringbuffer. Returns number of bytes read
  22. uint32_t read(uint8_t *data, uint32_t len);
  23. // read a byte from ring buffer. Returns true on success, false otherwise
  24. bool read_byte(uint8_t *data);
  25. /*
  26. update bytes at the read pointer. Used to update an object without
  27. popping it
  28. */
  29. bool update(const uint8_t *data, uint32_t len);
  30. // return size of ringbuffer
  31. uint32_t get_size(void) const { return size; }
  32. // set size of ringbuffer, caller responsible for locking
  33. bool set_size(uint32_t size);
  34. // advance the read pointer (discarding bytes)
  35. bool advance(uint32_t n);
  36. // Returns the pointer and size to a contiguous read of the next available data
  37. const uint8_t *readptr(uint32_t &available_bytes);
  38. // peek one byte without advancing read pointer. Return byte
  39. // or -1 if none available
  40. int16_t peek(uint32_t ofs) const;
  41. /*
  42. read len bytes without advancing the read pointer
  43. */
  44. uint32_t peekbytes(uint8_t *data, uint32_t len);
  45. // Similar to peekbytes(), but will fill out IoVec struct with
  46. // both parts of the ring buffer if wraparound is happening, or
  47. // just one part. Returns the number of parts written to.
  48. struct IoVec {
  49. uint8_t *data;
  50. uint32_t len;
  51. };
  52. uint8_t peekiovec(IoVec vec[2], uint32_t len);
  53. // Reserve `len` bytes and fills out `vec` with both parts of the
  54. // ring buffer (if wraparound is happening), or just one contiguous
  55. // part. Returns the number of `vec` elements filled out. Can be used
  56. // with system calls such as `readv()`.
  57. //
  58. // After a call to 'reserve()', 'write()' should never be called
  59. // until 'commit()' is called!
  60. uint8_t reserve(IoVec vec[2], uint32_t len);
  61. /*
  62. * "Releases" the memory previously reserved by 'reserve()' to be read.
  63. * Committer must inform how many bytes were actually written in 'len'.
  64. */
  65. bool commit(uint32_t len);
  66. private:
  67. uint8_t *buf;
  68. uint32_t size;
  69. std::atomic<uint32_t> head{0}; // where to read data
  70. std::atomic<uint32_t> tail{0}; // where to write data
  71. };
  72. /*
  73. ring buffer class for objects of fixed size
  74. */
  75. template <class T>
  76. class ObjectBuffer {
  77. public:
  78. ObjectBuffer(uint32_t _size) {
  79. // we set size to 1 more than requested as the byte buffer
  80. // gives one less byte than requested. We round up to a full
  81. // multiple of the object size so that we always get aligned
  82. // elements, which makes the readptr() method possible
  83. buffer = new ByteBuffer(((_size+1) * sizeof(T)));
  84. }
  85. ~ObjectBuffer(void) {
  86. delete buffer;
  87. }
  88. // Discards the buffer content, emptying it.
  89. void clear(void)
  90. {
  91. buffer->clear();
  92. }
  93. // return number of objects available to be read
  94. uint32_t available(void) const {
  95. return buffer->available() / sizeof(T);
  96. }
  97. // return number of objects that could be written
  98. uint32_t space(void) const {
  99. return buffer->space() / sizeof(T);
  100. }
  101. // true is available() == 0
  102. bool empty(void) const {
  103. return buffer->empty();
  104. }
  105. // push one object
  106. bool push(const T &object) {
  107. if (buffer->space() < sizeof(T)) {
  108. return false;
  109. }
  110. return buffer->write((uint8_t*)&object, sizeof(T)) == sizeof(T);
  111. }
  112. // push N objects
  113. bool push(const T *object, uint32_t n) {
  114. if (buffer->space() < n*sizeof(T)) {
  115. return false;
  116. }
  117. return buffer->write((uint8_t*)object, n*sizeof(T)) == n*sizeof(T);
  118. }
  119. /*
  120. throw away an object
  121. */
  122. bool pop(void) {
  123. return buffer->advance(sizeof(T));
  124. }
  125. /*
  126. pop earliest object off the queue
  127. */
  128. bool pop(T &object) {
  129. if (buffer->available() < sizeof(T)) {
  130. return false;
  131. }
  132. return buffer->read((uint8_t*)&object, sizeof(T)) == sizeof(T);
  133. }
  134. /*
  135. * push_force() is semantically equivalent to:
  136. * if (!push(t)) { pop(); push(t); }
  137. */
  138. bool push_force(const T &object) {
  139. if (buffer->space() < sizeof(T)) {
  140. buffer->advance(sizeof(T));
  141. }
  142. return push(object);
  143. }
  144. /*
  145. * push_force() N objects
  146. */
  147. bool push_force(const T *object, uint32_t n) {
  148. uint32_t _space = buffer->space();
  149. if (_space < sizeof(T)*n) {
  150. buffer->advance(sizeof(T)*(n-_space));
  151. }
  152. return push(object, n);
  153. }
  154. /*
  155. peek copies an object out without advancing the read pointer
  156. */
  157. bool peek(T &object) {
  158. return buffer->peekbytes((uint8_t*)&object, sizeof(T)) == sizeof(T);
  159. }
  160. /*
  161. return a pointer to first contiguous array of available
  162. objects. Return nullptr if none available
  163. */
  164. const T *readptr(uint32_t &n) {
  165. uint32_t avail_bytes = 0;
  166. const T *ret = (const T *)buffer->readptr(avail_bytes);
  167. if (!ret || avail_bytes < sizeof(T)) {
  168. return nullptr;
  169. }
  170. n = avail_bytes / sizeof(T);
  171. return ret;
  172. }
  173. // advance the read pointer (discarding objects)
  174. bool advance(uint32_t n) {
  175. return buffer->advance(n * sizeof(T));
  176. }
  177. /* update the object at the front of the queue (the one that would
  178. be fetched by pop()) */
  179. bool update(const T &object) {
  180. return buffer->update((uint8_t*)&object, sizeof(T));
  181. }
  182. private:
  183. ByteBuffer *buffer = nullptr;
  184. };
  185. /*
  186. ring buffer class for objects of fixed size with pointer
  187. access. Note that this is not thread safe, buf offers efficient
  188. array-like access
  189. */
  190. template <class T>
  191. class ObjectArray {
  192. public:
  193. ObjectArray(uint16_t size_) {
  194. _size = size_;
  195. _head = _count = 0;
  196. _buffer = new T[_size];
  197. }
  198. ~ObjectArray(void) {
  199. delete[] _buffer;
  200. }
  201. // return total number of objects
  202. uint16_t size(void) const {
  203. return _size;
  204. }
  205. // return number of objects available to be read
  206. uint16_t available(void) const {
  207. return _count;
  208. }
  209. // return number of objects that could be written
  210. uint16_t space(void) const {
  211. return _size - _count;
  212. }
  213. // true is available() == 0
  214. bool empty(void) const {
  215. return _count == 0;
  216. }
  217. // push one object
  218. bool push(const T &object) {
  219. if (space() == 0) {
  220. return false;
  221. }
  222. _buffer[(_head+_count)%_size] = object;
  223. _count++;
  224. return true;
  225. }
  226. /*
  227. throw away an object
  228. */
  229. bool pop(void) {
  230. if (empty()) {
  231. return false;
  232. }
  233. _head = (_head+1) % _size;
  234. _count--;
  235. return true;
  236. }
  237. // Discards the buffer content, emptying it.
  238. void clear(void)
  239. {
  240. _head = _count = 0;
  241. }
  242. /*
  243. pop earliest object off the queue
  244. */
  245. bool pop(T &object) {
  246. if (empty()) {
  247. return false;
  248. }
  249. object = _buffer[_head];
  250. return pop();
  251. }
  252. /*
  253. * push_force() is semantically equivalent to:
  254. * if (!push(t)) { pop(); push(t); }
  255. */
  256. bool push_force(const T &object) {
  257. if (space() == 0) {
  258. pop();
  259. }
  260. return push(object);
  261. }
  262. /*
  263. remove the Nth element from the array. First element is zero
  264. */
  265. bool remove(uint16_t n) {
  266. if (n >= _count) {
  267. return false;
  268. }
  269. if (n == _count-1) {
  270. // remove last element
  271. _count--;
  272. return true;
  273. }
  274. if (n == 0) {
  275. // remove first element
  276. return pop();
  277. }
  278. // take advantage of the [] operator for simple shift of the array elements
  279. for (uint16_t i=n; i<_count-1; i++) {
  280. *(*this)[i] = *(*this)[i+1];
  281. }
  282. _count--;
  283. return true;
  284. }
  285. // allow array indexing, based on current head. Returns a pointer
  286. // to the object or nullptr
  287. T * operator[](uint16_t i) {
  288. if (i >= _count) {
  289. return nullptr;
  290. }
  291. return &_buffer[(_head+i)%_size];
  292. }
  293. private:
  294. T *_buffer;
  295. uint16_t _size; // total buffer size
  296. uint16_t _count; // number in buffer now
  297. uint16_t _head; // first element
  298. };