10b57cec5SDimitry Andric //===-- list.h --------------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #ifndef SCUDO_LIST_H_
100b57cec5SDimitry Andric #define SCUDO_LIST_H_
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include "internal_defs.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric namespace scudo {
150b57cec5SDimitry Andric
16480093f4SDimitry Andric // Intrusive POD singly and doubly linked list.
170b57cec5SDimitry Andric // An object with all zero fields should represent a valid empty list. clear()
180b57cec5SDimitry Andric // should be called on all non-zero-initialized objects before using.
19480093f4SDimitry Andric
20480093f4SDimitry Andric template <class T> class IteratorBase {
21480093f4SDimitry Andric public:
IteratorBase(T * CurrentT)22480093f4SDimitry Andric explicit IteratorBase(T *CurrentT) : Current(CurrentT) {}
23480093f4SDimitry Andric IteratorBase &operator++() {
24480093f4SDimitry Andric Current = Current->Next;
25480093f4SDimitry Andric return *this;
26480093f4SDimitry Andric }
27480093f4SDimitry Andric bool operator!=(IteratorBase Other) const { return Current != Other.Current; }
28480093f4SDimitry Andric T &operator*() { return *Current; }
29480093f4SDimitry Andric
30480093f4SDimitry Andric private:
31480093f4SDimitry Andric T *Current;
32480093f4SDimitry Andric };
33480093f4SDimitry Andric
34480093f4SDimitry Andric template <class T> struct IntrusiveList {
emptyIntrusiveList35480093f4SDimitry Andric bool empty() const { return Size == 0; }
sizeIntrusiveList36480093f4SDimitry Andric uptr size() const { return Size; }
37480093f4SDimitry Andric
frontIntrusiveList38480093f4SDimitry Andric T *front() { return First; }
frontIntrusiveList39480093f4SDimitry Andric const T *front() const { return First; }
backIntrusiveList40480093f4SDimitry Andric T *back() { return Last; }
backIntrusiveList41480093f4SDimitry Andric const T *back() const { return Last; }
420b57cec5SDimitry Andric
clearIntrusiveList430b57cec5SDimitry Andric void clear() {
440b57cec5SDimitry Andric First = Last = nullptr;
450b57cec5SDimitry Andric Size = 0;
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric
48480093f4SDimitry Andric typedef IteratorBase<T> Iterator;
49480093f4SDimitry Andric typedef IteratorBase<const T> ConstIterator;
500b57cec5SDimitry Andric
beginIntrusiveList51480093f4SDimitry Andric Iterator begin() { return Iterator(First); }
endIntrusiveList52480093f4SDimitry Andric Iterator end() { return Iterator(nullptr); }
53480093f4SDimitry Andric
beginIntrusiveList54480093f4SDimitry Andric ConstIterator begin() const { return ConstIterator(First); }
endIntrusiveList55480093f4SDimitry Andric ConstIterator end() const { return ConstIterator(nullptr); }
56480093f4SDimitry Andric
57480093f4SDimitry Andric void checkConsistency() const;
58480093f4SDimitry Andric
59480093f4SDimitry Andric protected:
60fe6060f1SDimitry Andric uptr Size = 0;
61fe6060f1SDimitry Andric T *First = nullptr;
62fe6060f1SDimitry Andric T *Last = nullptr;
63480093f4SDimitry Andric };
64480093f4SDimitry Andric
checkConsistency()65480093f4SDimitry Andric template <class T> void IntrusiveList<T>::checkConsistency() const {
66480093f4SDimitry Andric if (Size == 0) {
67480093f4SDimitry Andric CHECK_EQ(First, nullptr);
68480093f4SDimitry Andric CHECK_EQ(Last, nullptr);
690b57cec5SDimitry Andric } else {
70480093f4SDimitry Andric uptr Count = 0;
71480093f4SDimitry Andric for (T *I = First;; I = I->Next) {
72480093f4SDimitry Andric Count++;
73480093f4SDimitry Andric if (I == Last)
74480093f4SDimitry Andric break;
75480093f4SDimitry Andric }
76480093f4SDimitry Andric CHECK_EQ(this->size(), Count);
77480093f4SDimitry Andric CHECK_EQ(Last->Next, nullptr);
78480093f4SDimitry Andric }
79480093f4SDimitry Andric }
80480093f4SDimitry Andric
81480093f4SDimitry Andric template <class T> struct SinglyLinkedList : public IntrusiveList<T> {
82480093f4SDimitry Andric using IntrusiveList<T>::First;
83480093f4SDimitry Andric using IntrusiveList<T>::Last;
84480093f4SDimitry Andric using IntrusiveList<T>::Size;
85480093f4SDimitry Andric using IntrusiveList<T>::empty;
86480093f4SDimitry Andric
push_backSinglyLinkedList87480093f4SDimitry Andric void push_back(T *X) {
880b57cec5SDimitry Andric X->Next = nullptr;
89480093f4SDimitry Andric if (empty())
90480093f4SDimitry Andric First = X;
91480093f4SDimitry Andric else
920b57cec5SDimitry Andric Last->Next = X;
930b57cec5SDimitry Andric Last = X;
940b57cec5SDimitry Andric Size++;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric
push_frontSinglyLinkedList97480093f4SDimitry Andric void push_front(T *X) {
98480093f4SDimitry Andric if (empty())
99480093f4SDimitry Andric Last = X;
1000b57cec5SDimitry Andric X->Next = First;
1010b57cec5SDimitry Andric First = X;
1020b57cec5SDimitry Andric Size++;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
pop_frontSinglyLinkedList1050b57cec5SDimitry Andric void pop_front() {
1060b57cec5SDimitry Andric DCHECK(!empty());
1070b57cec5SDimitry Andric First = First->Next;
1080b57cec5SDimitry Andric if (!First)
1090b57cec5SDimitry Andric Last = nullptr;
1100b57cec5SDimitry Andric Size--;
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric
113*bdd1243dSDimitry Andric // Insert X next to Prev
insertSinglyLinkedList114*bdd1243dSDimitry Andric void insert(T *Prev, T *X) {
115*bdd1243dSDimitry Andric DCHECK(!empty());
116*bdd1243dSDimitry Andric DCHECK_NE(Prev, nullptr);
117*bdd1243dSDimitry Andric DCHECK_NE(X, nullptr);
118*bdd1243dSDimitry Andric X->Next = Prev->Next;
119*bdd1243dSDimitry Andric Prev->Next = X;
120*bdd1243dSDimitry Andric if (Last == Prev)
121*bdd1243dSDimitry Andric Last = X;
122*bdd1243dSDimitry Andric ++Size;
123*bdd1243dSDimitry Andric }
124*bdd1243dSDimitry Andric
extractSinglyLinkedList125480093f4SDimitry Andric void extract(T *Prev, T *X) {
1260b57cec5SDimitry Andric DCHECK(!empty());
1270b57cec5SDimitry Andric DCHECK_NE(Prev, nullptr);
1280b57cec5SDimitry Andric DCHECK_NE(X, nullptr);
1290b57cec5SDimitry Andric DCHECK_EQ(Prev->Next, X);
1300b57cec5SDimitry Andric Prev->Next = X->Next;
1310b57cec5SDimitry Andric if (Last == X)
1320b57cec5SDimitry Andric Last = Prev;
1330b57cec5SDimitry Andric Size--;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
append_backSinglyLinkedList136480093f4SDimitry Andric void append_back(SinglyLinkedList<T> *L) {
1370b57cec5SDimitry Andric DCHECK_NE(this, L);
1380b57cec5SDimitry Andric if (L->empty())
1390b57cec5SDimitry Andric return;
1400b57cec5SDimitry Andric if (empty()) {
1410b57cec5SDimitry Andric *this = *L;
1420b57cec5SDimitry Andric } else {
1430b57cec5SDimitry Andric Last->Next = L->First;
1440b57cec5SDimitry Andric Last = L->Last;
1450b57cec5SDimitry Andric Size += L->size();
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric L->clear();
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric };
1500b57cec5SDimitry Andric
151480093f4SDimitry Andric template <class T> struct DoublyLinkedList : IntrusiveList<T> {
152480093f4SDimitry Andric using IntrusiveList<T>::First;
153480093f4SDimitry Andric using IntrusiveList<T>::Last;
154480093f4SDimitry Andric using IntrusiveList<T>::Size;
155480093f4SDimitry Andric using IntrusiveList<T>::empty;
1560b57cec5SDimitry Andric
push_frontDoublyLinkedList157480093f4SDimitry Andric void push_front(T *X) {
158480093f4SDimitry Andric X->Prev = nullptr;
159480093f4SDimitry Andric if (empty()) {
160480093f4SDimitry Andric Last = X;
161480093f4SDimitry Andric } else {
162480093f4SDimitry Andric DCHECK_EQ(First->Prev, nullptr);
163480093f4SDimitry Andric First->Prev = X;
164480093f4SDimitry Andric }
165480093f4SDimitry Andric X->Next = First;
166480093f4SDimitry Andric First = X;
167480093f4SDimitry Andric Size++;
168480093f4SDimitry Andric }
1690b57cec5SDimitry Andric
170480093f4SDimitry Andric // Inserts X before Y.
insertDoublyLinkedList171480093f4SDimitry Andric void insert(T *X, T *Y) {
172480093f4SDimitry Andric if (Y == First)
173480093f4SDimitry Andric return push_front(X);
174480093f4SDimitry Andric T *Prev = Y->Prev;
175480093f4SDimitry Andric // This is a hard CHECK to ensure consistency in the event of an intentional
176480093f4SDimitry Andric // corruption of Y->Prev, to prevent a potential write-{4,8}.
177480093f4SDimitry Andric CHECK_EQ(Prev->Next, Y);
178480093f4SDimitry Andric Prev->Next = X;
179480093f4SDimitry Andric X->Prev = Prev;
180480093f4SDimitry Andric X->Next = Y;
181480093f4SDimitry Andric Y->Prev = X;
182480093f4SDimitry Andric Size++;
183480093f4SDimitry Andric }
1840b57cec5SDimitry Andric
push_backDoublyLinkedList185480093f4SDimitry Andric void push_back(T *X) {
186480093f4SDimitry Andric X->Next = nullptr;
187480093f4SDimitry Andric if (empty()) {
188480093f4SDimitry Andric First = X;
189480093f4SDimitry Andric } else {
190480093f4SDimitry Andric DCHECK_EQ(Last->Next, nullptr);
191480093f4SDimitry Andric Last->Next = X;
192480093f4SDimitry Andric }
193480093f4SDimitry Andric X->Prev = Last;
194480093f4SDimitry Andric Last = X;
195480093f4SDimitry Andric Size++;
196480093f4SDimitry Andric }
197480093f4SDimitry Andric
pop_frontDoublyLinkedList198480093f4SDimitry Andric void pop_front() {
199480093f4SDimitry Andric DCHECK(!empty());
200480093f4SDimitry Andric First = First->Next;
201480093f4SDimitry Andric if (!First)
202480093f4SDimitry Andric Last = nullptr;
203480093f4SDimitry Andric else
204480093f4SDimitry Andric First->Prev = nullptr;
205480093f4SDimitry Andric Size--;
206480093f4SDimitry Andric }
207480093f4SDimitry Andric
208480093f4SDimitry Andric // The consistency of the adjacent links is aggressively checked in order to
209480093f4SDimitry Andric // catch potential corruption attempts, that could yield a mirrored
210480093f4SDimitry Andric // write-{4,8} primitive. nullptr checks are deemed less vital.
removeDoublyLinkedList211480093f4SDimitry Andric void remove(T *X) {
212480093f4SDimitry Andric T *Prev = X->Prev;
213480093f4SDimitry Andric T *Next = X->Next;
214480093f4SDimitry Andric if (Prev) {
215480093f4SDimitry Andric CHECK_EQ(Prev->Next, X);
216480093f4SDimitry Andric Prev->Next = Next;
217480093f4SDimitry Andric }
218480093f4SDimitry Andric if (Next) {
219480093f4SDimitry Andric CHECK_EQ(Next->Prev, X);
220480093f4SDimitry Andric Next->Prev = Prev;
221480093f4SDimitry Andric }
222480093f4SDimitry Andric if (First == X) {
223480093f4SDimitry Andric DCHECK_EQ(Prev, nullptr);
224480093f4SDimitry Andric First = Next;
225480093f4SDimitry Andric } else {
226480093f4SDimitry Andric DCHECK_NE(Prev, nullptr);
227480093f4SDimitry Andric }
228480093f4SDimitry Andric if (Last == X) {
229480093f4SDimitry Andric DCHECK_EQ(Next, nullptr);
230480093f4SDimitry Andric Last = Prev;
231480093f4SDimitry Andric } else {
232480093f4SDimitry Andric DCHECK_NE(Next, nullptr);
233480093f4SDimitry Andric }
234480093f4SDimitry Andric Size--;
235480093f4SDimitry Andric }
2360b57cec5SDimitry Andric };
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric } // namespace scudo
2390b57cec5SDimitry Andric
2400b57cec5SDimitry Andric #endif // SCUDO_LIST_H_
241