41#if defined(ARCH_arm64)
42 static constexpr size_t stable_cache_alignment = 256U;
43#elif defined(ARCH_ppc32)
44 static constexpr size_t stable_cache_alignment = 128U;
46 static constexpr size_t stable_cache_alignment = 64U;
49#ifdef __GCC_DESTRUCTIVE_SIZE
50static_assert(stable_cache_alignment >= __GCC_DESTRUCTIVE_SIZE,
51 "Stable cache alignment not sufficient");
62template<
typename SEQUENCE_TYPE>
66 using Sequence = SEQUENCE_TYPE;
67 using Generation = std::atomic<Sequence>;
70 static constexpr Sequence
const nil = 0U;
86 throw std::invalid_argument(
"Zero items not supported.");
88 if (items != std::bit_ceil(items))
89 throw std::invalid_argument(
"Number of items must be power of two.");
105 auto items = mask + 1;
106 if (items != std::bit_ceil(items))
107 throw std::length_error(
"Invalid mask.");
124template<
typename SEQUENCE_TYPE>
128 using Sequence = SEQUENCE_TYPE;
129 using Generation =
typename Ring_buffer<Sequence>::Generation;
131 template<
typename S,
typename T, auto G>
friend class Ring_buffer_producer;
132 template<
typename S,
typename T, auto G>
133 friend class Ring_buffer_consumer_raw;
153 {
return _alignment; }
161 {
return _mask + 1; }
171 alignas(stable_cache_alignment)
size_t _mask;
174 alignas(stable_cache_alignment) Generation _tail;
186template<
typename ITEM_TYPE>
187static constexpr size_t ring_slot_alignment = std::bit_ceil(
sizeof(ITEM_TYPE));
203template<
typename ITEM_TYPE, auto GENERATION_PTR>
208 using Item = ITEM_TYPE;
210 template<
typename S,
typename T, auto G>
friend class Ring_buffer_producer;
211 template<
typename S,
typename T, auto G>
212 friend class Ring_buffer_consumer_raw;
221 static size_t size(
size_t const items)
222 {
return items *
sizeof(This); }
227 auto generation() const noexcept
228 {
return std::atomic_ref(_data.*GENERATION_PTR); }
244template<
typename SEQUENCE_TYPE,
typename ITEM_TYPE, auto GENERATION_PTR>
251 using Item = ITEM_TYPE;
272 size_t const items) : _status(status), _slots(slots)
276 _status._version = version;
277 _status._alignment = stable_cache_alignment;
278 _status._mask =
items - 1;
281 for (
size_t i = 0; i <
items; ++i)
287 {
return _status.items(); }
299 auto next = ++_status._tail;
300 auto index = next & _status._mask;
302 auto &generation = _slots[index].generation();
303 auto &slot = _slots[index]._data;
305 generation.store(
Super::nil, std::memory_order_release);
307 generation.store(next, std::memory_order_release);
330template<
typename SEQUENCE_TYPE,
typename ITEM_TYPE, auto GENERATION_PTR>
337 using Sequence = SEQUENCE_TYPE;
338 using Item = ITEM_TYPE;
392 : _status(status), _slots(slots)
397 {
return _status.items(); }
433 Sequence *drops =
nullptr)
const
442 auto index = current & _status._mask;
444 auto const &generation = _slots[index].generation();
445 auto const &slot = _slots[index]._data;
447 auto seen = generation.load();
458 seen = generation.load();
471 Sequence head = _status._tail;
476 head -= _status._mask;
480 *drops = head - current;
483 return State::Dropped;
489 Status
const &_status;
506template<
typename SEQUENCE_TYPE,
typename ITEM_TYPE, auto GENERATION_PTR>
511 using Sequence = SEQUENCE_TYPE;
512 using Item = ITEM_TYPE;
521 using Yield = std::function<bool (Sequence)>;
533 : Super(status, slots)
557 State
peek(Item &item, Drop_policy policy, Sequence *drops =
nullptr)
559 const std::lock_guard guard(_lock);
593 Drop_policy policy, Yield
const &yield,
594 Sequence *drops =
nullptr)
600 size_t idle_cycles = 0;
604 Sequence current_drops;
605 auto status =
peek(
items[count], policy, ¤t_drops);
607 if (status == State::Dropped)
613 *drops = current_drops;
618 if (status == State::Ready)
624 if (count == capacity)
630 if (status == State::Idle)
640 if (yield(idle_cycles))
656 Sequence _current = 0;
State
Status of the dequeue operation.
Ring_buffer_consumer_raw(Status const &status, Slot const *slots)
Construct ring buffer consumer.
size_t items() const
Get the number of items.
State peek(Item &item, Drop_policy policy, Sequence ¤t, Sequence *drops=nullptr) const
Poll and possibly dequeue an item from the ring buffer.
Drop_policy
Item drop policy.
@ Minimal
Minimal item drop policy.
@ Conservative
Conservative item drop policy.
size_t dequeue(Item items[], size_t capacity, size_t burst, Drop_policy policy, Yield const &yield, Sequence *drops=nullptr)
Dequeue items from the ring buffer.
State peek(Item &item, Drop_policy policy, Sequence *drops=nullptr)
Poll and possibly dequeue an item from the ring buffer.
Ring_buffer_consumer(Status const &status, Slot const *slots)
Construct ring buffer consumer.
Ring_buffer_producer(Status &status, Slot &slots, unsigned const version, size_t const items)
Construct ring buffer producer.
void enqueue(Item const &item) const
Enqueue an item in the ring buffer.
size_t items() const
Get the number of items.
static void check_mask(size_t const mask)
Check that the item mask is a power of two minus one.
static constexpr Sequence const nil
Invalid (non-committed) items set their sequence counter to 0.
static void check_items(size_t const items)
Check that the number of items is a power of two.
static size_t size(size_t const items)
Get the size (in bytes) of the given count of items.
size_t mask() const
Get the item mask.
size_t items() const
Get the number of items.
size_t alignment() const
Get the stable alignment of the ring buffer status members.
unsigned version() const
Get the version of the ring buffer items.