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