зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1308317 - Part 10: Just use an nsCOMArray. r=froydnj
This switches over from using a half-baked auto array to nsCOMArray. MozReview-Commit-ID: 6FR2SjOhoZR
This commit is contained in:
Родитель
5b5f49eb80
Коммит
ac6647aa97
|
@ -6,12 +6,11 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsSupportsArrayEnumerator.h"
|
||||
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsSupportsArrayEnumerator.h"
|
||||
|
||||
nsresult
|
||||
nsQueryElementAt::operator()(const nsIID& aIID, void** aResult) const
|
||||
|
@ -29,69 +28,11 @@ nsQueryElementAt::operator()(const nsIID& aIID, void** aResult) const
|
|||
|
||||
nsSupportsArray::nsSupportsArray()
|
||||
{
|
||||
mArray = mAutoArray;
|
||||
mArraySize = kAutoArraySize;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
nsSupportsArray::~nsSupportsArray()
|
||||
{
|
||||
DeleteArray();
|
||||
}
|
||||
|
||||
bool
|
||||
nsSupportsArray::GrowArrayBy(uint32_t aGrowBy)
|
||||
{
|
||||
const uint32_t kGrowArrayBy = 8;
|
||||
const uint32_t kLinearThreshold = 16 * sizeof(nsISupports*);
|
||||
|
||||
// We have to grow the array. Grow by kGrowArrayBy slots if we're smaller
|
||||
// than kLinearThreshold bytes, or a power of two if we're larger.
|
||||
// This is much more efficient with most memory allocators, especially
|
||||
// if it's very large, or of the allocator is binned.
|
||||
if (aGrowBy < kGrowArrayBy) {
|
||||
aGrowBy = kGrowArrayBy;
|
||||
}
|
||||
|
||||
CheckedUint32 newCount(mArraySize);
|
||||
newCount += aGrowBy; // Minimum increase
|
||||
CheckedUint32 newSize(sizeof(mArray[0]));
|
||||
newSize *= newCount;
|
||||
|
||||
if (!newSize.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newSize.value() >= kLinearThreshold) {
|
||||
// newCount includes enough space for at least kGrowArrayBy new slots.
|
||||
// Select the next power-of-two size in bytes above that if newSize is
|
||||
// not a power of two.
|
||||
if (newSize.value() & (newSize.value() - 1)) {
|
||||
newSize = UINT64_C(1) << mozilla::CeilingLog2(newSize.value());
|
||||
if (!newSize.isValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
newCount = newSize / sizeof(mArray[0]);
|
||||
}
|
||||
// XXX This would be far more efficient in many allocators if we used
|
||||
// XXX PR_Realloc(), etc
|
||||
nsISupports** oldArray = mArray;
|
||||
|
||||
mArray = new nsISupports*[newCount.value()];
|
||||
mArraySize = newCount.value();
|
||||
|
||||
if (oldArray) { // need to move old data
|
||||
if (0 < mCount) {
|
||||
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||
}
|
||||
if (oldArray != &(mAutoArray[0])) {
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -120,43 +61,35 @@ nsSupportsArray::Read(nsIObjectInputStream* aStream)
|
|||
return rv;
|
||||
}
|
||||
|
||||
if (newArraySize <= kAutoArraySize) {
|
||||
if (mArray != mAutoArray) {
|
||||
delete[] mArray;
|
||||
mArray = mAutoArray;
|
||||
}
|
||||
newArraySize = kAutoArraySize;
|
||||
} else {
|
||||
if (newArraySize <= mArraySize) {
|
||||
// Keep non-default-size mArray, it's more than big enough.
|
||||
newArraySize = mArraySize;
|
||||
} else {
|
||||
nsISupports** array = new nsISupports*[newArraySize];
|
||||
if (mArray != mAutoArray) {
|
||||
delete[] mArray;
|
||||
}
|
||||
mArray = array;
|
||||
}
|
||||
}
|
||||
mArraySize = newArraySize;
|
||||
|
||||
rv = aStream->Read32(&mCount);
|
||||
uint32_t count;
|
||||
rv = aStream->Read32(&count);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!");
|
||||
if (mCount > mArraySize) {
|
||||
mCount = mArraySize;
|
||||
NS_ASSERTION(count <= newArraySize, "overlarge mCount!");
|
||||
if (count > newArraySize) {
|
||||
count = newArraySize;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mCount; i++) {
|
||||
rv = aStream->ReadObject(true, &mArray[i]);
|
||||
// Don't clear out our array until we know we have enough space for the new
|
||||
// one and have successfully copied everything out of the stream.
|
||||
nsCOMArray<nsISupports> tmp;
|
||||
tmp.SetCapacity(newArraySize);
|
||||
tmp.SetCount(count);
|
||||
|
||||
auto elems = tmp.Elements();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
rv = aStream->ReadObject(true, &elems[i]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Now clear out existing refs and replace with the new array.
|
||||
mArray.Clear();
|
||||
mArray.SwapElements(tmp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -165,17 +98,17 @@ nsSupportsArray::Write(nsIObjectOutputStream* aStream)
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aStream->Write32(mArraySize);
|
||||
rv = aStream->Write32(mArray.Capacity());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = aStream->Write32(mCount);
|
||||
rv = aStream->Write32(mArray.Length());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mCount; i++) {
|
||||
for (size_t i = 0; i < mArray.Length(); i++) {
|
||||
rv = aStream->WriteObject(mArray[i], true);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -185,83 +118,35 @@ nsSupportsArray::Write(nsIObjectOutputStream* aStream)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsSupportsArray::DeleteArray(void)
|
||||
{
|
||||
Clear();
|
||||
if (mArray != &(mAutoArray[0])) {
|
||||
delete[] mArray;
|
||||
mArray = mAutoArray;
|
||||
mArraySize = kAutoArraySize;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::GetElementAt(uint32_t aIndex, nsISupports** aOutPtr)
|
||||
{
|
||||
*aOutPtr = nullptr;
|
||||
if (aIndex < mCount) {
|
||||
NS_IF_ADDREF(*aOutPtr = mArray[aIndex]);
|
||||
}
|
||||
nsCOMPtr<nsISupports> elm = mArray.SafeElementAt(aIndex);
|
||||
elm.forget(aOutPtr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(int32_t)
|
||||
nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
|
||||
{
|
||||
const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
|
||||
const nsISupports** ep = start;
|
||||
const nsISupports** end = (start + mCount);
|
||||
while (ep < end) {
|
||||
if (aPossibleElement == *ep) {
|
||||
return (ep - start);
|
||||
}
|
||||
ep++;
|
||||
}
|
||||
return -1;
|
||||
// nsCOMArray takes a non-const param, but it just passes through to
|
||||
// nsTArray which takes a const param.
|
||||
return mArray.IndexOf(const_cast<nsISupports*>(aPossibleElement));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
nsSupportsArray::InsertElementAt(nsISupports* aElement, uint32_t aIndex)
|
||||
{
|
||||
if (aIndex <= mCount) {
|
||||
CheckedUint32 newCount(mCount);
|
||||
newCount += 1;
|
||||
if (!newCount.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mArraySize < newCount.value()) {
|
||||
// need to grow the array
|
||||
if (!GrowArrayBy(1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Could be slightly more efficient if GrowArrayBy knew about the
|
||||
// split, but the difference is trivial.
|
||||
uint32_t slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex + 1, mArray + aIndex,
|
||||
slide * sizeof(nsISupports*));
|
||||
}
|
||||
|
||||
mArray[aIndex] = aElement;
|
||||
NS_IF_ADDREF(aElement);
|
||||
mCount++;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return mArray.InsertObjectAt(aElement, aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
nsSupportsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex)
|
||||
{
|
||||
if (aIndex < mCount) {
|
||||
NS_IF_ADDREF(aElement); // addref first in case it's the same object!
|
||||
NS_IF_RELEASE(mArray[aIndex]);
|
||||
mArray[aIndex] = aElement;
|
||||
// nsCOMArray::ReplaceObjectAt will grow the array if necessary. Instead
|
||||
// we do the bounds check and only replace if it's in range.
|
||||
if (aIndex < mArray.Length()) {
|
||||
mArray.ReplaceElementAt(aIndex, aElement);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -270,49 +155,27 @@ nsSupportsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex)
|
|||
NS_IMETHODIMP_(bool)
|
||||
nsSupportsArray::RemoveElementAt(uint32_t aIndex)
|
||||
{
|
||||
if (aIndex + 1 <= mCount) {
|
||||
NS_IF_RELEASE(mArray[aIndex]);
|
||||
|
||||
mCount -= 1;
|
||||
int32_t slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex, mArray + aIndex + 1,
|
||||
slide * sizeof(nsISupports*));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return mArray.RemoveObjectAt(aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::RemoveElement(nsISupports* aElement)
|
||||
{
|
||||
int32_t theIndex = IndexOf(aElement);
|
||||
if (theIndex >= 0) {
|
||||
return RemoveElementAt(theIndex) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
return mArray.RemoveObject(aElement) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Clear(void)
|
||||
{
|
||||
if (0 < mCount) {
|
||||
do {
|
||||
--mCount;
|
||||
NS_IF_RELEASE(mArray[mCount]);
|
||||
} while (0 != mCount);
|
||||
}
|
||||
mArray.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Enumerate(nsIEnumerator** aResult)
|
||||
{
|
||||
nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this);
|
||||
*aResult = e;
|
||||
NS_ADDREF(e);
|
||||
RefPtr<nsSupportsArrayEnumerator> e = new nsSupportsArrayEnumerator(this);
|
||||
e.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -325,10 +188,10 @@ nsSupportsArray::Clone(nsISupportsArray** aResult)
|
|||
return rv;
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
Count(&count);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!newArray->InsertElementAt(mArray[i], i)) {
|
||||
for (size_t i = 0; i < mArray.Length(); i++) {
|
||||
// AppendElement does an odd cast of bool to nsresult, we just cast back
|
||||
// here.
|
||||
if (!(bool)newArray->AppendElement(mArray[i])) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,9 @@
|
|||
#define nsSupportsArray_h__
|
||||
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
static const uint32_t kAutoArraySize = 8;
|
||||
|
||||
class nsSupportsArray final : public nsISupportsArray
|
||||
{
|
||||
~nsSupportsArray(void); // nonvirtual since we're not subclassed
|
||||
|
@ -29,18 +28,16 @@ public:
|
|||
// nsICollection methods:
|
||||
NS_IMETHOD Count(uint32_t* aResult) override
|
||||
{
|
||||
*aResult = mCount;
|
||||
*aResult = mArray.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD GetElementAt(uint32_t aIndex, nsISupports** aResult) override;
|
||||
MOZ_MUST_USE NS_IMETHOD
|
||||
QueryElementAt(uint32_t aIndex, const nsIID& aIID, void** aResult) override
|
||||
{
|
||||
if (aIndex < mCount) {
|
||||
nsISupports* element = mArray[aIndex];
|
||||
if (element) {
|
||||
return element->QueryInterface(aIID, aResult);
|
||||
}
|
||||
nsISupports* element = mArray.SafeElementAt(aIndex);
|
||||
if (element) {
|
||||
return element->QueryInterface(aIID, aResult);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -52,7 +49,7 @@ public:
|
|||
MOZ_MUST_USE NS_IMETHOD AppendElement(nsISupports* aElement) override
|
||||
{
|
||||
// XXX Invalid cast of bool to nsresult (bug 778110)
|
||||
return (nsresult)InsertElementAt(aElement, mCount)/* ? NS_OK : NS_ERROR_FAILURE*/;
|
||||
return (nsresult)InsertElementAt(aElement, mArray.Length())/* ? NS_OK : NS_ERROR_FAILURE*/;
|
||||
}
|
||||
// XXX this is badly named - should be RemoveFirstElement
|
||||
MOZ_MUST_USE NS_IMETHOD RemoveElement(nsISupports* aElement) override;
|
||||
|
@ -84,19 +81,11 @@ public:
|
|||
|
||||
MOZ_MUST_USE NS_IMETHOD Clone(nsISupportsArray** aResult) override;
|
||||
|
||||
protected:
|
||||
void DeleteArray(void);
|
||||
|
||||
bool GrowArrayBy(uint32_t aGrowBy);
|
||||
|
||||
nsISupports** mArray;
|
||||
uint32_t mArraySize;
|
||||
uint32_t mCount;
|
||||
nsISupports* mAutoArray[kAutoArraySize];
|
||||
|
||||
private:
|
||||
// Copy constructors are not allowed
|
||||
explicit nsSupportsArray(const nsISupportsArray& aOther);
|
||||
|
||||
nsCOMArray<nsISupports> mArray;
|
||||
};
|
||||
|
||||
#endif // nsSupportsArray_h__
|
||||
|
|
Загрузка…
Ссылка в новой задаче