[Clang][SME2] Enable multi-vector loads & stores for SME2 (#75821)
[llvm-project.git] / compiler-rt / lib / scudo / standalone / list.h
blob0137667d1dcf3effde81f659f6880cefc5b0216a
1 //===-- list.h --------------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef SCUDO_LIST_H_
10 #define SCUDO_LIST_H_
12 #include "internal_defs.h"
14 namespace scudo {
16 // Intrusive POD singly and doubly linked list.
17 // An object with all zero fields should represent a valid empty list. clear()
18 // should be called on all non-zero-initialized objects before using.
20 template <class T> class IteratorBase {
21 public:
22 explicit IteratorBase(T *CurrentT) : Current(CurrentT) {}
23 IteratorBase &operator++() {
24 Current = Current->Next;
25 return *this;
27 bool operator!=(IteratorBase Other) const { return Current != Other.Current; }
28 T &operator*() { return *Current; }
30 private:
31 T *Current;
34 template <class T> struct IntrusiveList {
35 bool empty() const { return Size == 0; }
36 uptr size() const { return Size; }
38 T *front() { return First; }
39 const T *front() const { return First; }
40 T *back() { return Last; }
41 const T *back() const { return Last; }
43 void clear() {
44 First = Last = nullptr;
45 Size = 0;
48 typedef IteratorBase<T> Iterator;
49 typedef IteratorBase<const T> ConstIterator;
51 Iterator begin() { return Iterator(First); }
52 Iterator end() { return Iterator(nullptr); }
54 ConstIterator begin() const { return ConstIterator(First); }
55 ConstIterator end() const { return ConstIterator(nullptr); }
57 void checkConsistency() const;
59 protected:
60 uptr Size = 0;
61 T *First = nullptr;
62 T *Last = nullptr;
65 template <class T> void IntrusiveList<T>::checkConsistency() const {
66 if (Size == 0) {
67 CHECK_EQ(First, nullptr);
68 CHECK_EQ(Last, nullptr);
69 } else {
70 uptr Count = 0;
71 for (T *I = First;; I = I->Next) {
72 Count++;
73 if (I == Last)
74 break;
76 CHECK_EQ(this->size(), Count);
77 CHECK_EQ(Last->Next, nullptr);
81 template <class T> struct SinglyLinkedList : public IntrusiveList<T> {
82 using IntrusiveList<T>::First;
83 using IntrusiveList<T>::Last;
84 using IntrusiveList<T>::Size;
85 using IntrusiveList<T>::empty;
87 void push_back(T *X) {
88 X->Next = nullptr;
89 if (empty())
90 First = X;
91 else
92 Last->Next = X;
93 Last = X;
94 Size++;
97 void push_front(T *X) {
98 if (empty())
99 Last = X;
100 X->Next = First;
101 First = X;
102 Size++;
105 void pop_front() {
106 DCHECK(!empty());
107 First = First->Next;
108 if (!First)
109 Last = nullptr;
110 Size--;
113 // Insert X next to Prev
114 void insert(T *Prev, T *X) {
115 DCHECK(!empty());
116 DCHECK_NE(Prev, nullptr);
117 DCHECK_NE(X, nullptr);
118 X->Next = Prev->Next;
119 Prev->Next = X;
120 if (Last == Prev)
121 Last = X;
122 ++Size;
125 void extract(T *Prev, T *X) {
126 DCHECK(!empty());
127 DCHECK_NE(Prev, nullptr);
128 DCHECK_NE(X, nullptr);
129 DCHECK_EQ(Prev->Next, X);
130 Prev->Next = X->Next;
131 if (Last == X)
132 Last = Prev;
133 Size--;
136 void append_back(SinglyLinkedList<T> *L) {
137 DCHECK_NE(this, L);
138 if (L->empty())
139 return;
140 if (empty()) {
141 *this = *L;
142 } else {
143 Last->Next = L->First;
144 Last = L->Last;
145 Size += L->size();
147 L->clear();
151 template <class T> struct DoublyLinkedList : IntrusiveList<T> {
152 using IntrusiveList<T>::First;
153 using IntrusiveList<T>::Last;
154 using IntrusiveList<T>::Size;
155 using IntrusiveList<T>::empty;
157 void push_front(T *X) {
158 X->Prev = nullptr;
159 if (empty()) {
160 Last = X;
161 } else {
162 DCHECK_EQ(First->Prev, nullptr);
163 First->Prev = X;
165 X->Next = First;
166 First = X;
167 Size++;
170 // Inserts X before Y.
171 void insert(T *X, T *Y) {
172 if (Y == First)
173 return push_front(X);
174 T *Prev = Y->Prev;
175 // This is a hard CHECK to ensure consistency in the event of an intentional
176 // corruption of Y->Prev, to prevent a potential write-{4,8}.
177 CHECK_EQ(Prev->Next, Y);
178 Prev->Next = X;
179 X->Prev = Prev;
180 X->Next = Y;
181 Y->Prev = X;
182 Size++;
185 void push_back(T *X) {
186 X->Next = nullptr;
187 if (empty()) {
188 First = X;
189 } else {
190 DCHECK_EQ(Last->Next, nullptr);
191 Last->Next = X;
193 X->Prev = Last;
194 Last = X;
195 Size++;
198 void pop_front() {
199 DCHECK(!empty());
200 First = First->Next;
201 if (!First)
202 Last = nullptr;
203 else
204 First->Prev = nullptr;
205 Size--;
208 // The consistency of the adjacent links is aggressively checked in order to
209 // catch potential corruption attempts, that could yield a mirrored
210 // write-{4,8} primitive. nullptr checks are deemed less vital.
211 void remove(T *X) {
212 T *Prev = X->Prev;
213 T *Next = X->Next;
214 if (Prev) {
215 CHECK_EQ(Prev->Next, X);
216 Prev->Next = Next;
218 if (Next) {
219 CHECK_EQ(Next->Prev, X);
220 Next->Prev = Prev;
222 if (First == X) {
223 DCHECK_EQ(Prev, nullptr);
224 First = Next;
225 } else {
226 DCHECK_NE(Prev, nullptr);
228 if (Last == X) {
229 DCHECK_EQ(Next, nullptr);
230 Last = Prev;
231 } else {
232 DCHECK_NE(Next, nullptr);
234 Size--;
238 } // namespace scudo
240 #endif // SCUDO_LIST_H_