ringbuffer.h 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #ifndef RINGBUFFER_H
  2. #define RINGBUFFER_H
  3. #include <stddef.h>
  4. #include <atomic>
  5. #include <memory>
  6. #include <utility>
  7. #include "albyte.h"
  8. #include "almalloc.h"
  9. /* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
  10. * to include an element size. Consequently, parameters and return values for a
  11. * size or count is in 'elements', not bytes. Additionally, it only supports
  12. * single-consumer/single-provider operation.
  13. */
  14. struct ll_ringbuffer_data {
  15. al::byte *buf;
  16. size_t len;
  17. };
  18. using ll_ringbuffer_data_pair = std::pair<ll_ringbuffer_data,ll_ringbuffer_data>;
  19. struct RingBuffer {
  20. std::atomic<size_t> mWritePtr{0u};
  21. std::atomic<size_t> mReadPtr{0u};
  22. size_t mWriteSize{0u};
  23. size_t mSizeMask{0u};
  24. size_t mElemSize{0u};
  25. al::FlexArray<al::byte, 16> mBuffer;
  26. RingBuffer(const size_t count) : mBuffer{count} { }
  27. /** Reset the read and write pointers to zero. This is not thread safe. */
  28. void reset() noexcept;
  29. /**
  30. * The non-copying data reader. Returns two ringbuffer data pointers that
  31. * hold the current readable data. If the readable data is in one segment
  32. * the second segment has zero length.
  33. */
  34. ll_ringbuffer_data_pair getReadVector() const noexcept;
  35. /**
  36. * The non-copying data writer. Returns two ringbuffer data pointers that
  37. * hold the current writeable data. If the writeable data is in one segment
  38. * the second segment has zero length.
  39. */
  40. ll_ringbuffer_data_pair getWriteVector() const noexcept;
  41. /**
  42. * Return the number of elements available for reading. This is the number
  43. * of elements in front of the read pointer and behind the write pointer.
  44. */
  45. size_t readSpace() const noexcept;
  46. /**
  47. * The copying data reader. Copy at most `cnt' elements into `dest'.
  48. * Returns the actual number of elements copied.
  49. */
  50. size_t read(void *dest, size_t cnt) noexcept;
  51. /**
  52. * The copying data reader w/o read pointer advance. Copy at most `cnt'
  53. * elements into `dest'. Returns the actual number of elements copied.
  54. */
  55. size_t peek(void *dest, size_t cnt) const noexcept;
  56. /** Advance the read pointer `cnt' places. */
  57. void readAdvance(size_t cnt) noexcept;
  58. /**
  59. * Return the number of elements available for writing. This is the number
  60. * of elements in front of the write pointer and behind the read pointer.
  61. */
  62. size_t writeSpace() const noexcept;
  63. /**
  64. * The copying data writer. Copy at most `cnt' elements from `src'. Returns
  65. * the actual number of elements copied.
  66. */
  67. size_t write(const void *src, size_t cnt) noexcept;
  68. /** Advance the write pointer `cnt' places. */
  69. void writeAdvance(size_t cnt) noexcept;
  70. DEF_FAM_NEWDEL(RingBuffer, mBuffer)
  71. };
  72. using RingBufferPtr = std::unique_ptr<RingBuffer>;
  73. /**
  74. * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes.
  75. * The number of elements is rounded up to the next power of two (even if it is
  76. * already a power of two, to ensure the requested amount can be written).
  77. */
  78. RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes);
  79. #endif /* RINGBUFFER_H */