LCOV - code coverage report
Current view: top level - xpcom/ds - nsTObserverArray.h (source / functions) Hit Total Coverage
Test: output.info Lines: 109 125 87.2 %
Date: 2017-07-14 16:53:18 Functions: 229 504 45.4 %
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             : #ifndef nsTObserverArray_h___
       8             : #define nsTObserverArray_h___
       9             : 
      10             : #include "mozilla/MemoryReporting.h"
      11             : #include "nsTArray.h"
      12             : #include "nsCycleCollectionNoteChild.h"
      13             : 
      14             : #include <functional>
      15             : 
      16             : /**
      17             :  * An array of observers. Like a normal array, but supports iterators that are
      18             :  * stable even if the array is modified during iteration.
      19             :  * The template parameter T is the observer type the array will hold;
      20             :  * N is the number of built-in storage slots that come with the array.
      21             :  * NOTE: You probably want to use nsTObserverArray, unless you specifically
      22             :  * want built-in storage. See below.
      23             :  * @see nsTObserverArray, nsTArray
      24             :  */
      25             : 
      26             : class nsTObserverArray_base
      27             : {
      28             : public:
      29             :   typedef size_t index_type;
      30             :   typedef size_t size_type;
      31             :   typedef ptrdiff_t diff_type;
      32             : 
      33             : protected:
      34             :   class Iterator_base
      35             :   {
      36             :   protected:
      37             :     friend class nsTObserverArray_base;
      38             : 
      39        5853 :     Iterator_base(index_type aPosition, Iterator_base* aNext)
      40        5853 :       : mPosition(aPosition)
      41        5853 :       , mNext(aNext)
      42             :     {
      43        5853 :     }
      44             : 
      45             :     // The current position of the iterator. Its exact meaning differs
      46             :     // depending on iterator. See nsTObserverArray<T>::ForwardIterator.
      47             :     index_type mPosition;
      48             : 
      49             :     // The next iterator currently iterating the same array
      50             :     Iterator_base* mNext;
      51             :   };
      52             : 
      53        2425 :   nsTObserverArray_base() : mIterators(nullptr) {}
      54             : 
      55          43 :   ~nsTObserverArray_base()
      56          43 :   {
      57          43 :     NS_ASSERTION(mIterators == nullptr, "iterators outlasting array");
      58          43 :   }
      59             : 
      60             :   /**
      61             :    * Adjusts iterators after an element has been inserted or removed
      62             :    * from the array.
      63             :    * @param aModPos     Position where elements were added or removed.
      64             :    * @param aAdjustment -1 if an element was removed, 1 if an element was
      65             :    *                    added.
      66             :    */
      67             :   void AdjustIterators(index_type aModPos, diff_type aAdjustment);
      68             : 
      69             :   /**
      70             :    * Clears iterators when the array is destroyed.
      71             :    */
      72             :   void ClearIterators();
      73             : 
      74             :   mutable Iterator_base* mIterators;
      75             : };
      76             : 
      77             : template<class T, size_t N>
      78          43 : class nsAutoTObserverArray : protected nsTObserverArray_base
      79             : {
      80             : public:
      81             :   typedef T           elem_type;
      82             :   typedef nsTArray<T> array_type;
      83             : 
      84        2418 :   nsAutoTObserverArray() {}
      85             : 
      86             :   //
      87             :   // Accessor methods
      88             :   //
      89             : 
      90             :   // @return The number of elements in the array.
      91       19589 :   size_type Length() const { return mArray.Length(); }
      92             : 
      93             :   // @return True if the array is empty or false otherwise.
      94       12501 :   bool IsEmpty() const { return mArray.IsEmpty(); }
      95             : 
      96             :   // This method provides direct, readonly access to the array elements.
      97             :   // @return A pointer to the first element of the array.  If the array is
      98             :   // empty, then this pointer must not be dereferenced.
      99             :   const elem_type* Elements() const
     100             :   {
     101             :     return mArray.Elements();
     102             :   }
     103       27384 :   elem_type* Elements()
     104             :   {
     105       27384 :     return mArray.Elements();
     106             :   }
     107             : 
     108             :   // This method provides direct access to an element of the array. The given
     109             :   // index must be within the array bounds. If the underlying array may change
     110             :   // during iteration, use an iterator instead of this function.
     111             :   // @param aIndex The index of an element in the array.
     112             :   // @return A reference to the i'th element of the array.
     113       22985 :   elem_type& ElementAt(index_type aIndex)
     114             :   {
     115       22985 :     return mArray.ElementAt(aIndex);
     116             :   }
     117             : 
     118             :   // Same as above, but readonly.
     119         105 :   const elem_type& ElementAt(index_type aIndex) const
     120             :   {
     121         105 :     return mArray.ElementAt(aIndex);
     122             :   }
     123             : 
     124             :   // This method provides direct access to an element of the array in a bounds
     125             :   // safe manner. If the requested index is out of bounds the provided default
     126             :   // value is returned.
     127             :   // @param aIndex The index of an element in the array.
     128             :   // @param aDef   The value to return if the index is out of bounds.
     129             :   elem_type& SafeElementAt(index_type aIndex, elem_type& aDef)
     130             :   {
     131             :     return mArray.SafeElementAt(aIndex, aDef);
     132             :   }
     133             : 
     134             :   // Same as above, but readonly.
     135          42 :   const elem_type& SafeElementAt(index_type aIndex, const elem_type& aDef) const
     136             :   {
     137          42 :     return mArray.SafeElementAt(aIndex, aDef);
     138             :   }
     139             : 
     140             :   // No operator[] is provided because the point of this class is to support
     141             :   // allow modifying the array during iteration, and ElementAt() is not safe
     142             :   // in those conditions.
     143             : 
     144             :   //
     145             :   // Search methods
     146             :   //
     147             : 
     148             :   // This method searches, starting from the beginning of the array,
     149             :   // for the first element in this array that is equal to the given element.
     150             :   // 'operator==' must be defined for elem_type.
     151             :   // @param aItem The item to search for.
     152             :   // @return      true if the element was found.
     153             :   template<class Item>
     154         118 :   bool Contains(const Item& aItem) const
     155             :   {
     156         118 :     return IndexOf(aItem) != array_type::NoIndex;
     157             :   }
     158             : 
     159             :   // This method searches for the offset of the first element in this
     160             :   // array that is equal to the given element.
     161             :   // 'operator==' must be defined for elem_type.
     162             :   // @param aItem  The item to search for.
     163             :   // @param aStart The index to start from.
     164             :   // @return The index of the found element or NoIndex if not found.
     165             :   template<class Item>
     166         358 :   index_type IndexOf(const Item& aItem, index_type aStart = 0) const
     167             :   {
     168         358 :     return mArray.IndexOf(aItem, aStart);
     169             :   }
     170             : 
     171             :   //
     172             :   // Mutation methods
     173             :   //
     174             : 
     175             :   // Insert a given element at the given index.
     176             :   // @param aIndex The index at which to insert item.
     177             :   // @param aItem  The item to insert,
     178             :   // @return A pointer to the newly inserted element, or a null on DOM
     179             :   template<class Item>
     180           0 :   elem_type* InsertElementAt(index_type aIndex, const Item& aItem)
     181             :   {
     182           0 :     elem_type* item = mArray.InsertElementAt(aIndex, aItem);
     183           0 :     AdjustIterators(aIndex, 1);
     184           0 :     return item;
     185             :   }
     186             : 
     187             :   // Same as above but without copy constructing.
     188             :   // This is useful to avoid temporaries.
     189           0 :   elem_type* InsertElementAt(index_type aIndex)
     190             :   {
     191           0 :     elem_type* item = mArray.InsertElementAt(aIndex);
     192           0 :     AdjustIterators(aIndex, 1);
     193           0 :     return item;
     194             :   }
     195             : 
     196             :   // Prepend an element to the array unless it already exists in the array.
     197             :   // 'operator==' must be defined for elem_type.
     198             :   // @param aItem The item to prepend.
     199             :   // @return true if the element was found, or inserted successfully.
     200             :   template<class Item>
     201          55 :   bool PrependElementUnlessExists(const Item& aItem)
     202             :   {
     203          55 :     if (Contains(aItem)) {
     204           0 :       return true;
     205             :     }
     206             : 
     207          55 :     bool inserted = mArray.InsertElementAt(0, aItem) != nullptr;
     208          55 :     AdjustIterators(0, 1);
     209          55 :     return inserted;
     210             :   }
     211             : 
     212             :   // Append an element to the array.
     213             :   // @param aItem The item to append.
     214             :   // @return A pointer to the newly appended element, or null on OOM.
     215             :   template<class Item>
     216         301 :   elem_type* AppendElement(const Item& aItem)
     217             :   {
     218         301 :     return mArray.AppendElement(aItem);
     219             :   }
     220             : 
     221             :   // Same as above, but without copy-constructing. This is useful to avoid
     222             :   // temporaries.
     223        2280 :   elem_type* AppendElement()
     224             :   {
     225        2280 :     return mArray.AppendElement();
     226             :   }
     227             : 
     228             :   // Append an element to the array unless it already exists in the array.
     229             :   // 'operator==' must be defined for elem_type.
     230             :   // @param aItem The item to append.
     231             :   // @return true if the element was found, or inserted successfully.
     232             :   template<class Item>
     233           1 :   bool AppendElementUnlessExists(const Item& aItem)
     234             :   {
     235           1 :     return Contains(aItem) || AppendElement(aItem) != nullptr;
     236             :   }
     237             : 
     238             :   // Remove an element from the array.
     239             :   // @param aIndex The index of the item to remove.
     240         175 :   void RemoveElementAt(index_type aIndex)
     241             :   {
     242         175 :     NS_ASSERTION(aIndex < mArray.Length(), "invalid index");
     243         175 :     mArray.RemoveElementAt(aIndex);
     244         175 :     AdjustIterators(aIndex, -1);
     245         175 :   }
     246             : 
     247             :   // This helper function combines IndexOf with RemoveElementAt to "search
     248             :   // and destroy" the first element that is equal to the given element.
     249             :   // 'operator==' must be defined for elem_type.
     250             :   // @param aItem The item to search for.
     251             :   // @return true if the element was found and removed.
     252             :   template<class Item>
     253         137 :   bool RemoveElement(const Item& aItem)
     254             :   {
     255         137 :     index_type index = mArray.IndexOf(aItem, 0);
     256         137 :     if (index == array_type::NoIndex) {
     257           0 :       return false;
     258             :     }
     259             : 
     260         137 :     mArray.RemoveElementAt(index);
     261         137 :     AdjustIterators(index, -1);
     262         137 :     return true;
     263             :   }
     264             : 
     265             :   // See nsTArray::RemoveElementsBy.
     266             :   template <typename Predicate>
     267           1 :   void RemoveElementsBy(Predicate aPredicate)
     268             :   {
     269           1 :     index_type i = 0;
     270          12 :     mArray.RemoveElementsBy([&](const elem_type& aItem) {
     271          11 :       if (aPredicate(aItem)) {
     272             :         // This element is going to be removed.
     273          11 :         AdjustIterators(i, -1);
     274           1 :         return true;
     275             :       }
     276          10 :       ++i;
     277          10 :       return false;
     278             :     });
     279           1 :   }
     280             : 
     281             :   // Removes all observers and collapses all iterators to the beginning of
     282             :   // the array. The result is that forward iterators will see all elements
     283             :   // in the array.
     284          21 :   void Clear()
     285             :   {
     286          21 :     mArray.Clear();
     287          21 :     ClearIterators();
     288          21 :   }
     289             : 
     290             :   // Compact the array to minimize the memory it uses
     291         601 :   void Compact() { mArray.Compact(); }
     292             : 
     293             :   // Returns the number of bytes on the heap taken up by this object, not
     294             :   // including sizeof(*this). If you want to measure anything hanging off the
     295             :   // array, you must iterate over the elements and measure them individually;
     296             :   // hence the "Shallow" prefix.
     297          42 :   size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     298             :   {
     299          42 :     return mArray.ShallowSizeOfExcludingThis(aMallocSizeOf);
     300             :   }
     301             : 
     302             :   //
     303             :   // Iterators
     304             :   //
     305             : 
     306             :   // Base class for iterators. Do not use this directly.
     307             :   class Iterator : public Iterator_base
     308             :   {
     309             :   protected:
     310             :     friend class nsAutoTObserverArray;
     311             :     typedef nsAutoTObserverArray<T, N> array_type;
     312             : 
     313        5853 :     Iterator(index_type aPosition, const array_type& aArray)
     314             :       : Iterator_base(aPosition, aArray.mIterators)
     315        5853 :       , mArray(const_cast<array_type&>(aArray))
     316             :     {
     317        5853 :       aArray.mIterators = this;
     318        5853 :     }
     319             : 
     320        5851 :     ~Iterator()
     321             :     {
     322        5851 :       NS_ASSERTION(mArray.mIterators == this,
     323             :                    "Iterators must currently be destroyed in opposite order "
     324             :                    "from the construction order. It is suggested that you "
     325             :                    "simply put them on the stack");
     326        5851 :       mArray.mIterators = mNext;
     327        5851 :     }
     328             : 
     329             :     // The array we're iterating
     330             :     array_type& mArray;
     331             :   };
     332             : 
     333             :   // Iterates the array forward from beginning to end. mPosition points
     334             :   // to the element that will be returned on next call to GetNext.
     335             :   // Elements:
     336             :   // - prepended to the array during iteration *will not* be traversed
     337             :   // - appended during iteration *will* be traversed
     338             :   // - removed during iteration *will not* be traversed.
     339             :   // @see EndLimitedIterator
     340        5251 :   class ForwardIterator : protected Iterator
     341             :   {
     342             :   public:
     343             :     typedef nsAutoTObserverArray<T, N> array_type;
     344             :     typedef Iterator                   base_type;
     345             : 
     346        4268 :     explicit ForwardIterator(const array_type& aArray)
     347        4268 :       : Iterator(0, aArray)
     348             :     {
     349        4268 :     }
     350             : 
     351         985 :     ForwardIterator(const array_type& aArray, index_type aPos)
     352         985 :       : Iterator(aPos, aArray)
     353             :     {
     354         985 :     }
     355             : 
     356       43108 :     bool operator<(const ForwardIterator& aOther) const
     357             :     {
     358       43108 :       NS_ASSERTION(&this->mArray == &aOther.mArray,
     359             :                    "not iterating the same array");
     360       43108 :       return base_type::mPosition < aOther.mPosition;
     361             :     }
     362             : 
     363             :     // Returns true if there are more elements to iterate.
     364             :     // This must precede a call to GetNext(). If false is
     365             :     // returned, GetNext() must not be called.
     366       13281 :     bool HasMore() const
     367             :     {
     368       13281 :       return base_type::mPosition < base_type::mArray.Length();
     369             :     }
     370             : 
     371             :     // Returns the next element and steps one step. This must
     372             :     // be preceded by a call to HasMore().
     373             :     // @return The next observer.
     374        4999 :     elem_type& GetNext()
     375             :     {
     376        4999 :       NS_ASSERTION(HasMore(), "iterating beyond end of array");
     377        4999 :       return base_type::mArray.Elements()[base_type::mPosition++];
     378             :     }
     379             :   };
     380             : 
     381             :   // EndLimitedIterator works like ForwardIterator, but will not iterate new
     382             :   // observers appended to the array after the iterator was created.
     383         984 :   class EndLimitedIterator : protected ForwardIterator
     384             :   {
     385             :   public:
     386             :     typedef nsAutoTObserverArray<T, N> array_type;
     387             :     typedef Iterator                   base_type;
     388             : 
     389         985 :     explicit EndLimitedIterator(const array_type& aArray)
     390             :       : ForwardIterator(aArray)
     391         985 :       , mEnd(aArray, aArray.Length())
     392             :     {
     393         985 :     }
     394             : 
     395             :     // Returns true if there are more elements to iterate.
     396             :     // This must precede a call to GetNext(). If false is
     397             :     // returned, GetNext() must not be called.
     398       43108 :     bool HasMore() const { return *this < mEnd; }
     399             : 
     400             :     // Returns the next element and steps one step. This must
     401             :     // be preceded by a call to HasMore().
     402             :     // @return The next observer.
     403       21062 :     elem_type& GetNext()
     404             :     {
     405       21062 :       NS_ASSERTION(HasMore(), "iterating beyond end of array");
     406       21062 :       return base_type::mArray.Elements()[base_type::mPosition++];
     407             :     }
     408             : 
     409             :   private:
     410             :     ForwardIterator mEnd;
     411             :   };
     412             : 
     413             :   // Iterates the array backward from end to start. mPosition points
     414             :   // to the element that was returned last.
     415             :   // Elements:
     416             :   // - prepended to the array during iteration *will* be traversed,
     417             :   //   unless the iteration already arrived at the first element
     418             :   // - appended during iteration *will not* be traversed
     419             :   // - removed during iteration *will not* be traversed.
     420         600 :   class BackwardIterator : protected Iterator
     421             :   {
     422             :   public:
     423             :     typedef nsAutoTObserverArray<T, N> array_type;
     424             :     typedef Iterator                   base_type;
     425             : 
     426         600 :     explicit BackwardIterator(const array_type& aArray)
     427         600 :       : Iterator(aArray.Length(), aArray)
     428             :     {
     429         600 :     }
     430             : 
     431             :     // Returns true if there are more elements to iterate.
     432             :     // This must precede a call to GetNext(). If false is
     433             :     // returned, GetNext() must not be called.
     434        3246 :     bool HasMore() const { return base_type::mPosition > 0; }
     435             : 
     436             :     // Returns the next element and steps one step. This must
     437             :     // be preceded by a call to HasMore().
     438             :     // @return The next observer.
     439        1323 :     elem_type& GetNext()
     440             :     {
     441        1323 :       NS_ASSERTION(HasMore(), "iterating beyond start of array");
     442        1323 :       return base_type::mArray.Elements()[--base_type::mPosition];
     443             :     }
     444             : 
     445             :     // Removes the element at the current iterator position.
     446             :     // (the last element returned from |GetNext()|)
     447             :     // This will not affect the next call to |GetNext()|
     448           0 :     void Remove()
     449             :     {
     450           0 :       return base_type::mArray.RemoveElementAt(base_type::mPosition);
     451             :     }
     452             :   };
     453             : 
     454             : protected:
     455             :   AutoTArray<T, N> mArray;
     456             : };
     457             : 
     458             : template<class T>
     459           7 : class nsTObserverArray : public nsAutoTObserverArray<T, 0>
     460             : {
     461             : public:
     462             :   typedef nsAutoTObserverArray<T, 0>       base_type;
     463             :   typedef nsTObserverArray_base::size_type size_type;
     464             : 
     465             :   //
     466             :   // Initialization methods
     467             :   //
     468             : 
     469        1387 :   nsTObserverArray() {}
     470             : 
     471             :   // Initialize this array and pre-allocate some number of elements.
     472             :   explicit nsTObserverArray(size_type aCapacity)
     473             :   {
     474             :     base_type::mArray.SetCapacity(aCapacity);
     475             :   }
     476             : };
     477             : 
     478             : template<typename T, size_t N>
     479             : inline void
     480           0 : ImplCycleCollectionUnlink(nsAutoTObserverArray<T, N>& aField)
     481             : {
     482           0 :   aField.Clear();
     483           0 : }
     484             : 
     485             : template<typename T, size_t N>
     486             : inline void
     487           1 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
     488             :                             nsAutoTObserverArray<T, N>& aField,
     489             :                             const char* aName,
     490             :                             uint32_t aFlags = 0)
     491             : {
     492           1 :   aFlags |= CycleCollectionEdgeNameArrayFlag;
     493           1 :   size_t length = aField.Length();
     494           1 :   for (size_t i = 0; i < length; ++i) {
     495           0 :     ImplCycleCollectionTraverse(aCallback, aField.ElementAt(i), aName, aFlags);
     496             :   }
     497           1 : }
     498             : 
     499             : // XXXbz I wish I didn't have to pass in the observer type, but I
     500             : // don't see a way to get it out of array_.
     501             : // Note that this macro only works if the array holds pointers to XPCOM objects.
     502             : #define NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(array_, obstype_, func_, params_) \
     503             :   do {                                                                       \
     504             :     nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
     505             :     RefPtr<obstype_> obs_;                                                 \
     506             :     while (iter_.HasMore()) {                                                 \
     507             :       obs_ = iter_.GetNext();                                                \
     508             :       obs_ -> func_ params_ ;                                                \
     509             :     }                                                                        \
     510             :   } while(0)
     511             : 
     512             : // Note that this macro only works if the array holds pointers to XPCOM objects.
     513             : #define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, func_, params_) \
     514             :   do {                                                                       \
     515             :     nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
     516             :     obstype_* obs_;                                                          \
     517             :     while (iter_.HasMore()) {                                                \
     518             :       obs_ = iter_.GetNext();                                                \
     519             :       obs_ -> func_ params_ ;                                                \
     520             :     }                                                                        \
     521             :   } while(0)
     522             : 
     523             : #define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS_WITH_QI(array_, basetype_, obstype_, func_, params_) \
     524             :   do {                                                                       \
     525             :     nsTObserverArray<basetype_ *>::ForwardIterator iter_(array_);            \
     526             :     basetype_* obsbase_;                                                     \
     527             :     while (iter_.HasMore()) {                                                \
     528             :       obsbase_ = iter_.GetNext();                                            \
     529             :       nsCOMPtr<obstype_> obs_ = do_QueryInterface(obsbase_);                 \
     530             :       if (obs_) {                                                            \
     531             :         obs_ -> func_ params_ ;                                              \
     532             :       }                                                                      \
     533             :     }                                                                        \
     534             :   } while(0)
     535             : #endif // nsTObserverArray_h___

Generated by: LCOV version 1.13