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