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/. */
10 #include "mozilla/Attributes.h"
11 #include "mozilla/MemoryReporting.h"
13 #include "nsCycleCollectionNoteChild.h"
15 #include "nsISupports.h"
17 // See below for the definition of nsCOMArray<T>
19 // a class that's nsISupports-specific, so that we can contain the
20 // work of this class in the XPCOM dll
23 friend class nsArrayBase
;
26 explicit nsCOMArray_base(int32_t aCount
) : mArray(aCount
) {}
27 nsCOMArray_base(const nsCOMArray_base
& aOther
);
30 int32_t IndexOf(nsISupports
* aObject
, uint32_t aStartIndex
= 0) const;
31 bool Contains(nsISupports
* aObject
) const
33 return IndexOf(aObject
) != -1;
36 int32_t IndexOfObject(nsISupports
* aObject
) const;
37 bool ContainsObject(nsISupports
* aObject
) const
39 return IndexOfObject(aObject
) != -1;
42 typedef bool (*nsBaseArrayEnumFunc
)(void* aElement
, void* aData
);
44 // enumerate through the array with a callback.
45 bool EnumerateForwards(nsBaseArrayEnumFunc aFunc
, void* aData
) const;
47 bool EnumerateBackwards(nsBaseArrayEnumFunc aFunc
, void* aData
) const;
49 typedef int (*nsBaseArrayComparatorFunc
)(nsISupports
* aElement1
,
50 nsISupports
* aElement2
,
53 struct nsCOMArrayComparatorContext
55 nsBaseArrayComparatorFunc mComparatorFunc
;
59 static int nsCOMArrayComparator(const void* aElement1
, const void* aElement2
,
61 void Sort(nsBaseArrayComparatorFunc aFunc
, void* aData
);
63 bool InsertObjectAt(nsISupports
* aObject
, int32_t aIndex
);
64 void InsertElementAt(uint32_t aIndex
, nsISupports
* aElement
);
65 bool InsertObjectsAt(const nsCOMArray_base
& aObjects
, int32_t aIndex
);
66 void InsertElementsAt(uint32_t aIndex
, const nsCOMArray_base
& aElements
);
67 void InsertElementsAt(uint32_t aIndex
, nsISupports
* const* aElements
,
69 bool ReplaceObjectAt(nsISupports
* aObject
, int32_t aIndex
);
70 void ReplaceElementAt(uint32_t aIndex
, nsISupports
* aElement
)
72 nsISupports
* oldElement
= mArray
[aIndex
];
73 NS_IF_ADDREF(mArray
[aIndex
] = aElement
);
74 NS_IF_RELEASE(oldElement
);
76 bool AppendObject(nsISupports
* aObject
)
78 return InsertObjectAt(aObject
, Count());
80 void AppendElement(nsISupports
* aElement
)
82 InsertElementAt(Length(), aElement
);
84 bool AppendObjects(const nsCOMArray_base
& aObjects
)
86 return InsertObjectsAt(aObjects
, Count());
88 void AppendElements(const nsCOMArray_base
& aElements
)
90 return InsertElementsAt(Length(), aElements
);
92 void AppendElements(nsISupports
* const* aElements
, uint32_t aCount
)
94 return InsertElementsAt(Length(), aElements
, aCount
);
96 bool RemoveObject(nsISupports
* aObject
);
97 nsISupports
** Elements() { return mArray
.Elements(); }
98 void SwapElements(nsCOMArray_base
& aOther
)
100 mArray
.SwapElements(aOther
.mArray
);
103 void Adopt(nsISupports
** aElements
, uint32_t aCount
);
104 uint32_t Forget(nsISupports
*** aElements
);
106 // elements in the array (including null elements!)
107 int32_t Count() const { return mArray
.Length(); }
108 // nsTArray-compatible version
109 uint32_t Length() const { return mArray
.Length(); }
110 bool IsEmpty() const { return mArray
.IsEmpty(); }
112 // If the array grows, the newly created entries will all be null;
113 // if the array shrinks, the excess entries will all be released.
114 bool SetCount(int32_t aNewCount
);
115 // nsTArray-compatible version
116 void TruncateLength(uint32_t aNewLength
)
118 if (mArray
.Length() > aNewLength
) {
119 RemoveElementsAt(aNewLength
, mArray
.Length() - aNewLength
);
123 // remove all elements in the array, and call NS_RELEASE on each one
126 nsISupports
* ObjectAt(int32_t aIndex
) const { return mArray
[aIndex
]; }
127 // nsTArray-compatible version
128 nsISupports
* ElementAt(uint32_t aIndex
) const { return mArray
[aIndex
]; }
130 nsISupports
* SafeObjectAt(int32_t aIndex
) const
132 return mArray
.SafeElementAt(aIndex
, nullptr);
134 // nsTArray-compatible version
135 nsISupports
* SafeElementAt(uint32_t aIndex
) const
137 return mArray
.SafeElementAt(aIndex
, nullptr);
140 nsISupports
* operator[](int32_t aIndex
) const { return mArray
[aIndex
]; }
142 // remove an element at a specific position, shrinking the array
144 bool RemoveObjectAt(int32_t aIndex
);
145 // nsTArray-compatible version
146 void RemoveElementAt(uint32_t aIndex
);
148 // remove a range of elements at a specific position, shrinking the array
150 bool RemoveObjectsAt(int32_t aIndex
, int32_t aCount
);
151 // nsTArray-compatible version
152 void RemoveElementsAt(uint32_t aIndex
, uint32_t aCount
);
154 void SwapElementsAt(uint32_t aIndex1
, uint32_t aIndex2
)
156 nsISupports
* tmp
= mArray
[aIndex1
];
157 mArray
[aIndex1
] = mArray
[aIndex2
];
158 mArray
[aIndex2
] = tmp
;
161 // Ensures there is enough space to store a total of aCapacity objects.
162 // This method never deletes any objects.
163 void SetCapacity(uint32_t aCapacity
) { mArray
.SetCapacity(aCapacity
); }
164 uint32_t Capacity() { return mArray
.Capacity(); }
166 typedef size_t (*nsBaseArraySizeOfElementIncludingThisFunc
)(
167 nsISupports
* aElement
, mozilla::MallocSizeOf aMallocSizeOf
, void* aData
);
169 // Measures the size of the array's element storage, and if
170 // |aSizeOfElement| is non-nullptr, measures the size of things pointed to
172 size_t SizeOfExcludingThis(
173 nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis
,
174 mozilla::MallocSizeOf aMallocSizeOf
, void* aData
= nullptr) const;
178 // the actual storage
179 nsTArray
<nsISupports
*> mArray
;
181 // don't implement these, defaults will muck with refcounts!
182 nsCOMArray_base
& operator=(const nsCOMArray_base
& aOther
) MOZ_DELETE
;
186 ImplCycleCollectionUnlink(nsCOMArray_base
& aField
)
192 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
& aCallback
,
193 nsCOMArray_base
& aField
,
197 aFlags
|= CycleCollectionEdgeNameArrayFlag
;
198 int32_t length
= aField
.Count();
199 for (int32_t i
= 0; i
< length
; ++i
) {
200 CycleCollectionNoteChild(aCallback
, aField
[i
], aName
, aFlags
);
205 // a non-XPCOM, refcounting array of XPCOM objects
206 // used as a member variable or stack variable - this object is NOT
207 // refcounted, but the objects that it holds are
209 // most of the read-only accessors like ObjectAt()/etc do NOT refcount
210 // on the way out. This means that you can do one of two things:
212 // * does an addref, but holds onto a reference
213 // nsCOMPtr<T> foo = array[i];
215 // * avoids the refcount, but foo might go stale if array[i] is ever
216 // * modified/removed. Be careful not to NS_RELEASE(foo)!
217 // T* foo = array[i];
219 // This array will accept null as an argument for any object, and will
220 // store null in the array, just like nsVoidArray. But that also means
221 // that methods like ObjectAt() may return null when referring to an
222 // existing, but null entry in the array.
224 class nsCOMArray
: public nsCOMArray_base
228 explicit nsCOMArray(int32_t aCount
) : nsCOMArray_base(aCount
) {}
229 explicit nsCOMArray(const nsCOMArray
<T
>& aOther
) : nsCOMArray_base(aOther
) {}
230 nsCOMArray(nsCOMArray
<T
>&& aOther
) { SwapElements(aOther
); }
233 // We have a move assignment operator, but no copy assignment operator.
234 nsCOMArray
<T
>& operator=(nsCOMArray
<T
> && aOther
)
236 SwapElements(aOther
);
240 // these do NOT refcount on the way out, for speed
241 T
* ObjectAt(int32_t aIndex
) const
243 return static_cast<T
*>(nsCOMArray_base::ObjectAt(aIndex
));
245 // nsTArray-compatible version
246 T
* ElementAt(uint32_t aIndex
) const
248 return static_cast<T
*>(nsCOMArray_base::ElementAt(aIndex
));
251 // these do NOT refcount on the way out, for speed
252 T
* SafeObjectAt(int32_t aIndex
) const
254 return static_cast<T
*>(nsCOMArray_base::SafeObjectAt(aIndex
));
256 // nsTArray-compatible version
257 T
* SafeElementAt(uint32_t aIndex
) const
259 return static_cast<T
*>(nsCOMArray_base::SafeElementAt(aIndex
));
262 // indexing operator for syntactic sugar
263 T
* operator[](int32_t aIndex
) const { return ObjectAt(aIndex
); }
265 // index of the element in question.. does NOT refcount
266 // note: this does not check COM object identity. Use
267 // IndexOfObject() for that purpose
268 int32_t IndexOf(T
* aObject
, uint32_t aStartIndex
= 0) const
270 return nsCOMArray_base::IndexOf(aObject
, aStartIndex
);
272 bool Contains(T
* aObject
) const
274 return nsCOMArray_base::Contains(aObject
);
277 // index of the element in question.. be careful!
278 // this is much slower than IndexOf() because it uses
279 // QueryInterface to determine actual COM identity of the object
280 // if you need to do this frequently then consider enforcing
281 // COM object identity before adding/comparing elements
282 int32_t IndexOfObject(T
* aObject
) const
284 return nsCOMArray_base::IndexOfObject(aObject
);
286 bool ContainsObject(nsISupports
* aObject
) const
288 return nsCOMArray_base::ContainsObject(aObject
);
291 // inserts aObject at aIndex, shifting the objects at aIndex and
292 // later to make space
293 bool InsertObjectAt(T
* aObject
, int32_t aIndex
)
295 return nsCOMArray_base::InsertObjectAt(aObject
, aIndex
);
297 // nsTArray-compatible version
298 void InsertElementAt(uint32_t aIndex
, T
* aElement
)
300 nsCOMArray_base::InsertElementAt(aIndex
, aElement
);
303 // inserts the objects from aObject at aIndex, shifting the
304 // objects at aIndex and later to make space
305 bool InsertObjectsAt(const nsCOMArray
<T
>& aObjects
, int32_t aIndex
)
307 return nsCOMArray_base::InsertObjectsAt(aObjects
, aIndex
);
309 // nsTArray-compatible version
310 void InsertElementsAt(uint32_t aIndex
, const nsCOMArray
<T
>& aElements
)
312 nsCOMArray_base::InsertElementsAt(aIndex
, aElements
);
314 void InsertElementsAt(uint32_t aIndex
, T
* const* aElements
, uint32_t aCount
)
316 nsCOMArray_base::InsertElementsAt(
317 aIndex
, reinterpret_cast<nsISupports
* const*>(aElements
), aCount
);
320 // replaces an existing element. Warning: if the array grows,
321 // the newly created entries will all be null
322 bool ReplaceObjectAt(T
* aObject
, int32_t aIndex
)
324 return nsCOMArray_base::ReplaceObjectAt(aObject
, aIndex
);
326 // nsTArray-compatible version
327 void ReplaceElementAt(uint32_t aIndex
, T
* aElement
)
329 nsCOMArray_base::ReplaceElementAt(aIndex
, aElement
);
332 // Enumerator callback function. Return false to stop
333 // Here's a more readable form:
334 // bool enumerate(T* aElement, void* aData)
335 typedef bool (*nsCOMArrayEnumFunc
)(T
* aElement
, void* aData
);
337 // enumerate through the array with a callback.
338 bool EnumerateForwards(nsCOMArrayEnumFunc aFunc
, void* aData
)
340 return nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc(aFunc
),
344 bool EnumerateBackwards(nsCOMArrayEnumFunc aFunc
, void* aData
)
346 return nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc(aFunc
),
350 typedef int (*nsCOMArrayComparatorFunc
)(T
* aElement1
, T
* aElement2
,
353 void Sort(nsCOMArrayComparatorFunc aFunc
, void* aData
)
355 nsCOMArray_base::Sort(nsBaseArrayComparatorFunc(aFunc
), aData
);
358 // append an object, growing the array as necessary
359 bool AppendObject(T
* aObject
)
361 return nsCOMArray_base::AppendObject(aObject
);
363 // nsTArray-compatible version
364 void AppendElement(T
* aElement
)
366 nsCOMArray_base::AppendElement(aElement
);
369 // append objects, growing the array as necessary
370 bool AppendObjects(const nsCOMArray
<T
>& aObjects
)
372 return nsCOMArray_base::AppendObjects(aObjects
);
374 // nsTArray-compatible version
375 void AppendElements(const nsCOMArray
<T
>& aElements
)
377 return nsCOMArray_base::AppendElements(aElements
);
379 void AppendElements(T
* const* aElements
, uint32_t aCount
)
381 InsertElementsAt(Length(), aElements
, aCount
);
384 // remove the first instance of the given object and shrink the
385 // array as necessary
386 // Warning: if you pass null here, it will remove the first null element
387 bool RemoveObject(T
* aObject
)
389 return nsCOMArray_base::RemoveObject(aObject
);
391 // nsTArray-compatible version
392 bool RemoveElement(T
* aElement
)
394 return nsCOMArray_base::RemoveObject(aElement
);
399 return reinterpret_cast<T
**>(nsCOMArray_base::Elements());
401 void SwapElements(nsCOMArray
<T
>& aOther
)
403 nsCOMArray_base::SwapElements(aOther
);
406 // Each element in an nsCOMArray<T> is actually a T*, so this function is
407 // "IncludingThis" rather than "ExcludingThis" because it needs to measure
408 // the memory taken by the T itself as well as anything it points to.
409 typedef size_t (*nsCOMArraySizeOfElementIncludingThisFunc
)(
410 T
* aElement
, mozilla::MallocSizeOf aMallocSizeOf
, void* aData
);
412 size_t SizeOfExcludingThis(
413 nsCOMArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis
,
414 mozilla::MallocSizeOf aMallocSizeOf
, void* aData
= nullptr) const
416 return nsCOMArray_base::SizeOfExcludingThis(
417 nsBaseArraySizeOfElementIncludingThisFunc(aSizeOfElementIncludingThis
),
418 aMallocSizeOf
, aData
);
422 * Adopt parameters that resulted from an XPIDL outparam. The aElements
423 * parameter will be freed as a result of the call.
426 * nsCOMArray<nsISomeInterface> array;
427 * nsISomeInterface** elements;
429 * ptr->GetSomeArray(&elements, &length);
430 * array.Adopt(elements, length);
432 void Adopt(T
** aElements
, uint32_t aSize
)
434 nsCOMArray_base::Adopt(reinterpret_cast<nsISupports
**>(aElements
), aSize
);
438 * Export the contents of this array to an XPIDL outparam. The array will be
439 * Clear()'d after this operation.
442 * nsCOMArray<nsISomeInterface> array;
443 * *length = array.Forget(retval);
445 uint32_t Forget(T
*** aElements
)
447 return nsCOMArray_base::Forget(reinterpret_cast<nsISupports
***>(aElements
));
452 // don't implement these!
453 nsCOMArray
<T
>& operator=(const nsCOMArray
<T
>& aOther
) MOZ_DELETE
;
458 ImplCycleCollectionUnlink(nsCOMArray
<T
>& aField
)
465 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
& aCallback
,
466 nsCOMArray
<E
>& aField
,
470 aFlags
|= CycleCollectionEdgeNameArrayFlag
;
471 int32_t length
= aField
.Count();
472 for (int32_t i
= 0; i
< length
; ++i
) {
473 CycleCollectionNoteChild(aCallback
, aField
[i
], aName
, aFlags
);