µ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-2023 Liviu Ionescu. All rights reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software
7 * for any purpose is hereby granted, under the terms of the MIT license.
8 *
9 * If a copy of the license was not distributed with this file, it can
10 * be obtained from https://opensource.org/licenses/mit/.
11 */
12
13#ifndef CMSIS_PLUS_POSIX_DRIVER_CIRCULAR_BUFFER_H_
14#define CMSIS_PLUS_POSIX_DRIVER_CIRCULAR_BUFFER_H_
15
16#if defined(__cplusplus)
17
18// ----------------------------------------------------------------------------
19
20#include <cstdint>
21#include <cstddef>
22
23// ----------------------------------------------------------------------------
24
25namespace os
26{
27 namespace posix
28 {
29 // ------------------------------------------------------------------------
30
36 template<typename T>
38 {
39 // ----------------------------------------------------------------------
40
41 public:
42
46 using value_type = T;
47
53 public:
54
55 circular_buffer (const value_type* buf, std::size_t size,
56 std::size_t high_water_mark,
57 std::size_t low_water_mark = 0);
58
59 circular_buffer (const value_type* buf, std::size_t size);
60
65 // The rule of five.
66 circular_buffer (const circular_buffer&) = delete;
69 operator= (const circular_buffer&) = delete;
71 operator= (circular_buffer&&) = delete;
72
78
83 // --------------------------------------------------------------------
89 public:
90
91 void
92 clear (void);
93
94 const value_type&
95 operator[] (std::size_t idx) const;
96
97 // Insert bytes to the back of the buffer.
98 std::size_t
100
101 std::size_t
102 push_back (const value_type* buf, std::size_t count);
103
104 std::size_t
105 advance_back (std::size_t count);
106
107 void
108 retreat_back (void);
109
110 // Retrieve bytes from the front of the buffer.
111 std::size_t
112 pop_front (value_type* buf);
113
114 std::size_t
115 pop_front (value_type* buf, std::size_t size);
116
117 std::size_t
118 advance_front (std::size_t count);
119
120 // Get the address of the largest contiguous buffer in the front, and
121 // length; might be only partial, if buffer wraps.
122 std::size_t
124
125 // Get the address of the largest contiguous buffer in the back, and
126 // length; might be only partial, if buffer wraps.
127 std::size_t
129
130 bool
131 empty (void) const;
132
133 bool
134 full (void) const;
135
136 bool
137 above_high_water_mark (void) const;
138
139 bool
140 below_high_water_mark (void) const;
141
142 bool
143 above_low_water_mark (void) const;
144
145 bool
146 below_low_water_mark (void) const;
147
148 std::size_t
149 length (void) const;
150
151 std::size_t
152 size (void) const;
153
154 void
155 dump (void);
156
161 // --------------------------------------------------------------------
162 private:
163
168 const value_type* const buf_;
169 std::size_t const size_;
170 std::size_t const high_water_mark_;
171 std::size_t const low_water_mark_;
172
173 // The following are volatile because they can be updated on
174 // different threads or even on interrupts.
175
176 // Actual length: [0 - size].
177 std::size_t volatile len_;
178
179 // Next free position to push, at the back.
180 value_type* volatile back_;
181
182 // First used position to pop, at the front.
183 value_type* volatile front_;
184
189 };
190 // ========================================================================
191
198
199 // ==========================================================================
200 } /* namespace posix */
201} /* namespace os */
202
203// ===== Inline & template implementations ====================================
204
205namespace os
206{
207 namespace posix
208 {
209
210 template<typename T>
212 std::size_t siz,
213 std::size_t high_water_mark,
214 std::size_t low_water_mark) :
215 buf_ (buf), //
216 size_ (siz), //
217 high_water_mark_ (high_water_mark <= size_ ? high_water_mark : siz), //
218 low_water_mark_ (low_water_mark)
219 {
220 assert (low_water_mark_ <= high_water_mark_);
221
222 clear ();
223 }
224
225 template<typename T>
227 std::size_t siz) :
229 { buf, siz, siz, 0 }
230 {
231 trace::printf ("%s(%p,%u) %p\n", __func__, buf, siz, this);
232 }
233
234 template<typename T>
236 {
237 trace::printf ("%s() %p\n", __func__, this);
238 }
239
240 // ------------------------------------------------------------------------
241
242 template<typename T>
243 void
245 {
246 back_ = front_ = const_cast<value_type* volatile > (buf_);
247 len_ = 0;
248#if defined(DEBUG)
249 std::memset (static_cast<void*> (const_cast<value_type*> (buf_)), '?',
250 size_ * sizeof(value_type));
251#endif
252 }
253
254 template<typename T>
255 inline const typename circular_buffer<T>::value_type&
256 circular_buffer<T>::operator[] (std::size_t idx) const
257 {
258 return buf_[idx];
259 }
260
261 template<typename T>
262 inline bool
264 {
265 return (len_ == 0);
266 }
267
268 template<typename T>
269 inline bool
271 {
272 return (len_ >= size_);
273 }
274
275 template<typename T>
276 inline bool
278 {
279 // Allow for water mark to be size.
280 return (len_ >= high_water_mark_);
281 }
282
283 template<typename T>
284 inline bool
286 {
287 // Allow for water mark to be 0.
288 return (len_ <= low_water_mark_);
289 }
290
291 template<typename T>
292 inline bool
294 {
295 return !above_high_water_mark ();
296 }
297
298 template<typename T>
299 inline bool
301 {
302 return !below_low_water_mark ();
303 }
304
305 template<typename T>
306 inline std::size_t
308 {
309 return len_;
310 }
311
312 template<typename T>
313 inline std::size_t
315 {
316 return size_;
317 }
318
319 template<typename T>
320 std::size_t
322 {
323 if (full ())
324 {
325 return 0;
326 }
327
328 // Add to back.
329 *back_++ = v;
330 if (static_cast<std::size_t> (back_ - buf_) >= size_)
331 {
332 // Wrap.
333 back_ = const_cast<value_type* volatile > (buf_);
334 }
335 len_++;
336 return 1;
337 }
338
339 // Return the actual number of bytes, if not enough space for all.
340 template<typename T>
341 std::size_t
342 circular_buffer<T>::push_back (const value_type* buf, std::size_t count)
343 {
344 assert (buf != nullptr);
345
346 std::size_t len = count;
347 if (count > (size_ - len_))
348 {
349 len = size_ - len_;
350 }
351
352 if (len == 0)
353 {
354 return 0;
355 }
356
357 std::size_t sizeToEnd = static_cast<std::size_t> (size_
358 - static_cast<std::size_t> (back_ - buf_));
359 if (len <= sizeToEnd)
360 {
361 std::memcpy (back_, buf, len);
362 back_ += len;
363 if (static_cast<std::size_t> (back_ - buf_) >= size_)
364 {
365 // Wrap.
366 back_ = const_cast<value_type* volatile > (buf_);
367 }
368 len_ += len;
369 }
370 else
371 {
372 std::memcpy (back_, buf, sizeToEnd);
373 back_ = const_cast<value_type* volatile > (buf_);
374 std::memcpy (back_, buf + sizeToEnd, len - sizeToEnd);
375 back_ += (len - sizeToEnd);
376 len_ += len;
377 }
378 return len;
379 }
380
381 template<typename T>
382 std::size_t
384 {
385 std::size_t adjust = count;
386 if (count > (size_ - len_))
387 {
388 adjust = size_ - len_;
389 }
390
391 if (adjust == 0)
392 {
393 return 0;
394 }
395
396 back_ += adjust;
397 if (back_ >= (buf_ + size_))
398 {
399 // Wrap.
400 back_ -= size_;
401 }
402 len_ += adjust;
403
404 return adjust;
405 }
406
407 template<typename T>
408 void
410 {
411 if (back_ == buf_)
412 {
413 back_ = static_cast<value_type*> (const_cast<value_type*> (buf_)
414 + size_ - 1);
415 }
416 else
417 {
418 back_ -= 1;
419 }
420 len_--;
421 }
422
423 template<typename T>
424 std::size_t
426 {
427 assert (buf != nullptr);
428
429 value_type c;
430 if (len_ == 0)
431 {
432 return 0;
433 }
434 else
435 {
436 c = *front_++;
437 if (static_cast<std::size_t> (front_ - buf_) >= size_)
438 {
439 front_ = const_cast<value_type* volatile > (buf_);
440 }
441 len_--;
442 *buf = c;
443 return 1;
444 }
445 }
446
447 template<typename T>
448 std::size_t
450 {
451 assert (buf != nullptr);
452
453 std::size_t len = siz;
454 if (len > len_)
455 {
456 len = len_;
457 }
458
459 std::size_t sizeToEnd = size_
460 - static_cast<std::size_t> (front_ - buf_);
461 if (len <= sizeToEnd)
462 {
463 std::memcpy (buf, front_, len);
464 front_ += len;
465 if (static_cast<std::size_t> (front_ - buf_) >= size_)
466 {
467 front_ = const_cast<value_type* volatile > (buf_);
468 }
469 len_ -= len;
470 }
471 else
472 {
473 std::memcpy (buf, front_, sizeToEnd);
474 front_ = const_cast<value_type* volatile > (buf_);
475 std::memcpy (buf + sizeToEnd, front_, len - sizeToEnd);
476 front_ += (len - sizeToEnd);
477 len_ -= len;
478 }
479 return len;
480 }
481
482 template<typename T>
483 std::size_t
485 {
486 if (count == 0)
487 {
488 return 0;
489 }
490
491 std::size_t adjust = count;
492 if (adjust > len_)
493 {
494 adjust = len_;
495 }
496
497 front_ += adjust;
498 if (front_ >= (buf_ + size_))
499 {
500 // Wrap.
501 front_ -= size_;
502 }
503 len_ -= adjust;
504
505 return adjust;
506 }
507
508 template<typename T>
509 std::size_t
511 {
512 assert (ppbuf != nullptr);
513
514 *ppbuf = front_;
515
516 std::size_t sizeToEnd = size_
517 - static_cast<std::size_t> (front_ - buf_);
518 std::size_t len = sizeToEnd;
519 if (len > len_)
520 {
521 len = len_;
522 }
523
524 return len;
525 }
526
527 template<typename T>
528 std::size_t
530 {
531 assert (ppbuf != nullptr);
532
533 *ppbuf = back_;
534
535 std::size_t sizeToEnd = size_ - static_cast<std::size_t> (back_ - buf_);
536 std::size_t len = sizeToEnd;
537 if (len > (size_ - len_))
538 {
539 len = size_ - len_;
540 }
541
542 return len;
543 }
544
545 template<typename T>
546 void
548 {
549 os::trace::printf ("%s @%p {buf=%p, size=%d, len=%d, hwm=%d, lwn=%d}\n",
550 __PRETTY_FUNCTION__, buf_, size_, len_,
551 high_water_mark_, low_water_mark_);
552 }
553
554 // ==========================================================================
555 } /* namespace posix */
556} /* namespace os */
557
558// ----------------------------------------------------------------------------
559
560#endif /* __cplusplus */
561
562// ----------------------------------------------------------------------------
563
564#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:60
System namespace.