38template <
typename T>
class RingBuffer
41 explicit RingBuffer (
size_t size)
42 : size_ (size + 1), buf_ (std::make_unique<T[]> (size_)), read_head_ (0),
47 RingBuffer (
const RingBuffer &other)
48 : size_ (other.size_), buf_ (std::make_unique<T[]> (other.size_)),
49 read_head_ (other.read_head_.load ()),
50 write_head_ (other.write_head_.load ())
52 std::copy (other.buf_.get (), other.buf_.get () + size_, buf_.get ());
56 RingBuffer (RingBuffer &&other) noexcept
57 : size_ (other.size_), buf_ (std::move (other.buf_)),
58 read_head_ (other.read_head_.load ()),
59 write_head_ (other.write_head_.load ())
62 other.read_head_.store (0);
63 other.write_head_.store (0);
68 RingBuffer &operator= (
const RingBuffer &other)
73 buf_ = std::make_unique<T[]> (other.size_);
74 std::copy (other.buf_.get (), other.buf_.get () + size_, buf_.get ());
75 read_head_.store (other.read_head_.load ());
76 write_head_.store (other.write_head_.load ());
81 RingBuffer &operator= (RingBuffer &&other)
noexcept
86 buf_ = std::move (other.buf_);
87 read_head_.store (other.read_head_.load ());
88 write_head_.store (other.write_head_.load ());
90 other.read_head_.store (0);
91 other.write_head_.store (0);
97 bool write (
const T &src)
99 const size_t write_pos = write_head_.load (std::memory_order_relaxed);
100 const size_t next_pos = increment_pos (write_pos);
101 if (next_pos == read_head_.load (std::memory_order_acquire))
105 buf_[write_pos] = src;
106 write_head_.store (next_pos, std::memory_order_release);
110 void force_write (
const T &src)
112 const size_t write_pos = write_head_.load (std::memory_order_relaxed);
113 const size_t next_pos = increment_pos (write_pos);
115 if (next_pos == read_head_.load (std::memory_order_acquire))
119 increment_pos (read_head_.load (std::memory_order_relaxed)),
120 std::memory_order_release);
123 buf_[write_pos] = src;
124 write_head_.store (next_pos, std::memory_order_release);
127 bool write_multiple (
const T * src,
size_t count)
129 const size_t write_pos = write_head_.load (std::memory_order_relaxed);
130 const size_t read_pos = read_head_.load (std::memory_order_acquire);
131 const size_t available_space = (read_pos - write_pos - 1 + size_) % size_;
133 if (count > available_space)
138 for (
size_t i = 0; i < count; ++i)
140 buf_[(write_pos + i) % size_] = src[i];
143 write_head_.store ((write_pos + count) % size_, std::memory_order_release);
147 void force_write_multiple (
const T * src,
size_t count)
149 size_t write_pos = write_head_.load (std::memory_order_relaxed);
150 size_t read_pos = read_head_.load (std::memory_order_acquire);
152 for (
size_t i = 0; i < count; ++i)
154 buf_[write_pos] = src[i];
155 write_pos = increment_pos (write_pos);
157 if (write_pos == read_pos)
159 read_pos = increment_pos (read_pos);
163 write_head_.store (write_pos, std::memory_order_release);
164 read_head_.store (read_pos, std::memory_order_release);
167 bool skip (
size_t num_elements)
169 const size_t read_pos = read_head_.load (std::memory_order_relaxed);
170 const size_t write_pos = write_head_.load (std::memory_order_acquire);
171 const size_t available_elements = (write_pos - read_pos) % size_;
173 if (num_elements > available_elements)
179 (read_pos + num_elements) % size_, std::memory_order_release);
185 const size_t read_pos = read_head_.load (std::memory_order_relaxed);
186 if (read_pos == write_head_.load (std::memory_order_acquire))
190 dst = buf_[read_pos];
191 read_head_.store (increment_pos (read_pos), std::memory_order_release);
209 const size_t read_pos = read_head_.load (std::memory_order_acquire);
210 const size_t write_pos = write_head_.load (std::memory_order_acquire);
212 if (read_pos == write_pos)
217 dst = buf_[read_pos];
237 const size_t read_pos = read_head_.load (std::memory_order_acquire);
238 const size_t write_pos = write_head_.load (std::memory_order_acquire);
239 const size_t available = (write_pos - read_pos + size_) % size_;
241 size_t peeked = std::min (count, available);
243 for (
size_t i = 0; i < peeked; ++i)
245 dst[i] = buf_[(read_pos + i) % size_];
253 read_head_.store (0, std::memory_order_relaxed);
254 write_head_.store (0, std::memory_order_relaxed);
257 size_t capacity ()
const {
return size_ - 1; }
259 size_t write_space ()
const
261 size_t read_pos = read_head_.load (std::memory_order_relaxed);
262 size_t write_pos = write_head_.load (std::memory_order_relaxed);
263 if (write_pos >= read_pos)
265 return (size_ - write_pos) + read_pos - 1;
269 return read_pos - write_pos - 1;
273 size_t read_space ()
const
275 size_t read_pos = read_head_.load (std::memory_order_relaxed);
276 size_t write_pos = write_head_.load (std::memory_order_relaxed);
277 if (write_pos >= read_pos)
279 return write_pos - read_pos;
283 return (size_ - read_pos) + write_pos;
287 bool can_read_multiple (
size_t count)
const {
return count <= read_space (); }
289 bool read_multiple (T * dst,
size_t count)
291 const size_t read_pos = read_head_.load (std::memory_order_relaxed);
292 const size_t write_pos = write_head_.load (std::memory_order_acquire);
293 const size_t available = (write_pos - read_pos + size_) % size_;
295 if (count > available)
300 for (
size_t i = 0; i < count; ++i)
302 dst[i] = buf_[(read_pos + i) % size_];
305 read_head_.store ((read_pos + count) % size_, std::memory_order_release);
310 size_t increment_pos (
size_t pos)
const {
return (pos + 1) % size_; }
313 std::unique_ptr<T[]> buf_;
314 std::atomic<size_t> read_head_;
315 std::atomic<size_t> write_head_;