mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-03 15:26:07 +00:00

The standard placement new function is declared to not throw, which means that, per spec, a null check on its result is required. There are a number of places throughout xpcom/ where we know that we are passing non-null pointers to placement new (and receiving them as a return value), and we are therefore doing useless work performing these null checks. Therefore, we should be using an operator new overload that doesn't require the null check. MFBT has just such an overload, so use that.
324 lines
7.5 KiB
C++
324 lines
7.5 KiB
C++
/* -*- 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;
|
|
}
|