APM:Libraries
RingBuffer.cpp
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <string.h>
3 
4 #include "RingBuffer.h"
5 
6 ByteBuffer::ByteBuffer(uint32_t _size)
7 {
8  buf = (uint8_t*)calloc(1, _size);
9  size = buf ? _size : 0;
10 }
11 
13 {
14  free(buf);
15 }
16 
17 /*
18  * Caller is responsible for locking in set_size()
19  */
20 bool ByteBuffer::set_size(uint32_t _size)
21 {
22  head = tail = 0;
23  if (_size != size) {
24  free(buf);
25  buf = (uint8_t*)calloc(1, _size);
26  if (!buf) {
27  size = 0;
28  return false;
29  }
30 
31  size = _size;
32  }
33 
34  return true;
35 }
36 
37 uint32_t ByteBuffer::available(void) const
38 {
39  /* use a copy on stack to avoid race conditions of @tail being updated by
40  * the writer thread */
41  uint32_t _tail = tail;
42 
43  if (head > _tail) {
44  return size - head + _tail;
45  }
46  return _tail - head;
47 }
48 
50 {
51  head = tail = 0;
52 }
53 
54 uint32_t ByteBuffer::space(void) const
55 {
56  if (size == 0) {
57  return 0;
58  }
59 
60  /* use a copy on stack to avoid race conditions of @head being updated by
61  * the reader thread */
62  uint32_t _head = head;
63  uint32_t ret = 0;
64 
65  if (_head <= tail) {
66  ret = size;
67  }
68 
69  ret += _head - tail - 1;
70 
71  return ret;
72 }
73 
74 bool ByteBuffer::empty(void) const
75 {
76  return head == tail;
77 }
78 
79 uint32_t ByteBuffer::write(const uint8_t *data, uint32_t len)
80 {
81  ByteBuffer::IoVec vec[2];
82  const auto n_vec = reserve(vec, len);
83  uint32_t ret = 0;
84 
85  for (int i = 0; i < n_vec; i++) {
86  memcpy(vec[i].data, data + ret, vec[i].len);
87  ret += vec[i].len;
88  }
89 
90  commit(ret);
91  return ret;
92 }
93 
94 /*
95  update bytes at the read pointer. Used to update an object without
96  popping it
97  */
98 bool ByteBuffer::update(const uint8_t *data, uint32_t len)
99 {
100  if (len > available()) {
101  return false;
102  }
103  // perform as two memcpy calls
104  uint32_t n = size - head;
105  if (n > len) {
106  n = len;
107  }
108  memcpy(&buf[head], data, n);
109  data += n;
110  if (len > n) {
111  memcpy(&buf[0], data, len-n);
112  }
113  return true;
114 }
115 
116 bool ByteBuffer::advance(uint32_t n)
117 {
118  if (n > available()) {
119  return false;
120  }
121  head = (head + n) % size;
122  return true;
123 }
124 
125 uint8_t ByteBuffer::peekiovec(ByteBuffer::IoVec iovec[2], uint32_t len)
126 {
127  uint32_t n = available();
128 
129  if (len > n) {
130  len = n;
131  }
132  if (len == 0) {
133  return 0;
134  }
135 
136  auto b = readptr(n);
137  if (n > len) {
138  n = len;
139  }
140 
141  iovec[0].data = const_cast<uint8_t *>(b);
142  iovec[0].len = n;
143 
144  if (len <= n) {
145  return 1;
146  }
147 
148  iovec[1].data = buf;
149  iovec[1].len = len - n;
150 
151  return 2;
152 }
153 
154 /*
155  read len bytes without advancing the read pointer
156  */
157 uint32_t ByteBuffer::peekbytes(uint8_t *data, uint32_t len)
158 {
159  ByteBuffer::IoVec vec[2];
160  const auto n_vec = peekiovec(vec, len);
161  uint32_t ret = 0;
162 
163  for (int i = 0; i < n_vec; i++) {
164  memcpy(data + ret, vec[i].data, vec[i].len);
165  ret += vec[i].len;
166  }
167 
168  return ret;
169 }
170 
171 uint8_t ByteBuffer::reserve(ByteBuffer::IoVec iovec[2], uint32_t len)
172 {
173  uint32_t n = space();
174 
175  if (len > n) {
176  len = n;
177  }
178 
179  if (!len) {
180  return 0;
181  }
182 
183  iovec[0].data = &buf[tail];
184 
185  n = size - tail;
186  if (len <= n) {
187  iovec[0].len = len;
188  return 1;
189  }
190 
191  iovec[0].len = n;
192 
193  iovec[1].data = buf;
194  iovec[1].len = len - n;
195 
196  return 2;
197 }
198 
199 /*
200  * Advance the writer pointer by 'len'
201  */
202 bool ByteBuffer::commit(uint32_t len)
203 {
204  if (len > space()) {
205  return false; //Someone broke the agreement
206  }
207 
208  tail = (tail + len) % size;
209  return true;
210 }
211 
212 uint32_t ByteBuffer::read(uint8_t *data, uint32_t len)
213 {
214  uint32_t ret = peekbytes(data, len);
215  advance(ret);
216  return ret;
217 }
218 
219 bool ByteBuffer::read_byte(uint8_t *data)
220 {
221  if (!data) {
222  return false;
223  }
224 
225  int16_t ret = peek(0);
226  if (ret < 0) {
227  return false;
228  }
229 
230  *data = ret;
231 
232  return advance(1);
233 }
234 
235 /*
236  * Returns the pointer and size to a contiguous read in the buffer
237  */
238 const uint8_t *ByteBuffer::readptr(uint32_t &available_bytes)
239 {
240  uint32_t _tail = tail;
241  available_bytes = (head > _tail) ? size - head : _tail - head;
242 
243  return available_bytes ? &buf[head] : nullptr;
244 }
245 
246 int16_t ByteBuffer::peek(uint32_t ofs) const
247 {
248  if (ofs >= available()) {
249  return -1;
250  }
251  return buf[(head+ofs)%size];
252 }
uint32_t available(void) const
Definition: RingBuffer.cpp:37
uint32_t size
Definition: RingBuffer.h:88
const uint8_t * readptr(uint32_t &available_bytes)
Definition: RingBuffer.cpp:238
std::atomic< uint32_t > head
Definition: RingBuffer.h:90
uint8_t * data
Definition: RingBuffer.h:66
ByteBuffer(uint32_t size)
Definition: RingBuffer.cpp:6
bool commit(uint32_t len)
Definition: RingBuffer.cpp:202
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
void * calloc(size_t nmemb, size_t size)
Definition: malloc.c:76
bool empty(void) const
Definition: RingBuffer.cpp:74
uint8_t * buf
Definition: RingBuffer.h:87
void clear(void)
Definition: RingBuffer.cpp:49
bool advance(uint32_t n)
Definition: RingBuffer.cpp:116
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
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
void free(void *ptr)
Definition: malloc.c:81
int16_t peek(uint32_t ofs) const
Definition: RingBuffer.cpp:246
uint8_t reserve(IoVec vec[2], uint32_t len)
Definition: RingBuffer.cpp:171
std::atomic< uint32_t > tail
Definition: RingBuffer.h:91
bool read_byte(uint8_t *data)
Definition: RingBuffer.cpp:219