/gecko_api/include/nsTObserverArray.h
C Header | 382 lines | 177 code | 57 blank | 148 comment | 11 complexity | 32150759fc5a9a4579174fa19cb0d832 MD5 | raw file
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla.org code.
- *
- * The Initial Developer of the Original Code is Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2006
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Jonas Sicking <jonas@sicking.cc> (Original Author)
- * Daniel Witte <dwitte@stanford.edu>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- #ifndef nsTObserverArray_h___
- #define nsTObserverArray_h___
- #include "nsTArray.h"
- class NS_COM_GLUE nsTObserverArray_base {
- public:
- typedef PRUint32 index_type;
- typedef PRUint32 size_type;
- typedef PRInt32 diff_type;
- protected:
- class Iterator_base {
- protected:
- friend class nsTObserverArray_base;
- Iterator_base(index_type aPosition, Iterator_base* aNext)
- : mPosition(aPosition),
- mNext(aNext) {
- }
- // The current position of the iterator. Its exact meaning differs
- // depending on iterator. See nsTObserverArray<T>::ForwardIterator.
- index_type mPosition;
- // The next iterator currently iterating the same array
- Iterator_base* mNext;
- };
- nsTObserverArray_base()
- : mIterators(nsnull) {
- }
- ~nsTObserverArray_base() {
- NS_ASSERTION(mIterators == nsnull, "iterators outlasting array");
- }
- /**
- * Adjusts iterators after an element has been inserted or removed
- * from the array.
- * @param modPos Position where elements were added or removed.
- * @param adjustment -1 if an element was removed, 1 if an element was
- * added.
- */
- void AdjustIterators(index_type aModPos, diff_type aAdjustment);
- /**
- * Clears iterators when the array is destroyed.
- */
- void ClearIterators();
- mutable Iterator_base* mIterators;
- };
- /**
- * An array of observers. Like a normal array, but supports iterators that are
- * stable even if the array is modified during iteration.
- * The template parameter T is the observer type the array will hold;
- * N is the number of built-in storage slots that come with the array.
- * NOTE: You probably want to use nsTObserverArray, unless you specifically
- * want built-in storage. See below.
- * @see nsTObserverArray, nsTArray
- */
- template<class T, PRUint32 N>
- class nsAutoTObserverArray : protected nsTObserverArray_base {
- public:
- typedef T elem_type;
- typedef nsTArray<T> array_type;
- nsAutoTObserverArray() {
- }
- //
- // Accessor methods
- //
- // @return The number of elements in the array.
- size_type Length() const {
- return mArray.Length();
- }
- // @return True if the array is empty or false otherwise.
- PRBool IsEmpty() const {
- return mArray.IsEmpty();
- }
- // This method provides direct access to the i'th element of the array.
- // The given index must be within the array bounds.
- // @param i The index of an element in the array.
- // @return A reference to the i'th element of the array.
- elem_type& ElementAt(index_type i) {
- return mArray.ElementAt(i);
- }
- // Same as above, but readonly.
- const elem_type& ElementAt(index_type i) const {
- return mArray.ElementAt(i);
- }
- // This method provides direct access to the i'th element of the array in
- // a bounds safe manner. If the requested index is out of bounds the
- // provided default value is returned.
- // @param i The index of an element in the array.
- // @param def The value to return if the index is out of bounds.
- elem_type& SafeElementAt(index_type i, elem_type& def) {
- return mArray.SafeElementAt(i, def);
- }
- // Same as above, but readonly.
- const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
- return mArray.SafeElementAt(i, def);
- }
- //
- // Search methods
- //
- // This method searches, starting from the beginning of the array,
- // for the first element in this array that is equal to the given element.
- // 'operator==' must be defined for elem_type.
- // @param item The item to search for.
- // @return PR_TRUE if the element was found.
- template<class Item>
- PRBool Contains(const Item& item) const {
- return IndexOf(item) != array_type::NoIndex;
- }
- // This method searches for the offset of the first element in this
- // array that is equal to the given element.
- // 'operator==' must be defined for elem_type.
- // @param item The item to search for.
- // @param start The index to start from.
- // @return The index of the found element or NoIndex if not found.
- template<class Item>
- index_type IndexOf(const Item& item, index_type start = 0) const {
- return mArray.IndexOf(item, start);
- }
- //
- // Mutation methods
- //
- // Prepend an element to the array unless it already exists in the array.
- // 'operator==' must be defined for elem_type.
- // @param item The item to prepend.
- // @return PR_TRUE if the element was found, or inserted successfully.
- template<class Item>
- PRBool PrependElementUnlessExists(const Item& item) {
- return Contains(item) || mArray.InsertElementAt(0, item) != nsnull;
- }
- // Append an element to the array.
- // @param item The item to append.
- // @return A pointer to the newly appended element, or null on OOM.
- template<class Item>
- elem_type* AppendElement(const Item& item) {
- return mArray.AppendElement(item);
- }
- // Same as above, but without copy-constructing. This is useful to avoid
- // temporaries.
- elem_type* AppendElement() {
- return mArray.AppendElement();
- }
- // Append an element to the array unless it already exists in the array.
- // 'operator==' must be defined for elem_type.
- // @param item The item to append.
- // @return PR_TRUE if the element was found, or inserted successfully.
- template<class Item>
- PRBool AppendElementUnlessExists(const Item& item) {
- return Contains(item) || AppendElement(item) != nsnull;
- }
- // Remove an element from the array.
- // @param index The index of the item to remove.
- void RemoveElementAt(index_type index) {
- NS_ASSERTION(index < mArray.Length(), "invalid index");
- mArray.RemoveElementAt(index);
- AdjustIterators(index, -1);
- }
- // This helper function combines IndexOf with RemoveElementAt to "search
- // and destroy" the first element that is equal to the given element.
- // 'operator==' must be defined for elem_type.
- // @param item The item to search for.
- // @return PR_TRUE if the element was found and removed.
- template<class Item>
- PRBool RemoveElement(const Item& item) {
- index_type index = mArray.IndexOf(item, 0);
- if (index == array_type::NoIndex)
- return PR_FALSE;
- mArray.RemoveElementAt(index);
- AdjustIterators(index, -1);
- return PR_TRUE;
- }
- // Removes all observers and collapses all iterators to the beginning of
- // the array. The result is that forward iterators will see all elements
- // in the array.
- void Clear() {
- mArray.Clear();
- ClearIterators();
- }
- //
- // Iterators
- //
- // Base class for iterators. Do not use this directly.
- class Iterator : public Iterator_base {
- protected:
- friend class nsAutoTObserverArray;
- typedef nsAutoTObserverArray<T, N> array_type;
- Iterator(index_type aPosition, const array_type& aArray)
- : Iterator_base(aPosition, aArray.mIterators),
- mArray(const_cast<array_type&>(aArray)) {
- aArray.mIterators = this;
- }
- ~Iterator() {
- NS_ASSERTION(mArray.mIterators == this,
- "Iterators must currently be destroyed in opposite order "
- "from the construction order. It is suggested that you "
- "simply put them on the stack");
- mArray.mIterators = mNext;
- }
- // The array we're iterating
- array_type& mArray;
- };
- // Iterates the array forward from beginning to end. mPosition points
- // to the element that will be returned on next call to GetNext.
- // Elements:
- // - prepended to the array during iteration *will not* be traversed
- // - appended during iteration *will* be traversed
- // - removed during iteration *will not* be traversed.
- // @see EndLimitedIterator
- class ForwardIterator : protected Iterator {
- public:
- typedef nsAutoTObserverArray<T, N> array_type;
- typedef Iterator base_type;
- ForwardIterator(const array_type& aArray)
- : Iterator(0, aArray) {
- }
- ForwardIterator(const array_type& aArray, index_type aPos)
- : Iterator(aPos, aArray) {
- }
- PRBool operator <(const ForwardIterator& aOther) const {
- NS_ASSERTION(&this->mArray == &aOther.mArray,
- "not iterating the same array");
- return base_type::mPosition < aOther.mPosition;
- }
- // Returns PR_TRUE if there are more elements to iterate.
- // This must precede a call to GetNext(). If PR_FALSE is
- // returned, GetNext() must not be called.
- PRBool HasMore() const {
- return base_type::mPosition < base_type::mArray.Length();
- }
- // Returns the next element and steps one step. This must
- // be preceded by a call to HasMore().
- // @return The next observer.
- elem_type& GetNext() {
- NS_ASSERTION(HasMore(), "iterating beyond end of array");
- return base_type::mArray.ElementAt(base_type::mPosition++);
- }
- };
- // EndLimitedIterator works like ForwardIterator, but will not iterate new
- // observers appended to the array after the iterator was created.
- class EndLimitedIterator : protected ForwardIterator {
- public:
- typedef nsAutoTObserverArray<T, N> array_type;
- typedef Iterator base_type;
- EndLimitedIterator(const array_type& aArray)
- : ForwardIterator(aArray),
- mEnd(aArray, aArray.Length()) {
- }
- // Returns PR_TRUE if there are more elements to iterate.
- // This must precede a call to GetNext(). If PR_FALSE is
- // returned, GetNext() must not be called.
- PRBool HasMore() const {
- return *this < mEnd;
- }
- // Returns the next element and steps one step. This must
- // be preceded by a call to HasMore().
- // @return The next observer.
- elem_type& GetNext() {
- NS_ASSERTION(HasMore(), "iterating beyond end of array");
- return base_type::mArray.ElementAt(base_type::mPosition++);
- }
- private:
- ForwardIterator mEnd;
- };
- protected:
- nsAutoTArray<T, N> mArray;
- };
- template<class T>
- class nsTObserverArray : public nsAutoTObserverArray<T, 0> {
- public:
- typedef nsAutoTObserverArray<T, 0> base_type;
- typedef nsTObserverArray_base::size_type size_type;
- //
- // Initialization methods
- //
- nsTObserverArray() {}
- // Initialize this array and pre-allocate some number of elements.
- explicit nsTObserverArray(size_type capacity) {
- base_type::mArray.SetCapacity(capacity);
- }
- };
- // XXXbz I wish I didn't have to pass in the observer type, but I
- // don't see a way to get it out of array_.
- // Note that this macro only works if the array holds pointers to XPCOM objects.
- #define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, func_, params_) \
- PR_BEGIN_MACRO \
- nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_); \
- nsCOMPtr<obstype_> obs_; \
- while (iter_.HasMore()) { \
- obs_ = iter_.GetNext(); \
- obs_ -> func_ params_ ; \
- } \
- PR_END_MACRO
- #endif // nsTObserverArray_h___