PageRenderTime 360ms CodeModel.GetById 201ms app.highlight 19ms RepoModel.GetById 136ms app.codeStats 1ms

/gecko_api/include/nsTObserverArray.h

http://firefox-mac-pdf.googlecode.com/
C++ Header | 382 lines | 177 code | 57 blank | 148 comment | 11 complexity | 32150759fc5a9a4579174fa19cb0d832 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2/* ***** BEGIN LICENSE BLOCK *****
  3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4 *
  5 * The contents of this file are subject to the Mozilla Public License Version
  6 * 1.1 (the "License"); you may not use this file except in compliance with
  7 * the License. You may obtain a copy of the License at
  8 * http://www.mozilla.org/MPL/
  9 *
 10 * Software distributed under the License is distributed on an "AS IS" basis,
 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 12 * for the specific language governing rights and limitations under the
 13 * License.
 14 *
 15 * The Original Code is Mozilla.org code.
 16 *
 17 * The Initial Developer of the Original Code is Mozilla Corporation.
 18 * Portions created by the Initial Developer are Copyright (C) 2006
 19 * the Initial Developer. All Rights Reserved.
 20 *
 21 * Contributor(s):
 22 *   Jonas Sicking <jonas@sicking.cc> (Original Author)
 23 *   Daniel Witte <dwitte@stanford.edu>
 24 *
 25 * Alternatively, the contents of this file may be used under the terms of
 26 * either the GNU General Public License Version 2 or later (the "GPL"), or
 27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 28 * in which case the provisions of the GPL or the LGPL are applicable instead
 29 * of those above. If you wish to allow use of your version of this file only
 30 * under the terms of either the GPL or the LGPL, and not to allow others to
 31 * use your version of this file under the terms of the MPL, indicate your
 32 * decision by deleting the provisions above and replace them with the notice
 33 * and other provisions required by the GPL or the LGPL. If you do not delete
 34 * the provisions above, a recipient may use your version of this file under
 35 * the terms of any one of the MPL, the GPL or the LGPL.
 36 *
 37 * ***** END LICENSE BLOCK ***** */
 38
 39#ifndef nsTObserverArray_h___
 40#define nsTObserverArray_h___
 41
 42#include "nsTArray.h"
 43
 44class NS_COM_GLUE nsTObserverArray_base {
 45  public:
 46    typedef PRUint32 index_type;
 47    typedef PRUint32 size_type;
 48    typedef PRInt32  diff_type;
 49
 50  protected:
 51    class Iterator_base {
 52      protected:
 53        friend class nsTObserverArray_base;
 54
 55        Iterator_base(index_type aPosition, Iterator_base* aNext)
 56          : mPosition(aPosition),
 57            mNext(aNext) {
 58        }
 59
 60        // The current position of the iterator. Its exact meaning differs
 61        // depending on iterator. See nsTObserverArray<T>::ForwardIterator.
 62        index_type mPosition;
 63
 64        // The next iterator currently iterating the same array
 65        Iterator_base* mNext;
 66    };
 67
 68    nsTObserverArray_base()
 69      : mIterators(nsnull) {
 70    }
 71
 72    ~nsTObserverArray_base() {
 73      NS_ASSERTION(mIterators == nsnull, "iterators outlasting array");
 74    }
 75
 76    /**
 77     * Adjusts iterators after an element has been inserted or removed
 78     * from the array.
 79     * @param modPos     Position where elements were added or removed.
 80     * @param adjustment -1 if an element was removed, 1 if an element was
 81     *                   added.
 82     */
 83    void AdjustIterators(index_type aModPos, diff_type aAdjustment);
 84
 85    /**
 86     * Clears iterators when the array is destroyed.
 87     */
 88    void ClearIterators();
 89
 90    mutable Iterator_base* mIterators;
 91};
 92
 93/**
 94 * An array of observers. Like a normal array, but supports iterators that are
 95 * stable even if the array is modified during iteration.
 96 * The template parameter T is the observer type the array will hold;
 97 * N is the number of built-in storage slots that come with the array.
 98 * NOTE: You probably want to use nsTObserverArray, unless you specifically
 99 * want built-in storage. See below.
100 * @see nsTObserverArray, nsTArray
101 */
102
103template<class T, PRUint32 N>
104class nsAutoTObserverArray : protected nsTObserverArray_base {
105  public:
106    typedef T           elem_type;
107    typedef nsTArray<T> array_type;
108
109    nsAutoTObserverArray() {
110    }
111
112    //
113    // Accessor methods
114    //
115
116    // @return The number of elements in the array.
117    size_type Length() const {
118      return mArray.Length();
119    }
120
121    // @return True if the array is empty or false otherwise.
122    PRBool IsEmpty() const {
123      return mArray.IsEmpty();
124    }
125
126    // This method provides direct access to the i'th element of the array.
127    // The given index must be within the array bounds.
128    // @param i  The index of an element in the array.
129    // @return   A reference to the i'th element of the array.
130    elem_type& ElementAt(index_type i) {
131      return mArray.ElementAt(i);
132    }
133
134    // Same as above, but readonly.
135    const elem_type& ElementAt(index_type i) const {
136      return mArray.ElementAt(i);
137    }
138
139    // This method provides direct access to the i'th element of the array in
140    // a bounds safe manner. If the requested index is out of bounds the
141    // provided default value is returned.
142    // @param i  The index of an element in the array.
143    // @param def The value to return if the index is out of bounds.
144    elem_type& SafeElementAt(index_type i, elem_type& def) {
145      return mArray.SafeElementAt(i, def);
146    }
147
148    // Same as above, but readonly.
149    const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
150      return mArray.SafeElementAt(i, def);
151    }
152
153    //
154    // Search methods
155    //
156
157    // This method searches, starting from the beginning of the array,
158    // for the first element in this array that is equal to the given element.
159    // 'operator==' must be defined for elem_type.
160    // @param item   The item to search for.
161    // @return       PR_TRUE if the element was found.
162    template<class Item>
163    PRBool Contains(const Item& item) const {
164      return IndexOf(item) != array_type::NoIndex;
165    }
166
167    // This method searches for the offset of the first element in this
168    // array that is equal to the given element.
169    // 'operator==' must be defined for elem_type.
170    // @param item   The item to search for.
171    // @param start  The index to start from.
172    // @return       The index of the found element or NoIndex if not found.
173    template<class Item>
174    index_type IndexOf(const Item& item, index_type start = 0) const {
175      return mArray.IndexOf(item, start);
176    }
177
178    //
179    // Mutation methods
180    //
181
182    // Prepend an element to the array unless it already exists in the array.
183    // 'operator==' must be defined for elem_type.
184    // @param item   The item to prepend.
185    // @return       PR_TRUE if the element was found, or inserted successfully.
186    template<class Item>
187    PRBool PrependElementUnlessExists(const Item& item) {
188      return Contains(item) || mArray.InsertElementAt(0, item) != nsnull;
189    }
190
191    // Append an element to the array.
192    // @param item   The item to append.
193    // @return A pointer to the newly appended element, or null on OOM.
194    template<class Item>
195    elem_type* AppendElement(const Item& item) {
196      return mArray.AppendElement(item);
197    }
198
199    // Same as above, but without copy-constructing. This is useful to avoid
200    // temporaries.
201    elem_type* AppendElement() {
202      return mArray.AppendElement();
203    }
204
205    // Append an element to the array unless it already exists in the array.
206    // 'operator==' must be defined for elem_type.
207    // @param item   The item to append.
208    // @return       PR_TRUE if the element was found, or inserted successfully.
209    template<class Item>
210    PRBool AppendElementUnlessExists(const Item& item) {
211      return Contains(item) || AppendElement(item) != nsnull;
212    }
213
214    // Remove an element from the array.
215    // @param index  The index of the item to remove.
216    void RemoveElementAt(index_type index) {
217      NS_ASSERTION(index < mArray.Length(), "invalid index");
218      mArray.RemoveElementAt(index);
219      AdjustIterators(index, -1);
220    }
221
222    // This helper function combines IndexOf with RemoveElementAt to "search
223    // and destroy" the first element that is equal to the given element.
224    // 'operator==' must be defined for elem_type.
225    // @param item  The item to search for.
226    // @return PR_TRUE if the element was found and removed.
227    template<class Item>
228    PRBool RemoveElement(const Item& item) {
229      index_type index = mArray.IndexOf(item, 0);
230      if (index == array_type::NoIndex)
231        return PR_FALSE;
232
233      mArray.RemoveElementAt(index);
234      AdjustIterators(index, -1);
235      return PR_TRUE;
236    }
237
238    // Removes all observers and collapses all iterators to the beginning of
239    // the array. The result is that forward iterators will see all elements
240    // in the array.
241    void Clear() {
242      mArray.Clear();
243      ClearIterators();
244    }
245
246    //
247    // Iterators
248    //
249
250    // Base class for iterators. Do not use this directly.
251    class Iterator : public Iterator_base {
252      protected:
253        friend class nsAutoTObserverArray;
254        typedef nsAutoTObserverArray<T, N> array_type;
255
256        Iterator(index_type aPosition, const array_type& aArray)
257          : Iterator_base(aPosition, aArray.mIterators),
258            mArray(const_cast<array_type&>(aArray)) {
259          aArray.mIterators = this;
260        }
261
262        ~Iterator() {
263          NS_ASSERTION(mArray.mIterators == this,
264                       "Iterators must currently be destroyed in opposite order "
265                       "from the construction order. It is suggested that you "
266                       "simply put them on the stack");
267          mArray.mIterators = mNext;
268        }
269
270        // The array we're iterating
271        array_type& mArray;
272    };
273
274    // Iterates the array forward from beginning to end. mPosition points
275    // to the element that will be returned on next call to GetNext.
276    // Elements:
277    // - prepended to the array during iteration *will not* be traversed
278    // - appended during iteration *will* be traversed
279    // - removed during iteration *will not* be traversed.
280    // @see EndLimitedIterator
281    class ForwardIterator : protected Iterator {
282      public:
283        typedef nsAutoTObserverArray<T, N> array_type;
284        typedef Iterator                   base_type;
285
286        ForwardIterator(const array_type& aArray)
287          : Iterator(0, aArray) {
288        }
289
290        ForwardIterator(const array_type& aArray, index_type aPos)
291          : Iterator(aPos, aArray) {
292        }
293
294        PRBool operator <(const ForwardIterator& aOther) const {
295          NS_ASSERTION(&this->mArray == &aOther.mArray,
296                       "not iterating the same array");
297          return base_type::mPosition < aOther.mPosition;
298        }
299
300        // Returns PR_TRUE if there are more elements to iterate.
301        // This must precede a call to GetNext(). If PR_FALSE is
302        // returned, GetNext() must not be called.
303        PRBool HasMore() const {
304          return base_type::mPosition < base_type::mArray.Length();
305        }
306
307        // Returns the next element and steps one step. This must
308        // be preceded by a call to HasMore().
309        // @return The next observer.
310        elem_type& GetNext() {
311          NS_ASSERTION(HasMore(), "iterating beyond end of array");
312          return base_type::mArray.ElementAt(base_type::mPosition++);
313        }
314    };
315
316    // EndLimitedIterator works like ForwardIterator, but will not iterate new
317    // observers appended to the array after the iterator was created.
318    class EndLimitedIterator : protected ForwardIterator {
319      public:
320        typedef nsAutoTObserverArray<T, N> array_type;
321        typedef Iterator                   base_type;
322
323        EndLimitedIterator(const array_type& aArray)
324          : ForwardIterator(aArray),
325            mEnd(aArray, aArray.Length()) {
326        }
327
328        // Returns PR_TRUE if there are more elements to iterate.
329        // This must precede a call to GetNext(). If PR_FALSE is
330        // returned, GetNext() must not be called.
331        PRBool HasMore() const {
332          return *this < mEnd;
333        }
334
335        // Returns the next element and steps one step. This must
336        // be preceded by a call to HasMore().
337        // @return The next observer.
338        elem_type& GetNext() {
339          NS_ASSERTION(HasMore(), "iterating beyond end of array");
340          return base_type::mArray.ElementAt(base_type::mPosition++);
341        }
342
343      private:
344        ForwardIterator mEnd;
345    };
346
347  protected:
348    nsAutoTArray<T, N> mArray;
349};
350
351template<class T>
352class nsTObserverArray : public nsAutoTObserverArray<T, 0> {
353  public:
354    typedef nsAutoTObserverArray<T, 0>       base_type;
355    typedef nsTObserverArray_base::size_type size_type;
356
357    //
358    // Initialization methods
359    //
360
361    nsTObserverArray() {}
362
363    // Initialize this array and pre-allocate some number of elements.
364    explicit nsTObserverArray(size_type capacity) {
365      base_type::mArray.SetCapacity(capacity);
366    }
367};
368
369// XXXbz I wish I didn't have to pass in the observer type, but I
370// don't see a way to get it out of array_.
371// Note that this macro only works if the array holds pointers to XPCOM objects.
372#define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, func_, params_) \
373  PR_BEGIN_MACRO                                                             \
374    nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
375    nsCOMPtr<obstype_> obs_;                                                 \
376    while (iter_.HasMore()) {                                                 \
377      obs_ = iter_.GetNext();                                                \
378      obs_ -> func_ params_ ;                                                \
379    }                                                                        \
380  PR_END_MACRO
381
382#endif // nsTObserverArray_h___