Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/scudo/standalone/list.h
35291 views
1
//===-- list.h --------------------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef SCUDO_LIST_H_
10
#define SCUDO_LIST_H_
11
12
#include "internal_defs.h"
13
14
namespace scudo {
15
16
// Intrusive POD singly and doubly linked list.
17
// An object with all zero fields should represent a valid empty list. clear()
18
// should be called on all non-zero-initialized objects before using.
19
20
template <class T> class IteratorBase {
21
public:
22
explicit IteratorBase(T *CurrentT) : Current(CurrentT) {}
23
IteratorBase &operator++() {
24
Current = Current->Next;
25
return *this;
26
}
27
bool operator!=(IteratorBase Other) const { return Current != Other.Current; }
28
T &operator*() { return *Current; }
29
30
private:
31
T *Current;
32
};
33
34
template <class T> struct IntrusiveList {
35
bool empty() const { return Size == 0; }
36
uptr size() const { return Size; }
37
38
T *front() { return First; }
39
const T *front() const { return First; }
40
T *back() { return Last; }
41
const T *back() const { return Last; }
42
43
void clear() {
44
First = Last = nullptr;
45
Size = 0;
46
}
47
48
typedef IteratorBase<T> Iterator;
49
typedef IteratorBase<const T> ConstIterator;
50
51
Iterator begin() { return Iterator(First); }
52
Iterator end() { return Iterator(nullptr); }
53
54
ConstIterator begin() const { return ConstIterator(First); }
55
ConstIterator end() const { return ConstIterator(nullptr); }
56
57
void checkConsistency() const;
58
59
protected:
60
uptr Size = 0;
61
T *First = nullptr;
62
T *Last = nullptr;
63
};
64
65
template <class T> void IntrusiveList<T>::checkConsistency() const {
66
if (Size == 0) {
67
CHECK_EQ(First, nullptr);
68
CHECK_EQ(Last, nullptr);
69
} else {
70
uptr Count = 0;
71
for (T *I = First;; I = I->Next) {
72
Count++;
73
if (I == Last)
74
break;
75
}
76
CHECK_EQ(this->size(), Count);
77
CHECK_EQ(Last->Next, nullptr);
78
}
79
}
80
81
template <class T> struct SinglyLinkedList : public IntrusiveList<T> {
82
using IntrusiveList<T>::First;
83
using IntrusiveList<T>::Last;
84
using IntrusiveList<T>::Size;
85
using IntrusiveList<T>::empty;
86
87
void push_back(T *X) {
88
X->Next = nullptr;
89
if (empty())
90
First = X;
91
else
92
Last->Next = X;
93
Last = X;
94
Size++;
95
}
96
97
void push_front(T *X) {
98
if (empty())
99
Last = X;
100
X->Next = First;
101
First = X;
102
Size++;
103
}
104
105
void pop_front() {
106
DCHECK(!empty());
107
First = First->Next;
108
if (!First)
109
Last = nullptr;
110
Size--;
111
}
112
113
// Insert X next to Prev
114
void insert(T *Prev, T *X) {
115
DCHECK(!empty());
116
DCHECK_NE(Prev, nullptr);
117
DCHECK_NE(X, nullptr);
118
X->Next = Prev->Next;
119
Prev->Next = X;
120
if (Last == Prev)
121
Last = X;
122
++Size;
123
}
124
125
void extract(T *Prev, T *X) {
126
DCHECK(!empty());
127
DCHECK_NE(Prev, nullptr);
128
DCHECK_NE(X, nullptr);
129
DCHECK_EQ(Prev->Next, X);
130
Prev->Next = X->Next;
131
if (Last == X)
132
Last = Prev;
133
Size--;
134
}
135
136
void append_back(SinglyLinkedList<T> *L) {
137
DCHECK_NE(this, L);
138
if (L->empty())
139
return;
140
if (empty()) {
141
*this = *L;
142
} else {
143
Last->Next = L->First;
144
Last = L->Last;
145
Size += L->size();
146
}
147
L->clear();
148
}
149
};
150
151
template <class T> struct DoublyLinkedList : IntrusiveList<T> {
152
using IntrusiveList<T>::First;
153
using IntrusiveList<T>::Last;
154
using IntrusiveList<T>::Size;
155
using IntrusiveList<T>::empty;
156
157
void push_front(T *X) {
158
X->Prev = nullptr;
159
if (empty()) {
160
Last = X;
161
} else {
162
DCHECK_EQ(First->Prev, nullptr);
163
First->Prev = X;
164
}
165
X->Next = First;
166
First = X;
167
Size++;
168
}
169
170
// Inserts X before Y.
171
void insert(T *X, T *Y) {
172
if (Y == First)
173
return push_front(X);
174
T *Prev = Y->Prev;
175
// This is a hard CHECK to ensure consistency in the event of an intentional
176
// corruption of Y->Prev, to prevent a potential write-{4,8}.
177
CHECK_EQ(Prev->Next, Y);
178
Prev->Next = X;
179
X->Prev = Prev;
180
X->Next = Y;
181
Y->Prev = X;
182
Size++;
183
}
184
185
void push_back(T *X) {
186
X->Next = nullptr;
187
if (empty()) {
188
First = X;
189
} else {
190
DCHECK_EQ(Last->Next, nullptr);
191
Last->Next = X;
192
}
193
X->Prev = Last;
194
Last = X;
195
Size++;
196
}
197
198
void pop_front() {
199
DCHECK(!empty());
200
First = First->Next;
201
if (!First)
202
Last = nullptr;
203
else
204
First->Prev = nullptr;
205
Size--;
206
}
207
208
// The consistency of the adjacent links is aggressively checked in order to
209
// catch potential corruption attempts, that could yield a mirrored
210
// write-{4,8} primitive. nullptr checks are deemed less vital.
211
void remove(T *X) {
212
T *Prev = X->Prev;
213
T *Next = X->Next;
214
if (Prev) {
215
CHECK_EQ(Prev->Next, X);
216
Prev->Next = Next;
217
}
218
if (Next) {
219
CHECK_EQ(Next->Prev, X);
220
Next->Prev = Prev;
221
}
222
if (First == X) {
223
DCHECK_EQ(Prev, nullptr);
224
First = Next;
225
} else {
226
DCHECK_NE(Prev, nullptr);
227
}
228
if (Last == X) {
229
DCHECK_EQ(Next, nullptr);
230
Last = Prev;
231
} else {
232
DCHECK_NE(Next, nullptr);
233
}
234
Size--;
235
}
236
};
237
238
} // namespace scudo
239
240
#endif // SCUDO_LIST_H_
241
242