/src/mozilla-central/xpcom/ds/nsCOMArray.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 nsCOMArray_h__ |
8 | | #define nsCOMArray_h__ |
9 | | |
10 | | #include "mozilla/Attributes.h" |
11 | | #include "mozilla/ArrayIterator.h" |
12 | | #include "mozilla/MemoryReporting.h" |
13 | | #include "mozilla/ReverseIterator.h" |
14 | | |
15 | | #include "nsCycleCollectionNoteChild.h" |
16 | | #include "nsTArray.h" |
17 | | #include "nsISupports.h" |
18 | | |
19 | | // See below for the definition of nsCOMArray<T> |
20 | | |
21 | | // a class that's nsISupports-specific, so that we can contain the |
22 | | // work of this class in the XPCOM dll |
23 | | class nsCOMArray_base |
24 | | { |
25 | | friend class nsArrayBase; |
26 | | protected: |
27 | 20 | nsCOMArray_base() {} |
28 | 9 | explicit nsCOMArray_base(int32_t aCount) : mArray(aCount) {} |
29 | | nsCOMArray_base(const nsCOMArray_base& aOther); |
30 | | ~nsCOMArray_base(); |
31 | | |
32 | | int32_t IndexOf(nsISupports* aObject, uint32_t aStartIndex = 0) const; |
33 | | bool Contains(nsISupports* aObject) const |
34 | | { |
35 | | return IndexOf(aObject) != -1; |
36 | | } |
37 | | |
38 | | int32_t IndexOfObject(nsISupports* aObject) const; |
39 | | bool ContainsObject(nsISupports* aObject) const |
40 | | { |
41 | | return IndexOfObject(aObject) != -1; |
42 | | } |
43 | | |
44 | | typedef bool (*nsBaseArrayEnumFunc)(void* aElement, void* aData); |
45 | | |
46 | | // enumerate through the array with a callback. |
47 | | bool EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const; |
48 | | |
49 | | bool EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const; |
50 | | |
51 | | typedef int (*nsBaseArrayComparatorFunc)(nsISupports* aElement1, |
52 | | nsISupports* aElement2, |
53 | | void* aData); |
54 | | |
55 | | struct nsCOMArrayComparatorContext |
56 | | { |
57 | | nsBaseArrayComparatorFunc mComparatorFunc; |
58 | | void* mData; |
59 | | }; |
60 | | |
61 | | static int nsCOMArrayComparator(const void* aElement1, const void* aElement2, |
62 | | void* aData); |
63 | | void Sort(nsBaseArrayComparatorFunc aFunc, void* aData); |
64 | | |
65 | | bool InsertObjectAt(nsISupports* aObject, int32_t aIndex); |
66 | | void InsertElementAt(uint32_t aIndex, nsISupports* aElement); |
67 | | void InsertElementAt(uint32_t aIndex, already_AddRefed<nsISupports> aElement); |
68 | | bool InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex); |
69 | | void InsertElementsAt(uint32_t aIndex, const nsCOMArray_base& aElements); |
70 | | void InsertElementsAt(uint32_t aIndex, nsISupports* const* aElements, |
71 | | uint32_t aCount); |
72 | | void ReplaceObjectAt(nsISupports* aObject, int32_t aIndex); |
73 | | void ReplaceElementAt(uint32_t aIndex, nsISupports* aElement) |
74 | | { |
75 | | nsISupports* oldElement = mArray[aIndex]; |
76 | | NS_IF_ADDREF(mArray[aIndex] = aElement); |
77 | | NS_IF_RELEASE(oldElement); |
78 | | } |
79 | | bool AppendObject(nsISupports* aObject) |
80 | 3 | { |
81 | 3 | return InsertObjectAt(aObject, Count()); |
82 | 3 | } |
83 | | void AppendElement(nsISupports* aElement) |
84 | 3 | { |
85 | 3 | InsertElementAt(Length(), aElement); |
86 | 3 | } |
87 | | void AppendElement(already_AddRefed<nsISupports> aElement) |
88 | | { |
89 | | InsertElementAt(Length(), std::move(aElement)); |
90 | | } |
91 | | |
92 | | bool AppendObjects(const nsCOMArray_base& aObjects) |
93 | 0 | { |
94 | 0 | return InsertObjectsAt(aObjects, Count()); |
95 | 0 | } |
96 | | void AppendElements(const nsCOMArray_base& aElements) |
97 | | { |
98 | | return InsertElementsAt(Length(), aElements); |
99 | | } |
100 | | void AppendElements(nsISupports* const* aElements, uint32_t aCount) |
101 | | { |
102 | | return InsertElementsAt(Length(), aElements, aCount); |
103 | | } |
104 | | bool RemoveObject(nsISupports* aObject); |
105 | 0 | nsISupports** Elements() { return mArray.Elements(); } |
106 | | void SwapElements(nsCOMArray_base& aOther) |
107 | | { |
108 | | mArray.SwapElements(aOther.mArray); |
109 | | } |
110 | | |
111 | | void Adopt(nsISupports** aElements, uint32_t aCount); |
112 | | uint32_t Forget(nsISupports*** aElements); |
113 | | public: |
114 | | // elements in the array (including null elements!) |
115 | 35 | int32_t Count() const { return mArray.Length(); } |
116 | | // nsTArray-compatible version |
117 | 3 | uint32_t Length() const { return mArray.Length(); } |
118 | | bool IsEmpty() const { return mArray.IsEmpty(); } |
119 | | |
120 | | // If the array grows, the newly created entries will all be null; |
121 | | // if the array shrinks, the excess entries will all be released. |
122 | | bool SetCount(int32_t aNewCount); |
123 | | // nsTArray-compatible version |
124 | | void TruncateLength(uint32_t aNewLength) |
125 | | { |
126 | | if (mArray.Length() > aNewLength) { |
127 | | RemoveElementsAt(aNewLength, mArray.Length() - aNewLength); |
128 | | } |
129 | | } |
130 | | |
131 | | // remove all elements in the array, and call NS_RELEASE on each one |
132 | | void Clear(); |
133 | | |
134 | 3 | nsISupports* ObjectAt(int32_t aIndex) const { return mArray[aIndex]; } |
135 | | // nsTArray-compatible version |
136 | | nsISupports* ElementAt(uint32_t aIndex) const { return mArray[aIndex]; } |
137 | | |
138 | | nsISupports* SafeObjectAt(int32_t aIndex) const |
139 | 0 | { |
140 | 0 | return mArray.SafeElementAt(aIndex, nullptr); |
141 | 0 | } |
142 | | // nsTArray-compatible version |
143 | | nsISupports* SafeElementAt(uint32_t aIndex) const |
144 | | { |
145 | | return mArray.SafeElementAt(aIndex, nullptr); |
146 | | } |
147 | | |
148 | 3 | nsISupports* operator[](int32_t aIndex) const { return mArray[aIndex]; } |
149 | | |
150 | | // remove an element at a specific position, shrinking the array |
151 | | // as necessary |
152 | | bool RemoveObjectAt(int32_t aIndex); |
153 | | // nsTArray-compatible version |
154 | | void RemoveElementAt(uint32_t aIndex); |
155 | | |
156 | | // remove a range of elements at a specific position, shrinking the array |
157 | | // as necessary |
158 | | bool RemoveObjectsAt(int32_t aIndex, int32_t aCount); |
159 | | // nsTArray-compatible version |
160 | | void RemoveElementsAt(uint32_t aIndex, uint32_t aCount); |
161 | | |
162 | | void SwapElementsAt(uint32_t aIndex1, uint32_t aIndex2) |
163 | | { |
164 | | nsISupports* tmp = mArray[aIndex1]; |
165 | | mArray[aIndex1] = mArray[aIndex2]; |
166 | | mArray[aIndex2] = tmp; |
167 | | } |
168 | | |
169 | | // Ensures there is enough space to store a total of aCapacity objects. |
170 | | // This method never deletes any objects. |
171 | 0 | void SetCapacity(uint32_t aCapacity) { mArray.SetCapacity(aCapacity); } |
172 | | uint32_t Capacity() { return mArray.Capacity(); } |
173 | | |
174 | | // Measures the size of the array's element storage. If you want to measure |
175 | | // anything hanging off the array, you must iterate over the elements and |
176 | | // measure them individually; hence the "Shallow" prefix. Note that because |
177 | | // each element in an nsCOMArray<T> is actually a T* any such iteration |
178 | | // should use a SizeOfIncludingThis() function on each element rather than a |
179 | | // SizeOfExcludingThis() function, so that the memory taken by the T itself |
180 | | // is included as well as anything it points to. |
181 | | size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
182 | | { |
183 | | return mArray.ShallowSizeOfExcludingThis(aMallocSizeOf); |
184 | | } |
185 | | |
186 | | private: |
187 | | |
188 | | // the actual storage |
189 | | nsTArray<nsISupports*> mArray; |
190 | | |
191 | | // don't implement these, defaults will muck with refcounts! |
192 | | nsCOMArray_base& operator=(const nsCOMArray_base& aOther) = delete; |
193 | | }; |
194 | | |
195 | | inline void |
196 | | ImplCycleCollectionUnlink(nsCOMArray_base& aField) |
197 | | { |
198 | | aField.Clear(); |
199 | | } |
200 | | |
201 | | inline void |
202 | | ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, |
203 | | nsCOMArray_base& aField, |
204 | | const char* aName, |
205 | | uint32_t aFlags = 0) |
206 | 0 | { |
207 | 0 | aFlags |= CycleCollectionEdgeNameArrayFlag; |
208 | 0 | int32_t length = aField.Count(); |
209 | 0 | for (int32_t i = 0; i < length; ++i) { |
210 | 0 | CycleCollectionNoteChild(aCallback, aField[i], aName, aFlags); |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | |
215 | | // a non-XPCOM, refcounting array of XPCOM objects |
216 | | // used as a member variable or stack variable - this object is NOT |
217 | | // refcounted, but the objects that it holds are |
218 | | // |
219 | | // most of the read-only accessors like ObjectAt()/etc do NOT refcount |
220 | | // on the way out. This means that you can do one of two things: |
221 | | // |
222 | | // * does an addref, but holds onto a reference |
223 | | // nsCOMPtr<T> foo = array[i]; |
224 | | // |
225 | | // * avoids the refcount, but foo might go stale if array[i] is ever |
226 | | // * modified/removed. Be careful not to NS_RELEASE(foo)! |
227 | | // T* foo = array[i]; |
228 | | // |
229 | | // This array will accept null as an argument for any object, and will store |
230 | | // null in the array. But that also means that methods like ObjectAt() may |
231 | | // return null when referring to an existing, but null entry in the array. |
232 | | template<class T> |
233 | | class nsCOMArray : public nsCOMArray_base |
234 | | { |
235 | | public: |
236 | | typedef int32_t index_type; |
237 | | typedef mozilla::ArrayIterator<T*, nsCOMArray> iterator; |
238 | | typedef mozilla::ArrayIterator<const T*, nsCOMArray> const_iterator; |
239 | | typedef mozilla::ReverseIterator<iterator> reverse_iterator; |
240 | | typedef mozilla::ReverseIterator<const_iterator> const_reverse_iterator; |
241 | | |
242 | 0 | nsCOMArray() {} Unexecuted instantiation: nsCOMArray<nsIConsoleListener>::nsCOMArray() Unexecuted instantiation: nsCOMArray<nsIObserver>::nsCOMArray() Unexecuted instantiation: nsCOMArray<nsISupports>::nsCOMArray() |
243 | 3 | explicit nsCOMArray(int32_t aCount) : nsCOMArray_base(aCount) {} |
244 | | explicit nsCOMArray(const nsCOMArray<T>& aOther) : nsCOMArray_base(aOther) {} |
245 | | nsCOMArray(nsCOMArray<T>&& aOther) { SwapElements(aOther); } |
246 | | ~nsCOMArray() {} |
247 | | |
248 | | // We have a move assignment operator, but no copy assignment operator. |
249 | | nsCOMArray<T>& operator=(nsCOMArray<T> && aOther) |
250 | | { |
251 | | SwapElements(aOther); |
252 | | return *this; |
253 | | } |
254 | | |
255 | | // these do NOT refcount on the way out, for speed |
256 | | T* ObjectAt(int32_t aIndex) const |
257 | 0 | { |
258 | 0 | return static_cast<T*>(nsCOMArray_base::ObjectAt(aIndex)); |
259 | 0 | } Unexecuted instantiation: nsCOMArray<nsIConsoleListener>::ObjectAt(int) const Unexecuted instantiation: nsCOMArray<nsIObserver>::ObjectAt(int) const |
260 | | // nsTArray-compatible version |
261 | | T* ElementAt(uint32_t aIndex) const |
262 | | { |
263 | | return static_cast<T*>(nsCOMArray_base::ElementAt(aIndex)); |
264 | | } |
265 | | |
266 | | // these do NOT refcount on the way out, for speed |
267 | | T* SafeObjectAt(int32_t aIndex) const |
268 | | { |
269 | | return static_cast<T*>(nsCOMArray_base::SafeObjectAt(aIndex)); |
270 | | } |
271 | | // nsTArray-compatible version |
272 | | T* SafeElementAt(uint32_t aIndex) const |
273 | | { |
274 | | return static_cast<T*>(nsCOMArray_base::SafeElementAt(aIndex)); |
275 | | } |
276 | | |
277 | | // indexing operator for syntactic sugar |
278 | 0 | T* operator[](int32_t aIndex) const { return ObjectAt(aIndex); } Unexecuted instantiation: nsCOMArray<nsIConsoleListener>::operator[](int) const Unexecuted instantiation: nsCOMArray<nsIObserver>::operator[](int) const |
279 | | |
280 | | // index of the element in question.. does NOT refcount |
281 | | // note: this does not check COM object identity. Use |
282 | | // IndexOfObject() for that purpose |
283 | | int32_t IndexOf(T* aObject, uint32_t aStartIndex = 0) const |
284 | | { |
285 | | return nsCOMArray_base::IndexOf(aObject, aStartIndex); |
286 | | } |
287 | | bool Contains(T* aObject) const |
288 | | { |
289 | | return nsCOMArray_base::Contains(aObject); |
290 | | } |
291 | | |
292 | | // index of the element in question.. be careful! |
293 | | // this is much slower than IndexOf() because it uses |
294 | | // QueryInterface to determine actual COM identity of the object |
295 | | // if you need to do this frequently then consider enforcing |
296 | | // COM object identity before adding/comparing elements |
297 | | int32_t IndexOfObject(T* aObject) const |
298 | | { |
299 | | return nsCOMArray_base::IndexOfObject(aObject); |
300 | | } |
301 | | bool ContainsObject(nsISupports* aObject) const |
302 | | { |
303 | | return nsCOMArray_base::ContainsObject(aObject); |
304 | | } |
305 | | |
306 | | // inserts aObject at aIndex, shifting the objects at aIndex and |
307 | | // later to make space |
308 | | bool InsertObjectAt(T* aObject, int32_t aIndex) |
309 | | { |
310 | | return nsCOMArray_base::InsertObjectAt(aObject, aIndex); |
311 | | } |
312 | | // nsTArray-compatible version |
313 | | void InsertElementAt(uint32_t aIndex, T* aElement) |
314 | | { |
315 | | nsCOMArray_base::InsertElementAt(aIndex, aElement); |
316 | | } |
317 | | |
318 | | // inserts the objects from aObject at aIndex, shifting the |
319 | | // objects at aIndex and later to make space |
320 | | bool InsertObjectsAt(const nsCOMArray<T>& aObjects, int32_t aIndex) |
321 | | { |
322 | | return nsCOMArray_base::InsertObjectsAt(aObjects, aIndex); |
323 | | } |
324 | | // nsTArray-compatible version |
325 | | void InsertElementsAt(uint32_t aIndex, const nsCOMArray<T>& aElements) |
326 | | { |
327 | | nsCOMArray_base::InsertElementsAt(aIndex, aElements); |
328 | | } |
329 | | void InsertElementsAt(uint32_t aIndex, T* const* aElements, uint32_t aCount) |
330 | | { |
331 | | nsCOMArray_base::InsertElementsAt( |
332 | | aIndex, reinterpret_cast<nsISupports* const*>(aElements), aCount); |
333 | | } |
334 | | |
335 | | // replaces an existing element. Warning: if the array grows, |
336 | | // the newly created entries will all be null |
337 | | void ReplaceObjectAt(T* aObject, int32_t aIndex) |
338 | | { |
339 | | nsCOMArray_base::ReplaceObjectAt(aObject, aIndex); |
340 | | } |
341 | | // nsTArray-compatible version |
342 | | void ReplaceElementAt(uint32_t aIndex, T* aElement) |
343 | | { |
344 | | nsCOMArray_base::ReplaceElementAt(aIndex, aElement); |
345 | | } |
346 | | |
347 | | typedef int (*nsCOMArrayComparatorFunc)(T* aElement1, T* aElement2, |
348 | | void* aData); |
349 | | |
350 | | void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) |
351 | 3 | { |
352 | 3 | nsCOMArray_base::Sort(nsBaseArrayComparatorFunc(aFunc), aData); |
353 | 3 | } |
354 | | |
355 | | // append an object, growing the array as necessary |
356 | | bool AppendObject(T* aObject) |
357 | 0 | { |
358 | 0 | return nsCOMArray_base::AppendObject(aObject); |
359 | 0 | } Unexecuted instantiation: nsCOMArray<nsIConsoleListener>::AppendObject(nsIConsoleListener*) Unexecuted instantiation: nsCOMArray<nsIObserver>::AppendObject(nsIObserver*) Unexecuted instantiation: nsCOMArray<nsISupports>::AppendObject(nsISupports*) |
360 | | // nsTArray-compatible version |
361 | | void AppendElement(T* aElement) |
362 | 3 | { |
363 | 3 | nsCOMArray_base::AppendElement(aElement); |
364 | 3 | } |
365 | | void AppendElement(already_AddRefed<T> aElement) |
366 | | { |
367 | | nsCOMArray_base::AppendElement(std::move(aElement)); |
368 | | } |
369 | | |
370 | | // append objects, growing the array as necessary |
371 | | bool AppendObjects(const nsCOMArray<T>& aObjects) |
372 | | { |
373 | | return nsCOMArray_base::AppendObjects(aObjects); |
374 | | } |
375 | | // nsTArray-compatible version |
376 | | void AppendElements(const nsCOMArray<T>& aElements) |
377 | | { |
378 | | return nsCOMArray_base::AppendElements(aElements); |
379 | | } |
380 | | void AppendElements(T* const* aElements, uint32_t aCount) |
381 | | { |
382 | | InsertElementsAt(Length(), aElements, aCount); |
383 | | } |
384 | | |
385 | | // remove the first instance of the given object and shrink the |
386 | | // array as necessary |
387 | | // Warning: if you pass null here, it will remove the first null element |
388 | | bool RemoveObject(T* aObject) |
389 | 0 | { |
390 | 0 | return nsCOMArray_base::RemoveObject(aObject); |
391 | 0 | } |
392 | | // nsTArray-compatible version |
393 | | bool RemoveElement(T* aElement) |
394 | | { |
395 | | return nsCOMArray_base::RemoveObject(aElement); |
396 | | } |
397 | | |
398 | | T** Elements() |
399 | | { |
400 | | return reinterpret_cast<T**>(nsCOMArray_base::Elements()); |
401 | | } |
402 | | void SwapElements(nsCOMArray<T>& aOther) |
403 | | { |
404 | | nsCOMArray_base::SwapElements(aOther); |
405 | | } |
406 | | |
407 | | /** |
408 | | * Adopt parameters that resulted from an XPIDL outparam. The aElements |
409 | | * parameter will be freed as a result of the call. |
410 | | * |
411 | | * Example usage: |
412 | | * nsCOMArray<nsISomeInterface> array; |
413 | | * nsISomeInterface** elements; |
414 | | * uint32_t length; |
415 | | * ptr->GetSomeArray(&elements, &length); |
416 | | * array.Adopt(elements, length); |
417 | | */ |
418 | | void Adopt(T** aElements, uint32_t aSize) |
419 | | { |
420 | | nsCOMArray_base::Adopt(reinterpret_cast<nsISupports**>(aElements), aSize); |
421 | | } |
422 | | |
423 | | /** |
424 | | * Export the contents of this array to an XPIDL outparam. The array will be |
425 | | * Clear()'d after this operation. |
426 | | * |
427 | | * Example usage: |
428 | | * nsCOMArray<nsISomeInterface> array; |
429 | | * *length = array.Forget(retval); |
430 | | */ |
431 | | uint32_t Forget(T*** aElements) |
432 | | { |
433 | | return nsCOMArray_base::Forget(reinterpret_cast<nsISupports***>(aElements)); |
434 | | } |
435 | | |
436 | | // Methods for range-based for loops. |
437 | | iterator begin() { return iterator(*this, 0); } |
438 | | const_iterator begin() const { return const_iterator(*this, 0); } |
439 | | const_iterator cbegin() const { return begin(); } |
440 | | iterator end() { return iterator(*this, Length()); } |
441 | | const_iterator end() const { return const_iterator(*this, Length()); } |
442 | | const_iterator cend() const { return end(); } |
443 | | |
444 | | // Methods for reverse iterating. |
445 | | reverse_iterator rbegin() { return reverse_iterator(end()); } |
446 | | const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } |
447 | | const_reverse_iterator crbegin() const { return rbegin(); } |
448 | | reverse_iterator rend() { return reverse_iterator(begin()); } |
449 | | const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } |
450 | | const_reverse_iterator crend() const { return rend(); } |
451 | | |
452 | | private: |
453 | | |
454 | | // don't implement these! |
455 | | nsCOMArray<T>& operator=(const nsCOMArray<T>& aOther) = delete; |
456 | | }; |
457 | | |
458 | | template<typename T> |
459 | | inline void |
460 | | ImplCycleCollectionUnlink(nsCOMArray<T>& aField) |
461 | | { |
462 | | aField.Clear(); |
463 | | } |
464 | | |
465 | | template<typename E> |
466 | | inline void |
467 | | ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, |
468 | | nsCOMArray<E>& aField, |
469 | | const char* aName, |
470 | | uint32_t aFlags = 0) |
471 | | { |
472 | | aFlags |= CycleCollectionEdgeNameArrayFlag; |
473 | | int32_t length = aField.Count(); |
474 | | for (int32_t i = 0; i < length; ++i) { |
475 | | CycleCollectionNoteChild(aCallback, aField[i], aName, aFlags); |
476 | | } |
477 | | } |
478 | | |
479 | | #endif |