18#include "../CompilerSupport.hpp"
45template<
typename T, std::
size_t Capacity>
48 static_assert(Capacity > 1);
56 using container_type = std::array<std::byte, (Capacity + 1) *
sizeof(T)>;
58 using size_type =
typename container_type::size_type;
59 using reference = value_type &;
60 using const_reference = value_type
const &;
72 [[nodiscard]]
bool empty() const noexcept;
75 [[nodiscard]]
bool full() const noexcept;
83 [[nodiscard]] size_type
size() const noexcept;
86 [[nodiscard]] constexpr size_type
capacity() const noexcept {
return Capacity; }
99 requires std::is_same_v<std::decay_t<U>, T>
111 alignas(T) container_type _queue;
114 using atomic_itr = std::atomic<typename container_type::iterator>;
116#ifdef __cpp_lib_hardware_interference_size
119 DFX_DIAGNOSTIC_IGNORE(
"-Winterference-size")
120 static constexpr auto alignSize =
std::hardware_destructive_interference_size;
123 static constexpr auto alignSize = 64;
126 struct alignas(alignSize) ReadSide
131 struct alignas(alignSize) WriteSide
137template<
typename T, std::
size_t Capacity>
139 : _read {
std::begin(_queue) }
140 , _write {
std::begin(_queue) }
144template<
typename T, std::
size_t Capacity>
147 if constexpr (!std::is_trivially_destructible_v<T>)
150 for (
auto rItr = _read.itr.load(std::memory_order_relaxed); rItr != _write.itr.load(std::memory_order_relaxed);)
152 reinterpret_cast<T *
>(rItr)->~T();
155 if (rItr == std::end(_queue))
156 rItr = std::begin(_queue);
161template<
typename T, std::
size_t Capacity>
167template<
typename T, std::
size_t Capacity>
173template<
typename T, std::
size_t Capacity>
176 using const_iterator = container_type::const_iterator;
178 auto const rItr = const_iterator(_read.itr.load(std::memory_order_acquire));
179 auto const wItr = const_iterator(_write.itr.load(std::memory_order_acquire));
181 auto const rPos =
static_cast<size_type
>(std::distance(std::begin(_queue), rItr)) /
sizeof(T);
182 auto const wPos =
static_cast<size_type
>(std::distance(std::begin(_queue), wItr)) /
sizeof(T);
184 return wPos >= rPos ? (wPos - rPos) : (Capacity + 1 + wPos - rPos);
187template<
typename T, std::
size_t Capacity>
189requires std::is_same_v<std::decay_t<U>, T>
192 auto const wItr = _write.itr.load(std::memory_order_relaxed);
193 auto nextWItr = wItr +
sizeof(T);
194 if (nextWItr == std::end(_queue))
195 nextWItr = std::begin(_queue);
196 auto const isQueueFull = [nextWItr,
this]
noexcept {
return nextWItr == _read.itr.load(std::memory_order_acquire); };
201 new (wItr) T(std::forward<U>(value));
203 _write.itr.store(nextWItr, std::memory_order_release);
207template<
typename T, std::
size_t Capacity>
210 auto const rItr = _read.itr.load(std::memory_order_relaxed);
211 auto const isQueueEmpty = [&rItr,
this]
noexcept {
return rItr == _write.itr.load(std::memory_order_acquire); };
216 auto nextRItr = rItr +
sizeof(T);
217 if (nextRItr == std::end(_queue))
218 nextRItr = std::begin(_queue);
220 auto value = std::move(*std::launder(
reinterpret_cast<T *
>(rItr)));
222 if constexpr (!std::is_trivially_destructible_v<T>)
223 reinterpret_cast<T *
>(rItr)->~T();
225 _read.itr.store(nextRItr, std::memory_order_release);
Convenience macros to explicitly control copy and move semantics.
#define DFX_DISABLE_COPY_AND_MOVE(ClassName)
Disable both copy and move.
Definition CopyMoveControl.hpp:37
bool full() const noexcept
Definition SpscFixedQueue.hpp:168
constexpr size_type capacity() const noexcept
Returns the maximum capacity of the queue.
Definition SpscFixedQueue.hpp:86
size_type size() const noexcept
Definition SpscFixedQueue.hpp:174
SpscFixedQueue()
Default constructor.
Definition SpscFixedQueue.hpp:138
bool empty() const noexcept
Checks if the queue contains no elements.
Definition SpscFixedQueue.hpp:162
std::optional< T > tryPop()
Attempts to pop an element from the queue.
Definition SpscFixedQueue.hpp:208
~SpscFixedQueue()
Destructor.
Definition SpscFixedQueue.hpp:145
bool tryPush(U &&value)
Attempts to push an element into the queue.
Definition SpscFixedQueue.hpp:190
Definition SystemConfigCommandHandler.hpp:15