🛠️🐜 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.

94 lines
3.0 KiB

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