summaryrefslogtreecommitdiff
path: root/xpcom/glue/nsCOMArray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/glue/nsCOMArray.cpp')
-rw-r--r--xpcom/glue/nsCOMArray.cpp323
1 files changed, 323 insertions, 0 deletions
diff --git a/xpcom/glue/nsCOMArray.cpp b/xpcom/glue/nsCOMArray.cpp
new file mode 100644
index 0000000000..3522f7b0d1
--- /dev/null
+++ b/xpcom/glue/nsCOMArray.cpp
@@ -0,0 +1,323 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "nsCOMArray.h"
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/OperatorNewExtensions.h"
+
+#include "nsCOMPtr.h"
+
+// This specialization is private to nsCOMArray.
+// It exists solely to automatically zero-out newly created array elements.
+template<>
+class nsTArrayElementTraits<nsISupports*>
+{
+ typedef nsISupports* E;
+public:
+ // Zero out the value
+ static inline void Construct(E* aE)
+ {
+ new (mozilla::KnownNotNull, static_cast<void*>(aE)) E();
+ }
+ // Invoke the copy-constructor in place.
+ template<class A>
+ static inline void Construct(E* aE, const A& aArg)
+ {
+ new (mozilla::KnownNotNull, static_cast<void*>(aE)) E(aArg);
+ }
+ // Invoke the destructor in place.
+ static inline void Destruct(E* aE)
+ {
+ aE->~E();
+ }
+};
+
+static void ReleaseObjects(nsTArray<nsISupports*>& aArray);
+
+// implementations of non-trivial methods in nsCOMArray_base
+
+nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther)
+{
+ // make sure we do only one allocation
+ mArray.SetCapacity(aOther.Count());
+ AppendObjects(aOther);
+}
+
+nsCOMArray_base::~nsCOMArray_base()
+{
+ Clear();
+}
+
+int32_t
+nsCOMArray_base::IndexOf(nsISupports* aObject, uint32_t aStartIndex) const
+{
+ return mArray.IndexOf(aObject, aStartIndex);
+}
+
+int32_t
+nsCOMArray_base::IndexOfObject(nsISupports* aObject) const
+{
+ nsCOMPtr<nsISupports> supports = do_QueryInterface(aObject);
+ if (NS_WARN_IF(!supports)) {
+ return -1;
+ }
+
+ uint32_t i, count;
+ int32_t retval = -1;
+ count = mArray.Length();
+ for (i = 0; i < count; ++i) {
+ nsCOMPtr<nsISupports> arrayItem = do_QueryInterface(mArray[i]);
+ if (arrayItem == supports) {
+ retval = i;
+ break;
+ }
+ }
+ return retval;
+}
+
+bool
+nsCOMArray_base::EnumerateForwards(nsBaseArrayEnumFunc aFunc, void* aData) const
+{
+ for (uint32_t index = 0; index < mArray.Length(); ++index) {
+ if (!(*aFunc)(mArray[index], aData)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+nsCOMArray_base::EnumerateBackwards(nsBaseArrayEnumFunc aFunc, void* aData) const
+{
+ for (uint32_t index = mArray.Length(); index--; ) {
+ if (!(*aFunc)(mArray[index], aData)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int
+nsCOMArray_base::nsCOMArrayComparator(const void* aElement1,
+ const void* aElement2,
+ void* aData)
+{
+ nsCOMArrayComparatorContext* ctx =
+ static_cast<nsCOMArrayComparatorContext*>(aData);
+ return (*ctx->mComparatorFunc)(*static_cast<nsISupports* const*>(aElement1),
+ *static_cast<nsISupports* const*>(aElement2),
+ ctx->mData);
+}
+
+void
+nsCOMArray_base::Sort(nsBaseArrayComparatorFunc aFunc, void* aData)
+{
+ if (mArray.Length() > 1) {
+ nsCOMArrayComparatorContext ctx = {aFunc, aData};
+ NS_QuickSort(mArray.Elements(), mArray.Length(), sizeof(nsISupports*),
+ nsCOMArrayComparator, &ctx);
+ }
+}
+
+bool
+nsCOMArray_base::InsertObjectAt(nsISupports* aObject, int32_t aIndex)
+{
+ if ((uint32_t)aIndex > mArray.Length()) {
+ return false;
+ }
+
+ if (!mArray.InsertElementAt(aIndex, aObject)) {
+ return false;
+ }
+
+ NS_IF_ADDREF(aObject);
+ return true;
+}
+
+void
+nsCOMArray_base::InsertElementAt(uint32_t aIndex, nsISupports* aElement)
+{
+ mArray.InsertElementAt(aIndex, aElement);
+ NS_IF_ADDREF(aElement);
+}
+
+void
+nsCOMArray_base::InsertElementAt(uint32_t aIndex, already_AddRefed<nsISupports> aElement)
+{
+ mArray.InsertElementAt(aIndex, aElement.take());
+}
+
+bool
+nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, int32_t aIndex)
+{
+ if ((uint32_t)aIndex > mArray.Length()) {
+ return false;
+ }
+
+ if (!mArray.InsertElementsAt(aIndex, aObjects.mArray)) {
+ return false;
+ }
+
+ // need to addref all these
+ uint32_t count = aObjects.Length();
+ for (uint32_t i = 0; i < count; ++i) {
+ NS_IF_ADDREF(aObjects[i]);
+ }
+
+ return true;
+}
+
+void
+nsCOMArray_base::InsertElementsAt(uint32_t aIndex,
+ const nsCOMArray_base& aElements)
+{
+ mArray.InsertElementsAt(aIndex, aElements.mArray);
+
+ // need to addref all these
+ uint32_t count = aElements.Length();
+ for (uint32_t i = 0; i < count; ++i) {
+ NS_IF_ADDREF(aElements[i]);
+ }
+}
+
+void
+nsCOMArray_base::InsertElementsAt(uint32_t aIndex,
+ nsISupports* const* aElements,
+ uint32_t aCount)
+{
+ mArray.InsertElementsAt(aIndex, aElements, aCount);
+
+ // need to addref all these
+ for (uint32_t i = 0; i < aCount; ++i) {
+ NS_IF_ADDREF(aElements[i]);
+ }
+}
+
+void
+nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, int32_t aIndex)
+{
+ mArray.EnsureLengthAtLeast(aIndex + 1);
+ nsISupports* oldObject = mArray[aIndex];
+ // Make sure to addref first, in case aObject == oldObject
+ NS_IF_ADDREF(mArray[aIndex] = aObject);
+ NS_IF_RELEASE(oldObject);
+}
+
+bool
+nsCOMArray_base::RemoveObject(nsISupports* aObject)
+{
+ bool result = mArray.RemoveElement(aObject);
+ if (result) {
+ NS_IF_RELEASE(aObject);
+ }
+ return result;
+}
+
+bool
+nsCOMArray_base::RemoveObjectAt(int32_t aIndex)
+{
+ if (uint32_t(aIndex) < mArray.Length()) {
+ nsISupports* element = mArray[aIndex];
+
+ mArray.RemoveElementAt(aIndex);
+ NS_IF_RELEASE(element);
+ return true;
+ }
+
+ return false;
+}
+
+void
+nsCOMArray_base::RemoveElementAt(uint32_t aIndex)
+{
+ nsISupports* element = mArray[aIndex];
+ mArray.RemoveElementAt(aIndex);
+ NS_IF_RELEASE(element);
+}
+
+bool
+nsCOMArray_base::RemoveObjectsAt(int32_t aIndex, int32_t aCount)
+{
+ if (uint32_t(aIndex) + uint32_t(aCount) <= mArray.Length()) {
+ nsTArray<nsISupports*> elementsToDestroy(aCount);
+ elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount);
+ mArray.RemoveElementsAt(aIndex, aCount);
+ ReleaseObjects(elementsToDestroy);
+ return true;
+ }
+
+ return false;
+}
+
+void
+nsCOMArray_base::RemoveElementsAt(uint32_t aIndex, uint32_t aCount)
+{
+ nsTArray<nsISupports*> elementsToDestroy(aCount);
+ elementsToDestroy.AppendElements(mArray.Elements() + aIndex, aCount);
+ mArray.RemoveElementsAt(aIndex, aCount);
+ ReleaseObjects(elementsToDestroy);
+}
+
+// useful for destructors
+void
+ReleaseObjects(nsTArray<nsISupports*>& aArray)
+{
+ for (uint32_t i = 0; i < aArray.Length(); ++i) {
+ NS_IF_RELEASE(aArray[i]);
+ }
+}
+
+void
+nsCOMArray_base::Clear()
+{
+ nsTArray<nsISupports*> objects;
+ objects.SwapElements(mArray);
+ ReleaseObjects(objects);
+}
+
+bool
+nsCOMArray_base::SetCount(int32_t aNewCount)
+{
+ NS_ASSERTION(aNewCount >= 0, "SetCount(negative index)");
+ if (aNewCount < 0) {
+ return false;
+ }
+
+ int32_t count = mArray.Length();
+ if (count > aNewCount) {
+ RemoveObjectsAt(aNewCount, mArray.Length() - aNewCount);
+ }
+ mArray.SetLength(aNewCount);
+ return true;
+}
+
+void
+nsCOMArray_base::Adopt(nsISupports** aElements, uint32_t aSize)
+{
+ Clear();
+ mArray.AppendElements(aElements, aSize);
+
+ // Free the allocated array as well.
+ NS_Free(aElements);
+}
+
+uint32_t
+nsCOMArray_base::Forget(nsISupports*** aElements)
+{
+ uint32_t length = Length();
+ size_t array_size = sizeof(nsISupports*) * length;
+ nsISupports** array = static_cast<nsISupports**>(NS_Alloc(array_size));
+ memmove(array, Elements(), array_size);
+ *aElements = array;
+ // Don't Release the contained pointers; the caller of the method will
+ // do this eventually.
+ mArray.Clear();
+
+ return length;
+}