/src/mozilla-central/xpcom/ds/nsTObserverArray.h
Line | Count | Source (jump to first uncovered line) |
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 | | Iterator_base(index_type aPosition, Iterator_base* aNext) |
40 | | : mPosition(aPosition) |
41 | | , mNext(aNext) |
42 | | { |
43 | | } |
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 | | nsTObserverArray_base() : mIterators(nullptr) {} |
54 | | |
55 | | ~nsTObserverArray_base() |
56 | | { |
57 | | NS_ASSERTION(mIterators == nullptr, "iterators outlasting array"); |
58 | | } |
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 | | class nsAutoTObserverArray : protected nsTObserverArray_base |
79 | | { |
80 | | public: |
81 | | typedef T elem_type; |
82 | | typedef nsTArray<T> array_type; |
83 | | |
84 | 0 | nsAutoTObserverArray() {} |
85 | | |
86 | | // |
87 | | // Accessor methods |
88 | | // |
89 | | |
90 | | // @return The number of elements in the array. |
91 | 0 | size_type Length() const { return mArray.Length(); } Unexecuted instantiation: nsAutoTObserverArray<nsIMutationObserver*, 1ul>::Length() const Unexecuted instantiation: nsAutoTObserverArray<nsMessageListenerInfo, 1ul>::Length() const |
92 | | |
93 | | // @return True if the array is empty or false otherwise. |
94 | 0 | 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 | | elem_type* Elements() |
104 | 0 | { |
105 | 0 | return mArray.Elements(); |
106 | 0 | } Unexecuted instantiation: nsAutoTObserverArray<nsIMutationObserver*, 1ul>::Elements() Unexecuted instantiation: nsAutoTObserverArray<nsMessageListenerInfo, 1ul>::Elements() |
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 | | elem_type& ElementAt(index_type aIndex) |
114 | 0 | { |
115 | 0 | return mArray.ElementAt(aIndex); |
116 | 0 | } |
117 | | |
118 | | // Same as above, but readonly. |
119 | | const elem_type& ElementAt(index_type aIndex) const |
120 | | { |
121 | | 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 | | const elem_type& SafeElementAt(index_type aIndex, const elem_type& aDef) const |
136 | | { |
137 | | 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 | | bool Contains(const Item& aItem) const |
155 | | { |
156 | | 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 | | index_type IndexOf(const Item& aItem, index_type aStart = 0) const |
167 | | { |
168 | | 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 | | elem_type* InsertElementAt(index_type aIndex, const Item& aItem) |
181 | | { |
182 | | elem_type* item = mArray.InsertElementAt(aIndex, aItem); |
183 | | AdjustIterators(aIndex, 1); |
184 | | return item; |
185 | | } |
186 | | |
187 | | // Same as above but without copy constructing. |
188 | | // This is useful to avoid temporaries. |
189 | | elem_type* InsertElementAt(index_type aIndex) |
190 | | { |
191 | | elem_type* item = mArray.InsertElementAt(aIndex); |
192 | | AdjustIterators(aIndex, 1); |
193 | | 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 | | bool PrependElementUnlessExists(const Item& aItem) |
202 | | { |
203 | | if (Contains(aItem)) { |
204 | | return true; |
205 | | } |
206 | | |
207 | | bool inserted = mArray.InsertElementAt(0, aItem) != nullptr; |
208 | | AdjustIterators(0, 1); |
209 | | 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 | | elem_type* AppendElement(const Item& aItem) |
217 | 0 | { |
218 | 0 | return mArray.AppendElement(aItem); |
219 | 0 | } |
220 | | |
221 | | // Same as above, but without copy-constructing. This is useful to avoid |
222 | | // temporaries. |
223 | | elem_type* AppendElement() |
224 | 0 | { |
225 | 0 | return mArray.AppendElement(); |
226 | 0 | } |
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 | | bool AppendElementUnlessExists(const Item& aItem) |
234 | | { |
235 | | 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 | | void RemoveElementAt(index_type aIndex) |
241 | 0 | { |
242 | 0 | NS_ASSERTION(aIndex < mArray.Length(), "invalid index"); |
243 | 0 | mArray.RemoveElementAt(aIndex); |
244 | 0 | AdjustIterators(aIndex, -1); |
245 | 0 | } |
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 | | bool RemoveElement(const Item& aItem) |
254 | 0 | { |
255 | 0 | index_type index = mArray.IndexOf(aItem, 0); |
256 | 0 | if (index == array_type::NoIndex) { |
257 | 0 | return false; |
258 | 0 | } |
259 | 0 | |
260 | 0 | mArray.RemoveElementAt(index); |
261 | 0 | AdjustIterators(index, -1); |
262 | 0 | return true; |
263 | 0 | } Unexecuted instantiation: bool nsAutoTObserverArray<nsIMutationObserver*, 1ul>::RemoveElement<nsIMutationObserver*>(nsIMutationObserver* const&) Unexecuted instantiation: bool nsAutoTObserverArray<nsMessageListenerInfo, 1ul>::RemoveElement<nsMessageListenerInfo>(nsMessageListenerInfo const&) |
264 | | |
265 | | // See nsTArray::RemoveElementsBy. |
266 | | template <typename Predicate> |
267 | | void RemoveElementsBy(Predicate aPredicate) |
268 | | { |
269 | | index_type i = 0; |
270 | | mArray.RemoveElementsBy([&](const elem_type& aItem) { |
271 | | if (aPredicate(aItem)) { |
272 | | // This element is going to be removed. |
273 | | AdjustIterators(i, -1); |
274 | | return true; |
275 | | } |
276 | | ++i; |
277 | | return false; |
278 | | }); |
279 | | } |
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 | | void Clear() |
285 | | { |
286 | | mArray.Clear(); |
287 | | ClearIterators(); |
288 | | } |
289 | | |
290 | | // Compact the array to minimize the memory it uses |
291 | | 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 | | size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
298 | | { |
299 | | 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 | | Iterator(index_type aPosition, const array_type& aArray) |
314 | | : Iterator_base(aPosition, aArray.mIterators) |
315 | | , mArray(const_cast<array_type&>(aArray)) |
316 | 0 | { |
317 | 0 | aArray.mIterators = this; |
318 | 0 | } Unexecuted instantiation: nsAutoTObserverArray<nsMessageListenerInfo, 1ul>::Iterator::Iterator(unsigned long, nsAutoTObserverArray<nsMessageListenerInfo, 1ul> const&) Unexecuted instantiation: nsAutoTObserverArray<nsIMutationObserver*, 1ul>::Iterator::Iterator(unsigned long, nsAutoTObserverArray<nsIMutationObserver*, 1ul> const&) |
319 | | |
320 | | ~Iterator() |
321 | 0 | { |
322 | 0 | NS_ASSERTION(mArray.mIterators == this, |
323 | 0 | "Iterators must currently be destroyed in opposite order " |
324 | 0 | "from the construction order. It is suggested that you " |
325 | 0 | "simply put them on the stack"); |
326 | 0 | mArray.mIterators = mNext; |
327 | 0 | } Unexecuted instantiation: nsAutoTObserverArray<nsMessageListenerInfo, 1ul>::Iterator::~Iterator() Unexecuted instantiation: nsAutoTObserverArray<nsIMutationObserver*, 1ul>::Iterator::~Iterator() |
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 | | class ForwardIterator : protected Iterator |
341 | | { |
342 | | public: |
343 | | typedef nsAutoTObserverArray<T, N> array_type; |
344 | | typedef Iterator base_type; |
345 | | |
346 | | explicit ForwardIterator(const array_type& aArray) |
347 | | : Iterator(0, aArray) |
348 | 0 | { |
349 | 0 | } Unexecuted instantiation: nsAutoTObserverArray<nsMessageListenerInfo, 1ul>::ForwardIterator::ForwardIterator(nsAutoTObserverArray<nsMessageListenerInfo, 1ul> const&) Unexecuted instantiation: nsAutoTObserverArray<nsIMutationObserver*, 1ul>::ForwardIterator::ForwardIterator(nsAutoTObserverArray<nsIMutationObserver*, 1ul> const&) |
350 | | |
351 | | ForwardIterator(const array_type& aArray, index_type aPos) |
352 | | : Iterator(aPos, aArray) |
353 | 0 | { |
354 | 0 | } |
355 | | |
356 | | bool operator<(const ForwardIterator& aOther) const |
357 | 0 | { |
358 | 0 | NS_ASSERTION(&this->mArray == &aOther.mArray, |
359 | 0 | "not iterating the same array"); |
360 | 0 | return base_type::mPosition < aOther.mPosition; |
361 | 0 | } |
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 | | bool HasMore() const |
367 | 0 | { |
368 | 0 | return base_type::mPosition < base_type::mArray.Length(); |
369 | 0 | } |
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 | | elem_type& GetNext() |
375 | 0 | { |
376 | 0 | NS_ASSERTION(HasMore(), "iterating beyond end of array"); |
377 | 0 | return base_type::mArray.Elements()[base_type::mPosition++]; |
378 | 0 | } |
379 | | }; |
380 | | |
381 | | // EndLimitedIterator works like ForwardIterator, but will not iterate new |
382 | | // observers appended to the array after the iterator was created. |
383 | | class EndLimitedIterator : protected ForwardIterator |
384 | | { |
385 | | public: |
386 | | typedef nsAutoTObserverArray<T, N> array_type; |
387 | | typedef Iterator base_type; |
388 | | |
389 | | explicit EndLimitedIterator(const array_type& aArray) |
390 | | : ForwardIterator(aArray) |
391 | | , mEnd(aArray, aArray.Length()) |
392 | 0 | { |
393 | 0 | } |
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 | 0 | 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 | | elem_type& GetNext() |
404 | 0 | { |
405 | 0 | NS_ASSERTION(HasMore(), "iterating beyond end of array"); |
406 | 0 | return base_type::mArray.Elements()[base_type::mPosition++]; |
407 | 0 | } |
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 | | class BackwardIterator : protected Iterator |
421 | | { |
422 | | public: |
423 | | typedef nsAutoTObserverArray<T, N> array_type; |
424 | | typedef Iterator base_type; |
425 | | |
426 | | explicit BackwardIterator(const array_type& aArray) |
427 | | : Iterator(aArray.Length(), aArray) |
428 | | { |
429 | | } |
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 | | 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 | | elem_type& GetNext() |
440 | | { |
441 | | NS_ASSERTION(HasMore(), "iterating beyond start of array"); |
442 | | 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 | | void Remove() |
449 | | { |
450 | | 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 | | 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 | | 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 | | ImplCycleCollectionUnlink(nsAutoTObserverArray<T, N>& aField) |
481 | | { |
482 | | aField.Clear(); |
483 | | } |
484 | | |
485 | | template<typename T, size_t N> |
486 | | inline void |
487 | | ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, |
488 | | nsAutoTObserverArray<T, N>& aField, |
489 | | const char* aName, |
490 | | uint32_t aFlags = 0) |
491 | 0 | { |
492 | 0 | aFlags |= CycleCollectionEdgeNameArrayFlag; |
493 | 0 | size_t length = aField.Length(); |
494 | 0 | for (size_t i = 0; i < length; ++i) { |
495 | 0 | ImplCycleCollectionTraverse(aCallback, aField.ElementAt(i), aName, aFlags); |
496 | 0 | } |
497 | 0 | } |
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 | | // Note that this macro only works if the array holds pointers to XPCOM objects. |
524 | | #define NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, num_, func_, params_) \ |
525 | 0 | do { \ |
526 | 0 | nsAutoTObserverArray<obstype_ *, num_>::ForwardIterator iter_(array_); \ |
527 | 0 | obstype_* obs_; \ |
528 | 0 | while (iter_.HasMore()) { \ |
529 | 0 | obs_ = iter_.GetNext(); \ |
530 | 0 | obs_ -> func_ params_ ; \ |
531 | 0 | } \ |
532 | 0 | } while(0) |
533 | | |
534 | | #define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS_WITH_QI(array_, basetype_, obstype_, func_, params_) \ |
535 | | do { \ |
536 | | nsTObserverArray<basetype_ *>::ForwardIterator iter_(array_); \ |
537 | | basetype_* obsbase_; \ |
538 | | while (iter_.HasMore()) { \ |
539 | | obsbase_ = iter_.GetNext(); \ |
540 | | nsCOMPtr<obstype_> obs_ = do_QueryInterface(obsbase_); \ |
541 | | if (obs_) { \ |
542 | | obs_ -> func_ params_ ; \ |
543 | | } \ |
544 | | } \ |
545 | | } while(0) |
546 | | |
547 | | #define NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS_WITH_QI(array_, basetype_, num_, obstype_, func_, params_) \ |
548 | | do { \ |
549 | | nsAutoTObserverArray<basetype_ *, num_>::ForwardIterator iter_(array_); \ |
550 | | basetype_* obsbase_; \ |
551 | | while (iter_.HasMore()) { \ |
552 | | obsbase_ = iter_.GetNext(); \ |
553 | | nsCOMPtr<obstype_> obs_ = do_QueryInterface(obsbase_); \ |
554 | | if (obs_) { \ |
555 | | obs_ -> func_ params_ ; \ |
556 | | } \ |
557 | | } \ |
558 | | } while(0) |
559 | | #endif // nsTObserverArray_h___ |