54inline lock_free_spmc_ring_buffer_base::lock_free_spmc_ring_buffer_base(
size_t capacity):
55 head_(tagged_index_t(0, 0)),
56 tail_(tagged_index_t(0, 0)),
57 ring_size_(static_cast<index_type>(enforce_valid_size(capacity)))
59 static_assert(std::atomic<tagged_index_t>::is_always_lock_free);
65inline bool lock_free_spmc_ring_buffer_base::empty()
const
67 return tagged_index_t::empty(head_.load(std::memory_order_acquire), tail_.load(std::memory_order_acquire));
74inline bool lock_free_spmc_ring_buffer_base::full()
const
76 return tagged_index_t::full(head_.load(std::memory_order_acquire), tail_.load(std::memory_order_acquire));
81lock_free_spmc_ring_buffer_base::tagged_index_t
82inline lock_free_spmc_ring_buffer_base::next_index(tagged_index_t index)
const
84 const index_type i = ++index.index;
86 ? tagged_index_t(i, index.tag)
87 : tagged_index_t(0, index.tag + 1);
92inline size_t lock_free_spmc_ring_buffer_base::enforce_valid_size(
size_t size)
96 throw std::length_error(
"ring buffer capacitance cannot be zero");
98 if (size > num::NumTraits<index_type>::max)
100 throw std::length_error(
"exceeded maximum ring buffer capacitance");
110lock_free_spmc_value_ring_buffer<T>::lock_free_spmc_value_ring_buffer(
size_t capacity):
111 lock_free_spmc_ring_buffer_base(capacity),
122bool lock_free_spmc_value_ring_buffer<T>::try_push(
const value_type& x)
124 const tagged_index_t head = head_.load(std::memory_order_relaxed);
125 const tagged_index_t tail = tail_.load(std::memory_order_acquire);
126 if (tagged_index_t::full(head, tail))
128 LASS_ASSERT(head.tag == tail.tag + 1);
131 ring_[head.index].store(x, std::memory_order_release);
132 head_.store(next_index(head), std::memory_order_release);
142bool lock_free_spmc_value_ring_buffer<T>::try_push(value_type&& x)
144 const tagged_index_t head = head_.load(std::memory_order_relaxed);
145 const tagged_index_t tail = tail_.load(std::memory_order_acquire);
146 if (tagged_index_t::full(head, tail))
148 LASS_ASSERT(head.tag == tail.tag + 1);
151 ring_[head.index].store(std::move(x), std::memory_order_release);
152 head_.store(next_index(head), std::memory_order_release);
162template <
class... Args>
163bool lock_free_spmc_value_ring_buffer<T>::try_emplace(Args&&... args)
165 const tagged_index_t head = head_.load(std::memory_order_relaxed);
166 const tagged_index_t tail = tail_.load(std::memory_order_acquire);
167 if (tagged_index_t::full(head, tail))
169 LASS_ASSERT(head.tag == tail.tag + 1);
172 ring_[head.index].store(value_type(std::forward<Args...>(args...)), std::memory_order_release);
173 head_.store(next_index(head), std::memory_order_release);
183bool lock_free_spmc_value_ring_buffer<T>::try_pop(value_type& x)
185 tagged_index_t tail = tail_.load(std::memory_order_acquire);
188 const tagged_index_t head = head_.load(std::memory_order_acquire);
189 if (tagged_index_t::empty(head, tail))
193 x = ring_[tail.index].load(std::memory_order_acquire);
194 if (tail_.compare_exchange_weak(tail, next_index(tail)))
205template <
typename T,
typename A>
206lock_free_spmc_object_ring_buffer<T, A>::lock_free_spmc_object_ring_buffer(
size_t capacity):
207 lock_free_spmc_ring_buffer_base(capacity),
208 value_allocator_(sizeof(T)),
215template <
typename T,
typename A>
216lock_free_spmc_object_ring_buffer<T, A>::~lock_free_spmc_object_ring_buffer()
218 const tagged_index_t head = head_.load(std::memory_order_acquire);
219 const tagged_index_t tail = tail_.load(std::memory_order_acquire);
220 for (tagged_index_t i = tail; !tagged_index_t::empty(i, head); i = next_index(i))
222 value_type* p = ring_[i.index].load(std::memory_order_relaxed);
224 value_allocator_.deallocate(p);
233template <
typename T,
typename A>
234bool lock_free_spmc_object_ring_buffer<T, A>::try_push(
const value_type& x)
236 const tagged_index_t head = head_.load(std::memory_order_relaxed);
237 const tagged_index_t tail = tail_.load(std::memory_order_acquire);
238 if (tagged_index_t::full(head, tail))
242 void* p = value_allocator_.allocate();
245 ring_[head.index] =
new (p) value_type(x);
249 value_allocator_.deallocate(p);
252 head_.store(next_index(head), std::memory_order_release);
261template <
typename T,
typename A>
262bool lock_free_spmc_object_ring_buffer<T, A>::try_push(value_type&& x)
264 const tagged_index_t head = head_.load(std::memory_order_relaxed);
265 const tagged_index_t tail = tail_.load(std::memory_order_acquire);
266 if (tagged_index_t::full(head, tail))
270 void* p = value_allocator_.allocate();
273 ring_[head.index] =
new (p) value_type(std::move(x));
277 value_allocator_.deallocate(p);
280 head_.store(next_index(head), std::memory_order_release);
289template <
typename T,
typename A>
290template <
class... Args>
291bool lock_free_spmc_object_ring_buffer<T, A>::try_emplace(Args&&... args)
293 const tagged_index_t head = head_.load(std::memory_order_relaxed);
294 const tagged_index_t tail = tail_.load(std::memory_order_acquire);
295 if (tagged_index_t::full(head, tail))
299 void* p = value_allocator_.allocate();
302 ring_[head.index] =
new (p) value_type(std::forward<Args...>(args...));
306 value_allocator_.deallocate(p);
309 head_.store(next_index(head), std::memory_order_release);
317template <
typename T,
typename A>
318bool lock_free_spmc_object_ring_buffer<T, A>::try_pop(value_type& x)
320 tagged_index_t tail = tail_.load(std::memory_order_acquire);
323 const tagged_index_t head = head_.load(std::memory_order_acquire);
324 if (tagged_index_t::empty(head, tail))
328 value_type* p = ring_[tail.index];
329 if (tail_.compare_exchange_weak(tail, next_index(tail)))
333 value_allocator_.deallocate(p);
lass extensions to the standard library
Library for Assembled Shared Sources.