13cab2bb3Spatrick //===-- list.h --------------------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick
93cab2bb3Spatrick #ifndef SCUDO_LIST_H_
103cab2bb3Spatrick #define SCUDO_LIST_H_
113cab2bb3Spatrick
123cab2bb3Spatrick #include "internal_defs.h"
133cab2bb3Spatrick
143cab2bb3Spatrick namespace scudo {
153cab2bb3Spatrick
163cab2bb3Spatrick // Intrusive POD singly and doubly linked list.
173cab2bb3Spatrick // An object with all zero fields should represent a valid empty list. clear()
183cab2bb3Spatrick // should be called on all non-zero-initialized objects before using.
193cab2bb3Spatrick
203cab2bb3Spatrick template <class T> class IteratorBase {
213cab2bb3Spatrick public:
IteratorBase(T * CurrentT)223cab2bb3Spatrick explicit IteratorBase(T *CurrentT) : Current(CurrentT) {}
233cab2bb3Spatrick IteratorBase &operator++() {
243cab2bb3Spatrick Current = Current->Next;
253cab2bb3Spatrick return *this;
263cab2bb3Spatrick }
273cab2bb3Spatrick bool operator!=(IteratorBase Other) const { return Current != Other.Current; }
283cab2bb3Spatrick T &operator*() { return *Current; }
293cab2bb3Spatrick
303cab2bb3Spatrick private:
313cab2bb3Spatrick T *Current;
323cab2bb3Spatrick };
333cab2bb3Spatrick
343cab2bb3Spatrick template <class T> struct IntrusiveList {
emptyIntrusiveList353cab2bb3Spatrick bool empty() const { return Size == 0; }
sizeIntrusiveList363cab2bb3Spatrick uptr size() const { return Size; }
373cab2bb3Spatrick
frontIntrusiveList383cab2bb3Spatrick T *front() { return First; }
frontIntrusiveList393cab2bb3Spatrick const T *front() const { return First; }
backIntrusiveList403cab2bb3Spatrick T *back() { return Last; }
backIntrusiveList413cab2bb3Spatrick const T *back() const { return Last; }
423cab2bb3Spatrick
clearIntrusiveList433cab2bb3Spatrick void clear() {
443cab2bb3Spatrick First = Last = nullptr;
453cab2bb3Spatrick Size = 0;
463cab2bb3Spatrick }
473cab2bb3Spatrick
483cab2bb3Spatrick typedef IteratorBase<T> Iterator;
493cab2bb3Spatrick typedef IteratorBase<const T> ConstIterator;
503cab2bb3Spatrick
beginIntrusiveList513cab2bb3Spatrick Iterator begin() { return Iterator(First); }
endIntrusiveList523cab2bb3Spatrick Iterator end() { return Iterator(nullptr); }
533cab2bb3Spatrick
beginIntrusiveList543cab2bb3Spatrick ConstIterator begin() const { return ConstIterator(First); }
endIntrusiveList553cab2bb3Spatrick ConstIterator end() const { return ConstIterator(nullptr); }
563cab2bb3Spatrick
573cab2bb3Spatrick void checkConsistency() const;
583cab2bb3Spatrick
593cab2bb3Spatrick protected:
60d89ec533Spatrick uptr Size = 0;
61d89ec533Spatrick T *First = nullptr;
62d89ec533Spatrick T *Last = nullptr;
633cab2bb3Spatrick };
643cab2bb3Spatrick
checkConsistency()653cab2bb3Spatrick template <class T> void IntrusiveList<T>::checkConsistency() const {
663cab2bb3Spatrick if (Size == 0) {
673cab2bb3Spatrick CHECK_EQ(First, nullptr);
683cab2bb3Spatrick CHECK_EQ(Last, nullptr);
693cab2bb3Spatrick } else {
703cab2bb3Spatrick uptr Count = 0;
713cab2bb3Spatrick for (T *I = First;; I = I->Next) {
723cab2bb3Spatrick Count++;
733cab2bb3Spatrick if (I == Last)
743cab2bb3Spatrick break;
753cab2bb3Spatrick }
763cab2bb3Spatrick CHECK_EQ(this->size(), Count);
773cab2bb3Spatrick CHECK_EQ(Last->Next, nullptr);
783cab2bb3Spatrick }
793cab2bb3Spatrick }
803cab2bb3Spatrick
813cab2bb3Spatrick template <class T> struct SinglyLinkedList : public IntrusiveList<T> {
823cab2bb3Spatrick using IntrusiveList<T>::First;
833cab2bb3Spatrick using IntrusiveList<T>::Last;
843cab2bb3Spatrick using IntrusiveList<T>::Size;
853cab2bb3Spatrick using IntrusiveList<T>::empty;
863cab2bb3Spatrick
push_backSinglyLinkedList873cab2bb3Spatrick void push_back(T *X) {
883cab2bb3Spatrick X->Next = nullptr;
893cab2bb3Spatrick if (empty())
903cab2bb3Spatrick First = X;
913cab2bb3Spatrick else
923cab2bb3Spatrick Last->Next = X;
933cab2bb3Spatrick Last = X;
943cab2bb3Spatrick Size++;
953cab2bb3Spatrick }
963cab2bb3Spatrick
push_frontSinglyLinkedList973cab2bb3Spatrick void push_front(T *X) {
983cab2bb3Spatrick if (empty())
993cab2bb3Spatrick Last = X;
1003cab2bb3Spatrick X->Next = First;
1013cab2bb3Spatrick First = X;
1023cab2bb3Spatrick Size++;
1033cab2bb3Spatrick }
1043cab2bb3Spatrick
pop_frontSinglyLinkedList1053cab2bb3Spatrick void pop_front() {
1063cab2bb3Spatrick DCHECK(!empty());
1073cab2bb3Spatrick First = First->Next;
1083cab2bb3Spatrick if (!First)
1093cab2bb3Spatrick Last = nullptr;
1103cab2bb3Spatrick Size--;
1113cab2bb3Spatrick }
1123cab2bb3Spatrick
113*810390e3Srobert // Insert X next to Prev
insertSinglyLinkedList114*810390e3Srobert void insert(T *Prev, T *X) {
115*810390e3Srobert DCHECK(!empty());
116*810390e3Srobert DCHECK_NE(Prev, nullptr);
117*810390e3Srobert DCHECK_NE(X, nullptr);
118*810390e3Srobert X->Next = Prev->Next;
119*810390e3Srobert Prev->Next = X;
120*810390e3Srobert if (Last == Prev)
121*810390e3Srobert Last = X;
122*810390e3Srobert ++Size;
123*810390e3Srobert }
124*810390e3Srobert
extractSinglyLinkedList1253cab2bb3Spatrick void extract(T *Prev, T *X) {
1263cab2bb3Spatrick DCHECK(!empty());
1273cab2bb3Spatrick DCHECK_NE(Prev, nullptr);
1283cab2bb3Spatrick DCHECK_NE(X, nullptr);
1293cab2bb3Spatrick DCHECK_EQ(Prev->Next, X);
1303cab2bb3Spatrick Prev->Next = X->Next;
1313cab2bb3Spatrick if (Last == X)
1323cab2bb3Spatrick Last = Prev;
1333cab2bb3Spatrick Size--;
1343cab2bb3Spatrick }
1353cab2bb3Spatrick
append_backSinglyLinkedList1363cab2bb3Spatrick void append_back(SinglyLinkedList<T> *L) {
1373cab2bb3Spatrick DCHECK_NE(this, L);
1383cab2bb3Spatrick if (L->empty())
1393cab2bb3Spatrick return;
1403cab2bb3Spatrick if (empty()) {
1413cab2bb3Spatrick *this = *L;
1423cab2bb3Spatrick } else {
1433cab2bb3Spatrick Last->Next = L->First;
1443cab2bb3Spatrick Last = L->Last;
1453cab2bb3Spatrick Size += L->size();
1463cab2bb3Spatrick }
1473cab2bb3Spatrick L->clear();
1483cab2bb3Spatrick }
1493cab2bb3Spatrick };
1503cab2bb3Spatrick
1513cab2bb3Spatrick template <class T> struct DoublyLinkedList : IntrusiveList<T> {
1523cab2bb3Spatrick using IntrusiveList<T>::First;
1533cab2bb3Spatrick using IntrusiveList<T>::Last;
1543cab2bb3Spatrick using IntrusiveList<T>::Size;
1553cab2bb3Spatrick using IntrusiveList<T>::empty;
1563cab2bb3Spatrick
push_frontDoublyLinkedList1573cab2bb3Spatrick void push_front(T *X) {
1583cab2bb3Spatrick X->Prev = nullptr;
1593cab2bb3Spatrick if (empty()) {
1603cab2bb3Spatrick Last = X;
1613cab2bb3Spatrick } else {
1623cab2bb3Spatrick DCHECK_EQ(First->Prev, nullptr);
1633cab2bb3Spatrick First->Prev = X;
1643cab2bb3Spatrick }
1653cab2bb3Spatrick X->Next = First;
1663cab2bb3Spatrick First = X;
1673cab2bb3Spatrick Size++;
1683cab2bb3Spatrick }
1693cab2bb3Spatrick
1703cab2bb3Spatrick // Inserts X before Y.
insertDoublyLinkedList1713cab2bb3Spatrick void insert(T *X, T *Y) {
1723cab2bb3Spatrick if (Y == First)
1733cab2bb3Spatrick return push_front(X);
1743cab2bb3Spatrick T *Prev = Y->Prev;
1753cab2bb3Spatrick // This is a hard CHECK to ensure consistency in the event of an intentional
1763cab2bb3Spatrick // corruption of Y->Prev, to prevent a potential write-{4,8}.
1773cab2bb3Spatrick CHECK_EQ(Prev->Next, Y);
1783cab2bb3Spatrick Prev->Next = X;
1793cab2bb3Spatrick X->Prev = Prev;
1803cab2bb3Spatrick X->Next = Y;
1813cab2bb3Spatrick Y->Prev = X;
1823cab2bb3Spatrick Size++;
1833cab2bb3Spatrick }
1843cab2bb3Spatrick
push_backDoublyLinkedList1853cab2bb3Spatrick void push_back(T *X) {
1863cab2bb3Spatrick X->Next = nullptr;
1873cab2bb3Spatrick if (empty()) {
1883cab2bb3Spatrick First = X;
1893cab2bb3Spatrick } else {
1903cab2bb3Spatrick DCHECK_EQ(Last->Next, nullptr);
1913cab2bb3Spatrick Last->Next = X;
1923cab2bb3Spatrick }
1933cab2bb3Spatrick X->Prev = Last;
1943cab2bb3Spatrick Last = X;
1953cab2bb3Spatrick Size++;
1963cab2bb3Spatrick }
1973cab2bb3Spatrick
pop_frontDoublyLinkedList1983cab2bb3Spatrick void pop_front() {
1993cab2bb3Spatrick DCHECK(!empty());
2003cab2bb3Spatrick First = First->Next;
2013cab2bb3Spatrick if (!First)
2023cab2bb3Spatrick Last = nullptr;
2033cab2bb3Spatrick else
2043cab2bb3Spatrick First->Prev = nullptr;
2053cab2bb3Spatrick Size--;
2063cab2bb3Spatrick }
2073cab2bb3Spatrick
2083cab2bb3Spatrick // The consistency of the adjacent links is aggressively checked in order to
2093cab2bb3Spatrick // catch potential corruption attempts, that could yield a mirrored
2103cab2bb3Spatrick // write-{4,8} primitive. nullptr checks are deemed less vital.
removeDoublyLinkedList2113cab2bb3Spatrick void remove(T *X) {
2123cab2bb3Spatrick T *Prev = X->Prev;
2133cab2bb3Spatrick T *Next = X->Next;
2143cab2bb3Spatrick if (Prev) {
2153cab2bb3Spatrick CHECK_EQ(Prev->Next, X);
2163cab2bb3Spatrick Prev->Next = Next;
2173cab2bb3Spatrick }
2183cab2bb3Spatrick if (Next) {
2193cab2bb3Spatrick CHECK_EQ(Next->Prev, X);
2203cab2bb3Spatrick Next->Prev = Prev;
2213cab2bb3Spatrick }
2223cab2bb3Spatrick if (First == X) {
2233cab2bb3Spatrick DCHECK_EQ(Prev, nullptr);
2243cab2bb3Spatrick First = Next;
2253cab2bb3Spatrick } else {
2263cab2bb3Spatrick DCHECK_NE(Prev, nullptr);
2273cab2bb3Spatrick }
2283cab2bb3Spatrick if (Last == X) {
2293cab2bb3Spatrick DCHECK_EQ(Next, nullptr);
2303cab2bb3Spatrick Last = Prev;
2313cab2bb3Spatrick } else {
2323cab2bb3Spatrick DCHECK_NE(Next, nullptr);
2333cab2bb3Spatrick }
2343cab2bb3Spatrick Size--;
2353cab2bb3Spatrick }
2363cab2bb3Spatrick };
2373cab2bb3Spatrick
2383cab2bb3Spatrick } // namespace scudo
2393cab2bb3Spatrick
2403cab2bb3Spatrick #endif // SCUDO_LIST_H_
241