32template <
typename T,
size_t Capacity>
34 static_assert(Capacity >= 2 && (Capacity & (Capacity - 1)) == 0,
35 "PendingQueue capacity must be a power of two");
36 static_assert(std::is_default_constructible_v<T> && std::is_move_assignable_v<T>,
37 "PendingQueue payload must be default constructible and move assignable");
42 for (
size_t i = 0; i < Capacity; ++i) {
43 m_cells[i].sequence.store(i, std::memory_order_relaxed);
57 [[nodiscard]]
bool push(T&&
value)
noexcept(std::is_nothrow_move_assignable_v<T>)
59 size_t pos =
m_enqueue.load(std::memory_order_relaxed);
64 const size_t seq = cell->
sequence.load(std::memory_order_acquire);
65 const auto diff =
static_cast<std::intptr_t
>(seq) -
static_cast<std::intptr_t
>(pos);
68 if (
m_enqueue.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) {
71 }
else if (diff < 0) {
74 pos =
m_enqueue.load(std::memory_order_relaxed);
79 cell->
sequence.store(pos + 1, std::memory_order_release);
92 template <
typename Apply>
95 size_t pos =
m_dequeue.load(std::memory_order_relaxed);
100 if (cell.
sequence.load(std::memory_order_acquire) != pos + 1) {
106 cell.
sequence.store(pos + Capacity, std::memory_order_release);
109 m_dequeue.store(pos, std::memory_order_relaxed);
111 std::forward<Apply>(apply)(std::move(
value));
125 return m_enqueue.load(std::memory_order_relaxed)
126 !=
m_dequeue.load(std::memory_order_relaxed);
130 static constexpr size_t MASK = Capacity - 1;
std::atomic< size_t > m_dequeue
PendingQueue & operator=(const PendingQueue &)=delete
bool push(T &&value) noexcept(std::is_nothrow_move_assignable_v< T >)
Enqueue an operation from any thread.
std::atomic< size_t > m_enqueue
PendingQueue(const PendingQueue &)=delete
PendingQueue & operator=(PendingQueue &&)=delete
std::array< Cell, Capacity > m_cells
static constexpr size_t MASK
PendingQueue(PendingQueue &&)=delete
bool has_pending() const noexcept
Cheap check for claimed operations awaiting a drain.
size_t drain(Apply &&apply)
Apply and remove every published operation in claim order.
Bounded multi-producer, single-consumer queue of deferred operations.
std::atomic< size_t > sequence