DISTRHO Plugin Framework
RingBuffer.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
6  * or without fee is hereby granted, provided that the above copyright notice and this
7  * permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef DISTRHO_RING_BUFFER_HPP_INCLUDED
18 #define DISTRHO_RING_BUFFER_HPP_INCLUDED
19 
20 #include "../DistrhoUtils.hpp"
21 
22 START_NAMESPACE_DISTRHO
23 
24 // -----------------------------------------------------------------------
25 // Buffer structs
26 
27 /**
28  Base structure for all RingBuffer containers.
29  This struct details the data model used in DPF's RingBuffer class.
30 
31  DPF RingBuffer uses a struct just like this one to store positions, buffer data, size, etc.
32  The RingBuffer itself takes ownership of this struct and uses it to store any needed data.
33  This allows to dynamically change the way its ring buffer is allocated, simply by changing the template type.
34  For example, `RingBufferControl<HeapBuffer>` will create a ring buffer with heap memory, which can be of any size.
35  In the same vein, `RingBufferControl<SmallStackBuffer>` will create a ring buffer with stack memory,
36  directly tied to the RingBufferControl it belongs to.
37 
38  The main idea behind this model is to allow RingBufferControl over memory created elsewhere,
39  for example shared memory area.
40  One can create/place the Buffer struct in shared memory, and point RingBufferControl to it,
41  thus avoiding the pitfalls of sharing access to a non trivially-copyable/POD C++ class.
42 
43  Unlike other ring buffers, an extra variable is used to track pending writes.
44  This is so we can write a few bytes at a time and later mark the whole operation as complete,
45  thus avoiding the issue of reading data too early from the other side.
46  For example, write the size of some data first, and then the actual data.
47  The reading side will only see data available once size + data is completely written and "committed".
48  */
49 struct HeapBuffer {
50  /**
51  Size of the buffer, allocated in @a buf.
52  If the size is fixed (stack buffer), this variable can be static.
53  */
54  uint32_t size;
55 
56  /**
57  Current writing position, headmost position of the buffer.
58  Increments when writing.
59  */
60  uint32_t head;
61 
62  /**
63  Current reading position, last used position of the buffer.
64  Increments when reading.
65  head == tail means empty buffer.
66  */
67  uint32_t tail;
68 
69  /**
70  Temporary position of head until a commitWrite() is called.
71  If buffer writing fails, wrtn will be back to head position thus ignoring the last operation(s).
72  If buffer writing succeeds, head will be set to this variable.
73  */
74  uint32_t wrtn;
75 
76  /**
77  Boolean used to check if a write operation failed.
78  This ensures we don't get incomplete writes.
79  */
81 
82  /**
83  Pointer to buffer data.
84  This can be either stack or heap data, depending on the usecase.
85  */
86  uint8_t* buf;
87 };
88 
89 /**
90  RingBufferControl compatible struct with a relatively small stack size (4k bytes).
91  @see HeapBuffer
92 */
94  static const uint32_t size = 4096;
95  uint32_t head, tail, wrtn;
96  bool invalidateCommit;
97  uint8_t buf[size];
98 };
99 
100 /**
101  RingBufferControl compatible struct with a relatively big stack size (16k bytes).
102  @see HeapBuffer
103 */
105  static const uint32_t size = 16384;
106  uint32_t head, tail, wrtn;
107  bool invalidateCommit;
108  uint8_t buf[size];
109 };
110 
111 /**
112  RingBufferControl compatible struct with a huge stack size (64k bytes).
113  @see HeapBuffer
114 */
116  static const uint32_t size = 65536;
117  uint32_t head, tail, wrtn;
118  bool invalidateCommit;
119  uint8_t buf[size];
120 };
121 
122 #ifdef DISTRHO_PROPER_CPP11_SUPPORT
123 # define HeapBuffer_INIT {0, 0, 0, 0, false, nullptr}
124 # define StackBuffer_INIT {0, 0, 0, false, {0}}
125 #else
126 # define HeapBuffer_INIT
127 # define StackBuffer_INIT
128 #endif
129 
130 // -----------------------------------------------------------------------
131 // RingBufferControl templated class
132 
133 /**
134  DPF built-in RingBuffer class.
135  RingBufferControl takes one buffer struct to take control over, and operates over it.
136 
137  This is meant for single-writer, single-reader type of control.
138  Writing and reading is wait and lock-free.
139 
140  Typically usage involves:
141  ```
142  // definition
143  RingBufferControl<HeapBuffer> myHeapBuffer; // or HeapRingBuffer class directly
144 
145  // construction, only needed for heap buffers
146  myHeapBuffer.createBuffer(8192);
147 
148  // writing data
149  myHeapBuffer.writeUInt(size);
150  myHeapBuffer.writeCustomData(someOtherData, size);
151  myHeapBuffer.commitWrite();
152 
153  // reading data
154  if (myHeapBuffer.isDataAvailableForReading())
155  {
156  uint32_t size;
157  if (myHeapBuffer.readUInt(size) && readCustomData(&anotherData, size))
158  {
159  // do something with "anotherData"
160  }
161  }
162  ```
163 
164  @see HeapBuffer
165  */
166 template <class BufferStruct>
168 {
169 public:
170  /*
171  * Constructor for unitialized ring buffer.
172  * A call to setRingBuffer is required to tied this control to a ring buffer struct;
173  *
174  */
175  RingBufferControl() noexcept
176  : buffer(nullptr),
177  errorReading(false),
178  errorWriting(false) {}
179 
180  /*
181  * Destructor.
182  */
183  virtual ~RingBufferControl() noexcept {}
184 
185  // -------------------------------------------------------------------
186  // check operations
187 
188  /*
189  * Check if there is any data available for reading, regardless of size.
190  */
191  bool isDataAvailableForReading() const noexcept;
192 
193  /*
194  * Check if ring buffer is empty (that is, there is nothing to read).
195  */
196  bool isEmpty() const noexcept
197  {
198  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
199 
200  return (buffer->buf == nullptr || buffer->head == buffer->tail);
201  }
202 
203  /*
204  * Get the size of the data available to read.
205  */
206  uint32_t getAvailableDataSize() const noexcept
207  {
208  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, 0);
209 
210  const uint32_t wrap((buffer->tail > buffer->wrtn) ? 0 : buffer->size);
211 
212  return wrap + buffer->tail - buffer->wrtn;
213  }
214 
215  // -------------------------------------------------------------------
216  // clear/reset operations
217 
218  /*
219  * Clear the entire ring buffer data, marking the buffer as empty.
220  * Requires a buffer struct tied to this class.
221  */
222  void clearData() noexcept
223  {
224  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr,);
225 
226  buffer->head = 0;
227  buffer->tail = 0;
228  buffer->wrtn = 0;
229  buffer->invalidateCommit = false;
230 
231  std::memset(buffer->buf, 0, buffer->size);
232  }
233 
234  // -------------------------------------------------------------------
235  // read operations
236 
237  /*
238  * Read a single boolean value.
239  * Returns false if reading fails.
240  */
241  bool readBool() noexcept
242  {
243  bool b = false;
244  return tryRead(&b, sizeof(bool)) ? b : false;
245  }
246 
247  /*
248  * Read a single 8-bit byte.
249  * Returns 0 if reading fails.
250  */
251  uint8_t readByte() noexcept
252  {
253  uint8_t B = 0;
254  return tryRead(&B, sizeof(uint8_t)) ? B : 0;
255  }
256 
257  /*
258  * Read a short 16-bit integer.
259  * Returns 0 if reading fails.
260  */
261  int16_t readShort() noexcept
262  {
263  int16_t s = 0;
264  return tryRead(&s, sizeof(int16_t)) ? s : 0;
265  }
266 
267  /*
268  * Read a short unsigned 16-bit integer.
269  * Returns 0 if reading fails.
270  */
271  uint16_t readUShort() noexcept
272  {
273  uint16_t us = 0;
274  return tryRead(&us, sizeof(uint16_t)) ? us : 0;
275  }
276 
277  /*
278  * Read a regular 32-bit integer.
279  * Returns 0 if reading fails.
280  */
281  int32_t readInt() noexcept
282  {
283  int32_t i = 0;
284  return tryRead(&i, sizeof(int32_t)) ? i : 0;
285  }
286 
287  /*
288  * Read an unsigned 32-bit integer.
289  * Returns 0 if reading fails.
290  */
291  uint32_t readUInt() noexcept
292  {
293  uint32_t ui = 0;
294  return tryRead(&ui, sizeof(int32_t)) ? ui : 0;
295  }
296 
297  /*
298  * Read a long 64-bit integer.
299  * Returns 0 if reading fails.
300  */
301  int64_t readLong() noexcept
302  {
303  int64_t l = 0;
304  return tryRead(&l, sizeof(int64_t)) ? l : 0;
305  }
306 
307  /*
308  * Read a long unsigned 64-bit integer.
309  * Returns 0 if reading fails.
310  */
311  uint64_t readULong() noexcept
312  {
313  uint64_t ul = 0;
314  return tryRead(&ul, sizeof(int64_t)) ? ul : 0;
315  }
316 
317  /*
318  * Read a single-precision floating point number.
319  * Returns 0 if reading fails.
320  */
321  float readFloat() noexcept
322  {
323  float f = 0.0f;
324  return tryRead(&f, sizeof(float)) ? f : 0.0f;
325  }
326 
327  /*
328  * Read a double-precision floating point number.
329  * Returns 0 if reading fails.
330  */
331  double readDouble() noexcept
332  {
333  double d = 0.0;
334  return tryRead(&d, sizeof(double)) ? d : 0.0;
335  }
336 
337  /*!
338  * Read an arbitrary amount of data, specified by @a size.
339  * data pointer must be non-null, and size > 0.
340  *
341  * Returns true if reading succeeds.
342  * In case of failure, @a data pointer is automatically cleared by @a size bytes.
343  */
344  bool readCustomData(void* const data, const uint32_t size) noexcept
345  {
346  DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, false);
347  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
348 
349  if (tryRead(data, size))
350  return true;
351 
352  std::memset(data, 0, size);
353  return false;
354  }
355 
356  /*!
357  * Read a custom data type specified by the template typename used,
358  * with size being automatically deduced by the compiler (through the use of sizeof).
359  *
360  * Returns true if reading succeeds.
361  * In case of failure, @a type value is automatically cleared by its deduced size.
362  */
363  template <typename T>
364  bool readCustomType(T& type) noexcept
365  {
366  if (tryRead(&type, sizeof(T)))
367  return true;
368 
369  std::memset(&type, 0, sizeof(T));
370  return false;
371  }
372 
373  // -------------------------------------------------------------------
374  // write operations
375 
376  /*
377  * Write a single boolean value.
378  */
379  bool writeBool(const bool value) noexcept
380  {
381  return tryWrite(&value, sizeof(bool));
382  }
383 
384  /*
385  * Write a single 8-bit byte.
386  */
387  bool writeByte(const uint8_t value) noexcept
388  {
389  return tryWrite(&value, sizeof(uint8_t));
390  }
391 
392  /*
393  * Write a short 16-bit integer.
394  */
395  bool writeShort(const int16_t value) noexcept
396  {
397  return tryWrite(&value, sizeof(int16_t));
398  }
399 
400  /*
401  * Write a short unsigned 16-bit integer.
402  */
403  bool writeUShort(const uint16_t value) noexcept
404  {
405  return tryWrite(&value, sizeof(uint16_t));
406  }
407 
408  /*
409  * Write a regular 32-bit integer.
410  */
411  bool writeInt(const int32_t value) noexcept
412  {
413  return tryWrite(&value, sizeof(int32_t));
414  }
415 
416  /*
417  * Write an unsigned 32-bit integer.
418  */
419  bool writeUInt(const uint32_t value) noexcept
420  {
421  return tryWrite(&value, sizeof(uint32_t));
422  }
423 
424  /*
425  * Write a long 64-bit integer.
426  */
427  bool writeLong(const int64_t value) noexcept
428  {
429  return tryWrite(&value, sizeof(int64_t));
430  }
431 
432  /*
433  * Write a long unsigned 64-bit integer.
434  */
435  bool writeULong(const uint64_t value) noexcept
436  {
437  return tryWrite(&value, sizeof(uint64_t));
438  }
439 
440  /*
441  * Write a single-precision floating point number.
442  */
443  bool writeFloat(const float value) noexcept
444  {
445  return tryWrite(&value, sizeof(float));
446  }
447 
448  /*
449  * Write a double-precision floating point number.
450  */
451  bool writeDouble(const double value) noexcept
452  {
453  return tryWrite(&value, sizeof(double));
454  }
455 
456  /*!
457  * Write an arbitrary amount of data, specified by @a size.
458  * data pointer must be non-null, and size > 0.
459  */
460  bool writeCustomData(const void* const data, const uint32_t size) noexcept
461  {
462  DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, false);
463  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
464 
465  return tryWrite(data, size);
466  }
467 
468  /*!
469  * Write a custom data type specified by the template typename used,
470  * with size being automatically deduced by the compiler (through the use of sizeof).
471  */
472  template <typename T>
473  bool writeCustomType(const T& type) noexcept
474  {
475  return tryWrite(&type, sizeof(T));
476  }
477 
478  // -------------------------------------------------------------------
479 
480  /*!
481  * Commit all previous write operations to the ringbuffer.
482  * If a write operation has previously failed, this will reset/invalidate the previous write attempts.
483  */
484  bool commitWrite() noexcept
485  {
486  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
487 
488  if (buffer->invalidateCommit)
489  {
490  buffer->wrtn = buffer->head;
491  buffer->invalidateCommit = false;
492  return false;
493  }
494 
495  // nothing to commit?
496  DISTRHO_SAFE_ASSERT_RETURN(buffer->head != buffer->wrtn, false);
497 
498  // all ok
499  buffer->head = buffer->wrtn;
500  errorWriting = false;
501  return true;
502  }
503 
504  // -------------------------------------------------------------------
505 
506  /*
507  * Tie this ring buffer control to a ring buffer struct, optionally clearing its data.
508  */
509  void setRingBuffer(BufferStruct* const ringBuf, const bool clearRingBufferData) noexcept
510  {
511  DISTRHO_SAFE_ASSERT_RETURN(buffer != ringBuf,);
512 
513  buffer = ringBuf;
514 
515  if (clearRingBufferData && ringBuf != nullptr)
516  clearData();
517  }
518 
519  // -------------------------------------------------------------------
520 
521 protected:
522  /** @internal try reading from the buffer, can fail. */
523  bool tryRead(void* const buf, const uint32_t size) noexcept
524  {
525  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
526  #if defined(__clang__)
527  # pragma clang diagnostic push
528  # pragma clang diagnostic ignored "-Wtautological-pointer-compare"
529  #endif
530  DISTRHO_SAFE_ASSERT_RETURN(buffer->buf != nullptr, false);
531  #if defined(__clang__)
532  # pragma clang diagnostic pop
533  #endif
534  DISTRHO_SAFE_ASSERT_RETURN(buf != nullptr, false);
535  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
536  DISTRHO_SAFE_ASSERT_RETURN(size < buffer->size, false);
537 
538  // empty
539  if (buffer->head == buffer->tail)
540  return false;
541 
542  uint8_t* const bytebuf(static_cast<uint8_t*>(buf));
543 
544  const uint32_t head(buffer->head);
545  const uint32_t tail(buffer->tail);
546  const uint32_t wrap((head > tail) ? 0 : buffer->size);
547 
548  if (size > wrap + head - tail)
549  {
550  if (! errorReading)
551  {
552  errorReading = true;
553  d_stderr2("RingBuffer::tryRead(%p, %lu): failed, not enough space", buf, (ulong)size);
554  }
555  return false;
556  }
557 
558  uint32_t readto(tail + size);
559 
560  if (readto > buffer->size)
561  {
562  readto -= buffer->size;
563 
564  if (size == 1)
565  {
566  std::memcpy(bytebuf, buffer->buf + tail, 1);
567  }
568  else
569  {
570  const uint32_t firstpart(buffer->size - tail);
571  std::memcpy(bytebuf, buffer->buf + tail, firstpart);
572  std::memcpy(bytebuf + firstpart, buffer->buf, readto);
573  }
574  }
575  else
576  {
577  std::memcpy(bytebuf, buffer->buf + tail, size);
578 
579  if (readto == buffer->size)
580  readto = 0;
581  }
582 
583  buffer->tail = readto;
584  errorReading = false;
585  return true;
586  }
587 
588  /** @internal try writing to the buffer, can fail. */
589  bool tryWrite(const void* const buf, const uint32_t size) noexcept
590  {
591  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
592  DISTRHO_SAFE_ASSERT_RETURN(buf != nullptr, false);
593  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
594  DISTRHO_SAFE_ASSERT_UINT2_RETURN(size < buffer->size, size, buffer->size, false);
595 
596  const uint8_t* const bytebuf(static_cast<const uint8_t*>(buf));
597 
598  const uint32_t tail(buffer->tail);
599  const uint32_t wrtn(buffer->wrtn);
600  const uint32_t wrap((tail > wrtn) ? 0 : buffer->size);
601 
602  if (size >= wrap + tail - wrtn)
603  {
604  if (! errorWriting)
605  {
606  errorWriting = true;
607  d_stderr2("RingBuffer::tryWrite(%p, %lu): failed, not enough space", buf, (ulong)size);
608  }
609  buffer->invalidateCommit = true;
610  return false;
611  }
612 
613  uint32_t writeto(wrtn + size);
614 
615  if (writeto > buffer->size)
616  {
617  writeto -= buffer->size;
618 
619  if (size == 1)
620  {
621  std::memcpy(buffer->buf, bytebuf, 1);
622  }
623  else
624  {
625  const uint32_t firstpart(buffer->size - wrtn);
626  std::memcpy(buffer->buf + wrtn, bytebuf, firstpart);
627  std::memcpy(buffer->buf, bytebuf + firstpart, writeto);
628  }
629  }
630  else
631  {
632  std::memcpy(buffer->buf + wrtn, bytebuf, size);
633 
634  if (writeto == buffer->size)
635  writeto = 0;
636  }
637 
638  buffer->wrtn = writeto;
639  return true;
640  }
641 
642 private:
643  /** Buffer struct pointer. */
644  BufferStruct* buffer;
645 
646  /** Whether read errors have been printed to terminal. */
647  bool errorReading;
648 
649  /** Whether write errors have been printed to terminal. */
650  bool errorWriting;
651 
652  DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
653  DISTRHO_DECLARE_NON_COPYABLE(RingBufferControl)
654 };
655 
656 template <class BufferStruct>
658 {
659  return (buffer != nullptr && buffer->head != buffer->tail);
660 }
661 
662 template <>
664 {
665  return (buffer != nullptr && buffer->buf != nullptr && buffer->head != buffer->tail);
666 }
667 
668 // -----------------------------------------------------------------------
669 // RingBuffer using heap space
670 
671 /**
672  RingBufferControl with a heap buffer.
673  This is a convenience class that provides a method for creating and destroying the heap data.
674  Requires the use of createBuffer(uint32_t) to make the ring buffer usable.
675 */
676 class HeapRingBuffer : public RingBufferControl<HeapBuffer>
677 {
678 public:
679  /** Constructor. */
680  HeapRingBuffer() noexcept
681  : heapBuffer(HeapBuffer_INIT)
682  {
683 #ifndef DISTRHO_PROPER_CPP11_SUPPORT
684  std::memset(&heapBuffer, 0, sizeof(heapBuffer));
685 #endif
686  }
687 
688  /** Destructor. */
689  ~HeapRingBuffer() noexcept override
690  {
691  if (heapBuffer.buf == nullptr)
692  return;
693 
694  delete[] heapBuffer.buf;
695  heapBuffer.buf = nullptr;
696  }
697 
698  /** Create a buffer of the specified size. */
699  bool createBuffer(const uint32_t size) noexcept
700  {
701  DISTRHO_SAFE_ASSERT_RETURN(heapBuffer.buf == nullptr, false);
702  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
703 
704  const uint32_t p2size = d_nextPowerOf2(size);
705 
706  try {
707  heapBuffer.buf = new uint8_t[p2size];
708  } DISTRHO_SAFE_EXCEPTION_RETURN("HeapRingBuffer::createBuffer", false);
709 
710  heapBuffer.size = p2size;
711  setRingBuffer(&heapBuffer, true);
712  return true;
713  }
714 
715  /** Delete the previously allocated buffer. */
716  void deleteBuffer() noexcept
717  {
718  DISTRHO_SAFE_ASSERT_RETURN(heapBuffer.buf != nullptr,);
719 
720  setRingBuffer(nullptr, false);
721 
722  delete[] heapBuffer.buf;
723  heapBuffer.buf = nullptr;
724  heapBuffer.size = 0;
725  }
726 
727 private:
728  /** The heap buffer used for this class. */
729  HeapBuffer heapBuffer;
730 
731  DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
732  DISTRHO_DECLARE_NON_COPYABLE(HeapRingBuffer)
733 };
734 
735 // -----------------------------------------------------------------------
736 // RingBuffer using small stack space
737 
738 /**
739  RingBufferControl with an included small stack buffer.
740  No setup is necessary, this class is usable as-is.
741 */
742 class SmallStackRingBuffer : public RingBufferControl<SmallStackBuffer>
743 {
744 public:
745  /** Constructor. */
747  : stackBuffer(StackBuffer_INIT)
748  {
749 #ifndef DISTRHO_PROPER_CPP11_SUPPORT
750  std::memset(&stackBuffer, 0, sizeof(stackBuffer));
751 #endif
752  setRingBuffer(&stackBuffer, true);
753  }
754 
755 private:
756  /** The small stack buffer used for this class. */
757  SmallStackBuffer stackBuffer;
758 
759  DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
760  DISTRHO_DECLARE_NON_COPYABLE(SmallStackRingBuffer)
761 };
762 
763 // -----------------------------------------------------------------------
764 
765 END_NAMESPACE_DISTRHO
766 
767 #endif // DISTRHO_RING_BUFFER_HPP_INCLUDED
BigStackBuffer
Definition: RingBuffer.hpp:104
RingBufferControl::commitWrite
bool commitWrite() noexcept
Definition: RingBuffer.hpp:484
SmallStackRingBuffer::SmallStackRingBuffer
SmallStackRingBuffer() noexcept
Definition: RingBuffer.hpp:746
SmallStackRingBuffer
Definition: RingBuffer.hpp:742
HugeStackBuffer
Definition: RingBuffer.hpp:115
HeapBuffer::tail
uint32_t tail
Definition: RingBuffer.hpp:67
RingBufferControl::writeCustomType
bool writeCustomType(const T &type) noexcept
Definition: RingBuffer.hpp:473
HeapRingBuffer::HeapRingBuffer
HeapRingBuffer() noexcept
Definition: RingBuffer.hpp:680
RingBufferControl
Definition: RingBuffer.hpp:167
RingBufferControl::writeCustomData
bool writeCustomData(const void *const data, const uint32_t size) noexcept
Definition: RingBuffer.hpp:460
HeapBuffer::buf
uint8_t * buf
Definition: RingBuffer.hpp:86
HeapBuffer::head
uint32_t head
Definition: RingBuffer.hpp:60
RingBufferControl::readCustomData
bool readCustomData(void *const data, const uint32_t size) noexcept
Definition: RingBuffer.hpp:344
HeapBuffer::size
uint32_t size
Definition: RingBuffer.hpp:54
HeapRingBuffer
Definition: RingBuffer.hpp:676
HeapBuffer::wrtn
uint32_t wrtn
Definition: RingBuffer.hpp:74
HeapRingBuffer::createBuffer
bool createBuffer(const uint32_t size) noexcept
Definition: RingBuffer.hpp:699
SmallStackBuffer
Definition: RingBuffer.hpp:93
HeapRingBuffer::deleteBuffer
void deleteBuffer() noexcept
Definition: RingBuffer.hpp:716
HeapBuffer
Definition: RingBuffer.hpp:49
HeapRingBuffer::~HeapRingBuffer
~HeapRingBuffer() noexcept override
Definition: RingBuffer.hpp:689
HeapBuffer::invalidateCommit
bool invalidateCommit
Definition: RingBuffer.hpp:80
RingBufferControl::readCustomType
bool readCustomType(T &type) noexcept
Definition: RingBuffer.hpp:364