PageRenderTime 40ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/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. #ifndef nsTObserverArray_h___
  39. #define nsTObserverArray_h___
  40. #include "nsTArray.h"
  41. class NS_COM_GLUE nsTObserverArray_base {
  42. public:
  43. typedef PRUint32 index_type;
  44. typedef PRUint32 size_type;
  45. typedef PRInt32 diff_type;
  46. protected:
  47. class Iterator_base {
  48. protected:
  49. friend class nsTObserverArray_base;
  50. Iterator_base(index_type aPosition, Iterator_base* aNext)
  51. : mPosition(aPosition),
  52. mNext(aNext) {
  53. }
  54. // The current position of the iterator. Its exact meaning differs
  55. // depending on iterator. See nsTObserverArray<T>::ForwardIterator.
  56. index_type mPosition;
  57. // The next iterator currently iterating the same array
  58. Iterator_base* mNext;
  59. };
  60. nsTObserverArray_base()
  61. : mIterators(nsnull) {
  62. }
  63. ~nsTObserverArray_base() {
  64. NS_ASSERTION(mIterators == nsnull, "iterators outlasting array");
  65. }
  66. /**
  67. * Adjusts iterators after an element has been inserted or removed
  68. * from the array.
  69. * @param modPos Position where elements were added or removed.
  70. * @param adjustment -1 if an element was removed, 1 if an element was
  71. * added.
  72. */
  73. void AdjustIterators(index_type aModPos, diff_type aAdjustment);
  74. /**
  75. * Clears iterators when the array is destroyed.
  76. */
  77. void ClearIterators();
  78. mutable Iterator_base* mIterators;
  79. };
  80. /**
  81. * An array of observers. Like a normal array, but supports iterators that are
  82. * stable even if the array is modified during iteration.
  83. * The template parameter T is the observer type the array will hold;
  84. * N is the number of built-in storage slots that come with the array.
  85. * NOTE: You probably want to use nsTObserverArray, unless you specifically
  86. * want built-in storage. See below.
  87. * @see nsTObserverArray, nsTArray
  88. */
  89. template<class T, PRUint32 N>
  90. class nsAutoTObserverArray : protected nsTObserverArray_base {
  91. public:
  92. typedef T elem_type;
  93. typedef nsTArray<T> array_type;
  94. nsAutoTObserverArray() {
  95. }
  96. //
  97. // Accessor methods
  98. //
  99. // @return The number of elements in the array.
  100. size_type Length() const {
  101. return mArray.Length();
  102. }
  103. // @return True if the array is empty or false otherwise.
  104. PRBool IsEmpty() const {
  105. return mArray.IsEmpty();
  106. }
  107. // This method provides direct access to the i'th element of the array.
  108. // The given index must be within the array bounds.
  109. // @param i The index of an element in the array.
  110. // @return A reference to the i'th element of the array.
  111. elem_type& ElementAt(index_type i) {
  112. return mArray.ElementAt(i);
  113. }
  114. // Same as above, but readonly.
  115. const elem_type& ElementAt(index_type i) const {
  116. return mArray.ElementAt(i);
  117. }
  118. // This method provides direct access to the i'th element of the array in
  119. // a bounds safe manner. If the requested index is out of bounds the
  120. // provided default value is returned.
  121. // @param i The index of an element in the array.
  122. // @param def The value to return if the index is out of bounds.
  123. elem_type& SafeElementAt(index_type i, elem_type& def) {
  124. return mArray.SafeElementAt(i, def);
  125. }
  126. // Same as above, but readonly.
  127. const elem_type& SafeElementAt(index_type i, const elem_type& def) const {
  128. return mArray.SafeElementAt(i, def);
  129. }
  130. //
  131. // Search methods
  132. //
  133. // This method searches, starting from the beginning of the array,
  134. // for the first element in this array that is equal to the given element.
  135. // 'operator==' must be defined for elem_type.
  136. // @param item The item to search for.
  137. // @return PR_TRUE if the element was found.
  138. template<class Item>
  139. PRBool Contains(const Item& item) const {
  140. return IndexOf(item) != array_type::NoIndex;
  141. }
  142. // This method searches for the offset of the first element in this
  143. // array that is equal to the given element.
  144. // 'operator==' must be defined for elem_type.
  145. // @param item The item to search for.
  146. // @param start The index to start from.
  147. // @return The index of the found element or NoIndex if not found.
  148. template<class Item>
  149. index_type IndexOf(const Item& item, index_type start = 0) const {
  150. return mArray.IndexOf(item, start);
  151. }
  152. //
  153. // Mutation methods
  154. //
  155. // Prepend an element to the array unless it already exists in the array.
  156. // 'operator==' must be defined for elem_type.
  157. // @param item The item to prepend.
  158. // @return PR_TRUE if the element was found, or inserted successfully.
  159. template<class Item>
  160. PRBool PrependElementUnlessExists(const Item& item) {
  161. return Contains(item) || mArray.InsertElementAt(0, item) != nsnull;
  162. }
  163. // Append an element to the array.
  164. // @param item The item to append.
  165. // @return A pointer to the newly appended element, or null on OOM.
  166. template<class Item>
  167. elem_type* AppendElement(const Item& item) {
  168. return mArray.AppendElement(item);
  169. }
  170. // Same as above, but without copy-constructing. This is useful to avoid
  171. // temporaries.
  172. elem_type* AppendElement() {
  173. return mArray.AppendElement();
  174. }
  175. // Append 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 append.
  178. // @return PR_TRUE if the element was found, or inserted successfully.
  179. template<class Item>
  180. PRBool AppendElementUnlessExists(const Item& item) {
  181. return Contains(item) || AppendElement(item) != nsnull;
  182. }
  183. // Remove an element from the array.
  184. // @param index The index of the item to remove.
  185. void RemoveElementAt(index_type index) {
  186. NS_ASSERTION(index < mArray.Length(), "invalid index");
  187. mArray.RemoveElementAt(index);
  188. AdjustIterators(index, -1);
  189. }
  190. // This helper function combines IndexOf with RemoveElementAt to "search
  191. // and destroy" the first element that is equal to the given element.
  192. // 'operator==' must be defined for elem_type.
  193. // @param item The item to search for.
  194. // @return PR_TRUE if the element was found and removed.
  195. template<class Item>
  196. PRBool RemoveElement(const Item& item) {
  197. index_type index = mArray.IndexOf(item, 0);
  198. if (index == array_type::NoIndex)
  199. return PR_FALSE;
  200. mArray.RemoveElementAt(index);
  201. AdjustIterators(index, -1);
  202. return PR_TRUE;
  203. }
  204. // Removes all observers and collapses all iterators to the beginning of
  205. // the array. The result is that forward iterators will see all elements
  206. // in the array.
  207. void Clear() {
  208. mArray.Clear();
  209. ClearIterators();
  210. }
  211. //
  212. // Iterators
  213. //
  214. // Base class for iterators. Do not use this directly.
  215. class Iterator : public Iterator_base {
  216. protected:
  217. friend class nsAutoTObserverArray;
  218. typedef nsAutoTObserverArray<T, N> array_type;
  219. Iterator(index_type aPosition, const array_type& aArray)
  220. : Iterator_base(aPosition, aArray.mIterators),
  221. mArray(const_cast<array_type&>(aArray)) {
  222. aArray.mIterators = this;
  223. }
  224. ~Iterator() {
  225. NS_ASSERTION(mArray.mIterators == this,
  226. "Iterators must currently be destroyed in opposite order "
  227. "from the construction order. It is suggested that you "
  228. "simply put them on the stack");
  229. mArray.mIterators = mNext;
  230. }
  231. // The array we're iterating
  232. array_type& mArray;
  233. };
  234. // Iterates the array forward from beginning to end. mPosition points
  235. // to the element that will be returned on next call to GetNext.
  236. // Elements:
  237. // - prepended to the array during iteration *will not* be traversed
  238. // - appended during iteration *will* be traversed
  239. // - removed during iteration *will not* be traversed.
  240. // @see EndLimitedIterator
  241. class ForwardIterator : protected Iterator {
  242. public:
  243. typedef nsAutoTObserverArray<T, N> array_type;
  244. typedef Iterator base_type;
  245. ForwardIterator(const array_type& aArray)
  246. : Iterator(0, aArray) {
  247. }
  248. ForwardIterator(const array_type& aArray, index_type aPos)
  249. : Iterator(aPos, aArray) {
  250. }
  251. PRBool operator <(const ForwardIterator& aOther) const {
  252. NS_ASSERTION(&this->mArray == &aOther.mArray,
  253. "not iterating the same array");
  254. return base_type::mPosition < aOther.mPosition;
  255. }
  256. // Returns PR_TRUE if there are more elements to iterate.
  257. // This must precede a call to GetNext(). If PR_FALSE is
  258. // returned, GetNext() must not be called.
  259. PRBool HasMore() const {
  260. return base_type::mPosition < base_type::mArray.Length();
  261. }
  262. // Returns the next element and steps one step. This must
  263. // be preceded by a call to HasMore().
  264. // @return The next observer.
  265. elem_type& GetNext() {
  266. NS_ASSERTION(HasMore(), "iterating beyond end of array");
  267. return base_type::mArray.ElementAt(base_type::mPosition++);
  268. }
  269. };
  270. // EndLimitedIterator works like ForwardIterator, but will not iterate new
  271. // observers appended to the array after the iterator was created.
  272. class EndLimitedIterator : protected ForwardIterator {
  273. public:
  274. typedef nsAutoTObserverArray<T, N> array_type;
  275. typedef Iterator base_type;
  276. EndLimitedIterator(const array_type& aArray)
  277. : ForwardIterator(aArray),
  278. mEnd(aArray, aArray.Length()) {
  279. }
  280. // Returns PR_TRUE if there are more elements to iterate.
  281. // This must precede a call to GetNext(). If PR_FALSE is
  282. // returned, GetNext() must not be called.
  283. PRBool HasMore() const {
  284. return *this < mEnd;
  285. }
  286. // Returns the next element and steps one step. This must
  287. // be preceded by a call to HasMore().
  288. // @return The next observer.
  289. elem_type& GetNext() {
  290. NS_ASSERTION(HasMore(), "iterating beyond end of array");
  291. return base_type::mArray.ElementAt(base_type::mPosition++);
  292. }
  293. private:
  294. ForwardIterator mEnd;
  295. };
  296. protected:
  297. nsAutoTArray<T, N> mArray;
  298. };
  299. template<class T>
  300. class nsTObserverArray : public nsAutoTObserverArray<T, 0> {
  301. public:
  302. typedef nsAutoTObserverArray<T, 0> base_type;
  303. typedef nsTObserverArray_base::size_type size_type;
  304. //
  305. // Initialization methods
  306. //
  307. nsTObserverArray() {}
  308. // Initialize this array and pre-allocate some number of elements.
  309. explicit nsTObserverArray(size_type capacity) {
  310. base_type::mArray.SetCapacity(capacity);
  311. }
  312. };
  313. // XXXbz I wish I didn't have to pass in the observer type, but I
  314. // don't see a way to get it out of array_.
  315. // Note that this macro only works if the array holds pointers to XPCOM objects.
  316. #define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, func_, params_) \
  317. PR_BEGIN_MACRO \
  318. nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_); \
  319. nsCOMPtr<obstype_> obs_; \
  320. while (iter_.HasMore()) { \
  321. obs_ = iter_.GetNext(); \
  322. obs_ -> func_ params_ ; \
  323. } \
  324. PR_END_MACRO
  325. #endif // nsTObserverArray_h___