71# pragma warning(disable: 4324)
84template<
typename T, std::
size_t SIZE>
87 static_assert(SIZE >= 2,
88 "SPSCRing: SIZE must be at least 2");
89 static_assert((SIZE & (SIZE - 1u)) == 0u,
90 "SPSCRing: SIZE must be a power of two");
91 static_assert(SIZE <= (1u << 30u),
92 "SPSCRing: SIZE exceeds safe limit (2^30)");
93 static_assert(std::is_nothrow_move_constructible_v<T>,
94 "SPSCRing: T must be noexcept move-constructible");
95 static_assert(std::is_nothrow_move_assignable_v<T>,
96 "SPSCRing: T must be noexcept move-assignable");
98 static constexpr std::size_t MASK = SIZE - 1u;
104 [[nodiscard]]
static constexpr std::size_t
capacity() noexcept {
122 [[nodiscard]]
bool push(T&& item)
noexcept {
123 const std::size_t tail = tail_.load(std::memory_order_relaxed);
124 const std::size_t next = (tail + 1u) & MASK;
127 if (next == head_.load(std::memory_order_acquire)) {
131 buffer_[tail] = std::move(item);
134 tail_.store(next, std::memory_order_release);
147 std::is_nothrow_copy_constructible_v<T>) {
149 return push(std::move(copy));
165 [[nodiscard]] std::optional<T>
pop() noexcept {
166 const std::size_t head = head_.load(std::memory_order_relaxed);
169 if (head == tail_.load(std::memory_order_acquire)) {
173 T item{std::move(buffer_[head])};
176 head_.store((head + 1u) & MASK, std::memory_order_release);
189 const std::size_t t = tail_.load(std::memory_order_acquire);
190 const std::size_t h = head_.load(std::memory_order_acquire);
191 return (t - h + SIZE) & MASK;
200 return tail_.load(std::memory_order_acquire) ==
201 head_.load(std::memory_order_acquire);
210 const std::size_t t = tail_.load(std::memory_order_acquire);
211 const std::size_t h = head_.load(std::memory_order_acquire);
212 return ((t + 1u) & MASK) == h;
220 alignas(64) std::atomic<std::size_t> tail_{0};
224 alignas(64) std::atomic<std::size_t> head_{0};
227 std::array<T, SIZE> buffer_{};
Lock-free single-producer / single-consumer ring buffer.
std::optional< T > pop() noexcept
Try to dequeue one element.
bool full_approx() const noexcept
Approximate check for fullness.
bool push_copy(const T &item) noexcept(std::is_nothrow_copy_constructible_v< T >)
Try to enqueue a copy of one element.
static constexpr std::size_t capacity() noexcept
Maximum number of elements the ring can hold simultaneously.
std::size_t size_approx() const noexcept
Approximate number of elements currently in the ring.
bool empty_approx() const noexcept
Approximate check for emptiness.
bool push(T &&item) noexcept
Try to enqueue one element.