9 template<
class _Ty,
bool _Option = false,
class _Sty = u
int32_t>
12 using value_type = _Ty;
13 using size_type = _Sty;
15 static constexpr
bool use_option = _Option;
16 using optional_type = std::conditional_t<use_option, std::optional<value_type>, value_type>;
18 ring_queue(
size_t sz);
20 ring_queue(
const ring_queue&) =
delete;
21 ring_queue(ring_queue&&) =
default;
22 ring_queue& operator =(
const ring_queue&) =
delete;
23 ring_queue& operator =(ring_queue&&) =
default;
25 auto size() const noexcept->size_type;
26 auto capacity() const noexcept->size_type;
27 bool empty() const noexcept;
28 bool full() const noexcept;
30 bool try_push(U&& value) noexcept(std::is_nothrow_move_assignable_v<U>);
32 bool try_pop(U& value) noexcept(std::is_nothrow_move_assignable_v<value_type>);
34 using container_type = std::unique_ptr<optional_type[]>;
35 container_type m_bufferPtr;
36 size_type m_bufferSize;
38 size_type m_writeIndex;
39 size_type m_readIndex;
40 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
41 std::atomic<size_type> m_count;
44 auto nextIndex(size_type a_count)
const noexcept->size_type;
47 template<
class _Ty,
bool _Option,
class _Sty>
48 ring_queue<_Ty, _Option, _Sty>::ring_queue(
size_t sz)
49 : m_bufferPtr(new optional_type[sz + 1])
50 , m_bufferSize(static_cast<size_type>(sz + 1))
53 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
57 assert(sz < (std::numeric_limits<size_type>::max)());
60 template<
class _Ty,
bool _Option,
class _Sty>
61 auto ring_queue<_Ty, _Option, _Sty>::nextIndex(size_type a_count)
const noexcept->size_type
63 return static_cast<size_type
>((a_count + 1) % m_bufferSize);
66 template<
class _Ty,
bool _Option,
class _Sty>
67 auto ring_queue<_Ty, _Option, _Sty>::size() const noexcept->size_type
69 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
70 return m_count.load(std::memory_order_acquire);
72 if (m_writeIndex >= m_readIndex)
73 return (m_writeIndex - m_readIndex);
75 return (m_bufferSize + m_writeIndex - m_readIndex);
76 #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
79 template<
class _Ty,
bool _Option,
class _Sty>
80 auto ring_queue<_Ty, _Option, _Sty>::capacity() const noexcept->size_type
82 return m_bufferSize - 1;
85 template<
class _Ty,
bool _Option,
class _Sty>
86 bool ring_queue<_Ty, _Option, _Sty>::empty() const noexcept
88 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
89 return m_count.load(std::memory_order_acquire) == 0;
91 return m_writeIndex == m_readIndex;
92 #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
95 template<
class _Ty,
bool _Option,
class _Sty>
96 bool ring_queue<_Ty, _Option, _Sty>::full() const noexcept
98 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
99 return (m_count.load(std::memory_order_acquire) == (m_bufferSize - 1));
101 return nextIndex(m_writeIndex) == m_readIndex;
102 #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
105 template<
class _Ty,
bool _Option,
class _Sty>
107 bool ring_queue<_Ty, _Option, _Sty>::try_push(U&& value) noexcept(std::is_nothrow_move_assignable_v<U>)
109 auto nextWriteIndex = nextIndex(m_writeIndex);
110 if (nextWriteIndex == m_readIndex)
113 assert(m_writeIndex < m_bufferSize);
115 m_bufferPtr[m_writeIndex] = std::move(value);
116 m_writeIndex = nextWriteIndex;
118 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
119 m_count.fetch_add(1, std::memory_order_acq_rel);
124 template<
class _Ty,
bool _Option,
class _Sty>
126 bool ring_queue<_Ty, _Option, _Sty>::try_pop(U& value) noexcept(std::is_nothrow_move_assignable_v<value_type>)
128 if (m_readIndex == m_writeIndex)
131 optional_type& ov = m_bufferPtr[m_readIndex];
132 if constexpr (use_option)
134 value = std::move(ov).value();
139 value = std::move(ov);
142 m_readIndex = nextIndex(m_readIndex);
144 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
145 m_count.fetch_sub(1, std::memory_order_acq_rel);