gecko-dev/xpcom/glue/nsCOMArray.cpp
Nathan Froyd 41ba39b3b0 Bug 1295197 - use non-null-checked operator new in xpcom/; r=erahm
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.
2016-08-22 18:40:10 -04:00

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;
}