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