michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsArray.h" michael@0: #include "nsArrayEnumerator.h" michael@0: #include "nsIWeakReference.h" michael@0: #include "nsIWeakReferenceUtils.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: // used by IndexOf() michael@0: struct findIndexOfClosure michael@0: { michael@0: nsISupports *targetElement; michael@0: uint32_t startIndex; michael@0: uint32_t resultIndex; michael@0: }; michael@0: michael@0: static bool FindElementCallback(void* aElement, void* aClosure); michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(nsArray) michael@0: NS_INTERFACE_MAP_ENTRY(nsIArray) michael@0: NS_INTERFACE_MAP_ENTRY(nsIMutableArray) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMutableArray) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsArrayCC) michael@0: NS_INTERFACE_MAP_ENTRY(nsIArray) michael@0: NS_INTERFACE_MAP_ENTRY(nsIMutableArray) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMutableArray) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: nsArray::~nsArray() michael@0: { michael@0: Clear(); michael@0: } michael@0: michael@0: michael@0: NS_IMPL_ADDREF(nsArray) michael@0: NS_IMPL_RELEASE(nsArray) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(nsArrayCC) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsArrayCC) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(nsArrayCC) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsArrayCC) michael@0: tmp->Clear(); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsArrayCC) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArray) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::GetLength(uint32_t* aLength) michael@0: { michael@0: *aLength = mArray.Count(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::QueryElementAt(uint32_t aIndex, michael@0: const nsIID& aIID, michael@0: void ** aResult) michael@0: { michael@0: nsISupports * obj = mArray.SafeObjectAt(aIndex); michael@0: if (!obj) return NS_ERROR_ILLEGAL_VALUE; michael@0: michael@0: // no need to worry about a leak here, because SafeObjectAt() michael@0: // doesn't addref its result michael@0: return obj->QueryInterface(aIID, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::IndexOf(uint32_t aStartIndex, nsISupports* aElement, michael@0: uint32_t* aResult) michael@0: { michael@0: // optimize for the common case by forwarding to mArray michael@0: if (aStartIndex == 0) { michael@0: uint32_t idx = mArray.IndexOf(aElement); michael@0: if (idx == UINT32_MAX) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *aResult = idx; michael@0: return NS_OK; michael@0: } michael@0: michael@0: findIndexOfClosure closure = { aElement, aStartIndex, 0 }; michael@0: bool notFound = mArray.EnumerateForwards(FindElementCallback, &closure); michael@0: if (notFound) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *aResult = closure.resultIndex; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::Enumerate(nsISimpleEnumerator **aResult) michael@0: { michael@0: return NS_NewArrayEnumerator(aResult, static_cast(this)); michael@0: } michael@0: michael@0: // nsIMutableArray implementation michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::AppendElement(nsISupports* aElement, bool aWeak) michael@0: { michael@0: bool result; michael@0: if (aWeak) { michael@0: nsCOMPtr elementRef = do_GetWeakReference(aElement); michael@0: NS_ASSERTION(elementRef, "AppendElement: Trying to use weak references on an object that doesn't support it"); michael@0: if (!elementRef) michael@0: return NS_ERROR_FAILURE; michael@0: result = mArray.AppendObject(elementRef); michael@0: } michael@0: michael@0: else { michael@0: // add the object directly michael@0: result = mArray.AppendObject(aElement); michael@0: } michael@0: return result ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::RemoveElementAt(uint32_t aIndex) michael@0: { michael@0: bool result = mArray.RemoveObjectAt(aIndex); michael@0: return result ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::InsertElementAt(nsISupports* aElement, uint32_t aIndex, bool aWeak) michael@0: { michael@0: nsCOMPtr elementRef; michael@0: if (aWeak) { michael@0: elementRef = do_GetWeakReference(aElement); michael@0: NS_ASSERTION(elementRef, "InsertElementAt: Trying to use weak references on an object that doesn't support it"); michael@0: if (!elementRef) michael@0: return NS_ERROR_FAILURE; michael@0: } else { michael@0: elementRef = aElement; michael@0: } michael@0: bool result = mArray.InsertObjectAt(elementRef, aIndex); michael@0: return result ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex, bool aWeak) michael@0: { michael@0: nsCOMPtr elementRef; michael@0: if (aWeak) { michael@0: elementRef = do_GetWeakReference(aElement); michael@0: NS_ASSERTION(elementRef, "ReplaceElementAt: Trying to use weak references on an object that doesn't support it"); michael@0: if (!elementRef) michael@0: return NS_ERROR_FAILURE; michael@0: } else { michael@0: elementRef = aElement; michael@0: } michael@0: bool result = mArray.ReplaceObjectAt(elementRef, aIndex); michael@0: return result ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsArray::Clear() michael@0: { michael@0: mArray.Clear(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // static helper routines michael@0: // michael@0: bool michael@0: FindElementCallback(void *aElement, void* aClosure) michael@0: { michael@0: findIndexOfClosure* closure = michael@0: static_cast(aClosure); michael@0: michael@0: nsISupports* element = michael@0: static_cast(aElement); michael@0: michael@0: // don't start searching until we're past the startIndex michael@0: if (closure->resultIndex >= closure->startIndex && michael@0: element == closure->targetElement) { michael@0: return false; // stop! We found it michael@0: } michael@0: closure->resultIndex++; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: nsArray::XPCOMConstructor(nsISupports *aOuter, const nsIID& aIID, void **aResult) michael@0: { michael@0: if (aOuter) michael@0: return NS_ERROR_NO_AGGREGATION; michael@0: michael@0: nsCOMPtr inst = Create(); michael@0: return inst->QueryInterface(aIID, aResult); michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsArray::Create() michael@0: { michael@0: nsCOMPtr inst = NS_IsMainThread() ? new nsArrayCC : new nsArray; michael@0: return inst.forget(); michael@0: }