µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
circular-buffer.h
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ distribution.
3 * (https://github.com/micro-os-plus)
4 * Copyright (c) 2015 Liviu Ionescu.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28#ifndef CMSIS_PLUS_POSIX_DRIVER_CIRCULAR_BUFFER_H_
29#define CMSIS_PLUS_POSIX_DRIVER_CIRCULAR_BUFFER_H_
30
31#if defined(__cplusplus)
32
33// ----------------------------------------------------------------------------
34
35#include <cstdint>
36#include <cstddef>
37
38// ----------------------------------------------------------------------------
39
40namespace os
41{
42 namespace posix
43 {
44 // ------------------------------------------------------------------------
45
51 template<typename T>
53 {
54 // ----------------------------------------------------------------------
55
56 public:
57
61 using value_type = T;
62
68 public:
69
70 circular_buffer (const value_type* buf, std::size_t size,
71 std::size_t high_water_mark,
72 std::size_t low_water_mark = 0);
73
74 circular_buffer (const value_type* buf, std::size_t size);
75
80 // The rule of five.
81 circular_buffer (const circular_buffer&) = delete;
84 operator= (const circular_buffer&) = delete;
86 operator= (circular_buffer&&) = delete;
87
93
98 // --------------------------------------------------------------------
104 public:
105
106 void
107 clear (void);
108
109 const value_type&
110 operator[] (std::size_t idx) const;
111
112 // Insert bytes to the back of the buffer.
113 std::size_t
115
116 std::size_t
117 push_back (const value_type* buf, std::size_t count);
118
119 std::size_t
120 advance_back (std::size_t count);
121
122 void
123 retreat_back (void);
124
125 // Retrieve bytes from the front of the buffer.
126 std::size_t
127 pop_front (value_type* buf);
128
129 std::size_t
130 pop_front (value_type* buf, std::size_t size);
131
132 std::size_t
133 advance_front (std::size_t count);
134
135 // Get the address of the largest contiguous buffer in the front, and
136 // length; might be only partial, if buffer wraps.
137 std::size_t
139
140 // Get the address of the largest contiguous buffer in the back, and
141 // length; might be only partial, if buffer wraps.
142 std::size_t
144
145 bool
146 empty (void) const;
147
148 bool
149 full (void) const;
150
151 bool
152 above_high_water_mark (void) const;
153
154 bool
155 below_high_water_mark (void) const;
156
157 bool
158 above_low_water_mark (void) const;
159
160 bool
161 below_low_water_mark (void) const;
162
163 std::size_t
164 length (void) const;
165
166 std::size_t
167 size (void) const;
168
169 void
170 dump (void);
171
176 // --------------------------------------------------------------------
177 private:
178
183 const value_type* const buf_;
184 std::size_t const size_;
185 std::size_t const high_water_mark_;
186 std::size_t const low_water_mark_;
187
188 // The following are volatile because they can be updated on
189 // different threads or even on interrupts.
190
191 // Actual length: [0 - size].
192 std::size_t volatile len_;
193
194 // Next free position to push, at the back.
195 value_type* volatile back_;
196
197 // First used position to pop, at the front.
198 value_type* volatile front_;
199
204 };
205 // ========================================================================
206
213
214 // ==========================================================================
215 } /* namespace posix */
216} /* namespace os */
217
218// ===== Inline & template implementations ====================================
219
220namespace os
221{
222 namespace posix
223 {
224
225 template<typename T>
227 std::size_t siz,
228 std::size_t high_water_mark,
229 std::size_t low_water_mark) :
230 buf_ (buf), //
231 size_ (siz), //
232 high_water_mark_ (high_water_mark <= size_ ? high_water_mark : siz), //
233 low_water_mark_ (low_water_mark)
234 {
235 assert (low_water_mark_ <= high_water_mark_);
236
237 clear ();
238 }
239
240 template<typename T>
242 std::size_t siz) :
244 { buf, siz, siz, 0 }
245 {
246 trace::printf ("%s(%p,%u) %p\n", __func__, buf, siz, this);
247 }
248
249 template<typename T>
251 {
252 trace::printf ("%s() %p\n", __func__, this);
253 }
254
255 // ------------------------------------------------------------------------
256
257 template<typename T>
258 void
260 {
261 back_ = front_ = const_cast<value_type* volatile > (buf_);
262 len_ = 0;
263#if defined(DEBUG)
264 std::memset (static_cast<void*> (const_cast<value_type*> (buf_)), '?',
265 size_ * sizeof(value_type));
266#endif
267 }
268
269 template<typename T>
270 inline const typename circular_buffer<T>::value_type&
271 circular_buffer<T>::operator[] (std::size_t idx) const
272 {
273 return buf_[idx];
274 }
275
276 template<typename T>
277 inline bool
279 {
280 return (len_ == 0);
281 }
282
283 template<typename T>
284 inline bool
286 {
287 return (len_ >= size_);
288 }
289
290 template<typename T>
291 inline bool
293 {
294 // Allow for water mark to be size.
295 return (len_ >= high_water_mark_);
296 }
297
298 template<typename T>
299 inline bool
301 {
302 // Allow for water mark to be 0.
303 return (len_ <= low_water_mark_);
304 }
305
306 template<typename T>
307 inline bool
309 {
310 return !above_high_water_mark ();
311 }
312
313 template<typename T>
314 inline bool
316 {
317 return !below_low_water_mark ();
318 }
319
320 template<typename T>
321 inline std::size_t
323 {
324 return len_;
325 }
326
327 template<typename T>
328 inline std::size_t
330 {
331 return size_;
332 }
333
334 template<typename T>
335 std::size_t
337 {
338 if (full ())
339 {
340 return 0;
341 }
342
343 // Add to back.
344 *back_++ = v;
345 if (static_cast<std::size_t> (back_ - buf_) >= size_)
346 {
347 // Wrap.
348 back_ = const_cast<value_type* volatile > (buf_);
349 }
350 len_++;
351 return 1;
352 }
353
354 // Return the actual number of bytes, if not enough space for all.
355 template<typename T>
356 std::size_t
357 circular_buffer<T>::push_back (const value_type* buf, std::size_t count)
358 {
359 assert (buf != nullptr);
360
361 std::size_t len = count;
362 if (count > (size_ - len_))
363 {
364 len = size_ - len_;
365 }
366
367 if (len == 0)
368 {
369 return 0;
370 }
371
372 std::size_t sizeToEnd = static_cast<std::size_t> (size_
373 - static_cast<std::size_t> (back_ - buf_));
374 if (len <= sizeToEnd)
375 {
376 std::memcpy (back_, buf, len);
377 back_ += len;
378 if (static_cast<std::size_t> (back_ - buf_) >= size_)
379 {
380 // Wrap.
381 back_ = const_cast<value_type* volatile > (buf_);
382 }
383 len_ += len;
384 }
385 else
386 {
387 std::memcpy (back_, buf, sizeToEnd);
388 back_ = const_cast<value_type* volatile > (buf_);
389 std::memcpy (back_, buf + sizeToEnd, len - sizeToEnd);
390 back_ += (len - sizeToEnd);
391 len_ += len;
392 }
393 return len;
394 }
395
396 template<typename T>
397 std::size_t
399 {
400 std::size_t adjust = count;
401 if (count > (size_ - len_))
402 {
403 adjust = size_ - len_;
404 }
405
406 if (adjust == 0)
407 {
408 return 0;
409 }
410
411 back_ += adjust;
412 if (back_ >= (buf_ + size_))
413 {
414 // Wrap.
415 back_ -= size_;
416 }
417 len_ += adjust;
418
419 return adjust;
420 }
421
422 template<typename T>
423 void
425 {
426 if (back_ == buf_)
427 {
428 back_ = static_cast<value_type*> (const_cast<value_type*> (buf_)
429 + size_ - 1);
430 }
431 else
432 {
433 back_ -= 1;
434 }
435 len_--;
436 }
437
438 template<typename T>
439 std::size_t
441 {
442 assert (buf != nullptr);
443
444 value_type c;
445 if (len_ == 0)
446 {
447 return 0;
448 }
449 else
450 {
451 c = *front_++;
452 if (static_cast<std::size_t> (front_ - buf_) >= size_)
453 {
454 front_ = const_cast<value_type* volatile > (buf_);
455 }
456 len_--;
457 *buf = c;
458 return 1;
459 }
460 }
461
462 template<typename T>
463 std::size_t
465 {
466 assert (buf != nullptr);
467
468 std::size_t len = siz;
469 if (len > len_)
470 {
471 len = len_;
472 }
473
474 std::size_t sizeToEnd = size_
475 - static_cast<std::size_t> (front_ - buf_);
476 if (len <= sizeToEnd)
477 {
478 std::memcpy (buf, front_, len);
479 front_ += len;
480 if (static_cast<std::size_t> (front_ - buf_) >= size_)
481 {
482 front_ = const_cast<value_type* volatile > (buf_);
483 }
484 len_ -= len;
485 }
486 else
487 {
488 std::memcpy (buf, front_, sizeToEnd);
489 front_ = const_cast<value_type* volatile > (buf_);
490 std::memcpy (buf + sizeToEnd, front_, len - sizeToEnd);
491 front_ += (len - sizeToEnd);
492 len_ -= len;
493 }
494 return len;
495 }
496
497 template<typename T>
498 std::size_t
500 {
501 if (count == 0)
502 {
503 return 0;
504 }
505
506 std::size_t adjust = count;
507 if (adjust > len_)
508 {
509 adjust = len_;
510 }
511
512 front_ += adjust;
513 if (front_ >= (buf_ + size_))
514 {
515 // Wrap.
516 front_ -= size_;
517 }
518 len_ -= adjust;
519
520 return adjust;
521 }
522
523 template<typename T>
524 std::size_t
526 {
527 assert (ppbuf != nullptr);
528
529 *ppbuf = front_;
530
531 std::size_t sizeToEnd = size_
532 - static_cast<std::size_t> (front_ - buf_);
533 std::size_t len = sizeToEnd;
534 if (len > len_)
535 {
536 len = len_;
537 }
538
539 return len;
540 }
541
542 template<typename T>
543 std::size_t
545 {
546 assert (ppbuf != nullptr);
547
548 *ppbuf = back_;
549
550 std::size_t sizeToEnd = size_ - static_cast<std::size_t> (back_ - buf_);
551 std::size_t len = sizeToEnd;
552 if (len > (size_ - len_))
553 {
554 len = size_ - len_;
555 }
556
557 return len;
558 }
559
560 template<typename T>
561 void
563 {
564 os::trace::printf ("%s @%p {buf=%p, size=%d, len=%d, hwm=%d, lwn=%d}\n",
565 __PRETTY_FUNCTION__, buf_, size_, len_,
566 high_water_mark_, low_water_mark_);
567 }
568
569 // ==========================================================================
570 } /* namespace posix */
571} /* namespace os */
572
573// ----------------------------------------------------------------------------
574
575#endif /* __cplusplus */
576
577// ----------------------------------------------------------------------------
578
579#endif /* CMSIS_PLUS_POSIX_DRIVER_CIRCULAR_BUFFER_H_ */
Circular buffer class template.
std::size_t pop_front(value_type *buf)
std::size_t back_contiguous_buffer(value_type **ppbuf)
bool below_high_water_mark(void) const
std::size_t advance_front(std::size_t count)
std::size_t size(void) const
circular_buffer(const value_type *buf, std::size_t size, std::size_t high_water_mark, std::size_t low_water_mark=0)
std::size_t front_contiguous_buffer(value_type **ppbuf)
bool below_low_water_mark(void) const
bool above_high_water_mark(void) const
T value_type
Standard type definition.
std::size_t push_back(value_type v)
bool above_low_water_mark(void) const
const value_type & operator[](std::size_t idx) const
std::size_t advance_back(std::size_t count)
std::size_t length(void) const
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:74
System namespace.