xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/scudo/standalone/list.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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