xpcom/glue/nsTObserverArray.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; 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/. */
     6 #ifndef nsTObserverArray_h___
     7 #define nsTObserverArray_h___
     9 #include "mozilla/MemoryReporting.h"
    10 #include "nsTArray.h"
    11 #include "nsCycleCollectionNoteChild.h"
    13 /**
    14  * An array of observers. Like a normal array, but supports iterators that are
    15  * stable even if the array is modified during iteration.
    16  * The template parameter T is the observer type the array will hold;
    17  * N is the number of built-in storage slots that come with the array.
    18  * NOTE: You probably want to use nsTObserverArray, unless you specifically
    19  * want built-in storage. See below.
    20  * @see nsTObserverArray, nsTArray
    21  */
    23 class NS_COM_GLUE nsTObserverArray_base {
    24   public:
    25     typedef uint32_t index_type;
    26     typedef uint32_t size_type;
    27     typedef int32_t  diff_type;
    29   protected:
    30     class Iterator_base {
    31       protected:
    32         friend class nsTObserverArray_base;
    34         Iterator_base(index_type aPosition, Iterator_base* aNext)
    35           : mPosition(aPosition),
    36             mNext(aNext) {
    37         }
    39         // The current position of the iterator. Its exact meaning differs
    40         // depending on iterator. See nsTObserverArray<T>::ForwardIterator.
    41         index_type mPosition;
    43         // The next iterator currently iterating the same array
    44         Iterator_base* mNext;
    45     };
    47     nsTObserverArray_base()
    48       : mIterators(nullptr) {
    49     }
    51     ~nsTObserverArray_base() {
    52       NS_ASSERTION(mIterators == nullptr, "iterators outlasting array");
    53     }
    55     /**
    56      * Adjusts iterators after an element has been inserted or removed
    57      * from the array.
    58      * @param modPos     Position where elements were added or removed.
    59      * @param adjustment -1 if an element was removed, 1 if an element was
    60      *                   added.
    61      */
    62     void AdjustIterators(index_type aModPos, diff_type aAdjustment);
    64     /**
    65      * Clears iterators when the array is destroyed.
    66      */
    67     void ClearIterators();
    69     mutable Iterator_base* mIterators;
    70 };
    72 template<class T, uint32_t N>
    73 class nsAutoTObserverArray : protected nsTObserverArray_base {
    74   public:
    75     typedef T           elem_type;
    76     typedef nsTArray<T> array_type;
    78     nsAutoTObserverArray() {
    79     }
    81     //
    82     // Accessor methods
    83     //
    85     // @return The number of elements in the array.
    86     size_type Length() const {
    87       return mArray.Length();
    88     }
    90     // @return True if the array is empty or false otherwise.
    91     bool IsEmpty() const {
    92       return mArray.IsEmpty();
    93     }
    95     // This method provides direct access to the i'th element of the array.
    96     // The given index must be within the array bounds. If the underlying array
    97     // may change during iteration, use an iterator instead of this function.
    98     // @param i  The index of an element in the array.
    99     // @return   A reference to the i'th element of the array.
   100     elem_type& ElementAt(index_type i) {
   101       return mArray.ElementAt(i);
   102     }
   104     // Same as above, but readonly.
   105     const elem_type& ElementAt(index_type i) const {
   106       return mArray.ElementAt(i);
   107     }
   109     // This method provides direct access to the i'th element of the array in
   110     // a bounds safe manner. If the requested index is out of bounds the
   111     // provided default value is returned.
   112     // @param i  The index of an element in the array.
   113     // @param def The value to return if the index is out of bounds.
   114     elem_type& SafeElementAt(index_type i, elem_type& def) {
   115       return mArray.SafeElementAt(i, def);
   116     }
   118     // Same as above, but readonly.
   119     const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
   120       return mArray.SafeElementAt(i, def);
   121     }
   123     // No operator[] is provided because the point of this class is to support
   124     // allow modifying the array during iteration, and ElementAt() is not safe
   125     // in those conditions.
   127     //
   128     // Search methods
   129     //
   131     // This method searches, starting from the beginning of the array,
   132     // for the first element in this array that is equal to the given element.
   133     // 'operator==' must be defined for elem_type.
   134     // @param item   The item to search for.
   135     // @return       true if the element was found.
   136     template<class Item>
   137     bool Contains(const Item& item) const {
   138       return IndexOf(item) != array_type::NoIndex;
   139     }
   141     // This method searches for the offset of the first element in this
   142     // array that is equal to the given element.
   143     // 'operator==' must be defined for elem_type.
   144     // @param item   The item to search for.
   145     // @param start  The index to start from.
   146     // @return       The index of the found element or NoIndex if not found.
   147     template<class Item>
   148     index_type IndexOf(const Item& item, index_type start = 0) const {
   149       return mArray.IndexOf(item, start);
   150     }
   152     //
   153     // Mutation methods
   154     //
   156     // Insert a given element at the given index.
   157     // @param index  The index at which to insert item.
   158     // @param item   The item to insert,
   159     // @return       A pointer to the newly inserted element, or a null on DOM
   160     template<class Item>
   161     elem_type *InsertElementAt(index_type aIndex, const Item& aItem) {
   162       elem_type* item = mArray.InsertElementAt(aIndex, aItem);
   163       AdjustIterators(aIndex, 1);
   164       return item;
   165     }
   167     // Same as above but without copy constructing.
   168     // This is useful to avoid temporaries.
   169     elem_type* InsertElementAt(index_type aIndex) {
   170       elem_type* item = mArray.InsertElementAt(aIndex);
   171       AdjustIterators(aIndex, 1);
   172       return item;
   173     }
   175     // Prepend an element to the array unless it already exists in the array.
   176     // 'operator==' must be defined for elem_type.
   177     // @param item   The item to prepend.
   178     // @return       true if the element was found, or inserted successfully.
   179     template<class Item>
   180     bool PrependElementUnlessExists(const Item& item) {
   181       if (Contains(item)) {
   182         return true;
   183       }
   185       bool inserted = mArray.InsertElementAt(0, item) != nullptr;
   186       AdjustIterators(0, 1);
   187       return inserted;
   188     }
   190     // Append an element to the array.
   191     // @param item   The item to append.
   192     // @return A pointer to the newly appended element, or null on OOM.
   193     template<class Item>
   194     elem_type* AppendElement(const Item& item) {
   195       return mArray.AppendElement(item);
   196     }
   198     // Same as above, but without copy-constructing. This is useful to avoid
   199     // temporaries.
   200     elem_type* AppendElement() {
   201       return mArray.AppendElement();
   202     }
   204     // Append an element to the array unless it already exists in the array.
   205     // 'operator==' must be defined for elem_type.
   206     // @param item   The item to append.
   207     // @return       true if the element was found, or inserted successfully.
   208     template<class Item>
   209     bool AppendElementUnlessExists(const Item& item) {
   210       return Contains(item) || AppendElement(item) != nullptr;
   211     }
   213     // Remove an element from the array.
   214     // @param index  The index of the item to remove.
   215     void RemoveElementAt(index_type index) {
   216       NS_ASSERTION(index < mArray.Length(), "invalid index");
   217       mArray.RemoveElementAt(index);
   218       AdjustIterators(index, -1);
   219     }
   221     // This helper function combines IndexOf with RemoveElementAt to "search
   222     // and destroy" the first element that is equal to the given element.
   223     // 'operator==' must be defined for elem_type.
   224     // @param item  The item to search for.
   225     // @return true if the element was found and removed.
   226     template<class Item>
   227     bool RemoveElement(const Item& item) {
   228       index_type index = mArray.IndexOf(item, 0);
   229       if (index == array_type::NoIndex)
   230         return false;
   232       mArray.RemoveElementAt(index);
   233       AdjustIterators(index, -1);
   234       return true;
   235     }
   237     // Removes all observers and collapses all iterators to the beginning of
   238     // the array. The result is that forward iterators will see all elements
   239     // in the array.
   240     void Clear() {
   241       mArray.Clear();
   242       ClearIterators();
   243     }
   245     // Returns the number of bytes on the heap taken up by this object, not
   246     // including sizeof(*this).
   247     size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   248       return mArray.SizeOfExcludingThis(mallocSizeOf);
   249     }
   251     //
   252     // Iterators
   253     //
   255     // Base class for iterators. Do not use this directly.
   256     class Iterator : public Iterator_base {
   257       protected:
   258         friend class nsAutoTObserverArray;
   259         typedef nsAutoTObserverArray<T, N> array_type;
   261         Iterator(index_type aPosition, const array_type& aArray)
   262           : Iterator_base(aPosition, aArray.mIterators),
   263             mArray(const_cast<array_type&>(aArray)) {
   264           aArray.mIterators = this;
   265         }
   267         ~Iterator() {
   268           NS_ASSERTION(mArray.mIterators == this,
   269                        "Iterators must currently be destroyed in opposite order "
   270                        "from the construction order. It is suggested that you "
   271                        "simply put them on the stack");
   272           mArray.mIterators = mNext;
   273         }
   275         // The array we're iterating
   276         array_type& mArray;
   277     };
   279     // Iterates the array forward from beginning to end. mPosition points
   280     // to the element that will be returned on next call to GetNext.
   281     // Elements:
   282     // - prepended to the array during iteration *will not* be traversed
   283     // - appended during iteration *will* be traversed
   284     // - removed during iteration *will not* be traversed.
   285     // @see EndLimitedIterator
   286     class ForwardIterator : protected Iterator {
   287       public:
   288         typedef nsAutoTObserverArray<T, N> array_type;
   289         typedef Iterator                   base_type;
   291         ForwardIterator(const array_type& aArray)
   292           : Iterator(0, aArray) {
   293         }
   295         ForwardIterator(const array_type& aArray, index_type aPos)
   296           : Iterator(aPos, aArray) {
   297         }
   299         bool operator <(const ForwardIterator& aOther) const {
   300           NS_ASSERTION(&this->mArray == &aOther.mArray,
   301                        "not iterating the same array");
   302           return base_type::mPosition < aOther.mPosition;
   303         }
   305         // Returns true if there are more elements to iterate.
   306         // This must precede a call to GetNext(). If false is
   307         // returned, GetNext() must not be called.
   308         bool HasMore() const {
   309           return base_type::mPosition < base_type::mArray.Length();
   310         }
   312         // Returns the next element and steps one step. This must
   313         // be preceded by a call to HasMore().
   314         // @return The next observer.
   315         elem_type& GetNext() {
   316           NS_ASSERTION(HasMore(), "iterating beyond end of array");
   317           return base_type::mArray.ElementAt(base_type::mPosition++);
   318         }
   319     };
   321     // EndLimitedIterator works like ForwardIterator, but will not iterate new
   322     // observers appended to the array after the iterator was created.
   323     class EndLimitedIterator : protected ForwardIterator {
   324       public:
   325         typedef nsAutoTObserverArray<T, N> array_type;
   326         typedef Iterator                   base_type;
   328         EndLimitedIterator(const array_type& aArray)
   329           : ForwardIterator(aArray),
   330             mEnd(aArray, aArray.Length()) {
   331         }
   333         // Returns true if there are more elements to iterate.
   334         // This must precede a call to GetNext(). If false is
   335         // returned, GetNext() must not be called.
   336         bool HasMore() const {
   337           return *this < mEnd;
   338         }
   340         // Returns the next element and steps one step. This must
   341         // be preceded by a call to HasMore().
   342         // @return The next observer.
   343         elem_type& GetNext() {
   344           NS_ASSERTION(HasMore(), "iterating beyond end of array");
   345           return base_type::mArray.ElementAt(base_type::mPosition++);
   346         }
   348       private:
   349         ForwardIterator mEnd;
   350     };
   352   protected:
   353     nsAutoTArray<T, N> mArray;
   354 };
   356 template<class T>
   357 class nsTObserverArray : public nsAutoTObserverArray<T, 0> {
   358   public:
   359     typedef nsAutoTObserverArray<T, 0>       base_type;
   360     typedef nsTObserverArray_base::size_type size_type;
   362     //
   363     // Initialization methods
   364     //
   366     nsTObserverArray() {}
   368     // Initialize this array and pre-allocate some number of elements.
   369     explicit nsTObserverArray(size_type capacity) {
   370       base_type::mArray.SetCapacity(capacity);
   371     }
   372 };
   374 template <typename T, uint32_t N>
   375 inline void
   376 ImplCycleCollectionUnlink(nsAutoTObserverArray<T, N>& aField)
   377 {
   378   aField.Clear();
   379 }
   381 template <typename T, uint32_t N>
   382 inline void
   383 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
   384                             nsAutoTObserverArray<T, N>& aField,
   385                             const char* aName,
   386                             uint32_t aFlags = 0)
   387 {
   388   aFlags |= CycleCollectionEdgeNameArrayFlag;
   389   uint32_t length = aField.Length();
   390   for (uint32_t i = 0; i < length; ++i) {
   391     ImplCycleCollectionTraverse(aCallback, aField.ElementAt(i), aName, aFlags);
   392   }
   393 }
   395 // XXXbz I wish I didn't have to pass in the observer type, but I
   396 // don't see a way to get it out of array_.
   397 // Note that this macro only works if the array holds pointers to XPCOM objects.
   398 #define NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(array_, obstype_, func_, params_) \
   399   PR_BEGIN_MACRO                                                             \
   400     nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
   401     nsRefPtr<obstype_> obs_;                                                 \
   402     while (iter_.HasMore()) {                                                 \
   403       obs_ = iter_.GetNext();                                                \
   404       obs_ -> func_ params_ ;                                                \
   405     }                                                                        \
   406   PR_END_MACRO
   408 // Note that this macro only works if the array holds pointers to XPCOM objects.
   409 #define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, func_, params_) \
   410   PR_BEGIN_MACRO                                                             \
   411     nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
   412     obstype_* obs_;                                                          \
   413     while (iter_.HasMore()) {                                                \
   414       obs_ = iter_.GetNext();                                                \
   415       obs_ -> func_ params_ ;                                                \
   416     }                                                                        \
   417   PR_END_MACRO
   418 #endif // nsTObserverArray_h___

mercurial