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