Line data Source code
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 "nsArray.h"
8 : #include "nsArrayEnumerator.h"
9 : #include "nsIWeakReference.h"
10 : #include "nsIWeakReferenceUtils.h"
11 : #include "nsThreadUtils.h"
12 :
13 : // used by IndexOf()
14 : struct MOZ_STACK_CLASS findIndexOfClosure
15 : {
16 : // This is only used for pointer comparison, so we can just use a void*.
17 : void* targetElement;
18 : uint32_t startIndex;
19 : uint32_t resultIndex;
20 : };
21 :
22 : static bool FindElementCallback(void* aElement, void* aClosure);
23 :
24 0 : NS_INTERFACE_MAP_BEGIN(nsArray)
25 0 : NS_INTERFACE_MAP_ENTRY(nsIArray)
26 0 : NS_INTERFACE_MAP_ENTRY(nsIArrayExtensions)
27 0 : NS_INTERFACE_MAP_ENTRY(nsIMutableArray)
28 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMutableArray)
29 0 : NS_INTERFACE_MAP_END
30 :
31 58 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsArrayCC)
32 56 : NS_INTERFACE_MAP_ENTRY(nsIArray)
33 48 : NS_INTERFACE_MAP_ENTRY(nsIArrayExtensions)
34 48 : NS_INTERFACE_MAP_ENTRY(nsIMutableArray)
35 40 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMutableArray)
36 31 : NS_INTERFACE_MAP_END
37 :
38 0 : nsArrayBase::~nsArrayBase()
39 : {
40 0 : Clear();
41 0 : }
42 :
43 :
44 0 : NS_IMPL_ADDREF(nsArray)
45 0 : NS_IMPL_RELEASE(nsArray)
46 :
47 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsArrayCC)
48 :
49 35 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsArrayCC)
50 27 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsArrayCC)
51 :
52 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsArrayCC)
53 0 : tmp->Clear();
54 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
55 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsArrayCC)
56 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArray)
57 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
58 :
59 : NS_IMETHODIMP
60 5 : nsArrayBase::GetLength(uint32_t* aLength)
61 : {
62 5 : *aLength = mArray.Count();
63 5 : return NS_OK;
64 : }
65 :
66 : NS_IMETHODIMP
67 12 : nsArrayBase::QueryElementAt(uint32_t aIndex,
68 : const nsIID& aIID,
69 : void** aResult)
70 : {
71 12 : nsISupports* obj = mArray.SafeObjectAt(aIndex);
72 12 : if (!obj) {
73 8 : return NS_ERROR_ILLEGAL_VALUE;
74 : }
75 :
76 : // no need to worry about a leak here, because SafeObjectAt()
77 : // doesn't addref its result
78 4 : return obj->QueryInterface(aIID, aResult);
79 : }
80 :
81 : NS_IMETHODIMP
82 0 : nsArrayBase::IndexOf(uint32_t aStartIndex, nsISupports* aElement,
83 : uint32_t* aResult)
84 : {
85 : // optimize for the common case by forwarding to mArray
86 0 : if (aStartIndex == 0) {
87 0 : uint32_t idx = mArray.IndexOf(aElement);
88 0 : if (idx == UINT32_MAX) {
89 0 : return NS_ERROR_FAILURE;
90 : }
91 :
92 0 : *aResult = idx;
93 0 : return NS_OK;
94 : }
95 :
96 0 : findIndexOfClosure closure = { aElement, aStartIndex, 0 };
97 0 : bool notFound = mArray.EnumerateForwards(FindElementCallback, &closure);
98 0 : if (notFound) {
99 0 : return NS_ERROR_FAILURE;
100 : }
101 :
102 0 : *aResult = closure.resultIndex;
103 0 : return NS_OK;
104 : }
105 :
106 : NS_IMETHODIMP
107 0 : nsArrayBase::Enumerate(nsISimpleEnumerator** aResult)
108 : {
109 0 : return NS_NewArrayEnumerator(aResult, static_cast<nsIArray*>(this));
110 : }
111 :
112 : // nsIMutableArray implementation
113 :
114 : NS_IMETHODIMP
115 6 : nsArrayBase::AppendElement(nsISupports* aElement, bool aWeak)
116 : {
117 : bool result;
118 6 : if (aWeak) {
119 0 : nsCOMPtr<nsIWeakReference> elementRef = do_GetWeakReference(aElement);
120 0 : NS_ASSERTION(elementRef,
121 : "AppendElement: Trying to use weak references on an object that doesn't support it");
122 0 : if (!elementRef) {
123 0 : return NS_ERROR_FAILURE;
124 : }
125 0 : result = mArray.AppendObject(elementRef);
126 : }
127 :
128 : else {
129 : // add the object directly
130 6 : result = mArray.AppendObject(aElement);
131 : }
132 6 : return result ? NS_OK : NS_ERROR_FAILURE;
133 : }
134 :
135 : NS_IMETHODIMP
136 0 : nsArrayBase::RemoveElementAt(uint32_t aIndex)
137 : {
138 0 : bool result = mArray.RemoveObjectAt(aIndex);
139 0 : return result ? NS_OK : NS_ERROR_FAILURE;
140 : }
141 :
142 : NS_IMETHODIMP
143 0 : nsArrayBase::InsertElementAt(nsISupports* aElement, uint32_t aIndex, bool aWeak)
144 : {
145 0 : nsCOMPtr<nsISupports> elementRef;
146 0 : if (aWeak) {
147 0 : elementRef = do_GetWeakReference(aElement);
148 0 : NS_ASSERTION(elementRef,
149 : "InsertElementAt: Trying to use weak references on an object that doesn't support it");
150 0 : if (!elementRef) {
151 0 : return NS_ERROR_FAILURE;
152 : }
153 : } else {
154 0 : elementRef = aElement;
155 : }
156 0 : bool result = mArray.InsertObjectAt(elementRef, aIndex);
157 0 : return result ? NS_OK : NS_ERROR_FAILURE;
158 : }
159 :
160 : NS_IMETHODIMP
161 0 : nsArrayBase::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex, bool aWeak)
162 : {
163 0 : nsCOMPtr<nsISupports> elementRef;
164 0 : if (aWeak) {
165 0 : elementRef = do_GetWeakReference(aElement);
166 0 : NS_ASSERTION(elementRef,
167 : "ReplaceElementAt: Trying to use weak references on an object that doesn't support it");
168 0 : if (!elementRef) {
169 0 : return NS_ERROR_FAILURE;
170 : }
171 : } else {
172 0 : elementRef = aElement;
173 : }
174 0 : mArray.ReplaceObjectAt(elementRef, aIndex);
175 0 : return NS_OK;
176 : }
177 :
178 : NS_IMETHODIMP
179 0 : nsArrayBase::Clear()
180 : {
181 0 : mArray.Clear();
182 0 : return NS_OK;
183 : }
184 :
185 : // nsIArrayExtensions implementation.
186 :
187 : NS_IMETHODIMP
188 0 : nsArrayBase::Count(uint32_t* aResult)
189 : {
190 0 : return GetLength(aResult);
191 : }
192 :
193 : NS_IMETHODIMP
194 0 : nsArrayBase::GetElementAt(uint32_t aIndex, nsISupports** aResult)
195 : {
196 0 : nsCOMPtr<nsISupports> obj = mArray.SafeObjectAt(aIndex);
197 0 : obj.forget(aResult);
198 0 : return NS_OK;
199 : }
200 :
201 : //
202 : // static helper routines
203 : //
204 : bool
205 0 : FindElementCallback(void* aElement, void* aClosure)
206 : {
207 0 : findIndexOfClosure* closure = static_cast<findIndexOfClosure*>(aClosure);
208 0 : nsISupports* element = static_cast<nsISupports*>(aElement);
209 :
210 : // don't start searching until we're past the startIndex
211 0 : if (closure->resultIndex >= closure->startIndex &&
212 0 : element == closure->targetElement) {
213 0 : return false; // stop! We found it
214 : }
215 0 : closure->resultIndex++;
216 :
217 0 : return true;
218 : }
219 :
220 : nsresult
221 2 : nsArrayBase::XPCOMConstructor(nsISupports* aOuter, const nsIID& aIID,
222 : void** aResult)
223 : {
224 2 : if (aOuter) {
225 0 : return NS_ERROR_NO_AGGREGATION;
226 : }
227 :
228 4 : nsCOMPtr<nsIMutableArray> inst = Create();
229 2 : return inst->QueryInterface(aIID, aResult);
230 : }
231 :
232 : already_AddRefed<nsIMutableArray>
233 2 : nsArrayBase::Create()
234 : {
235 4 : nsCOMPtr<nsIMutableArray> inst;
236 2 : if (NS_IsMainThread()) {
237 2 : inst = new nsArrayCC;
238 : } else {
239 0 : inst = new nsArray;
240 : }
241 4 : return inst.forget();
242 : }
|