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