17 #ifndef DISTRHO_RING_BUFFER_HPP_INCLUDED
18 #define DISTRHO_RING_BUFFER_HPP_INCLUDED
20 #include "../DistrhoUtils.hpp"
22 START_NAMESPACE_DISTRHO
94 static const uint32_t size = 4096;
95 uint32_t head, tail, wrtn;
96 bool invalidateCommit;
105 static const uint32_t size = 16384;
106 uint32_t head, tail, wrtn;
107 bool invalidateCommit;
116 static const uint32_t size = 65536;
117 uint32_t head, tail, wrtn;
118 bool invalidateCommit;
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}}
126 # define HeapBuffer_INIT
127 # define StackBuffer_INIT
166 template <
class BufferStruct>
178 errorWriting(
false) {}
191 bool isDataAvailableForReading()
const noexcept;
196 bool isEmpty()
const noexcept
198 DISTRHO_SAFE_ASSERT_RETURN(buffer !=
nullptr,
false);
200 return (buffer->buf ==
nullptr || buffer->head == buffer->tail);
206 uint32_t getAvailableDataSize()
const noexcept
208 DISTRHO_SAFE_ASSERT_RETURN(buffer !=
nullptr, 0);
210 const uint32_t wrap((buffer->tail > buffer->wrtn) ? 0 : buffer->size);
212 return wrap + buffer->tail - buffer->wrtn;
222 void clearData() noexcept
224 DISTRHO_SAFE_ASSERT_RETURN(buffer !=
nullptr,);
229 buffer->invalidateCommit =
false;
231 std::memset(buffer->buf, 0, buffer->size);
241 bool readBool() noexcept
244 return tryRead(&b,
sizeof(
bool)) ? b :
false;
251 uint8_t readByte() noexcept
254 return tryRead(&B,
sizeof(uint8_t)) ? B : 0;
261 int16_t readShort() noexcept
264 return tryRead(&s,
sizeof(int16_t)) ? s : 0;
271 uint16_t readUShort() noexcept
274 return tryRead(&us,
sizeof(uint16_t)) ? us : 0;
281 int32_t readInt() noexcept
284 return tryRead(&i,
sizeof(int32_t)) ? i : 0;
291 uint32_t readUInt() noexcept
294 return tryRead(&ui,
sizeof(int32_t)) ? ui : 0;
301 int64_t readLong() noexcept
304 return tryRead(&l,
sizeof(int64_t)) ? l : 0;
311 uint64_t readULong() noexcept
314 return tryRead(&ul,
sizeof(int64_t)) ? ul : 0;
321 float readFloat() noexcept
324 return tryRead(&f,
sizeof(
float)) ? f : 0.0f;
331 double readDouble() noexcept
334 return tryRead(&d,
sizeof(
double)) ? d : 0.0;
346 DISTRHO_SAFE_ASSERT_RETURN(data !=
nullptr,
false);
347 DISTRHO_SAFE_ASSERT_RETURN(size > 0,
false);
349 if (tryRead(data, size))
352 std::memset(data, 0, size);
363 template <
typename T>
366 if (tryRead(&type,
sizeof(T)))
369 std::memset(&type, 0,
sizeof(T));
379 bool writeBool(
const bool value) noexcept
381 return tryWrite(&value,
sizeof(
bool));
387 bool writeByte(
const uint8_t value) noexcept
389 return tryWrite(&value,
sizeof(uint8_t));
395 bool writeShort(
const int16_t value) noexcept
397 return tryWrite(&value,
sizeof(int16_t));
403 bool writeUShort(
const uint16_t value) noexcept
405 return tryWrite(&value,
sizeof(uint16_t));
411 bool writeInt(
const int32_t value) noexcept
413 return tryWrite(&value,
sizeof(int32_t));
419 bool writeUInt(
const uint32_t value) noexcept
421 return tryWrite(&value,
sizeof(uint32_t));
427 bool writeLong(
const int64_t value) noexcept
429 return tryWrite(&value,
sizeof(int64_t));
435 bool writeULong(
const uint64_t value) noexcept
437 return tryWrite(&value,
sizeof(uint64_t));
443 bool writeFloat(
const float value) noexcept
445 return tryWrite(&value,
sizeof(
float));
451 bool writeDouble(
const double value) noexcept
453 return tryWrite(&value,
sizeof(
double));
462 DISTRHO_SAFE_ASSERT_RETURN(data !=
nullptr,
false);
463 DISTRHO_SAFE_ASSERT_RETURN(size > 0,
false);
465 return tryWrite(data, size);
472 template <
typename T>
475 return tryWrite(&type,
sizeof(T));
486 DISTRHO_SAFE_ASSERT_RETURN(buffer !=
nullptr,
false);
488 if (buffer->invalidateCommit)
490 buffer->wrtn = buffer->head;
491 buffer->invalidateCommit =
false;
496 DISTRHO_SAFE_ASSERT_RETURN(buffer->head != buffer->wrtn,
false);
499 buffer->head = buffer->wrtn;
500 errorWriting =
false;
509 void setRingBuffer(BufferStruct*
const ringBuf,
const bool clearRingBufferData) noexcept
511 DISTRHO_SAFE_ASSERT_RETURN(buffer != ringBuf,);
515 if (clearRingBufferData && ringBuf !=
nullptr)
523 bool tryRead(
void*
const buf,
const uint32_t size) noexcept
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"
530 DISTRHO_SAFE_ASSERT_RETURN(buffer->buf !=
nullptr,
false);
531 #if defined(__clang__)
532 # pragma clang diagnostic pop
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);
539 if (buffer->head == buffer->tail)
542 uint8_t*
const bytebuf(
static_cast<uint8_t*
>(buf));
544 const uint32_t head(buffer->head);
545 const uint32_t tail(buffer->tail);
546 const uint32_t wrap((head > tail) ? 0 : buffer->size);
548 if (size > wrap + head - tail)
553 d_stderr2(
"RingBuffer::tryRead(%p, %lu): failed, not enough space", buf, (ulong)size);
558 uint32_t readto(tail + size);
560 if (readto > buffer->size)
562 readto -= buffer->size;
566 std::memcpy(bytebuf, buffer->buf + tail, 1);
570 const uint32_t firstpart(buffer->size - tail);
571 std::memcpy(bytebuf, buffer->buf + tail, firstpart);
572 std::memcpy(bytebuf + firstpart, buffer->buf, readto);
577 std::memcpy(bytebuf, buffer->buf + tail, size);
579 if (readto == buffer->size)
583 buffer->tail = readto;
584 errorReading =
false;
589 bool tryWrite(
const void*
const buf,
const uint32_t size) noexcept
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);
596 const uint8_t*
const bytebuf(
static_cast<const uint8_t*
>(buf));
598 const uint32_t tail(buffer->tail);
599 const uint32_t wrtn(buffer->wrtn);
600 const uint32_t wrap((tail > wrtn) ? 0 : buffer->size);
602 if (size >= wrap + tail - wrtn)
607 d_stderr2(
"RingBuffer::tryWrite(%p, %lu): failed, not enough space", buf, (ulong)size);
609 buffer->invalidateCommit =
true;
613 uint32_t writeto(wrtn + size);
615 if (writeto > buffer->size)
617 writeto -= buffer->size;
621 std::memcpy(buffer->buf, bytebuf, 1);
625 const uint32_t firstpart(buffer->size - wrtn);
626 std::memcpy(buffer->buf + wrtn, bytebuf, firstpart);
627 std::memcpy(buffer->buf, bytebuf + firstpart, writeto);
632 std::memcpy(buffer->buf + wrtn, bytebuf, size);
634 if (writeto == buffer->size)
638 buffer->wrtn = writeto;
644 BufferStruct* buffer;
652 DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
656 template <
class BufferStruct>
659 return (buffer !=
nullptr && buffer->head != buffer->tail);
665 return (buffer !=
nullptr && buffer->buf !=
nullptr && buffer->head != buffer->tail);
681 : heapBuffer(HeapBuffer_INIT)
683 #ifndef DISTRHO_PROPER_CPP11_SUPPORT
684 std::memset(&heapBuffer, 0,
sizeof(heapBuffer));
691 if (heapBuffer.
buf ==
nullptr)
694 delete[] heapBuffer.
buf;
695 heapBuffer.
buf =
nullptr;
701 DISTRHO_SAFE_ASSERT_RETURN(heapBuffer.
buf ==
nullptr,
false);
702 DISTRHO_SAFE_ASSERT_RETURN(size > 0,
false);
704 const uint32_t p2size = d_nextPowerOf2(size);
707 heapBuffer.
buf =
new uint8_t[p2size];
708 } DISTRHO_SAFE_EXCEPTION_RETURN(
"HeapRingBuffer::createBuffer",
false);
710 heapBuffer.
size = p2size;
711 setRingBuffer(&heapBuffer,
true);
718 DISTRHO_SAFE_ASSERT_RETURN(heapBuffer.
buf !=
nullptr,);
720 setRingBuffer(
nullptr,
false);
722 delete[] heapBuffer.
buf;
723 heapBuffer.
buf =
nullptr;
731 DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
747 : stackBuffer(StackBuffer_INIT)
749 #ifndef DISTRHO_PROPER_CPP11_SUPPORT
750 std::memset(&stackBuffer, 0,
sizeof(stackBuffer));
752 setRingBuffer(&stackBuffer,
true);
759 DISTRHO_PREVENT_VIRTUAL_HEAP_ALLOCATION
765 END_NAMESPACE_DISTRHO
767 #endif // DISTRHO_RING_BUFFER_HPP_INCLUDED