xpcom/glue/nsTObserverArray.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial