mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 22:25:30 +00:00
383 lines
10 KiB
C++
383 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "nsISupportsArray.h"
|
|
|
|
static NS_DEFINE_IID(kISupportsArrayIID, NS_ISUPPORTSARRAY_IID);
|
|
|
|
static const PRInt32 kGrowArrayBy = 8;
|
|
static const PRInt32 kAutoArraySize = 4;
|
|
|
|
class SupportsArrayImpl : public nsISupportsArray {
|
|
public:
|
|
SupportsArrayImpl(void);
|
|
~SupportsArrayImpl(void);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_IMETHOD_(nsISupportsArray&) operator=(const nsISupportsArray& aOther);
|
|
NS_IMETHOD_(PRBool) operator==(const nsISupportsArray& aOther) const { return Equals(&aOther); }
|
|
NS_IMETHOD_(PRBool) Equals(const nsISupportsArray* aOther) const;
|
|
|
|
NS_IMETHOD_(PRInt32) Count(void) const { return mCount; }
|
|
|
|
NS_IMETHOD_(nsISupports*) ElementAt(PRInt32 aIndex) const;
|
|
NS_IMETHOD_(nsISupports*) operator[](PRInt32 aIndex) const { return ElementAt(aIndex); }
|
|
|
|
NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement, PRInt32 aStartIndex = 0) const;
|
|
NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement) const;
|
|
|
|
NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRInt32 aIndex);
|
|
|
|
NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRInt32 aIndex);
|
|
|
|
NS_IMETHOD_(PRBool) AppendElement(nsISupports* aElement) {
|
|
return InsertElementAt(aElement, mCount);
|
|
}
|
|
|
|
NS_IMETHOD_(PRBool) RemoveElementAt(PRInt32 aIndex);
|
|
NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRInt32 aStartIndex = 0);
|
|
NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement);
|
|
|
|
NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements);
|
|
|
|
NS_IMETHOD_(void) Clear(void);
|
|
|
|
NS_IMETHOD_(void) Compact(void);
|
|
|
|
NS_IMETHOD_(PRBool) EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) const;
|
|
NS_IMETHOD_(PRBool) EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) const;
|
|
|
|
protected:
|
|
void DeleteArray(void);
|
|
|
|
nsISupports** mArray;
|
|
PRInt32 mArraySize;
|
|
PRInt32 mCount;
|
|
nsISupports* mAutoArray[kAutoArraySize];
|
|
|
|
private:
|
|
// Copy constructors are not allowed
|
|
SupportsArrayImpl(const nsISupportsArray& other);
|
|
};
|
|
|
|
|
|
SupportsArrayImpl::SupportsArrayImpl()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mArray = &(mAutoArray[0]);
|
|
mArraySize = kAutoArraySize;
|
|
mCount = 0;
|
|
}
|
|
|
|
SupportsArrayImpl::~SupportsArrayImpl()
|
|
{
|
|
DeleteArray();
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(SupportsArrayImpl, kISupportsArrayIID);
|
|
|
|
void SupportsArrayImpl::DeleteArray(void)
|
|
{
|
|
Clear();
|
|
if (mArray != &(mAutoArray[0])) {
|
|
delete[] mArray;
|
|
mArray = &(mAutoArray[0]);
|
|
mArraySize = kAutoArraySize;
|
|
}
|
|
}
|
|
|
|
nsISupportsArray& SupportsArrayImpl::operator=(const nsISupportsArray& aOther)
|
|
{
|
|
PRInt32 otherCount = aOther.Count();
|
|
|
|
if (otherCount > mArraySize) {
|
|
DeleteArray();
|
|
mArraySize = otherCount;
|
|
mArray = new nsISupports*[mArraySize];
|
|
}
|
|
else {
|
|
Clear();
|
|
}
|
|
mCount = otherCount;
|
|
while (0 <= --otherCount) {
|
|
mArray[otherCount] = aOther.ElementAt(otherCount);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::Equals(const nsISupportsArray* aOther) const
|
|
{
|
|
if (0 != aOther) {
|
|
const SupportsArrayImpl* other = (const SupportsArrayImpl*)aOther;
|
|
if (mCount == other->mCount) {
|
|
PRInt32 index = mCount;
|
|
while (0 <= --index) {
|
|
if (mArray[index] != other->mArray[index]) {
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
nsISupports* SupportsArrayImpl::ElementAt(PRInt32 aIndex) const
|
|
{
|
|
if ((0 <= aIndex) && (aIndex < mCount)) {
|
|
nsISupports* element = mArray[aIndex];
|
|
NS_ADDREF(element);
|
|
return element;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
PRInt32 SupportsArrayImpl::IndexOf(const nsISupports* aPossibleElement, PRInt32 aStartIndex) const
|
|
{
|
|
if ((0 <= aStartIndex) && (aStartIndex < mCount)) {
|
|
const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
|
|
const nsISupports** ep = (start + aStartIndex);
|
|
const nsISupports** end = (start + mCount);
|
|
while (ep < end) {
|
|
if (aPossibleElement == *ep) {
|
|
return (ep - start);
|
|
}
|
|
ep++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
PRInt32 SupportsArrayImpl::LastIndexOf(const nsISupports* aPossibleElement) const
|
|
{
|
|
if (0 < mCount) {
|
|
const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
|
|
const nsISupports** ep = (start + mCount);
|
|
while (start <= --ep) {
|
|
if (aPossibleElement == *ep) {
|
|
return (ep - start);
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::InsertElementAt(nsISupports* aElement, PRInt32 aIndex)
|
|
{
|
|
if ((0 <= aIndex) && (aIndex <= mCount)) {
|
|
if (mArraySize < (mCount + 1)) { // need to grow the array
|
|
mArraySize += kGrowArrayBy;
|
|
nsISupports** oldArray = mArray;
|
|
mArray = new nsISupports*[mArraySize];
|
|
if (0 == mArray) { // ran out of memory
|
|
mArray = oldArray;
|
|
mArraySize -= kGrowArrayBy;
|
|
return PR_FALSE;
|
|
}
|
|
if (0 != oldArray) { // need to move old data
|
|
if (0 < aIndex) {
|
|
::memcpy(mArray, oldArray, aIndex * sizeof(nsISupports*));
|
|
}
|
|
PRInt32 slide = (mCount - aIndex);
|
|
if (0 < slide) {
|
|
::memcpy(mArray + aIndex + 1, oldArray + aIndex, slide * sizeof(nsISupports*));
|
|
}
|
|
if (oldArray != &(mAutoArray[0])) {
|
|
delete[] oldArray;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PRInt32 slide = (mCount - aIndex);
|
|
if (0 < slide) {
|
|
::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*));
|
|
}
|
|
}
|
|
|
|
mArray[aIndex] = aElement;
|
|
NS_ADDREF(aElement);
|
|
mCount++;
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::ReplaceElementAt(nsISupports* aElement, PRInt32 aIndex)
|
|
{
|
|
if ((0 <= aIndex) && (aIndex < mCount)) {
|
|
NS_ADDREF(aElement); // addref first in case it's the same object!
|
|
NS_RELEASE(mArray[aIndex]);
|
|
mArray[aIndex] = aElement;
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::RemoveElementAt(PRInt32 aIndex)
|
|
{
|
|
if ((0 <= aIndex) && (aIndex < mCount)) {
|
|
NS_RELEASE(mArray[aIndex]);
|
|
mCount--;
|
|
PRInt32 slide = (mCount - aIndex);
|
|
if (0 < slide) {
|
|
::memmove(mArray + aIndex, mArray + aIndex + 1,
|
|
slide * sizeof(nsISupports*));
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::RemoveElement(const nsISupports* aElement, PRInt32 aStartIndex)
|
|
{
|
|
if ((0 <= aStartIndex) && (aStartIndex < mCount)) {
|
|
nsISupports** ep = mArray;
|
|
nsISupports** end = ep + mCount;
|
|
while (ep < end) {
|
|
if (*ep == aElement) {
|
|
return RemoveElementAt(PRInt32(ep - mArray));
|
|
}
|
|
ep++;
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::RemoveLastElement(const nsISupports* aElement)
|
|
{
|
|
if (0 < mCount) {
|
|
nsISupports** ep = (mArray + mCount);
|
|
while (mArray <= --ep) {
|
|
if (*ep == aElement) {
|
|
return RemoveElementAt(PRInt32(ep - mArray));
|
|
}
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::AppendElements(nsISupportsArray* aElements)
|
|
{
|
|
SupportsArrayImpl* elements = (SupportsArrayImpl*)aElements;
|
|
|
|
if (elements && (0 < elements->mCount)) {
|
|
if (mArraySize < (mCount + elements->mCount)) { // need to grow the array
|
|
PRInt32 count = mCount + elements->mCount;
|
|
PRInt32 oldSize = mArraySize;
|
|
while (mArraySize < count) { // ick
|
|
mArraySize += kGrowArrayBy;
|
|
}
|
|
nsISupports** oldArray = mArray;
|
|
mArray = new nsISupports*[mArraySize];
|
|
if (0 == mArray) { // ran out of memory
|
|
mArray = oldArray;
|
|
mArraySize = oldSize;
|
|
return PR_FALSE;
|
|
}
|
|
if (0 != oldArray) { // need to move old data
|
|
if (0 < mCount) {
|
|
::memcpy(mArray, oldArray, mCount);
|
|
}
|
|
if (oldArray != &(mAutoArray[0])) {
|
|
delete[] oldArray;
|
|
}
|
|
}
|
|
}
|
|
|
|
PRInt32 index = 0;
|
|
while (index < elements->mCount) {
|
|
NS_ADDREF(elements->mArray[index]);
|
|
mArray[mCount++] = elements->mArray[index++];
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
void SupportsArrayImpl::Clear(void)
|
|
{
|
|
while (0 <= --mCount) {
|
|
NS_RELEASE(mArray[mCount]);
|
|
}
|
|
mCount = 0;
|
|
}
|
|
|
|
void SupportsArrayImpl::Compact(void)
|
|
{
|
|
if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
|
|
nsISupports** oldArray = mArray;
|
|
PRInt32 oldArraySize = mArraySize;
|
|
if (mCount <= kAutoArraySize) {
|
|
mArray = &(mAutoArray[0]);
|
|
mArraySize = kAutoArraySize;
|
|
}
|
|
else {
|
|
mArray = new nsISupports*[mCount];
|
|
mArraySize = mCount;
|
|
}
|
|
if (0 == mArray) {
|
|
mArray = oldArray;
|
|
mArraySize = oldArraySize;
|
|
return;
|
|
}
|
|
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
|
delete[] oldArray;
|
|
}
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) const
|
|
{
|
|
PRInt32 index = -1;
|
|
PRBool running = PR_TRUE;
|
|
|
|
while (running && (++index < mCount)) {
|
|
running = (*aFunc)(mArray[index], aData);
|
|
}
|
|
return running;
|
|
}
|
|
|
|
PRBool SupportsArrayImpl::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) const
|
|
{
|
|
PRInt32 index = mCount;
|
|
PRBool running = PR_TRUE;
|
|
|
|
while (running && (0 <= --index)) {
|
|
running = (*aFunc)(mArray[index], aData);
|
|
}
|
|
return running;
|
|
}
|
|
|
|
|
|
NS_COM nsresult
|
|
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
|
|
{
|
|
if (aInstancePtrResult == 0) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
SupportsArrayImpl *it = new SupportsArrayImpl();
|
|
|
|
if (0 == it) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return it->QueryInterface(kISupportsArrayIID, (void **) aInstancePtrResult);
|
|
}
|
|
|