Condy v1.1.0
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
8#include "condy/utils.hpp"
9#include <cassert>
10#include <utility>
11
12namespace condy {
13
14struct SingleLinkEntry {
15 SingleLinkEntry *next = nullptr;
16};
17
18struct DoubleLinkEntry {
19 DoubleLinkEntry *next = nullptr;
20 DoubleLinkEntry *prev = nullptr;
21#ifndef NDEBUG
22 void *owner = nullptr;
23#endif
24};
25
26template <typename T, SingleLinkEntry T::*Member> class IntrusiveSingleList {
27public:
28 IntrusiveSingleList() = default;
29 IntrusiveSingleList(IntrusiveSingleList &&other) noexcept
30 : head_(std::exchange(other.head_, nullptr)),
31 tail_(std::exchange(other.tail_, nullptr)) {}
32 IntrusiveSingleList &operator=(IntrusiveSingleList &&other) noexcept {
33 if (this != &other) {
34 head_ = std::exchange(other.head_, nullptr);
35 tail_ = std::exchange(other.tail_, nullptr);
36 }
37 return *this;
38 }
39
40 IntrusiveSingleList(const IntrusiveSingleList &) = delete;
41 IntrusiveSingleList &operator=(const IntrusiveSingleList &) = delete;
42
43 void push_back(T *item) noexcept {
44 assert(item != nullptr);
45 SingleLinkEntry *entry = &(item->*Member);
46 assert(entry->next == nullptr);
47 entry->next = nullptr;
48 if (!head_) {
49 head_ = entry;
50 tail_ = entry;
51 } else {
52 tail_->next = entry;
53 tail_ = entry;
54 }
55 }
56
57 void push_back(IntrusiveSingleList other) noexcept {
58 if (other.empty()) {
59 return;
60 }
61 if (empty()) {
62 head_ = other.head_;
63 tail_ = other.tail_;
64 } else {
65 tail_->next = other.head_;
66 tail_ = other.tail_;
67 }
68 }
69
70 bool empty() const noexcept { return head_ == nullptr; }
71
72 T *pop_front() noexcept {
73 if (empty()) {
74 return nullptr;
75 }
76 SingleLinkEntry *entry = head_;
77 head_ = head_->next;
78 if (!head_) {
79 tail_ = nullptr;
80 }
81 entry->next = nullptr;
82 return container_of(Member, entry);
83 }
84
85private:
86 SingleLinkEntry *head_ = nullptr;
87 SingleLinkEntry *tail_ = nullptr;
88};
89
90template <typename T, DoubleLinkEntry T::*Member> class IntrusiveDoubleList {
91public:
92 IntrusiveDoubleList() = default;
93
94 void push_back(T *item) noexcept {
95 assert(item != nullptr);
96 DoubleLinkEntry *entry = &(item->*Member);
97 assert(entry->next == nullptr && entry->prev == nullptr);
98 entry->next = nullptr;
99 entry->prev = tail_;
100 if (!head_) {
101 head_ = entry;
102 tail_ = entry;
103 } else {
104 tail_->next = entry;
105 tail_ = entry;
106 }
107#ifndef NDEBUG
108 assert(entry->owner == nullptr);
109 entry->owner = this;
110#endif
111 }
112
113 bool empty() const noexcept { return head_ == nullptr; }
114
115 T *pop_front() noexcept {
116 if (empty()) {
117 return nullptr;
118 }
119 DoubleLinkEntry *entry = head_;
120 head_ = head_->next;
121 if (head_) {
122 head_->prev = nullptr;
123 } else {
124 tail_ = nullptr;
125 }
126 entry->next = nullptr;
127 entry->prev = nullptr;
128#ifndef NDEBUG
129 assert(entry->owner == this);
130 entry->owner = nullptr;
131#endif
132 return container_of(Member, entry);
133 }
134
135 bool remove(T *item) noexcept {
136 assert(item != nullptr);
137 DoubleLinkEntry *entry = &(item->*Member);
138#ifndef NDEBUG
139 assert(entry->owner == this);
140 entry->owner = nullptr;
141#endif
142 if (entry->prev == nullptr && entry->next == nullptr &&
143 head_ != entry) {
144 return false;
145 }
146 if (entry->prev) {
147 entry->prev->next = entry->next;
148 } else {
149 assert(head_ == entry);
150 head_ = entry->next;
151 }
152 if (entry->next) {
153 entry->next->prev = entry->prev;
154 } else {
155 assert(tail_ == entry);
156 tail_ = entry->prev;
157 }
158 entry->next = nullptr;
159 entry->prev = nullptr;
160 return true;
161 }
162
163private:
164 DoubleLinkEntry *head_ = nullptr;
165 DoubleLinkEntry *tail_ = nullptr;
166};
167
168} // namespace condy
The main namespace for the Condy library.
Definition condy.hpp:28
Internal utility classes and functions used by Condy.