Condy v1.8
C++ Asynchronous System Call Layer for Linux
Loading...
Searching...
No Matches
intrusive.hpp
Go to the documentation of this file.
1
5
6#pragma once
7
9#include <cassert>
10#include <utility>
11
12namespace condy {
13namespace detail {
14
15template <typename M, typename T>
16constexpr ptrdiff_t offset_of(M T::*member) noexcept {
17 constexpr T *dummy = nullptr;
18 return reinterpret_cast<ptrdiff_t>(&(dummy->*member));
19}
20
21template <typename M, typename T>
22T *container_of(M T::*member, M *ptr) noexcept {
23 auto offset = offset_of(member);
24 // NOLINTNEXTLINE(performance-no-int-to-ptr)
25 return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(ptr) - offset);
26}
27
28struct SingleLinkEntry {
29 SingleLinkEntry *next = nullptr;
30};
31
32struct DoubleLinkEntry {
33 DoubleLinkEntry *next = nullptr;
34 DoubleLinkEntry *prev = nullptr;
35};
36
37class SingleLinkListImpl {
38public:
39 SingleLinkListImpl() = default;
40 SingleLinkListImpl(SingleLinkListImpl &&other) noexcept
41 : head_(std::exchange(other.head_, nullptr)),
42 tail_(std::exchange(other.tail_, nullptr)) {}
43 SingleLinkListImpl &operator=(SingleLinkListImpl &&other) noexcept {
44 if (this != &other) {
45 assert(empty());
46 head_ = std::exchange(other.head_, nullptr);
47 tail_ = std::exchange(other.tail_, nullptr);
48 }
49 return *this;
50 }
51
52 CONDY_DELETE_COPY(SingleLinkListImpl);
53
54 void push_back(SingleLinkEntry *entry) noexcept {
55 assert(entry != nullptr);
56 assert(entry->next == nullptr);
57 if (!head_) {
58 head_ = entry;
59 tail_ = entry;
60 } else {
61 tail_->next = entry;
62 tail_ = entry;
63 }
64 }
65
66 void push_back(SingleLinkListImpl &other) noexcept {
67 if (other.empty()) {
68 return;
69 }
70 if (empty()) {
71 head_ = other.head_;
72 tail_ = other.tail_;
73 } else {
74 tail_->next = other.head_;
75 tail_ = other.tail_;
76 }
77 other.head_ = nullptr;
78 other.tail_ = nullptr;
79 }
80
81 bool empty() const noexcept { return head_ == nullptr; }
82
83 SingleLinkEntry *pop_front() noexcept {
84 if (empty()) {
85 return nullptr;
86 }
87 SingleLinkEntry *entry = head_;
88 head_ = head_->next;
89 if (!head_) {
90 tail_ = nullptr;
91 }
92 entry->next = nullptr;
93 return entry;
94 }
95
96private:
97 SingleLinkEntry *head_ = nullptr;
98 SingleLinkEntry *tail_ = nullptr;
99};
100
101class DoubleLinkListImpl {
102public:
103 DoubleLinkListImpl() = default;
104 DoubleLinkListImpl(DoubleLinkListImpl &&other) noexcept
105 : head_(std::exchange(other.head_, nullptr)),
106 tail_(std::exchange(other.tail_, nullptr)) {}
107 DoubleLinkListImpl &operator=(DoubleLinkListImpl &&other) noexcept {
108 if (this != &other) {
109 assert(empty());
110 head_ = std::exchange(other.head_, nullptr);
111 tail_ = std::exchange(other.tail_, nullptr);
112 }
113 return *this;
114 }
115
116 CONDY_DELETE_COPY(DoubleLinkListImpl);
117
118 void push_back(DoubleLinkEntry *entry) noexcept {
119 assert(entry != nullptr);
120 assert(entry->next == nullptr && entry->prev == nullptr);
121 entry->next = nullptr;
122 entry->prev = tail_;
123 if (!head_) {
124 head_ = entry;
125 tail_ = entry;
126 } else {
127 tail_->next = entry;
128 tail_ = entry;
129 }
130 }
131
132 bool empty() const noexcept { return head_ == nullptr; }
133
134 DoubleLinkEntry *pop_front() noexcept {
135 if (empty()) {
136 return nullptr;
137 }
138 DoubleLinkEntry *entry = head_;
139 head_ = head_->next;
140 if (head_) {
141 head_->prev = nullptr;
142 } else {
143 tail_ = nullptr;
144 }
145 entry->next = nullptr;
146 entry->prev = nullptr;
147 return entry;
148 }
149
150 bool remove(DoubleLinkEntry *entry) noexcept {
151 assert(entry != nullptr);
152 if (entry->prev == nullptr && entry->next == nullptr &&
153 head_ != entry) {
154 return false;
155 }
156 if (entry->prev) {
157 entry->prev->next = entry->next;
158 } else {
159 assert(head_ == entry);
160 head_ = entry->next;
161 }
162 if (entry->next) {
163 entry->next->prev = entry->prev;
164 } else {
165 assert(tail_ == entry);
166 tail_ = entry->prev;
167 }
168 entry->next = nullptr;
169 entry->prev = nullptr;
170 return true;
171 }
172
173private:
174 DoubleLinkEntry *head_ = nullptr;
175 DoubleLinkEntry *tail_ = nullptr;
176};
177
178template <typename T, SingleLinkEntry T::*Member> class IntrusiveSingleList {
179public:
180 void push_back(T *item) noexcept { impl_.push_back(&(item->*Member)); }
181
182 void push_back(IntrusiveSingleList other) noexcept {
183 impl_.push_back(other.impl_);
184 }
185
186 bool empty() const noexcept { return impl_.empty(); }
187
188 T *pop_front() noexcept {
189 SingleLinkEntry *entry = impl_.pop_front();
190 return entry ? container_of(Member, entry) : nullptr;
191 }
192
193private:
194 SingleLinkListImpl impl_;
195};
196
197template <typename T, DoubleLinkEntry T::*Member> class IntrusiveDoubleList {
198public:
199 void push_back(T *item) noexcept { impl_.push_back(&(item->*Member)); }
200
201 bool empty() const noexcept { return impl_.empty(); }
202
203 T *pop_front() noexcept {
204 DoubleLinkEntry *entry = impl_.pop_front();
205 return entry ? container_of(Member, entry) : nullptr;
206 }
207
208 bool remove(T *item) noexcept { return impl_.remove(&(item->*Member)); }
209
210private:
211 DoubleLinkListImpl impl_;
212};
213
214} // namespace detail
215} // namespace condy
The main namespace for the Condy library.
Definition condy.hpp:37
Internal utility classes and functions used by Condy.