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