LinkedList.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* A type-safe doubly-linked list class. */
  6. /*
  7. * The classes LinkedList<T> and LinkedListElement<T> together form a
  8. * convenient, type-safe doubly-linked list implementation.
  9. *
  10. * The class T which will be inserted into the linked list must inherit from
  11. * LinkedListElement<T>. A given object may be in only one linked list at a
  12. * time.
  13. *
  14. * A LinkedListElement automatically removes itself from the list upon
  15. * destruction, and a LinkedList will fatally assert in debug builds if it's
  16. * non-empty when it's destructed.
  17. *
  18. * For example, you might use LinkedList in a simple observer list class as
  19. * follows.
  20. *
  21. * class Observer : public LinkedListElement<Observer>
  22. * {
  23. * public:
  24. * void observe(char* aTopic) { ... }
  25. * };
  26. *
  27. * class ObserverContainer
  28. * {
  29. * private:
  30. * LinkedList<Observer> list;
  31. *
  32. * public:
  33. * void addObserver(Observer* aObserver)
  34. * {
  35. * // Will assert if |aObserver| is part of another list.
  36. * list.insertBack(aObserver);
  37. * }
  38. *
  39. * void removeObserver(Observer* aObserver)
  40. * {
  41. * // Will assert if |aObserver| is not part of some list.
  42. * aObserver.remove();
  43. * // Or, will assert if |aObserver| is not part of |list| specifically.
  44. * // aObserver.removeFrom(list);
  45. * }
  46. *
  47. * void notifyObservers(char* aTopic)
  48. * {
  49. * for (Observer* o = list.getFirst(); o != nullptr; o = o->getNext()) {
  50. * o->observe(aTopic);
  51. * }
  52. * }
  53. * };
  54. *
  55. * Additionally, the class AutoCleanLinkedList<T> is a LinkedList<T> that will
  56. * remove and delete each element still within itself upon destruction. Note
  57. * that because each element is deleted, elements must have been allocated
  58. * using |new|.
  59. */
  60. #ifndef mozilla_LinkedList_h
  61. #define mozilla_LinkedList_h
  62. #include "mozilla/Assertions.h"
  63. #include "mozilla/Attributes.h"
  64. #include "mozilla/MemoryReporting.h"
  65. #include "mozilla/Move.h"
  66. #include "mozilla/RefPtr.h"
  67. #ifdef __cplusplus
  68. namespace mozilla {
  69. template<typename T>
  70. class LinkedListElement;
  71. namespace detail {
  72. /**
  73. * LinkedList supports refcounted elements using this adapter class. Clients
  74. * using LinkedList<RefPtr<T>> will get a data structure that holds a strong
  75. * reference to T as long as T is in the list.
  76. */
  77. template<typename T>
  78. struct LinkedListElementTraits
  79. {
  80. typedef T* RawType;
  81. typedef const T* ConstRawType;
  82. typedef T* ClientType;
  83. typedef const T* ConstClientType;
  84. // These static methods are called when an element is added to or removed from
  85. // a linked list. It can be used to keep track ownership in lists that are
  86. // supposed to own their elements. If elements are transferred from one list
  87. // to another, no enter or exit calls happen since the elements still belong
  88. // to a list.
  89. static void enterList(LinkedListElement<T>* elt) {}
  90. static void exitList(LinkedListElement<T>* elt) {}
  91. };
  92. template<typename T>
  93. struct LinkedListElementTraits<RefPtr<T>>
  94. {
  95. typedef T* RawType;
  96. typedef const T* ConstRawType;
  97. typedef RefPtr<T> ClientType;
  98. typedef RefPtr<const T> ConstClientType;
  99. static void enterList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->AddRef(); }
  100. static void exitList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->Release(); }
  101. };
  102. } /* namespace detail */
  103. template<typename T>
  104. class LinkedList;
  105. template<typename T>
  106. class LinkedListElement
  107. {
  108. typedef typename detail::LinkedListElementTraits<T> Traits;
  109. typedef typename Traits::RawType RawType;
  110. typedef typename Traits::ConstRawType ConstRawType;
  111. typedef typename Traits::ClientType ClientType;
  112. typedef typename Traits::ConstClientType ConstClientType;
  113. /*
  114. * It's convenient that we return nullptr when getNext() or getPrevious()
  115. * hits the end of the list, but doing so costs an extra word of storage in
  116. * each linked list node (to keep track of whether |this| is the sentinel
  117. * node) and a branch on this value in getNext/getPrevious.
  118. *
  119. * We could get rid of the extra word of storage by shoving the "is
  120. * sentinel" bit into one of the pointers, although this would, of course,
  121. * have performance implications of its own.
  122. *
  123. * But the goal here isn't to win an award for the fastest or slimmest
  124. * linked list; rather, we want a *convenient* linked list. So we won't
  125. * waste time guessing which micro-optimization strategy is best.
  126. *
  127. *
  128. * Speaking of unnecessary work, it's worth addressing here why we wrote
  129. * mozilla::LinkedList in the first place, instead of using stl::list.
  130. *
  131. * The key difference between mozilla::LinkedList and stl::list is that
  132. * mozilla::LinkedList stores the mPrev/mNext pointers in the object itself,
  133. * while stl::list stores the mPrev/mNext pointers in a list element which
  134. * itself points to the object being stored.
  135. *
  136. * mozilla::LinkedList's approach makes it harder to store an object in more
  137. * than one list. But the upside is that you can call next() / prev() /
  138. * remove() directly on the object. With stl::list, you'd need to store a
  139. * pointer to its iterator in the object in order to accomplish this. Not
  140. * only would this waste space, but you'd have to remember to update that
  141. * pointer every time you added or removed the object from a list.
  142. *
  143. * In-place, constant-time removal is a killer feature of doubly-linked
  144. * lists, and supporting this painlessly was a key design criterion.
  145. */
  146. private:
  147. LinkedListElement* mNext;
  148. LinkedListElement* mPrev;
  149. const bool mIsSentinel;
  150. public:
  151. LinkedListElement()
  152. : mNext(this),
  153. mPrev(this),
  154. mIsSentinel(false)
  155. { }
  156. /*
  157. * Moves |aOther| into |*this|. If |aOther| is already in a list, then
  158. * |aOther| is removed from the list and replaced by |*this|.
  159. */
  160. LinkedListElement(LinkedListElement<T>&& aOther)
  161. : mIsSentinel(aOther.mIsSentinel)
  162. {
  163. adjustLinkForMove(Move(aOther));
  164. }
  165. LinkedListElement& operator=(LinkedListElement<T>&& aOther)
  166. {
  167. MOZ_ASSERT(mIsSentinel == aOther.mIsSentinel, "Mismatch NodeKind!");
  168. MOZ_ASSERT(!isInList(),
  169. "Assigning to an element in a list messes up that list!");
  170. adjustLinkForMove(Move(aOther));
  171. return *this;
  172. }
  173. ~LinkedListElement()
  174. {
  175. if (!mIsSentinel && isInList()) {
  176. remove();
  177. }
  178. }
  179. /*
  180. * Get the next element in the list, or nullptr if this is the last element
  181. * in the list.
  182. */
  183. RawType getNext() { return mNext->asT(); }
  184. ConstRawType getNext() const { return mNext->asT(); }
  185. /*
  186. * Get the previous element in the list, or nullptr if this is the first
  187. * element in the list.
  188. */
  189. RawType getPrevious() { return mPrev->asT(); }
  190. ConstRawType getPrevious() const { return mPrev->asT(); }
  191. /*
  192. * Insert aElem after this element in the list. |this| must be part of a
  193. * linked list when you call setNext(); otherwise, this method will assert.
  194. */
  195. void setNext(RawType aElem)
  196. {
  197. MOZ_ASSERT(isInList());
  198. setNextUnsafe(aElem);
  199. }
  200. /*
  201. * Insert aElem before this element in the list. |this| must be part of a
  202. * linked list when you call setPrevious(); otherwise, this method will
  203. * assert.
  204. */
  205. void setPrevious(RawType aElem)
  206. {
  207. MOZ_ASSERT(isInList());
  208. setPreviousUnsafe(aElem);
  209. }
  210. /*
  211. * Remove this element from the list which contains it. If this element is
  212. * not currently part of a linked list, this method asserts.
  213. */
  214. void remove()
  215. {
  216. MOZ_ASSERT(isInList());
  217. mPrev->mNext = mNext;
  218. mNext->mPrev = mPrev;
  219. mNext = this;
  220. mPrev = this;
  221. Traits::exitList(this);
  222. }
  223. /*
  224. * Remove this element from the list containing it. Returns a pointer to the
  225. * element that follows this element (before it was removed). This method
  226. * asserts if the element does not belong to a list.
  227. */
  228. ClientType removeAndGetNext()
  229. {
  230. ClientType r = getNext();
  231. remove();
  232. return r;
  233. }
  234. /*
  235. * Remove this element from the list containing it. Returns a pointer to the
  236. * previous element in the containing list (before the removal). This method
  237. * asserts if the element does not belong to a list.
  238. */
  239. ClientType removeAndGetPrevious()
  240. {
  241. ClientType r = getPrevious();
  242. remove();
  243. return r;
  244. }
  245. /*
  246. * Identical to remove(), but also asserts in debug builds that this element
  247. * is in aList.
  248. */
  249. void removeFrom(const LinkedList<T>& aList)
  250. {
  251. aList.assertContains(asT());
  252. remove();
  253. }
  254. /*
  255. * Return true if |this| part is of a linked list, and false otherwise.
  256. */
  257. bool isInList() const
  258. {
  259. MOZ_ASSERT((mNext == this) == (mPrev == this));
  260. return mNext != this;
  261. }
  262. private:
  263. friend class LinkedList<T>;
  264. friend struct detail::LinkedListElementTraits<T>;
  265. enum class NodeKind {
  266. Normal,
  267. Sentinel
  268. };
  269. explicit LinkedListElement(NodeKind nodeKind)
  270. : mNext(this),
  271. mPrev(this),
  272. mIsSentinel(nodeKind == NodeKind::Sentinel)
  273. { }
  274. /*
  275. * Return |this| cast to T* if we're a normal node, or return nullptr if
  276. * we're a sentinel node.
  277. */
  278. RawType asT()
  279. {
  280. return mIsSentinel ? nullptr : static_cast<RawType>(this);
  281. }
  282. ConstRawType asT() const
  283. {
  284. return mIsSentinel ? nullptr : static_cast<ConstRawType>(this);
  285. }
  286. /*
  287. * Insert aElem after this element, but don't check that this element is in
  288. * the list. This is called by LinkedList::insertFront().
  289. */
  290. void setNextUnsafe(RawType aElem)
  291. {
  292. LinkedListElement *listElem = static_cast<LinkedListElement*>(aElem);
  293. if (listElem->isInList())
  294. return;
  295. listElem->mNext = this->mNext;
  296. listElem->mPrev = this;
  297. this->mNext->mPrev = listElem;
  298. this->mNext = listElem;
  299. Traits::enterList(aElem);
  300. }
  301. /*
  302. * Insert aElem before this element, but don't check that this element is in
  303. * the list. This is called by LinkedList::insertBack().
  304. */
  305. void setPreviousUnsafe(RawType aElem)
  306. {
  307. LinkedListElement<T>* listElem = static_cast<LinkedListElement<T>*>(aElem);
  308. if (listElem->isInList())
  309. return;
  310. listElem->mNext = this;
  311. listElem->mPrev = this->mPrev;
  312. this->mPrev->mNext = listElem;
  313. this->mPrev = listElem;
  314. Traits::enterList(aElem);
  315. }
  316. /*
  317. * Adjust mNext and mPrev for implementing move constructor and move
  318. * assignment.
  319. */
  320. void adjustLinkForMove(LinkedListElement<T>&& aOther)
  321. {
  322. if (!aOther.isInList()) {
  323. mNext = this;
  324. mPrev = this;
  325. return;
  326. }
  327. if (!mIsSentinel) {
  328. Traits::enterList(this);
  329. }
  330. MOZ_ASSERT(aOther.mNext->mPrev == &aOther);
  331. MOZ_ASSERT(aOther.mPrev->mNext == &aOther);
  332. /*
  333. * Initialize |this| with |aOther|'s mPrev/mNext pointers, and adjust those
  334. * element to point to this one.
  335. */
  336. mNext = aOther.mNext;
  337. mPrev = aOther.mPrev;
  338. mNext->mPrev = this;
  339. mPrev->mNext = this;
  340. /*
  341. * Adjust |aOther| so it doesn't think it's in a list. This makes it
  342. * safely destructable.
  343. */
  344. aOther.mNext = &aOther;
  345. aOther.mPrev = &aOther;
  346. if (!mIsSentinel) {
  347. Traits::exitList(&aOther);
  348. }
  349. }
  350. LinkedListElement& operator=(const LinkedListElement<T>& aOther) = delete;
  351. LinkedListElement(const LinkedListElement<T>& aOther) = delete;
  352. };
  353. template<typename T>
  354. class LinkedList
  355. {
  356. private:
  357. typedef typename detail::LinkedListElementTraits<T> Traits;
  358. typedef typename Traits::RawType RawType;
  359. typedef typename Traits::ConstRawType ConstRawType;
  360. typedef typename Traits::ClientType ClientType;
  361. typedef typename Traits::ConstClientType ConstClientType;
  362. LinkedListElement<T> sentinel;
  363. public:
  364. class Iterator {
  365. RawType mCurrent;
  366. public:
  367. explicit Iterator(RawType aCurrent) : mCurrent(aCurrent) {}
  368. RawType operator *() const {
  369. return mCurrent;
  370. }
  371. const Iterator& operator++() {
  372. mCurrent = mCurrent->getNext();
  373. return *this;
  374. }
  375. bool operator!=(Iterator& aOther) const {
  376. return mCurrent != aOther.mCurrent;
  377. }
  378. };
  379. LinkedList() : sentinel(LinkedListElement<T>::NodeKind::Sentinel) { }
  380. LinkedList(LinkedList<T>&& aOther)
  381. : sentinel(mozilla::Move(aOther.sentinel))
  382. { }
  383. LinkedList& operator=(LinkedList<T>&& aOther)
  384. {
  385. MOZ_ASSERT(isEmpty(), "Assigning to a non-empty list leaks elements in that list!");
  386. sentinel = mozilla::Move(aOther.sentinel);
  387. return *this;
  388. }
  389. ~LinkedList() {
  390. MOZ_ASSERT(isEmpty(),
  391. "failing this assertion means this LinkedList's creator is "
  392. "buggy: it should have removed all this list's elements before "
  393. "the list's destruction");
  394. }
  395. /*
  396. * Add aElem to the front of the list.
  397. */
  398. void insertFront(RawType aElem)
  399. {
  400. /* Bypass setNext()'s this->isInList() assertion. */
  401. sentinel.setNextUnsafe(aElem);
  402. }
  403. /*
  404. * Add aElem to the back of the list.
  405. */
  406. void insertBack(RawType aElem)
  407. {
  408. sentinel.setPreviousUnsafe(aElem);
  409. }
  410. /*
  411. * Get the first element of the list, or nullptr if the list is empty.
  412. */
  413. RawType getFirst() { return sentinel.getNext(); }
  414. ConstRawType getFirst() const { return sentinel.getNext(); }
  415. /*
  416. * Get the last element of the list, or nullptr if the list is empty.
  417. */
  418. RawType getLast() { return sentinel.getPrevious(); }
  419. ConstRawType getLast() const { return sentinel.getPrevious(); }
  420. /*
  421. * Get and remove the first element of the list. If the list is empty,
  422. * return nullptr.
  423. */
  424. ClientType popFirst()
  425. {
  426. ClientType ret = sentinel.getNext();
  427. if (ret) {
  428. static_cast<LinkedListElement<T>*>(RawType(ret))->remove();
  429. }
  430. return ret;
  431. }
  432. /*
  433. * Get and remove the last element of the list. If the list is empty,
  434. * return nullptr.
  435. */
  436. ClientType popLast()
  437. {
  438. ClientType ret = sentinel.getPrevious();
  439. if (ret) {
  440. static_cast<LinkedListElement<T>*>(RawType(ret))->remove();
  441. }
  442. return ret;
  443. }
  444. /*
  445. * Return true if the list is empty, or false otherwise.
  446. */
  447. bool isEmpty() const
  448. {
  449. return !sentinel.isInList();
  450. }
  451. /*
  452. * Remove all the elements from the list.
  453. *
  454. * This runs in time linear to the list's length, because we have to mark
  455. * each element as not in the list.
  456. */
  457. void clear()
  458. {
  459. while (popFirst()) {
  460. continue;
  461. }
  462. }
  463. /*
  464. * Allow range-based iteration:
  465. *
  466. * for (MyElementType* elt : myList) { ... }
  467. */
  468. Iterator begin() {
  469. return Iterator(getFirst());
  470. }
  471. Iterator end() {
  472. return Iterator(nullptr);
  473. }
  474. /*
  475. * Measures the memory consumption of the list excluding |this|. Note that
  476. * it only measures the list elements themselves. If the list elements
  477. * contain pointers to other memory blocks, those blocks must be measured
  478. * separately during a subsequent iteration over the list.
  479. */
  480. size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  481. {
  482. size_t n = 0;
  483. for (const T* t = getFirst(); t; t = t->getNext()) {
  484. n += aMallocSizeOf(t);
  485. }
  486. return n;
  487. }
  488. /*
  489. * Like sizeOfExcludingThis(), but measures |this| as well.
  490. */
  491. size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  492. {
  493. return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf);
  494. }
  495. /*
  496. * In a debug build, make sure that the list is sane (no cycles, consistent
  497. * mNext/mPrev pointers, only one sentinel). Has no effect in release builds.
  498. */
  499. void debugAssertIsSane() const
  500. {
  501. #ifdef DEBUG
  502. const LinkedListElement<T>* slow;
  503. const LinkedListElement<T>* fast1;
  504. const LinkedListElement<T>* fast2;
  505. /*
  506. * Check for cycles in the forward singly-linked list using the
  507. * tortoise/hare algorithm.
  508. */
  509. for (slow = sentinel.mNext,
  510. fast1 = sentinel.mNext->mNext,
  511. fast2 = sentinel.mNext->mNext->mNext;
  512. slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel;
  513. slow = slow->mNext, fast1 = fast2->mNext, fast2 = fast1->mNext) {
  514. MOZ_ASSERT(slow != fast1);
  515. MOZ_ASSERT(slow != fast2);
  516. }
  517. /* Check for cycles in the backward singly-linked list. */
  518. for (slow = sentinel.mPrev,
  519. fast1 = sentinel.mPrev->mPrev,
  520. fast2 = sentinel.mPrev->mPrev->mPrev;
  521. slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel;
  522. slow = slow->mPrev, fast1 = fast2->mPrev, fast2 = fast1->mPrev) {
  523. MOZ_ASSERT(slow != fast1);
  524. MOZ_ASSERT(slow != fast2);
  525. }
  526. /*
  527. * Check that |sentinel| is the only node in the list with
  528. * mIsSentinel == true.
  529. */
  530. for (const LinkedListElement<T>* elem = sentinel.mNext;
  531. elem != &sentinel;
  532. elem = elem->mNext) {
  533. MOZ_ASSERT(!elem->mIsSentinel);
  534. }
  535. /* Check that the mNext/mPrev pointers match up. */
  536. const LinkedListElement<T>* prev = &sentinel;
  537. const LinkedListElement<T>* cur = sentinel.mNext;
  538. do {
  539. MOZ_ASSERT(cur->mPrev == prev);
  540. MOZ_ASSERT(prev->mNext == cur);
  541. prev = cur;
  542. cur = cur->mNext;
  543. } while (cur != &sentinel);
  544. #endif /* ifdef DEBUG */
  545. }
  546. private:
  547. friend class LinkedListElement<T>;
  548. void assertContains(const RawType aValue) const
  549. {
  550. #ifdef DEBUG
  551. for (ConstRawType elem = getFirst(); elem; elem = elem->getNext()) {
  552. if (elem == aValue) {
  553. return;
  554. }
  555. }
  556. MOZ_CRASH("element wasn't found in this list!");
  557. #endif
  558. }
  559. LinkedList& operator=(const LinkedList<T>& aOther) = delete;
  560. LinkedList(const LinkedList<T>& aOther) = delete;
  561. };
  562. template <typename T>
  563. class AutoCleanLinkedList : public LinkedList<T>
  564. {
  565. public:
  566. ~AutoCleanLinkedList()
  567. {
  568. while (T* element = this->popFirst()) {
  569. delete element;
  570. }
  571. }
  572. };
  573. } /* namespace mozilla */
  574. #endif /* __cplusplus */
  575. #endif /* mozilla_LinkedList_h */