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