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 }