list.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. // Insert X next to Prev
  94. void insert(T *Prev, T *X) {
  95. DCHECK(!empty());
  96. DCHECK_NE(Prev, nullptr);
  97. DCHECK_NE(X, nullptr);
  98. X->Next = Prev->Next;
  99. Prev->Next = X;
  100. if (Last == Prev)
  101. Last = X;
  102. ++Size;
  103. }
  104. void extract(T *Prev, T *X) {
  105. DCHECK(!empty());
  106. DCHECK_NE(Prev, nullptr);
  107. DCHECK_NE(X, nullptr);
  108. DCHECK_EQ(Prev->Next, X);
  109. Prev->Next = X->Next;
  110. if (Last == X)
  111. Last = Prev;
  112. Size--;
  113. }
  114. void append_back(SinglyLinkedList<T> *L) {
  115. DCHECK_NE(this, L);
  116. if (L->empty())
  117. return;
  118. if (empty()) {
  119. *this = *L;
  120. } else {
  121. Last->Next = L->First;
  122. Last = L->Last;
  123. Size += L->size();
  124. }
  125. L->clear();
  126. }
  127. };
  128. template <class T> struct DoublyLinkedList : IntrusiveList<T> {
  129. using IntrusiveList<T>::First;
  130. using IntrusiveList<T>::Last;
  131. using IntrusiveList<T>::Size;
  132. using IntrusiveList<T>::empty;
  133. void push_front(T *X) {
  134. X->Prev = nullptr;
  135. if (empty()) {
  136. Last = X;
  137. } else {
  138. DCHECK_EQ(First->Prev, nullptr);
  139. First->Prev = X;
  140. }
  141. X->Next = First;
  142. First = X;
  143. Size++;
  144. }
  145. // Inserts X before Y.
  146. void insert(T *X, T *Y) {
  147. if (Y == First)
  148. return push_front(X);
  149. T *Prev = Y->Prev;
  150. // This is a hard CHECK to ensure consistency in the event of an intentional
  151. // corruption of Y->Prev, to prevent a potential write-{4,8}.
  152. CHECK_EQ(Prev->Next, Y);
  153. Prev->Next = X;
  154. X->Prev = Prev;
  155. X->Next = Y;
  156. Y->Prev = X;
  157. Size++;
  158. }
  159. void push_back(T *X) {
  160. X->Next = nullptr;
  161. if (empty()) {
  162. First = X;
  163. } else {
  164. DCHECK_EQ(Last->Next, nullptr);
  165. Last->Next = X;
  166. }
  167. X->Prev = Last;
  168. Last = X;
  169. Size++;
  170. }
  171. void pop_front() {
  172. DCHECK(!empty());
  173. First = First->Next;
  174. if (!First)
  175. Last = nullptr;
  176. else
  177. First->Prev = nullptr;
  178. Size--;
  179. }
  180. // The consistency of the adjacent links is aggressively checked in order to
  181. // catch potential corruption attempts, that could yield a mirrored
  182. // write-{4,8} primitive. nullptr checks are deemed less vital.
  183. void remove(T *X) {
  184. T *Prev = X->Prev;
  185. T *Next = X->Next;
  186. if (Prev) {
  187. CHECK_EQ(Prev->Next, X);
  188. Prev->Next = Next;
  189. }
  190. if (Next) {
  191. CHECK_EQ(Next->Prev, X);
  192. Next->Prev = Prev;
  193. }
  194. if (First == X) {
  195. DCHECK_EQ(Prev, nullptr);
  196. First = Next;
  197. } else {
  198. DCHECK_NE(Prev, nullptr);
  199. }
  200. if (Last == X) {
  201. DCHECK_EQ(Next, nullptr);
  202. Last = Prev;
  203. } else {
  204. DCHECK_NE(Next, nullptr);
  205. }
  206. Size--;
  207. }
  208. };
  209. } // namespace scudo
  210. #endif // SCUDO_LIST_H_