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