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