librf

intrusive_link_queue.h
1 #pragma once
2
3 namespace resumef
4 {
5 template<class _Node, class _Nodeptr = _Node*, class _Sty = uint32_t>
6 struct intrusive_link_queue
7 {
8 using node_type = _Node;
9 using node_ptr_type = _Nodeptr;
10 using size_type = _Sty;
11 public:
12 intrusive_link_queue();
13
14 intrusive_link_queue(const intrusive_link_queue&) = delete;
15 intrusive_link_queue(intrusive_link_queue&&) = default;
16 intrusive_link_queue& operator =(const intrusive_link_queue&) = delete;
17 intrusive_link_queue& operator =(intrusive_link_queue&&) = default;
18
19 auto size() const noexcept->size_type;
20 bool empty() const noexcept;
21 void push_back(node_ptr_type node) noexcept;
22 auto try_pop() noexcept->node_ptr_type;
23 private:
24 node_ptr_type _head;
25 node_ptr_type _tail;
26
27 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
28 std::atomic<size_type> m_count;
29 #endif
30 };
31
32 template<class _Node, class _Nodeptr, class _Sty>
33 intrusive_link_queue<_Node, _Nodeptr, _Sty>::intrusive_link_queue()
34 : _head(nullptr)
35 , _tail(nullptr)
36 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
37 , m_count(0)
38 #endif
39 {
40 }
41
42 template<class _Node, class _Nodeptr, class _Sty>
43 auto intrusive_link_queue<_Node, _Nodeptr, _Sty>::size() const noexcept->size_type
44 {
45 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
46 return m_count.load(std::memory_order_acquire);
47 #else
48 size_type count = 0;
49 for (node_type* node = _head; node != nullptr; node = node->next)
50 ++count;
51 return count;
52 #endif // _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
53 }
54
55 template<class _Node, class _Nodeptr, class _Sty>
56 bool intrusive_link_queue<_Node, _Nodeptr, _Sty>::empty() const noexcept
57 {
58 return _head == nullptr;
59 }
60
61 template<class _Node, class _Nodeptr, class _Sty>
62 void intrusive_link_queue<_Node, _Nodeptr, _Sty>::push_back(node_ptr_type node) noexcept
63 {
64 assert(node != nullptr);
65
66 node->_next = nullptr;
67 if (_head == nullptr)
68 {
69 _head = _tail = node;
70 }
71 else
72 {
73 _tail->_next = node;
74 _tail = node;
75 }
76
77 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
78 m_count.fetch_add(1, std::memory_order_acq_rel);
79 #endif
80 }
81
82 template<class _Node, class _Nodeptr, class _Sty>
83 auto intrusive_link_queue<_Node, _Nodeptr, _Sty>::try_pop() noexcept->node_ptr_type
84 {
85 if (_head == nullptr)
86 return nullptr;
87
88 node_ptr_type node = _head;
89 _head = node->_next;
90 node->_next = nullptr;
91
92 if (_tail == node)
93 {
94 assert(node->_next == nullptr);
95 _tail = nullptr;
96 }
97
98 #ifdef _WITH_LOCK_FREE_Q_KEEP_REAL_SIZE
99 m_count.fetch_sub(1, std::memory_order_acq_rel);
100 #endif
101
102 return node;
103 }
104 }