|
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 #include "nsCOMArray.h" |
|
7 |
|
8 #include "mozilla/MemoryReporting.h" |
|
9 |
|
10 #include "nsCOMPtr.h" |
|
11 |
|
12 // This specialization is private to nsCOMArray. |
|
13 // It exists solely to automatically zero-out newly created array elements. |
|
14 template<> |
|
15 class nsTArrayElementTraits<nsISupports*> |
|
16 { |
|
17 typedef nsISupports* E; |
|
18 public: |
|
19 // Zero out the value |
|
20 static inline void Construct(E *e) { |
|
21 new (static_cast<void *>(e)) E(); |
|
22 } |
|
23 // Invoke the copy-constructor in place. |
|
24 template<class A> |
|
25 static inline void Construct(E *e, const A &arg) { |
|
26 new (static_cast<void *>(e)) E(arg); |
|
27 } |
|
28 // Invoke the destructor in place. |
|
29 static inline void Destruct(E *e) { |
|
30 e->~E(); |
|
31 } |
|
32 }; |
|
33 |
|
34 static void ReleaseObjects(nsTArray<nsISupports*> &aArray); |
|
35 |
|
36 // implementations of non-trivial methods in nsCOMArray_base |
|
37 |
|
38 nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) |
|
39 { |
|
40 // make sure we do only one allocation |
|
41 mArray.SetCapacity(aOther.Count()); |
|
42 AppendObjects(aOther); |
|
43 } |
|
44 |
|
45 nsCOMArray_base::~nsCOMArray_base() |
|
46 { |
|
47 Clear(); |
|
48 } |
|
49 |
|
50 int32_t |
|
51 nsCOMArray_base::IndexOf(nsISupports* aObject, uint32_t aStartIndex) const |
|
52 { |
|
53 return mArray.IndexOf(aObject, aStartIndex); |
|
54 } |
|
55 |
|
56 int32_t |
|
57 nsCOMArray_base::IndexOfObject(nsISupports* aObject) const |
|
58 { |
|
59 nsCOMPtr<nsISupports> supports = do_QueryInterface(aObject); |
|
60 if (NS_WARN_IF(!supports)) |
|
61 return -1; |
|
62 |
|
63 uint32_t i, count; |
|
64 int32_t retval = -1; |
|
65 count = mArray.Length(); |
|
66 for (i = 0; i < count; ++i) { |
|
67 nsCOMPtr<nsISupports> arrayItem = do_QueryInterface(mArray[i]); |
|
68 if (arrayItem == supports) { |
|
69 retval = i; |
|
70 break; |
|
71 } |
|
72 } |
|
73 return retval; |
|
74 } |
|
75 |
|
76 bool |
|
77 nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const |
|
78 { |
|
79 for (uint32_t index = 0; index < mArray.Length(); index++) |
|
80 if (!(*aFunc)(mArray[index], aData)) |
|
81 return false; |
|
82 |
|
83 return true; |
|
84 } |
|
85 |
|
86 bool |
|
87 nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const |
|
88 { |
|
89 for (uint32_t index = mArray.Length(); index--; ) |
|
90 if (!(*aFunc)(mArray[index], aData)) |
|
91 return false; |
|
92 |
|
93 return true; |
|
94 } |
|
95 |
|
96 int |
|
97 nsCOMArray_base::nsCOMArrayComparator(const void* aElement1, const void* aElement2, void* aData) |
|
98 { |
|
99 nsCOMArrayComparatorContext* ctx = static_cast<nsCOMArrayComparatorContext*>(aData); |
|
100 return (*ctx->mComparatorFunc)(*static_cast<nsISupports* const*>(aElement1), |
|
101 *static_cast<nsISupports* const*>(aElement2), |
|
102 ctx->mData); |
|
103 } |
|
104 |
|
105 void |
|
106 nsCOMArray_base::Sort(nsBaseArrayComparatorFunc aFunc, void* aData) |
|
107 { |
|
108 if (mArray.Length() > 1) { |
|
109 nsCOMArrayComparatorContext ctx = {aFunc, aData}; |
|
110 NS_QuickSort(mArray.Elements(), mArray.Length(), sizeof(nsISupports*), |
|
111 nsCOMArrayComparator, &ctx); |
|
112 } |
|
113 } |
|
114 |
|
115 bool |
|
116 nsCOMArray_base::InsertObjectAt(nsISupports* aObject, int32_t aIndex) |
|
117 { |
|
118 if ((uint32_t)aIndex > mArray.Length()) |
|
119 return false; |
|
120 |
|
121 if (!mArray.InsertElementAt(aIndex, aObject)) |
|
122 return false; |
|
123 |
|
124 NS_IF_ADDREF(aObject); |
|
125 return true; |
|
126 } |
|
127 |
|
128 void |
|
129 nsCOMArray_base::InsertElementAt(uint32_t aIndex, nsISupports* aElement) |
|
130 { |
|
131 mArray.InsertElementAt(aIndex, aElement); |
|
132 NS_IF_ADDREF(aElement); |
|
133 } |
|
134 |
|
135 bool |
|
136 nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex) |
|
137 { |
|
138 if ((uint32_t)aIndex > mArray.Length()) |
|
139 return false; |
|
140 |
|
141 if (!mArray.InsertElementsAt(aIndex, aObjects.mArray)) |
|
142 return false; |
|
143 |
|
144 // need to addref all these |
|
145 uint32_t count = aObjects.Length(); |
|
146 for (uint32_t i = 0; i < count; ++i) |
|
147 NS_IF_ADDREF(aObjects[i]); |
|
148 |
|
149 return true; |
|
150 } |
|
151 |
|
152 void |
|
153 nsCOMArray_base::InsertElementsAt(uint32_t aIndex, const nsCOMArray_base& aElements) |
|
154 { |
|
155 mArray.InsertElementsAt(aIndex, aElements.mArray); |
|
156 |
|
157 // need to addref all these |
|
158 uint32_t count = aElements.Length(); |
|
159 for (uint32_t i = 0; i < count; ++i) |
|
160 NS_IF_ADDREF(aElements[i]); |
|
161 } |
|
162 |
|
163 void |
|
164 nsCOMArray_base::InsertElementsAt(uint32_t aIndex, nsISupports* const* aElements, uint32_t aCount) |
|
165 { |
|
166 mArray.InsertElementsAt(aIndex, aElements, aCount); |
|
167 |
|
168 // need to addref all these |
|
169 for (uint32_t i = 0; i < aCount; ++i) |
|
170 NS_IF_ADDREF(aElements[i]); |
|
171 } |
|
172 |
|
173 bool |
|
174 nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, int32_t aIndex) |
|
175 { |
|
176 mArray.EnsureLengthAtLeast(aIndex + 1); |
|
177 nsISupports *oldObject = mArray[aIndex]; |
|
178 // Make sure to addref first, in case aObject == oldObject |
|
179 NS_IF_ADDREF(mArray[aIndex] = aObject); |
|
180 NS_IF_RELEASE(oldObject); |
|
181 // XXX make this return void |
|
182 return true; |
|
183 } |
|
184 |
|
185 bool |
|
186 nsCOMArray_base::RemoveObject(nsISupports *aObject) |
|
187 { |
|
188 bool result = mArray.RemoveElement(aObject); |
|
189 if (result) |
|
190 NS_IF_RELEASE(aObject); |
|
191 return result; |
|
192 } |
|
193 |
|
194 bool |
|
195 nsCOMArray_base::RemoveObjectAt(int32_t aIndex) |
|
196 { |
|
197 if (uint32_t(aIndex) < mArray.Length()) { |
|
198 nsISupports* element = mArray[aIndex]; |
|
199 |
|
200 mArray.RemoveElementAt(aIndex); |
|
201 NS_IF_RELEASE(element); |
|
202 return true; |
|
203 } |
|
204 |
|
205 return false; |
|
206 } |
|
207 |
|
208 void |
|
209 nsCOMArray_base::RemoveElementAt(uint32_t aIndex) |
|
210 { |
|
211 nsISupports* element = mArray[aIndex]; |
|
212 mArray.RemoveElementAt(aIndex); |
|
213 NS_IF_RELEASE(element); |
|
214 } |
|
215 |
|
216 bool |
|
217 nsCOMArray_base::RemoveObjectsAt(int32_t aIndex, int32_t aCount) |
|
218 { |
|
219 if (uint32_t(aIndex) + uint32_t(aCount) <= mArray.Length()) { |
|
220 nsTArray<nsISupports*> elementsToDestroy(aCount); |
|
221 elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount); |
|
222 mArray.RemoveElementsAt(aIndex, aCount); |
|
223 ReleaseObjects(elementsToDestroy); |
|
224 return true; |
|
225 } |
|
226 |
|
227 return false; |
|
228 } |
|
229 |
|
230 void |
|
231 nsCOMArray_base::RemoveElementsAt(uint32_t aIndex, uint32_t aCount) |
|
232 { |
|
233 nsTArray<nsISupports*> elementsToDestroy(aCount); |
|
234 elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount); |
|
235 mArray.RemoveElementsAt(aIndex, aCount); |
|
236 ReleaseObjects(elementsToDestroy); |
|
237 } |
|
238 |
|
239 // useful for destructors |
|
240 void |
|
241 ReleaseObjects(nsTArray<nsISupports*> &aArray) |
|
242 { |
|
243 for (uint32_t i = 0; i < aArray.Length(); i++) |
|
244 NS_IF_RELEASE(aArray[i]); |
|
245 } |
|
246 |
|
247 void |
|
248 nsCOMArray_base::Clear() |
|
249 { |
|
250 nsTArray<nsISupports*> objects; |
|
251 objects.SwapElements(mArray); |
|
252 ReleaseObjects(objects); |
|
253 } |
|
254 |
|
255 bool |
|
256 nsCOMArray_base::SetCount(int32_t aNewCount) |
|
257 { |
|
258 NS_ASSERTION(aNewCount >= 0,"SetCount(negative index)"); |
|
259 if (aNewCount < 0) |
|
260 return false; |
|
261 |
|
262 int32_t count = mArray.Length(); |
|
263 if (count > aNewCount) |
|
264 RemoveObjectsAt(aNewCount, mArray.Length() - aNewCount); |
|
265 mArray.SetLength(aNewCount); |
|
266 return true; |
|
267 } |
|
268 |
|
269 size_t |
|
270 nsCOMArray_base::SizeOfExcludingThis( |
|
271 nsBaseArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, |
|
272 mozilla::MallocSizeOf aMallocSizeOf, void* aData) const |
|
273 { |
|
274 size_t n = mArray.SizeOfExcludingThis(aMallocSizeOf); |
|
275 |
|
276 if (aSizeOfElementIncludingThis) |
|
277 for (uint32_t index = 0; index < mArray.Length(); index++) |
|
278 n += aSizeOfElementIncludingThis(mArray[index], aMallocSizeOf, aData); |
|
279 |
|
280 return n; |
|
281 } |
|
282 |
|
283 |
|
284 void |
|
285 nsCOMArray_base::Adopt(nsISupports** aElements, uint32_t aSize) |
|
286 { |
|
287 Clear(); |
|
288 mArray.AppendElements(aElements, aSize); |
|
289 |
|
290 // Free the allocated array as well. |
|
291 NS_Free(aElements); |
|
292 } |
|
293 |
|
294 uint32_t |
|
295 nsCOMArray_base::Forget(nsISupports*** elements) |
|
296 { |
|
297 uint32_t length = Length(); |
|
298 size_t array_size = sizeof(nsISupports*) * length; |
|
299 nsISupports** array = static_cast<nsISupports**>(NS_Alloc(array_size)); |
|
300 memmove(array, Elements(), array_size); |
|
301 *elements = array; |
|
302 // Don't Release the contained pointers; the caller of the method will |
|
303 // do this eventually. |
|
304 mArray.Clear(); |
|
305 |
|
306 return length; |
|
307 } |