🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.7 KiB

  1. #ifndef RINGBUFFER_H
  2. #define RINGBUFFER_H
  3. #include <atomic>
  4. #include <memory>
  5. #include <stddef.h>
  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 RingBuffer {
  15. private:
  16. std::atomic<size_t> mWritePtr{0u};
  17. std::atomic<size_t> mReadPtr{0u};
  18. size_t mWriteSize{0u};
  19. size_t mSizeMask{0u};
  20. size_t mElemSize{0u};
  21. al::FlexArray<al::byte, 16> mBuffer;
  22. public:
  23. struct Data {
  24. al::byte *buf;
  25. size_t len;
  26. };
  27. using DataPair = std::pair<Data,Data>;
  28. RingBuffer(const size_t count) : mBuffer{count} { }
  29. /** Reset the read and write pointers to zero. This is not thread safe. */
  30. void reset() noexcept;
  31. /**
  32. * The non-copying data reader. Returns two ringbuffer data pointers that
  33. * hold the current readable data. If the readable data is in one segment
  34. * the second segment has zero length.
  35. */
  36. DataPair getReadVector() const noexcept;
  37. /**
  38. * The non-copying data writer. Returns two ringbuffer data pointers that
  39. * hold the current writeable data. If the writeable data is in one segment
  40. * the second segment has zero length.
  41. */
  42. DataPair getWriteVector() const noexcept;
  43. /**
  44. * Return the number of elements available for reading. This is the number
  45. * of elements in front of the read pointer and behind the write pointer.
  46. */
  47. size_t readSpace() const noexcept
  48. {
  49. const size_t w{mWritePtr.load(std::memory_order_acquire)};
  50. const size_t r{mReadPtr.load(std::memory_order_acquire)};
  51. return (w-r) & mSizeMask;
  52. }
  53. /**
  54. * The copying data reader. Copy at most `cnt' elements into `dest'.
  55. * Returns the actual number of elements copied.
  56. */
  57. size_t read(void *dest, size_t cnt) noexcept;
  58. /**
  59. * The copying data reader w/o read pointer advance. Copy at most `cnt'
  60. * elements into `dest'. Returns the actual number of elements copied.
  61. */
  62. size_t peek(void *dest, size_t cnt) const noexcept;
  63. /** Advance the read pointer `cnt' places. */
  64. void readAdvance(size_t cnt) noexcept
  65. { mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); }
  66. /**
  67. * Return the number of elements available for writing. This is the number
  68. * of elements in front of the write pointer and behind the read pointer.
  69. */
  70. size_t writeSpace() const noexcept
  71. {
  72. const size_t w{mWritePtr.load(std::memory_order_acquire)};
  73. const size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
  74. return (r-w-1) & mSizeMask;
  75. }
  76. /**
  77. * The copying data writer. Copy at most `cnt' elements from `src'. Returns
  78. * the actual number of elements copied.
  79. */
  80. size_t write(const void *src, size_t cnt) noexcept;
  81. /** Advance the write pointer `cnt' places. */
  82. void writeAdvance(size_t cnt) noexcept
  83. { mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); }
  84. size_t getElemSize() const noexcept { return mElemSize; }
  85. /**
  86. * Create a new ringbuffer to hold at least `sz' elements of `elem_sz'
  87. * bytes. The number of elements is rounded up to the next power of two
  88. * (even if it is already a power of two, to ensure the requested amount
  89. * can be written).
  90. */
  91. static std::unique_ptr<RingBuffer> Create(size_t sz, size_t elem_sz, int limit_writes);
  92. DEF_FAM_NEWDEL(RingBuffer, mBuffer)
  93. };
  94. using RingBufferPtr = std::unique_ptr<RingBuffer>;
  95. #endif /* RINGBUFFER_H */