list.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. //===----------------------------------------------------------------------===//
  8. #ifndef SCUDO_LIST_H_
  9. #define SCUDO_LIST_H_
  10. #include "internal_defs.h"
  11. namespace scudo {
  12. // Intrusive POD singly and doubly linked list.
  13. // An object with all zero fields should represent a valid empty list. clear()
  14. // should be called on all non-zero-initialized objects before using.
  15. template <class T> class IteratorBase {
  16. public:
  17. explicit IteratorBase(T *CurrentT) : Current(CurrentT) {}
  18. IteratorBase &operator++() {
  19. Current = Current->Next;
  20. return *this;
  21. }
  22. bool operator!=(IteratorBase Other) const { return Current != Other.Current; }
  23. T &operator*() { return *Current; }
  24. private:
  25. T *Current;
  26. };
  27. template <class T> struct IntrusiveList {
  28. bool empty() const { return Size == 0; }
  29. uptr size() const { return Size; }
  30. T *front() { return First; }
  31. const T *front() const { return First; }
  32. T *back() { return Last; }
  33. const T *back() const { return Last; }
  34. void clear() {
  35. First = Last = nullptr;
  36. Size = 0;
  37. }
  38. typedef IteratorBase<T> Iterator;
  39. typedef IteratorBase<const T> ConstIterator;
  40. Iterator begin() { return Iterator(First); }
  41. Iterator end() { return Iterator(nullptr); }
  42. ConstIterator begin() const { return ConstIterator(First); }
  43. ConstIterator end() const { return ConstIterator(nullptr); }
  44. void checkConsistency() const;
  45. protected:
  46. uptr Size = 0;
  47. T *First = nullptr;
  48. T *Last = nullptr;
  49. };
  50. template <class T> void IntrusiveList<T>::checkConsistency() const {
  51. if (Size == 0) {
  52. CHECK_EQ(First, nullptr);
  53. CHECK_EQ(Last, nullptr);
  54. } else {
  55. uptr Count = 0;
  56. for (T *I = First;; I = I->Next) {
  57. Count++;
  58. if (I == Last)
  59. break;
  60. }
  61. CHECK_EQ(this->size(), Count);
  62. CHECK_EQ(Last->Next, nullptr);
  63. }
  64. }
  65. template <class T> struct SinglyLinkedList : public IntrusiveList<T> {
  66. using IntrusiveList<T>::First;
  67. using IntrusiveList<T>::Last;
  68. using IntrusiveList<T>::Size;
  69. using IntrusiveList<T>::empty;
  70. void push_back(T *X) {
  71. X->Next = nullptr;
  72. if (empty())
  73. First = X;
  74. else
  75. Last->Next = X;
  76. Last = X;
  77. Size++;
  78. }
  79. void push_front(T *X) {
  80. if (empty())
  81. Last = X;
  82. X->Next = First;
  83. First = X;
  84. Size++;
  85. }
  86. void pop_front() {
  87. DCHECK(!empty());
  88. First = First->Next;
  89. if (!First)
  90. Last = nullptr;
  91. Size--;
  92. }
  93. void extract(T *Prev, T *X) {
  94. DCHECK(!empty());
  95. DCHECK_NE(Prev, nullptr);
  96. DCHECK_NE(X, nullptr);
  97. DCHECK_EQ(Prev->Next, X);
  98. Prev->Next = X->Next;
  99. if (Last == X)
  100. Last = Prev;
  101. Size--;
  102. }
  103. void append_back(SinglyLinkedList<T> *L) {
  104. DCHECK_NE(this, L);
  105. if (L->empty())
  106. return;
  107. if (empty()) {
  108. *this = *L;
  109. } else {
  110. Last->Next = L->First;
  111. Last = L->Last;
  112. Size += L->size();
  113. }
  114. L->clear();
  115. }
  116. };
  117. template <class T> struct DoublyLinkedList : IntrusiveList<T> {
  118. using IntrusiveList<T>::First;
  119. using IntrusiveList<T>::Last;
  120. using IntrusiveList<T>::Size;
  121. using IntrusiveList<T>::empty;
  122. void push_front(T *X) {
  123. X->Prev = nullptr;
  124. if (empty()) {
  125. Last = X;
  126. } else {
  127. DCHECK_EQ(First->Prev, nullptr);
  128. First->Prev = X;
  129. }
  130. X->Next = First;
  131. First = X;
  132. Size++;
  133. }
  134. // Inserts X before Y.
  135. void insert(T *X, T *Y) {
  136. if (Y == First)
  137. return push_front(X);
  138. T *Prev = Y->Prev;
  139. // This is a hard CHECK to ensure consistency in the event of an intentional
  140. // corruption of Y->Prev, to prevent a potential write-{4,8}.
  141. CHECK_EQ(Prev->Next, Y);
  142. Prev->Next = X;
  143. X->Prev = Prev;
  144. X->Next = Y;
  145. Y->Prev = X;
  146. Size++;
  147. }
  148. void push_back(T *X) {
  149. X->Next = nullptr;
  150. if (empty()) {
  151. First = X;
  152. } else {
  153. DCHECK_EQ(Last->Next, nullptr);
  154. Last->Next = X;
  155. }
  156. X->Prev = Last;
  157. Last = X;
  158. Size++;
  159. }
  160. void pop_front() {
  161. DCHECK(!empty());
  162. First = First->Next;
  163. if (!First)
  164. Last = nullptr;
  165. else
  166. First->Prev = nullptr;
  167. Size--;
  168. }
  169. // The consistency of the adjacent links is aggressively checked in order to
  170. // catch potential corruption attempts, that could yield a mirrored
  171. // write-{4,8} primitive. nullptr checks are deemed less vital.
  172. void remove(T *X) {
  173. T *Prev = X->Prev;
  174. T *Next = X->Next;
  175. if (Prev) {
  176. CHECK_EQ(Prev->Next, X);
  177. Prev->Next = Next;
  178. }
  179. if (Next) {
  180. CHECK_EQ(Next->Prev, X);
  181. Next->Prev = Prev;
  182. }
  183. if (First == X) {
  184. DCHECK_EQ(Prev, nullptr);
  185. First = Next;
  186. } else {
  187. DCHECK_NE(Prev, nullptr);
  188. }
  189. if (Last == X) {
  190. DCHECK_EQ(Next, nullptr);
  191. Last = Prev;
  192. } else {
  193. DCHECK_NE(Next, nullptr);
  194. }
  195. Size--;
  196. }
  197. };
  198. } // namespace scudo
  199. #endif // SCUDO_LIST_H_