Path: blob/main/contrib/llvm-project/compiler-rt/lib/scudo/standalone/list.h
35291 views
//===-- list.h --------------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef SCUDO_LIST_H_9#define SCUDO_LIST_H_1011#include "internal_defs.h"1213namespace scudo {1415// Intrusive POD singly and doubly linked list.16// An object with all zero fields should represent a valid empty list. clear()17// should be called on all non-zero-initialized objects before using.1819template <class T> class IteratorBase {20public:21explicit IteratorBase(T *CurrentT) : Current(CurrentT) {}22IteratorBase &operator++() {23Current = Current->Next;24return *this;25}26bool operator!=(IteratorBase Other) const { return Current != Other.Current; }27T &operator*() { return *Current; }2829private:30T *Current;31};3233template <class T> struct IntrusiveList {34bool empty() const { return Size == 0; }35uptr size() const { return Size; }3637T *front() { return First; }38const T *front() const { return First; }39T *back() { return Last; }40const T *back() const { return Last; }4142void clear() {43First = Last = nullptr;44Size = 0;45}4647typedef IteratorBase<T> Iterator;48typedef IteratorBase<const T> ConstIterator;4950Iterator begin() { return Iterator(First); }51Iterator end() { return Iterator(nullptr); }5253ConstIterator begin() const { return ConstIterator(First); }54ConstIterator end() const { return ConstIterator(nullptr); }5556void checkConsistency() const;5758protected:59uptr Size = 0;60T *First = nullptr;61T *Last = nullptr;62};6364template <class T> void IntrusiveList<T>::checkConsistency() const {65if (Size == 0) {66CHECK_EQ(First, nullptr);67CHECK_EQ(Last, nullptr);68} else {69uptr Count = 0;70for (T *I = First;; I = I->Next) {71Count++;72if (I == Last)73break;74}75CHECK_EQ(this->size(), Count);76CHECK_EQ(Last->Next, nullptr);77}78}7980template <class T> struct SinglyLinkedList : public IntrusiveList<T> {81using IntrusiveList<T>::First;82using IntrusiveList<T>::Last;83using IntrusiveList<T>::Size;84using IntrusiveList<T>::empty;8586void push_back(T *X) {87X->Next = nullptr;88if (empty())89First = X;90else91Last->Next = X;92Last = X;93Size++;94}9596void push_front(T *X) {97if (empty())98Last = X;99X->Next = First;100First = X;101Size++;102}103104void pop_front() {105DCHECK(!empty());106First = First->Next;107if (!First)108Last = nullptr;109Size--;110}111112// Insert X next to Prev113void insert(T *Prev, T *X) {114DCHECK(!empty());115DCHECK_NE(Prev, nullptr);116DCHECK_NE(X, nullptr);117X->Next = Prev->Next;118Prev->Next = X;119if (Last == Prev)120Last = X;121++Size;122}123124void extract(T *Prev, T *X) {125DCHECK(!empty());126DCHECK_NE(Prev, nullptr);127DCHECK_NE(X, nullptr);128DCHECK_EQ(Prev->Next, X);129Prev->Next = X->Next;130if (Last == X)131Last = Prev;132Size--;133}134135void append_back(SinglyLinkedList<T> *L) {136DCHECK_NE(this, L);137if (L->empty())138return;139if (empty()) {140*this = *L;141} else {142Last->Next = L->First;143Last = L->Last;144Size += L->size();145}146L->clear();147}148};149150template <class T> struct DoublyLinkedList : IntrusiveList<T> {151using IntrusiveList<T>::First;152using IntrusiveList<T>::Last;153using IntrusiveList<T>::Size;154using IntrusiveList<T>::empty;155156void push_front(T *X) {157X->Prev = nullptr;158if (empty()) {159Last = X;160} else {161DCHECK_EQ(First->Prev, nullptr);162First->Prev = X;163}164X->Next = First;165First = X;166Size++;167}168169// Inserts X before Y.170void insert(T *X, T *Y) {171if (Y == First)172return push_front(X);173T *Prev = Y->Prev;174// This is a hard CHECK to ensure consistency in the event of an intentional175// corruption of Y->Prev, to prevent a potential write-{4,8}.176CHECK_EQ(Prev->Next, Y);177Prev->Next = X;178X->Prev = Prev;179X->Next = Y;180Y->Prev = X;181Size++;182}183184void push_back(T *X) {185X->Next = nullptr;186if (empty()) {187First = X;188} else {189DCHECK_EQ(Last->Next, nullptr);190Last->Next = X;191}192X->Prev = Last;193Last = X;194Size++;195}196197void pop_front() {198DCHECK(!empty());199First = First->Next;200if (!First)201Last = nullptr;202else203First->Prev = nullptr;204Size--;205}206207// The consistency of the adjacent links is aggressively checked in order to208// catch potential corruption attempts, that could yield a mirrored209// write-{4,8} primitive. nullptr checks are deemed less vital.210void remove(T *X) {211T *Prev = X->Prev;212T *Next = X->Next;213if (Prev) {214CHECK_EQ(Prev->Next, X);215Prev->Next = Next;216}217if (Next) {218CHECK_EQ(Next->Prev, X);219Next->Prev = Prev;220}221if (First == X) {222DCHECK_EQ(Prev, nullptr);223First = Next;224} else {225DCHECK_NE(Prev, nullptr);226}227if (Last == X) {228DCHECK_EQ(Next, nullptr);229Last = Prev;230} else {231DCHECK_NE(Next, nullptr);232}233Size--;234}235};236237} // namespace scudo238239#endif // SCUDO_LIST_H_240241242