LCOV - code coverage report
Current view: top level - mfbt - LinkedList.h (source / functions) Hit Total Coverage
Test: output.info Lines: 126 157 80.3 %
Date: 2017-07-14 16:53:18 Functions: 585 3858 15.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13