MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RingBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
3namespace MayaFlux::Journal {
4
5/**
6 * @brief Lock-free SPSC (Single Producer Single Consumer) ring buffer
7 *
8 * Designed for wait-free writes from realtime threads.
9 * Uses atomic operations and careful memory ordering.
10 *
11 * @tparam T Element type (must be trivially copyable)
12 * @tparam Capacity Buffer size (must be power of 2 for fast modulo)
13 */
14template <typename T, size_t Capacity>
16 static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be power of 2");
17 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
18
19public:
21 : m_write_index(0)
22 , m_read_index(0)
23 {
24 }
25
26 /**
27 * @brief Attempt to write an element (wait-free)
28 * @return true if write succeeded, false if buffer full
29 */
30 bool try_push(const T& item) noexcept
31 {
32 const auto current_write = m_write_index.load(std::memory_order_relaxed);
33 const auto next_write = increment(current_write);
34
35 if (next_write == m_read_index.load(std::memory_order_acquire)) {
36 return false;
37 }
38
39 m_buffer[current_write] = item;
40
41 m_write_index.store(next_write, std::memory_order_release);
42
43 return true;
44 }
45
46 /**
47 * @brief Attempt to read an element
48 * @return Element if available, nullopt if buffer empty
49 */
50 std::optional<T> try_pop() noexcept
51 {
52 const auto current_read = m_read_index.load(std::memory_order_relaxed);
53
54 if (current_read == m_write_index.load(std::memory_order_acquire)) {
55 return std::nullopt;
56 }
57
58 T item = m_buffer[current_read];
59
60 // (release semantics for writer)
61 m_read_index.store(increment(current_read), std::memory_order_release);
62
63 return item;
64 }
65
66 /**
67 * @brief Check if buffer is empty
68 */
69 [[nodiscard]] bool empty() const noexcept
70 {
71 return m_read_index.load(std::memory_order_acquire) == m_write_index.load(std::memory_order_acquire);
72 }
73
74 /**
75 * @brief Get approximate size (may be stale)
76 */
77 [[nodiscard]] size_t size() const noexcept
78 {
79 const auto write = m_write_index.load(std::memory_order_acquire);
80 const auto read = m_read_index.load(std::memory_order_acquire);
81 return (write >= read) ? (write - read) : (Capacity - read + write);
82 }
83
84 /**
85 * @brief Get buffer capacity
86 */
87 static constexpr size_t capacity() noexcept
88 {
89 return Capacity;
90 }
91
92private:
93 static constexpr size_t increment(size_t index) noexcept
94 {
95 return (index + 1) & (Capacity - 1);
96 }
97
98 alignas(64) std::atomic<size_t> m_write_index;
99 alignas(64) std::atomic<size_t> m_read_index;
100 std::array<T, Capacity> m_buffer;
101};
102
103} // namespace MayaFlux::Journal
std::array< T, Capacity > m_buffer
bool empty() const noexcept
Check if buffer is empty.
static constexpr size_t increment(size_t index) noexcept
std::atomic< size_t > m_read_index
bool try_push(const T &item) noexcept
Attempt to write an element (wait-free)
std::optional< T > try_pop() noexcept
Attempt to read an element.
static constexpr size_t capacity() noexcept
Get buffer capacity.
std::atomic< size_t > m_write_index
size_t size() const noexcept
Get approximate size (may be stale)
Lock-free SPSC (Single Producer Single Consumer) ring buffer.