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 
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  HeapRingBuffer myHeapBuffer; // or RingBufferControl<HeapBuffer> class for more control
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 uninitialised 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 getReadableDataSize() const noexcept
207  {
208  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, 0);
209 
210  const uint32_t wrap = buffer->head > buffer->tail ? 0 : buffer->size;
211 
212  return wrap + buffer->head - buffer->tail;
213  }
214 
215  /*
216  * Get the size of the data available to write.
217  */
218  uint32_t getWritableDataSize() const noexcept
219  {
220  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, 0);
221 
222  const uint32_t wrap = (buffer->tail > buffer->wrtn) ? 0 : buffer->size;
223 
224  return wrap + buffer->tail - buffer->wrtn;
225  }
226 
227  // -------------------------------------------------------------------
228  // clear/reset operations
229 
230  /*
231  * Clear the entire ring buffer data, marking the buffer as empty.
232  * Requires a buffer struct tied to this class.
233  */
234  void clearData() noexcept
235  {
236  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr,);
237 
238  buffer->head = 0;
239  buffer->tail = 0;
240  buffer->wrtn = 0;
241  buffer->invalidateCommit = false;
242 
243  std::memset(buffer->buf, 0, buffer->size);
244  }
245 
246  // -------------------------------------------------------------------
247  // read operations
248 
249  /*
250  * Read a single boolean value.
251  * Returns false if reading fails.
252  */
253  bool readBool() noexcept
254  {
255  bool b = false;
256  return tryRead(&b, sizeof(bool)) ? b : false;
257  }
258 
259  /*
260  * Read a single 8-bit byte.
261  * Returns 0 if reading fails.
262  */
263  uint8_t readByte() noexcept
264  {
265  uint8_t B = 0;
266  return tryRead(&B, sizeof(uint8_t)) ? B : 0;
267  }
268 
269  /*
270  * Read a short 16-bit integer.
271  * Returns 0 if reading fails.
272  */
273  int16_t readShort() noexcept
274  {
275  int16_t s = 0;
276  return tryRead(&s, sizeof(int16_t)) ? s : 0;
277  }
278 
279  /*
280  * Read a short unsigned 16-bit integer.
281  * Returns 0 if reading fails.
282  */
283  uint16_t readUShort() noexcept
284  {
285  uint16_t us = 0;
286  return tryRead(&us, sizeof(uint16_t)) ? us : 0;
287  }
288 
289  /*
290  * Read a regular 32-bit integer.
291  * Returns 0 if reading fails.
292  */
293  int32_t readInt() noexcept
294  {
295  int32_t i = 0;
296  return tryRead(&i, sizeof(int32_t)) ? i : 0;
297  }
298 
299  /*
300  * Read an unsigned 32-bit integer.
301  * Returns 0 if reading fails.
302  */
303  uint32_t readUInt() noexcept
304  {
305  uint32_t ui = 0;
306  return tryRead(&ui, sizeof(int32_t)) ? ui : 0;
307  }
308 
309  /*
310  * Read a long 64-bit integer.
311  * Returns 0 if reading fails.
312  */
313  int64_t readLong() noexcept
314  {
315  int64_t l = 0;
316  return tryRead(&l, sizeof(int64_t)) ? l : 0;
317  }
318 
319  /*
320  * Read a long unsigned 64-bit integer.
321  * Returns 0 if reading fails.
322  */
323  uint64_t readULong() noexcept
324  {
325  uint64_t ul = 0;
326  return tryRead(&ul, sizeof(int64_t)) ? ul : 0;
327  }
328 
329  /*
330  * Read a single-precision floating point number.
331  * Returns 0 if reading fails.
332  */
333  float readFloat() noexcept
334  {
335  float f = 0.0f;
336  return tryRead(&f, sizeof(float)) ? f : 0.0f;
337  }
338 
339  /*
340  * Read a double-precision floating point number.
341  * Returns 0 if reading fails.
342  */
343  double readDouble() noexcept
344  {
345  double d = 0.0;
346  return tryRead(&d, sizeof(double)) ? d : 0.0;
347  }
348 
349  /*!
350  * Read an arbitrary amount of data, specified by @a size.
351  * data pointer must be non-null, and size > 0.
352  *
353  * Returns true if reading succeeds.
354  * In case of failure, @a data pointer is automatically cleared by @a size bytes.
355  */
356  bool readCustomData(void* const data, const uint32_t size) noexcept
357  {
358  DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, false);
359  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
360 
361  if (tryRead(data, size))
362  return true;
363 
364  std::memset(data, 0, size);
365  return false;
366  }
367 
368  /*!
369  * Read a custom data type specified by the template typename used,
370  * with size being automatically deduced by the compiler (through the use of sizeof).
371  *
372  * Returns true if reading succeeds.
373  * In case of failure, @a type value is automatically cleared by its deduced size.
374  */
375  template <typename T>
376  bool readCustomType(T& type) noexcept
377  {
378  if (tryRead(&type, sizeof(T)))
379  return true;
380 
381  std::memset(&type, 0, sizeof(T));
382  return false;
383  }
384 
385  // -------------------------------------------------------------------
386  // write operations
387 
388  /*
389  * Write a single boolean value.
390  */
391  bool writeBool(const bool value) noexcept
392  {
393  return tryWrite(&value, sizeof(bool));
394  }
395 
396  /*
397  * Write a single 8-bit byte.
398  */
399  bool writeByte(const uint8_t value) noexcept
400  {
401  return tryWrite(&value, sizeof(uint8_t));
402  }
403 
404  /*
405  * Write a short 16-bit integer.
406  */
407  bool writeShort(const int16_t value) noexcept
408  {
409  return tryWrite(&value, sizeof(int16_t));
410  }
411 
412  /*
413  * Write a short unsigned 16-bit integer.
414  */
415  bool writeUShort(const uint16_t value) noexcept
416  {
417  return tryWrite(&value, sizeof(uint16_t));
418  }
419 
420  /*
421  * Write a regular 32-bit integer.
422  */
423  bool writeInt(const int32_t value) noexcept
424  {
425  return tryWrite(&value, sizeof(int32_t));
426  }
427 
428  /*
429  * Write an unsigned 32-bit integer.
430  */
431  bool writeUInt(const uint32_t value) noexcept
432  {
433  return tryWrite(&value, sizeof(uint32_t));
434  }
435 
436  /*
437  * Write a long 64-bit integer.
438  */
439  bool writeLong(const int64_t value) noexcept
440  {
441  return tryWrite(&value, sizeof(int64_t));
442  }
443 
444  /*
445  * Write a long unsigned 64-bit integer.
446  */
447  bool writeULong(const uint64_t value) noexcept
448  {
449  return tryWrite(&value, sizeof(uint64_t));
450  }
451 
452  /*
453  * Write a single-precision floating point number.
454  */
455  bool writeFloat(const float value) noexcept
456  {
457  return tryWrite(&value, sizeof(float));
458  }
459 
460  /*
461  * Write a double-precision floating point number.
462  */
463  bool writeDouble(const double value) noexcept
464  {
465  return tryWrite(&value, sizeof(double));
466  }
467 
468  /*!
469  * Write an arbitrary amount of data, specified by @a size.
470  * data pointer must be non-null, and size > 0.
471  */
472  bool writeCustomData(const void* const data, const uint32_t size) noexcept
473  {
474  DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, false);
475  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
476 
477  return tryWrite(data, size);
478  }
479 
480  /*!
481  * Write a custom data type specified by the template typename used,
482  * with size being automatically deduced by the compiler (through the use of sizeof).
483  */
484  template <typename T>
485  bool writeCustomType(const T& type) noexcept
486  {
487  return tryWrite(&type, sizeof(T));
488  }
489 
490  // -------------------------------------------------------------------
491 
492  /*!
493  * Commit all previous write operations to the ringbuffer.
494  * If a write operation has previously failed, this will reset/invalidate the previous write attempts.
495  */
496  bool commitWrite() noexcept
497  {
498  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
499 
500  if (buffer->invalidateCommit)
501  {
502  buffer->wrtn = buffer->head;
503  buffer->invalidateCommit = false;
504  return false;
505  }
506 
507  // nothing to commit?
508  DISTRHO_SAFE_ASSERT_RETURN(buffer->head != buffer->wrtn, false);
509 
510  // all ok
511  buffer->head = buffer->wrtn;
512  errorWriting = false;
513  return true;
514  }
515 
516  // -------------------------------------------------------------------
517 
518  /*
519  * Tie this ring buffer control to a ring buffer struct, optionally clearing its data.
520  */
521  void setRingBuffer(BufferStruct* const ringBuf, const bool clearRingBufferData) noexcept
522  {
523  DISTRHO_SAFE_ASSERT_RETURN(buffer != ringBuf,);
524 
525  buffer = ringBuf;
526 
527  if (clearRingBufferData && ringBuf != nullptr)
528  clearData();
529  }
530 
531  // -------------------------------------------------------------------
532 
533 protected:
534  /** @internal try reading from the buffer, can fail. */
535  bool tryRead(void* const buf, const uint32_t size) noexcept
536  {
537  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
538  #if defined(__clang__)
539  # pragma clang diagnostic push
540  # pragma clang diagnostic ignored "-Wtautological-pointer-compare"
541  #endif
542  DISTRHO_SAFE_ASSERT_RETURN(buffer->buf != nullptr, false);
543  #if defined(__clang__)
544  # pragma clang diagnostic pop
545  #endif
546  DISTRHO_SAFE_ASSERT_RETURN(buf != nullptr, false);
547  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
548  DISTRHO_SAFE_ASSERT_RETURN(size < buffer->size, false);
549 
550  // empty
551  if (buffer->head == buffer->tail)
552  return false;
553 
554  uint8_t* const bytebuf(static_cast<uint8_t*>(buf));
555 
556  const uint32_t head(buffer->head);
557  const uint32_t tail(buffer->tail);
558  const uint32_t wrap((head > tail) ? 0 : buffer->size);
559 
560  if (size > wrap + head - tail)
561  {
562  if (! errorReading)
563  {
564  errorReading = true;
565  d_stderr2("RingBuffer::tryRead(%p, %lu): failed, not enough space", buf, (ulong)size);
566  }
567  return false;
568  }
569 
570  uint32_t readto(tail + size);
571 
572  if (readto > buffer->size)
573  {
574  readto -= buffer->size;
575 
576  if (size == 1)
577  {
578  std::memcpy(bytebuf, buffer->buf + tail, 1);
579  }
580  else
581  {
582  const uint32_t firstpart(buffer->size - tail);
583  std::memcpy(bytebuf, buffer->buf + tail, firstpart);
584  std::memcpy(bytebuf + firstpart, buffer->buf, readto);
585  }
586  }
587  else
588  {
589  std::memcpy(bytebuf, buffer->buf + tail, size);
590 
591  if (readto == buffer->size)
592  readto = 0;
593  }
594 
595  buffer->tail = readto;
596  errorReading = false;
597  return true;
598  }
599 
600  /** @internal try writing to the buffer, can fail. */
601  bool tryWrite(const void* const buf, const uint32_t size) noexcept
602  {
603  DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
604  DISTRHO_SAFE_ASSERT_RETURN(buf != nullptr, false);
605  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
606  DISTRHO_SAFE_ASSERT_UINT2_RETURN(size < buffer->size, size, buffer->size, false);
607 
608  const uint8_t* const bytebuf(static_cast<const uint8_t*>(buf));
609 
610  const uint32_t tail(buffer->tail);
611  const uint32_t wrtn(buffer->wrtn);
612  const uint32_t wrap((tail > wrtn) ? 0 : buffer->size);
613 
614  if (size >= wrap + tail - wrtn)
615  {
616  if (! errorWriting)
617  {
618  errorWriting = true;
619  d_stderr2("RingBuffer::tryWrite(%p, %lu): failed, not enough space", buf, (ulong)size);
620  }
621  buffer->invalidateCommit = true;
622  return false;
623  }
624 
625  uint32_t writeto(wrtn + size);
626 
627  if (writeto > buffer->size)
628  {
629  writeto -= buffer->size;
630 
631  if (size == 1)
632  {
633  std::memcpy(buffer->buf, bytebuf, 1);
634  }
635  else
636  {
637  const uint32_t firstpart(buffer->size - wrtn);
638  std::memcpy(buffer->buf + wrtn, bytebuf, firstpart);
639  std::memcpy(buffer->buf, bytebuf + firstpart, writeto);
640  }
641  }
642  else
643  {
644  std::memcpy(buffer->buf + wrtn, bytebuf, size);
645 
646  if (writeto == buffer->size)
647  writeto = 0;
648  }
649 
650  buffer->wrtn = writeto;
651  return true;
652  }
653 
654 private:
655  /** Buffer struct pointer. */
656  BufferStruct* buffer;
657 
658  /** Whether read errors have been printed to terminal. */
659  bool errorReading;
660 
661  /** Whether write errors have been printed to terminal. */
662  bool errorWriting;
663 
664  DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
665  DISTRHO_DECLARE_NON_COPYABLE(RingBufferControl)
666 };
667 
668 template <class BufferStruct>
670 {
671  return (buffer != nullptr && buffer->head != buffer->tail);
672 }
673 
674 template <>
676 {
677  return (buffer != nullptr && buffer->buf != nullptr && buffer->head != buffer->tail);
678 }
679 
680 // -----------------------------------------------------------------------
681 // RingBuffer using heap space
682 
683 /**
684  RingBufferControl with a heap buffer.
685  This is a convenience class that provides a method for creating and destroying the heap data.
686  Requires the use of createBuffer(uint32_t) to make the ring buffer usable.
687 */
688 class HeapRingBuffer : public RingBufferControl<HeapBuffer>
689 {
690 public:
691  /** Constructor. */
692  HeapRingBuffer() noexcept
693  : heapBuffer(HeapBuffer_INIT)
694  {
695 #ifndef DISTRHO_PROPER_CPP11_SUPPORT
696  std::memset(&heapBuffer, 0, sizeof(heapBuffer));
697 #endif
698  }
699 
700  /** Destructor. */
701  ~HeapRingBuffer() noexcept override
702  {
703  if (heapBuffer.buf == nullptr)
704  return;
705 
706  delete[] heapBuffer.buf;
707  heapBuffer.buf = nullptr;
708  }
709 
710  /** Create a buffer of the specified size. */
711  bool createBuffer(const uint32_t size) noexcept
712  {
713  DISTRHO_SAFE_ASSERT_RETURN(heapBuffer.buf == nullptr, false);
714  DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
715 
716  const uint32_t p2size = d_nextPowerOf2(size);
717 
718  try {
719  heapBuffer.buf = new uint8_t[p2size];
720  } DISTRHO_SAFE_EXCEPTION_RETURN("HeapRingBuffer::createBuffer", false);
721 
722  heapBuffer.size = p2size;
723  setRingBuffer(&heapBuffer, true);
724  return true;
725  }
726 
727  /** Delete the previously allocated buffer. */
728  void deleteBuffer() noexcept
729  {
730  DISTRHO_SAFE_ASSERT_RETURN(heapBuffer.buf != nullptr,);
731 
732  setRingBuffer(nullptr, false);
733 
734  delete[] heapBuffer.buf;
735  heapBuffer.buf = nullptr;
736  heapBuffer.size = 0;
737  }
738 
739  void copyFromAndClearOther(HeapRingBuffer& other)
740  {
741  DISTRHO_SAFE_ASSERT_RETURN(other.heapBuffer.size == heapBuffer.size,);
742 
743  std::memcpy(&heapBuffer, &other.heapBuffer, sizeof(HeapBuffer) - sizeof(uint8_t*));
744  std::memcpy(heapBuffer.buf, other.heapBuffer.buf, sizeof(uint8_t) * heapBuffer.size);
745  other.clearData();
746  }
747 
748 private:
749  /** The heap buffer used for this class. */
750  HeapBuffer heapBuffer;
751 
752  DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
753  DISTRHO_DECLARE_NON_COPYABLE(HeapRingBuffer)
754 };
755 
756 // -----------------------------------------------------------------------
757 // RingBuffer using small stack space
758 
759 /**
760  RingBufferControl with an included small stack buffer.
761  No setup is necessary, this class is usable as-is.
762 */
763 class SmallStackRingBuffer : public RingBufferControl<SmallStackBuffer>
764 {
765 public:
766  /** Constructor. */
768  : stackBuffer(StackBuffer_INIT)
769  {
770 #ifndef DISTRHO_PROPER_CPP11_SUPPORT
771  std::memset(&stackBuffer, 0, sizeof(stackBuffer));
772 #endif
773  setRingBuffer(&stackBuffer, true);
774  }
775 
776 private:
777  /** The small stack buffer used for this class. */
778  SmallStackBuffer stackBuffer;
779 
780  DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
781  DISTRHO_DECLARE_NON_COPYABLE(SmallStackRingBuffer)
782 };
783 
784 // -----------------------------------------------------------------------
785 
787 
788 #endif // DISTRHO_RING_BUFFER_HPP_INCLUDED
Definition: RingBuffer.hpp:689
HeapRingBuffer() noexcept
Definition: RingBuffer.hpp:692
void deleteBuffer() noexcept
Definition: RingBuffer.hpp:728
bool createBuffer(const uint32_t size) noexcept
Definition: RingBuffer.hpp:711
~HeapRingBuffer() noexcept override
Definition: RingBuffer.hpp:701
Definition: RingBuffer.hpp:168
bool writeCustomType(const T &type) noexcept
Definition: RingBuffer.hpp:485
bool writeCustomData(const void *const data, const uint32_t size) noexcept
Definition: RingBuffer.hpp:472
bool readCustomType(T &type) noexcept
Definition: RingBuffer.hpp:376
bool readCustomData(void *const data, const uint32_t size) noexcept
Definition: RingBuffer.hpp:356
bool commitWrite() noexcept
Definition: RingBuffer.hpp:496
Definition: RingBuffer.hpp:764
SmallStackRingBuffer() noexcept
Definition: RingBuffer.hpp:767
static uint32_t d_nextPowerOf2(uint32_t size) noexcept
Definition: DistrhoUtils.hpp:298
#define END_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:834
#define START_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:828
static void d_stderr2(const char *const fmt,...) noexcept
Definition: DistrhoUtils.hpp:161
Definition: RingBuffer.hpp:104
Definition: RingBuffer.hpp:49
bool invalidateCommit
Definition: RingBuffer.hpp:80
uint32_t wrtn
Definition: RingBuffer.hpp:74
uint32_t head
Definition: RingBuffer.hpp:60
uint32_t size
Definition: RingBuffer.hpp:54
uint32_t tail
Definition: RingBuffer.hpp:67
uint8_t * buf
Definition: RingBuffer.hpp:86
Definition: RingBuffer.hpp:115
Definition: RingBuffer.hpp:93