Line data Source code
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 1308 : nsCOMArray_base() {}
28 30 : 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 0 : bool Contains(nsISupports* aObject) const
34 : {
35 0 : 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 3840 : bool AppendObject(nsISupports* aObject)
80 : {
81 3840 : return InsertObjectAt(aObject, Count());
82 : }
83 3 : void AppendElement(nsISupports* aElement)
84 : {
85 3 : InsertElementAt(Length(), aElement);
86 3 : }
87 45 : void AppendElement(already_AddRefed<nsISupports> aElement)
88 : {
89 45 : InsertElementAt(Length(), mozilla::Move(aElement));
90 45 : }
91 :
92 758 : bool AppendObjects(const nsCOMArray_base& aObjects)
93 : {
94 758 : return InsertObjectsAt(aObjects, Count());
95 : }
96 0 : void AppendElements(const nsCOMArray_base& aElements)
97 : {
98 0 : 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 1 : void SwapElements(nsCOMArray_base& aOther)
107 : {
108 1 : mArray.SwapElements(aOther.mArray);
109 1 : }
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 7216 : int32_t Count() const { return mArray.Length(); }
116 : // nsTArray-compatible version
117 1466 : uint32_t Length() const { return mArray.Length(); }
118 47 : 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 0 : void TruncateLength(uint32_t aNewLength)
125 : {
126 0 : if (mArray.Length() > aNewLength) {
127 0 : RemoveElementsAt(aNewLength, mArray.Length() - aNewLength);
128 : }
129 0 : }
130 :
131 : // remove all elements in the array, and call NS_RELEASE on each one
132 : void Clear();
133 :
134 10472 : nsISupports* ObjectAt(int32_t aIndex) const { return mArray[aIndex]; }
135 : // nsTArray-compatible version
136 565 : nsISupports* ElementAt(uint32_t aIndex) const { return mArray[aIndex]; }
137 :
138 21 : nsISupports* SafeObjectAt(int32_t aIndex) const
139 : {
140 21 : return mArray.SafeElementAt(aIndex, nullptr);
141 : }
142 : // nsTArray-compatible version
143 0 : nsISupports* SafeElementAt(uint32_t aIndex) const
144 : {
145 0 : return mArray.SafeElementAt(aIndex, nullptr);
146 : }
147 :
148 47 : 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 208 : 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 5 : size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
182 : {
183 5 : 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 0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
203 : nsCOMArray_base& aField,
204 : const char* aName,
205 : uint32_t aFlags = 0)
206 : {
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 : }
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 1306 : nsCOMArray() {}
243 30 : explicit nsCOMArray(int32_t aCount) : nsCOMArray_base(aCount) {}
244 758 : explicit nsCOMArray(const nsCOMArray<T>& aOther) : nsCOMArray_base(aOther) {}
245 0 : nsCOMArray(nsCOMArray<T>&& aOther) { SwapElements(aOther); }
246 901 : ~nsCOMArray() {}
247 :
248 : // We have a move assignment operator, but no copy assignment operator.
249 1 : nsCOMArray<T>& operator=(nsCOMArray<T> && aOther)
250 : {
251 1 : SwapElements(aOther);
252 1 : return *this;
253 : }
254 :
255 : // these do NOT refcount on the way out, for speed
256 10472 : T* ObjectAt(int32_t aIndex) const
257 : {
258 10472 : return static_cast<T*>(nsCOMArray_base::ObjectAt(aIndex));
259 : }
260 : // nsTArray-compatible version
261 565 : T* ElementAt(uint32_t aIndex) const
262 : {
263 565 : return static_cast<T*>(nsCOMArray_base::ElementAt(aIndex));
264 : }
265 :
266 : // these do NOT refcount on the way out, for speed
267 9 : T* SafeObjectAt(int32_t aIndex) const
268 : {
269 9 : return static_cast<T*>(nsCOMArray_base::SafeObjectAt(aIndex));
270 : }
271 : // nsTArray-compatible version
272 0 : T* SafeElementAt(uint32_t aIndex) const
273 : {
274 0 : return static_cast<T*>(nsCOMArray_base::SafeElementAt(aIndex));
275 : }
276 :
277 : // indexing operator for syntactic sugar
278 10388 : T* operator[](int32_t aIndex) const { return ObjectAt(aIndex); }
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 1 : int32_t IndexOf(T* aObject, uint32_t aStartIndex = 0) const
284 : {
285 1 : return nsCOMArray_base::IndexOf(aObject, aStartIndex);
286 : }
287 0 : bool Contains(T* aObject) const
288 : {
289 0 : 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 1 : int32_t IndexOfObject(T* aObject) const
298 : {
299 1 : 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 11 : bool InsertObjectAt(T* aObject, int32_t aIndex)
309 : {
310 11 : return nsCOMArray_base::InsertObjectAt(aObject, aIndex);
311 : }
312 : // nsTArray-compatible version
313 0 : void InsertElementAt(uint32_t aIndex, T* aElement)
314 : {
315 0 : nsCOMArray_base::InsertElementAt(aIndex, aElement);
316 0 : }
317 :
318 : // inserts the objects from aObject at aIndex, shifting the
319 : // objects at aIndex and later to make space
320 0 : bool InsertObjectsAt(const nsCOMArray<T>& aObjects, int32_t aIndex)
321 : {
322 0 : 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 0 : void ReplaceObjectAt(T* aObject, int32_t aIndex)
338 : {
339 0 : nsCOMArray_base::ReplaceObjectAt(aObject, aIndex);
340 0 : }
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 6 : void Sort(nsCOMArrayComparatorFunc aFunc, void* aData)
351 : {
352 6 : nsCOMArray_base::Sort(nsBaseArrayComparatorFunc(aFunc), aData);
353 6 : }
354 :
355 : // append an object, growing the array as necessary
356 3834 : bool AppendObject(T* aObject)
357 : {
358 3834 : return nsCOMArray_base::AppendObject(aObject);
359 : }
360 : // nsTArray-compatible version
361 3 : void AppendElement(T* aElement)
362 : {
363 3 : nsCOMArray_base::AppendElement(aElement);
364 3 : }
365 45 : void AppendElement(already_AddRefed<T> aElement)
366 : {
367 45 : nsCOMArray_base::AppendElement(mozilla::Move(aElement));
368 45 : }
369 :
370 : // append objects, growing the array as necessary
371 0 : bool AppendObjects(const nsCOMArray<T>& aObjects)
372 : {
373 0 : return nsCOMArray_base::AppendObjects(aObjects);
374 : }
375 : // nsTArray-compatible version
376 0 : void AppendElements(const nsCOMArray<T>& aElements)
377 : {
378 0 : 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 22 : bool RemoveObject(T* aObject)
389 : {
390 22 : return nsCOMArray_base::RemoveObject(aObject);
391 : }
392 : // nsTArray-compatible version
393 0 : bool RemoveElement(T* aElement)
394 : {
395 0 : return nsCOMArray_base::RemoveObject(aElement);
396 : }
397 :
398 : T** Elements()
399 : {
400 : return reinterpret_cast<T**>(nsCOMArray_base::Elements());
401 : }
402 1 : void SwapElements(nsCOMArray<T>& aOther)
403 : {
404 1 : nsCOMArray_base::SwapElements(aOther);
405 1 : }
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 0 : uint32_t Forget(T*** aElements)
432 : {
433 0 : return nsCOMArray_base::Forget(reinterpret_cast<nsISupports***>(aElements));
434 : }
435 :
436 : // Methods for range-based for loops.
437 162 : iterator begin() { return iterator(*this, 0); }
438 140 : const_iterator begin() const { return const_iterator(*this, 0); }
439 : const_iterator cbegin() const { return begin(); }
440 162 : iterator end() { return iterator(*this, Length()); }
441 140 : 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 0 : ImplCycleCollectionUnlink(nsCOMArray<T>& aField)
461 : {
462 0 : aField.Clear();
463 0 : }
464 :
465 : template<typename E>
466 : inline void
467 1 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
468 : nsCOMArray<E>& aField,
469 : const char* aName,
470 : uint32_t aFlags = 0)
471 : {
472 1 : aFlags |= CycleCollectionEdgeNameArrayFlag;
473 1 : int32_t length = aField.Count();
474 1 : for (int32_t i = 0; i < length; ++i) {
475 0 : CycleCollectionNoteChild(aCallback, aField[i], aName, aFlags);
476 : }
477 1 : }
478 :
479 : #endif
|