123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- //===-- list.h --------------------------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #ifndef SCUDO_LIST_H_
- #define SCUDO_LIST_H_
- #include "internal_defs.h"
- namespace scudo {
- // Intrusive POD singly and doubly linked list.
- // An object with all zero fields should represent a valid empty list. clear()
- // should be called on all non-zero-initialized objects before using.
- template <class T> class IteratorBase {
- public:
- explicit IteratorBase(T *CurrentT) : Current(CurrentT) {}
- IteratorBase &operator++() {
- Current = Current->Next;
- return *this;
- }
- bool operator!=(IteratorBase Other) const { return Current != Other.Current; }
- T &operator*() { return *Current; }
- private:
- T *Current;
- };
- template <class T> struct IntrusiveList {
- bool empty() const { return Size == 0; }
- uptr size() const { return Size; }
- T *front() { return First; }
- const T *front() const { return First; }
- T *back() { return Last; }
- const T *back() const { return Last; }
- void clear() {
- First = Last = nullptr;
- Size = 0;
- }
- typedef IteratorBase<T> Iterator;
- typedef IteratorBase<const T> ConstIterator;
- Iterator begin() { return Iterator(First); }
- Iterator end() { return Iterator(nullptr); }
- ConstIterator begin() const { return ConstIterator(First); }
- ConstIterator end() const { return ConstIterator(nullptr); }
- void checkConsistency() const;
- protected:
- uptr Size = 0;
- T *First = nullptr;
- T *Last = nullptr;
- };
- template <class T> void IntrusiveList<T>::checkConsistency() const {
- if (Size == 0) {
- CHECK_EQ(First, nullptr);
- CHECK_EQ(Last, nullptr);
- } else {
- uptr Count = 0;
- for (T *I = First;; I = I->Next) {
- Count++;
- if (I == Last)
- break;
- }
- CHECK_EQ(this->size(), Count);
- CHECK_EQ(Last->Next, nullptr);
- }
- }
- template <class T> struct SinglyLinkedList : public IntrusiveList<T> {
- using IntrusiveList<T>::First;
- using IntrusiveList<T>::Last;
- using IntrusiveList<T>::Size;
- using IntrusiveList<T>::empty;
- void push_back(T *X) {
- X->Next = nullptr;
- if (empty())
- First = X;
- else
- Last->Next = X;
- Last = X;
- Size++;
- }
- void push_front(T *X) {
- if (empty())
- Last = X;
- X->Next = First;
- First = X;
- Size++;
- }
- void pop_front() {
- DCHECK(!empty());
- First = First->Next;
- if (!First)
- Last = nullptr;
- Size--;
- }
- // Insert X next to Prev
- void insert(T *Prev, T *X) {
- DCHECK(!empty());
- DCHECK_NE(Prev, nullptr);
- DCHECK_NE(X, nullptr);
- X->Next = Prev->Next;
- Prev->Next = X;
- if (Last == Prev)
- Last = X;
- ++Size;
- }
- void extract(T *Prev, T *X) {
- DCHECK(!empty());
- DCHECK_NE(Prev, nullptr);
- DCHECK_NE(X, nullptr);
- DCHECK_EQ(Prev->Next, X);
- Prev->Next = X->Next;
- if (Last == X)
- Last = Prev;
- Size--;
- }
- void append_back(SinglyLinkedList<T> *L) {
- DCHECK_NE(this, L);
- if (L->empty())
- return;
- if (empty()) {
- *this = *L;
- } else {
- Last->Next = L->First;
- Last = L->Last;
- Size += L->size();
- }
- L->clear();
- }
- };
- template <class T> struct DoublyLinkedList : IntrusiveList<T> {
- using IntrusiveList<T>::First;
- using IntrusiveList<T>::Last;
- using IntrusiveList<T>::Size;
- using IntrusiveList<T>::empty;
- void push_front(T *X) {
- X->Prev = nullptr;
- if (empty()) {
- Last = X;
- } else {
- DCHECK_EQ(First->Prev, nullptr);
- First->Prev = X;
- }
- X->Next = First;
- First = X;
- Size++;
- }
- // Inserts X before Y.
- void insert(T *X, T *Y) {
- if (Y == First)
- return push_front(X);
- T *Prev = Y->Prev;
- // This is a hard CHECK to ensure consistency in the event of an intentional
- // corruption of Y->Prev, to prevent a potential write-{4,8}.
- CHECK_EQ(Prev->Next, Y);
- Prev->Next = X;
- X->Prev = Prev;
- X->Next = Y;
- Y->Prev = X;
- Size++;
- }
- void push_back(T *X) {
- X->Next = nullptr;
- if (empty()) {
- First = X;
- } else {
- DCHECK_EQ(Last->Next, nullptr);
- Last->Next = X;
- }
- X->Prev = Last;
- Last = X;
- Size++;
- }
- void pop_front() {
- DCHECK(!empty());
- First = First->Next;
- if (!First)
- Last = nullptr;
- else
- First->Prev = nullptr;
- Size--;
- }
- // The consistency of the adjacent links is aggressively checked in order to
- // catch potential corruption attempts, that could yield a mirrored
- // write-{4,8} primitive. nullptr checks are deemed less vital.
- void remove(T *X) {
- T *Prev = X->Prev;
- T *Next = X->Next;
- if (Prev) {
- CHECK_EQ(Prev->Next, X);
- Prev->Next = Next;
- }
- if (Next) {
- CHECK_EQ(Next->Prev, X);
- Next->Prev = Prev;
- }
- if (First == X) {
- DCHECK_EQ(Prev, nullptr);
- First = Next;
- } else {
- DCHECK_NE(Prev, nullptr);
- }
- if (Last == X) {
- DCHECK_EQ(Next, nullptr);
- Last = Prev;
- } else {
- DCHECK_NE(Next, nullptr);
- }
- Size--;
- }
- };
- } // namespace scudo
- #endif // SCUDO_LIST_H_
|