6 #ifndef XENIUM_VYUKOV_BOUNDED_QUEUE_HPP
7 #define XENIUM_VYUKOV_BOUNDED_QUEUE_HPP
9 #include <xenium/parameter.hpp>
10 #include <xenium/utils.hpp>
19 #pragma warning(disable : 4324) // structure was padded due to alignment specifier
58 template <
class T,
class... Policies>
63 static constexpr
bool default_to_weak =
72 assert(size >= 2 && utils::is_power_of_two(size));
73 for (std::size_t i = 0; i < size; ++i) {
74 cells[i].sequence.store(i, std::memory_order_relaxed);
76 enqueue_pos.store(0, std::memory_order_relaxed);
77 dequeue_pos.store(0, std::memory_order_relaxed);
98 template <
class... Args>
100 return do_try_push<default_to_weak>(std::forward<Args>(args)...);
120 template <
class... Args>
122 return do_try_push<false>(std::forward<Args>(args)...);
142 template <
class... Args>
144 return do_try_push<true>(std::forward<Args>(args)...);
158 [[nodiscard]]
bool try_pop(T& result) {
return do_try_pop<default_to_weak>(result); }
171 [[nodiscard]]
bool try_pop_strong(T& result) {
return do_try_pop<false>(result); }
184 [[nodiscard]]
bool try_pop_weak(T& result) {
return do_try_pop<true>(result); }
187 template <
bool Weak,
class... Args>
188 bool do_try_push(Args&&... args) {
190 std::size_t pos = enqueue_pos.load(std::memory_order_relaxed);
192 c = &cells[pos & index_mask];
194 std::size_t seq = c->sequence.load(std::memory_order_acquire);
196 if (enqueue_pos.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) {
204 pos = enqueue_pos.load(std::memory_order_relaxed);
206 auto pos2 = enqueue_pos.load(std::memory_order_relaxed);
207 if (pos2 == pos && dequeue_pos.load(std::memory_order_relaxed) + index_mask + 1 == pos) {
214 assign_value(c->value, std::forward<Args>(args)...);
216 c->sequence.store(pos + 1, std::memory_order_release);
221 bool do_try_pop(T& result) {
223 std::size_t pos = dequeue_pos.load(std::memory_order_relaxed);
225 c = &cells[pos & index_mask];
227 std::size_t seq = c->sequence.load(std::memory_order_acquire);
228 auto new_pos = pos + 1;
229 if (seq == new_pos) {
230 if (dequeue_pos.compare_exchange_weak(pos, new_pos, std::memory_order_relaxed)) {
238 pos = dequeue_pos.load(std::memory_order_relaxed);
240 auto pos2 = dequeue_pos.load(std::memory_order_relaxed);
241 if (pos2 == pos && enqueue_pos.load(std::memory_order_relaxed) == pos) {
248 result = std::move(c->value);
250 c->sequence.store(pos + index_mask + 1, std::memory_order_release);
254 void assign_value(T& v,
const T& source) { v = source; }
255 void assign_value(T& v, T&& source) { v = std::move(source); }
256 template <
class... Args>
257 void assign_value(T& v, Args&&... args) {
258 v = T{std::forward<Args>(args)...};
263 std::atomic<std::size_t> sequence;
267 std::unique_ptr<cell[]> cells;
268 const std::size_t index_mask;
269 alignas(64) std::atomic<size_t> enqueue_pos;
270 alignas(64) std::atomic<size_t> dequeue_pos;