diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/libs/xpcom18a4/xpcom/ds | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
105 files changed, 27285 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/ds/.cvsignore b/src/libs/xpcom18a4/xpcom/ds/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/ds/Makefile.in b/src/libs/xpcom18a4/xpcom/ds/Makefile.in new file mode 100644 index 00000000..8da8853c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/Makefile.in @@ -0,0 +1,171 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_ds +LIBRARY_NAME = xpcomds_s +GRE_MODULE = 1 + +REQUIRES = \ + string \ + $(NULL) + +CSRCS = \ + pldhash.c \ + $(NULL) + +CPPSRCS = \ + nsAtomTable.cpp \ + nsAtomService.cpp \ + nsByteBuffer.cpp \ + nsCheapSets.cpp \ + nsCRT.cpp \ + nsDeque.cpp \ + nsEmptyEnumerator.cpp \ + nsEnumeratorUtils.cpp \ + nsFixedSizeAllocator.cpp \ + nsHashSets.cpp \ + nsHashtable.cpp \ + nsObserverList.cpp \ + nsObserverService.cpp \ + nsProperties.cpp \ + nsPersistentProperties.cpp \ + nsQuickSort.cpp \ + nsRecyclingAllocator.cpp \ + nsStaticNameTable.cpp \ + nsStringEnumerator.cpp \ + nsSupportsArray.cpp \ + nsSupportsArrayEnumerator.cpp \ + nsSupportsPrimitives.cpp \ + nsTHashtable.cpp \ + nsUnicharBuffer.cpp \ + nsVariant.cpp \ + nsVoidArray.cpp \ + nsTextFormatter.cpp \ + nsTimelineService.cpp \ + nsValueArray.cpp \ + nsCOMArray.cpp \ + nsArray.cpp \ + nsArrayEnumerator.cpp \ + $(NULL) + +EXPORTS = \ + nsAtomService.h \ + nsBaseHashtable.h \ + nsCheapSets.h \ + nsClassHashtable.h \ + nsCppSharedAllocator.h \ + nsCRT.h \ + nsDataHashtable.h \ + nsDeque.h \ + nsDoubleHashtable.h \ + nsEnumeratorUtils.h \ + nsFixedSizeAllocator.h \ + nsHashSets.h \ + nsHashKeys.h \ + nsHashtable.h \ + nsIByteBuffer.h \ + nsIUnicharBuffer.h \ + nsInt64.h \ + nsInterfaceHashtable.h \ + nsObserverService.h \ + nsQuickSort.h \ + nsRecyclingAllocator.h \ + nsRefPtrHashtable.h \ + nsStaticNameTable.h \ + nsStaticAtom.h \ + nsSupportsArray.h \ + nsSupportsPrimitives.h \ + nsTHashtable.h \ + nsTime.h \ + nsUnitConversion.h \ + nsVariant.h \ + nsVoidArray.h \ + pldhash.h \ + nsTextFormatter.h \ + nsValueArray.h \ + nsArray.h \ + nsArrayEnumerator.h \ + nsCOMArray.h \ + nsStringEnumerator.h \ + nsAutoBuffer.h \ + $(NULL) + +XPIDLSRCS = \ + nsIAtom.idl \ + nsIAtomService.idl \ + nsICollection.idl \ + nsIEnumerator.idl \ + nsIPersistentProperties2.idl \ + nsIPropertyBag.idl \ + nsIRecyclingAllocator.idl \ + nsIVariant.idl \ + nsISerializable.idl \ + nsIStringEnumerator.idl \ + nsISupportsArray.idl \ + nsISupportsIterators.idl \ + nsITimelineService.idl \ + nsIArray.idl \ + $(NULL) + +SDK_XPIDLSRCS = \ + nsIObserverService.idl \ + nsIObserver.idl \ + nsIProperties.idl \ + nsISimpleEnumerator.idl \ + nsISupportsPrimitives.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + + +DEFINES += -D_IMPL_NS_COM diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsArray.cpp new file mode 100644 index 00000000..9eaf7868 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArray.cpp @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is XPCOM Array implementation. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsArray.h" +#include "nsArrayEnumerator.h" +#include "nsWeakReference.h" + +// used by IndexOf() +struct findIndexOfClosure +{ + nsISupports *targetElement; + PRUint32 startIndex; + PRUint32 resultIndex; +}; + +PR_STATIC_CALLBACK(PRBool) FindElementCallback(void* aElement, void* aClosure); + + +NS_IMPL_ISUPPORTS2(nsArray, nsIArray, nsIMutableArray) + +nsArray::~nsArray() +{ + Clear(); +} + +NS_IMETHODIMP +nsArray::GetLength(PRUint32* aLength) +{ + *aLength = mArray.Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsArray::QueryElementAt(PRUint32 aIndex, + const nsIID& aIID, + void ** aResult) +{ + nsISupports * obj = mArray.ObjectAt(aIndex); + if (!obj) return NS_ERROR_UNEXPECTED; + + // no need to worry about a leak here, because ObjectAt() doesn't + // addref its result + return obj->QueryInterface(aIID, aResult); +} + +NS_IMETHODIMP +nsArray::IndexOf(PRUint32 aStartIndex, nsISupports* aElement, + PRUint32* aResult) +{ + // optimize for the common case by forwarding to mArray + if (aStartIndex == 0) { + *aResult = mArray.IndexOf(aElement); + if (*aResult == -1) + return NS_ERROR_FAILURE; + return NS_OK; + } + + findIndexOfClosure closure = { aElement, aStartIndex, 0 }; + PRBool notFound = mArray.EnumerateForwards(FindElementCallback, &closure); + if (notFound) + return NS_ERROR_FAILURE; + + *aResult = closure.resultIndex; + return NS_OK; +} + +NS_IMETHODIMP +nsArray::Enumerate(nsISimpleEnumerator **aResult) +{ + return NS_NewArrayEnumerator(aResult, NS_STATIC_CAST(nsIArray*, this)); +} + +// nsIMutableArray implementation + +NS_IMETHODIMP +nsArray::AppendElement(nsISupports* aElement, PRBool aWeak) +{ + PRBool result; + if (aWeak) { + nsCOMPtr<nsISupports> elementRef = + getter_AddRefs(NS_STATIC_CAST(nsISupports*, + NS_GetWeakReference(aElement))); + NS_ASSERTION(elementRef, "AppendElement: Trying to use weak references on an object that doesn't support it"); + if (!elementRef) + return NS_ERROR_FAILURE; + result = mArray.AppendObject(elementRef); + } + + else { + // add the object directly + result = mArray.AppendObject(aElement); + } + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::RemoveElementAt(PRUint32 aIndex) +{ + PRBool result = mArray.RemoveObjectAt(aIndex); + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex, PRBool aWeak) +{ + nsCOMPtr<nsISupports> elementRef; + if (aWeak) { + elementRef = + getter_AddRefs(NS_STATIC_CAST(nsISupports*, + NS_GetWeakReference(aElement))); + NS_ASSERTION(elementRef, "InsertElementAt: Trying to use weak references on an object that doesn't support it"); + if (!elementRef) + return NS_ERROR_FAILURE; + } else { + elementRef = aElement; + } + PRBool result = mArray.InsertObjectAt(elementRef, aIndex); + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::Clear() +{ + mArray.Clear(); + return NS_OK; +} + +// +// static helper routines +// +PRBool +FindElementCallback(void *aElement, void* aClosure) +{ + findIndexOfClosure* closure = + NS_STATIC_CAST(findIndexOfClosure*, aClosure); + + nsISupports* element = + NS_STATIC_CAST(nsISupports*, aElement); + + // don't start searching until we're past the startIndex + if (closure->resultIndex >= closure->startIndex && + element == closure->targetElement) { + return PR_FALSE; // stop! We found it + } + closure->resultIndex++; + + return PR_TRUE; +} + +// +// do_QueryElementAt helper stuff +// +nsresult +nsQueryArrayElementAt::operator()(const nsIID& aIID, void** aResult) const + { + nsresult status = mArray + ? mArray->QueryElementAt(mIndex, aIID, aResult) + : NS_ERROR_NULL_POINTER; + + if (mErrorPtr) + *mErrorPtr = status; + + return status; + } + +// +// exported constructor routines +// +nsresult +NS_NewArray(nsIMutableArray** aResult) +{ + nsArray* arr = new nsArray; + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIMutableArray*,arr); + NS_ADDREF(*aResult); + + return NS_OK; +} + +nsresult +NS_NewArray(nsIMutableArray** aResult, const nsCOMArray_base& aBaseArray) +{ + nsArray* arr = new nsArray(aBaseArray); + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIMutableArray*, arr); + NS_ADDREF(*aResult); + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArray.h b/src/libs/xpcom18a4/xpcom/ds/nsArray.h new file mode 100644 index 00000000..4a4f6cf2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArray.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsArray_h__ +#define nsArray_h__ + +#include "nsIArray.h" +#include "nsCOMArray.h" +#include "nsCOMPtr.h" + +#define NS_ARRAY_CLASSNAME \ + "nsIArray implementation" + +// {35C66FD1-95E9-4e0a-80C5-C3BD2B375481} +#define NS_ARRAY_CID \ +{ 0x35c66fd1, 0x95e9, 0x4e0a, \ + { 0x80, 0xc5, 0xc3, 0xbd, 0x2b, 0x37, 0x54, 0x81 } } + + +// create a new, empty array +nsresult NS_COM +NS_NewArray(nsIMutableArray** aResult); + +// The resulting array will hold an owning reference to every element +// in the original nsCOMArray<T>. This also means that any further +// changes to the original nsCOMArray<T> will not affect the new +// array, and that the original array can go away and the new array +// will still hold valid elements. +nsresult NS_COM +NS_NewArray(nsIMutableArray** aResult, const nsCOMArray_base& base); + +// adapter class to map nsIArray->nsCOMArray +// do NOT declare this as a stack or member variable, use +// nsCOMArray instead! +// if you need to convert a nsCOMArray->nsIArray, see NS_NewArray above +class nsArray : public nsIMutableArray +{ +public: + nsArray() { } + nsArray(const nsCOMArray_base& aBaseArray) : mArray(aBaseArray) + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIARRAY + NS_DECL_NSIMUTABLEARRAY + +private: + ~nsArray(); + + nsCOMArray_base mArray; +}; + + +// helper class for do_QueryElementAt +class NS_COM nsQueryArrayElementAt : public nsCOMPtr_helper + { + public: + nsQueryArrayElementAt(nsIArray* aArray, PRUint32 aIndex, + nsresult* aErrorPtr) + : mArray(aArray), + mIndex(aIndex), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const; + + private: + nsIArray* mArray; + PRUint32 mIndex; + nsresult* mErrorPtr; + }; + +inline +const nsQueryArrayElementAt +do_QueryElementAt(nsIArray* aArray, PRUint32 aIndex, nsresult* aErrorPtr = 0) + { + return nsQueryArrayElementAt(aArray, aIndex, aErrorPtr); + } + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp new file mode 100644 index 00000000..c105622a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsArrayEnumerator.h" + +NS_IMPL_ISUPPORTS1(nsSimpleArrayEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsSimpleArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + *aResult = (mIndex < cnt); + return NS_OK; +} + +NS_IMETHODIMP +nsSimpleArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + if (mIndex >= cnt) + return NS_ERROR_UNEXPECTED; + + return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports), (void**)aResult); +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsIArray* array) +{ + nsSimpleArrayEnumerator* enumer = new nsSimpleArrayEnumerator(array); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*result = enumer); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +// enumerator implementation for nsCOMArray +// creates a snapshot of the array in question +// you MUST use NS_NewArrayEnumerator to create this, so that +// allocation is done correctly +class nsCOMArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + // nsSimpleArrayEnumerator methods + nsCOMArrayEnumerator() : mIndex(0) { + } + + // specialized operator to make sure we make room for mValues + void* operator new (size_t size, const nsCOMArray_base& aArray) CPP_THROW_NEW; + void operator delete(void* ptr) { + ::operator delete(ptr); + } + +private: + ~nsCOMArrayEnumerator(void); + +protected: + PRUint32 mIndex; // current position + PRUint32 mArraySize; // size of the array + + // this is actually bigger + nsISupports* mValueArray[1]; +}; + +NS_IMPL_ISUPPORTS1(nsCOMArrayEnumerator, nsISimpleEnumerator) + +nsCOMArrayEnumerator::~nsCOMArrayEnumerator() +{ + // only release the entries that we haven't visited yet + for (; mIndex < mArraySize; ++mIndex) { + NS_IF_RELEASE(mValueArray[mIndex]); + } +} + +NS_IMETHODIMP +nsCOMArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = (mIndex < mArraySize); + return NS_OK; +} + +NS_IMETHODIMP +nsCOMArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mIndex >= mArraySize) + return NS_ERROR_UNEXPECTED; + + // pass the ownership of the reference to the caller. Since + // we AddRef'ed during creation of |this|, there is no need + // to AddRef here + *aResult = mValueArray[mIndex++]; + + // this really isn't necessary. just pretend this happens, since + // we'll never visit this value again! + // mValueArray[(mIndex-1)] = nsnull; + + return NS_OK; +} + +void* +nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) + CPP_THROW_NEW +{ + // create enough space such that mValueArray points to a large + // enough value. Note that the initial value of size gives us + // space for mValueArray[0], so we must subtract + size += (aArray.Count() - 1) * sizeof(aArray[0]); + + // do the actual allocation + nsCOMArrayEnumerator * result = + NS_STATIC_CAST(nsCOMArrayEnumerator*, ::operator new(size)); + + // now need to copy over the values, and addref each one + // now this might seem like alot of work, but we're actually just + // doing all our AddRef's ahead of time since GetNext() doesn't + // need to AddRef() on the way out + PRUint32 i; + PRUint32 max = result->mArraySize = aArray.Count(); + for (i = 0; i<max; i++) { + result->mValueArray[i] = aArray[i]; + NS_IF_ADDREF(result->mValueArray[i]); + } + + return result; +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, + const nsCOMArray_base& aArray) +{ + nsCOMArrayEnumerator *enumerator = new (aArray) nsCOMArrayEnumerator(); + if (!enumerator) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*aResult = enumerator); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h new file mode 100644 index 00000000..e22302b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsArrayEnumerator_h__ +#define nsArrayEnumerator_h__ + +// enumerator implementation for nsIArray + +#include "nsIArray.h" +#include "nsCOMArray.h" +#include "nsISimpleEnumerator.h" +#include "nsCOMPtr.h" + +class nsSimpleArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + // nsSimpleArrayEnumerator methods + nsSimpleArrayEnumerator(nsIArray* aValueArray) : + mValueArray(aValueArray), mIndex(0) { + } + +private: + ~nsSimpleArrayEnumerator() {} + +protected: + nsCOMPtr<nsIArray> mValueArray; + PRUint32 mIndex; +}; + + +// Create an enumerator for an existing nsIArray implementation +// The enumerator holds an owning reference to the array. +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsIArray* array); + + +// create an enumerator for an existing nsCOMArray<T> implementation +// The enumerator will hold an owning reference to each ELEMENT in +// the array. This means that the nsCOMArray<T> can safely go away +// without its objects going away. +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, + const nsCOMArray_base& aArray); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp new file mode 100644 index 00000000..f0366043 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsAtomService.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsAtomService, nsIAtomService) + +nsAtomService::nsAtomService() +{ +} + +nsresult +nsAtomService::GetAtom(const PRUnichar *aString, nsIAtom ** aResult) +{ + *aResult = NS_NewAtom(aString); + + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +nsresult +nsAtomService::GetPermanentAtom(const PRUnichar *aString, nsIAtom ** aResult) +{ + *aResult = NS_NewPermanentAtom(aString); + + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h new file mode 100644 index 00000000..ae036b80 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nsAtomService_h +#define __nsAtomService_h + +#include "nsIAtomService.h" + +class nsAtomService : public nsIAtomService +{ + public: + nsAtomService(); + NS_DECL_ISUPPORTS + + NS_DECL_NSIATOMSERVICE + + private: + ~nsAtomService() {} +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp new file mode 100644 index 00000000..fc92dec8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp @@ -0,0 +1,616 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:cindent:ts=2:et:sw=2: +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsAtomTable.h" +#include "nsStaticAtom.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "pldhash.h" +#include "prenv.h" +#include "nsVoidArray.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "plarena.h" + +class nsStaticAtomWrapper; + +/** + * The shared hash table for atom lookups. + * + * XXX This should be manipulated in a threadsafe way or we should make + * sure it's only manipulated from the main thread. Probably the latter + * is better, since the former would hurt performance. + * + * If |gAtomTable.ops| is 0, then the table is uninitialized. + */ +static PLDHashTable gAtomTable; + +// this is where we keep the nsStaticAtomWrapper objects + +static PLArenaPool* gStaticAtomArena = 0; + +class nsStaticAtomWrapper : public nsIAtom +{ +public: + nsStaticAtomWrapper(const nsStaticAtom* aAtom) : + mStaticAtom(aAtom) + { + MOZ_COUNT_CTOR(nsStaticAtomWrapper); + } + ~nsStaticAtomWrapper() { // no subclasses -> not virtual + // this is arena allocated and won't be called except in debug + // builds. If this function ever does anything non-debug, be sure + // to get rid of the ifdefs in AtomTableClearEntry! + MOZ_COUNT_DTOR(nsStaticAtomWrapper); + } + + NS_IMETHOD QueryInterface(REFNSIID aIID, + void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + NS_DECL_NSIATOM + + const nsStaticAtom* GetStaticAtom() { + return mStaticAtom; + } +private: + const nsStaticAtom* mStaticAtom; +}; + +// the atomtableentry can contain either an AtomImpl or a +// nsStaticAtomWrapper, indicated by the first bit of PtrBits +typedef unsigned long PtrBits; + +struct AtomTableEntry : public PLDHashEntryHdr { + // mAtom & 0x1 means (mAtom & ~0x1) points to an nsStaticAtomWrapper + // else it points to an nsAtomImpl + PtrBits mAtom; + + inline PRBool IsStaticAtom() const { + return (mAtom & 0x1) != 0; + } + + inline void SetAtomImpl(AtomImpl* aAtom) { + NS_ASSERTION(aAtom, "Setting null atom"); + mAtom = PtrBits(aAtom); + } + + inline void SetStaticAtomWrapper(nsStaticAtomWrapper* aAtom) { + NS_ASSERTION(aAtom, "Setting null atom"); + NS_ASSERTION((PtrBits(aAtom) & ~0x1) == PtrBits(aAtom), + "Pointers must align or this is broken"); + + mAtom = PtrBits(aAtom) | 0x1; + } + + inline void ClearAtom() { + mAtom = nsnull; + } + + inline PRBool HasValue() const { + return (mAtom & ~0x1) != 0; + } + + // these accessors assume that you already know the type + inline AtomImpl *GetAtomImpl() const { + NS_ASSERTION(!IsStaticAtom(), "This is a static atom, not an AtomImpl"); + return (AtomImpl*) (mAtom & ~0x1); + } + + inline nsStaticAtomWrapper *GetStaticAtomWrapper() const { + NS_ASSERTION(IsStaticAtom(), "This is an AtomImpl, not a static atom"); + return (nsStaticAtomWrapper*) (mAtom & ~0x1); + } + + inline const nsStaticAtom* GetStaticAtom() const { + return GetStaticAtomWrapper()->GetStaticAtom(); + } + + // type-agnostic accessors + + // get the string buffer + inline const char* get() const { + return IsStaticAtom() ? GetStaticAtom()->mString : GetAtomImpl()->mString; + } + + // get an addreffed nsIAtom - not using already_AddRef'ed atom + // because the callers are not (and should not be) using nsCOMPtr + inline nsIAtom* GetAtom() const { + nsIAtom* result; + + if (IsStaticAtom()) + result = GetStaticAtomWrapper(); + else { + result = GetAtomImpl(); + NS_ADDREF(result); + } + + return result; + } +}; + +PR_STATIC_CALLBACK(const void *) +AtomTableGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry); + NS_ASSERTION(he->HasValue(), "Empty atom. how did that happen?"); + return he->get(); +} + +PR_STATIC_CALLBACK(PRBool) +AtomTableMatchKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const AtomTableEntry *he = NS_STATIC_CAST(const AtomTableEntry*, entry); + const char* keyStr = NS_STATIC_CAST(const char*, key); + return nsCRT::strcmp(keyStr, he->get()) == 0; +} + +PR_STATIC_CALLBACK(void) +AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry); + + he->keyHash = 0; + + if (!he->IsStaticAtom()) { + AtomImpl *atom = he->GetAtomImpl(); + // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and + // they then remove themselves from the table. In other words, they + // are owned by the callers who own references to them. + // |PermanentAtomImpl| permanent atoms ignore their refcount and are + // deleted when they are removed from the table at table destruction. + // In other words, they are owned by the atom table. + if (atom->IsPermanent()) + delete NS_STATIC_CAST(PermanentAtomImpl*, atom); + } + else { + he->GetStaticAtomWrapper()->~nsStaticAtomWrapper(); + } + + he->ClearAtom(); +} + +static const PLDHashTableOps AtomTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + AtomTableGetKey, + PL_DHashStringKey, + AtomTableMatchKey, + PL_DHashMoveEntryStub, + AtomTableClearEntry, + PL_DHashFinalizeStub, + NULL +}; + + +#ifdef DEBUG + +PR_STATIC_CALLBACK(PLDHashOperator) +DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he, + PRUint32 index, void *arg) +{ + AtomTableEntry *entry = NS_STATIC_CAST(AtomTableEntry*, he); + + if (entry->IsStaticAtom()) + return PL_DHASH_NEXT; + + AtomImpl* atom = entry->GetAtomImpl(); + if (!atom->IsPermanent()) { + ++*NS_STATIC_CAST(PRUint32*, arg); + const char *str; + atom->GetUTF8String(&str); + fputs(str, stdout); + fputs("\n", stdout); + } + return PL_DHASH_NEXT; +} + +#endif + +static inline +void PromoteToPermanent(AtomImpl* aAtom) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + { + nsrefcnt refcount = aAtom->GetRefCount(); + do { + NS_LOG_RELEASE(aAtom, --refcount, "AtomImpl"); + } while (refcount); + } +#endif + aAtom = new (aAtom) PermanentAtomImpl(); +} + +void NS_PurgeAtomTable() +{ + if (gAtomTable.ops) { +#ifdef DEBUG + if (PR_GetEnv("MOZ_DUMP_ATOM_LEAKS")) { + PRUint32 leaked = 0; + printf("*** %d atoms still exist (including permanent):\n", + gAtomTable.entryCount); + PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked); + printf("*** %u non-permanent atoms leaked\n", leaked); + } +#endif + PL_DHashTableFinish(&gAtomTable); + gAtomTable.entryCount = 0; + gAtomTable.ops = nsnull; + + if (gStaticAtomArena) { + PL_FinishArenaPool(gStaticAtomArena); + delete gStaticAtomArena; + gStaticAtomArena = nsnull; + } + } +} + +AtomImpl::AtomImpl() +{ +} + +AtomImpl::~AtomImpl() +{ + NS_PRECONDITION(gAtomTable.ops, "uninitialized atom hashtable"); + // Permanent atoms are removed from the hashtable at shutdown, and we + // don't want to remove them twice. See comment above in + // |AtomTableClearEntry|. + if (!IsPermanent()) { + PL_DHashTableOperate(&gAtomTable, mString, PL_DHASH_REMOVE); + if (gAtomTable.entryCount == 0) { + PL_DHashTableFinish(&gAtomTable); + NS_ASSERTION(gAtomTable.entryCount == 0, + "PL_DHashTableFinish changed the entry count"); + } + } +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(AtomImpl, nsIAtom) + +NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::Release() +{ + return 1; +} + +/* virtual */ PRBool +AtomImpl::IsPermanent() +{ + return PR_FALSE; +} + +/* virtual */ PRBool +PermanentAtomImpl::IsPermanent() +{ + return PR_TRUE; +} + +void* AtomImpl::operator new ( size_t size, const nsACString& aString ) CPP_THROW_NEW +{ + /* + Note: since the |size| will initially also include the |PRUnichar| member + |mString|, our size calculation will give us one character too many. + We use that extra character for a zero-terminator. + + Note: this construction is not guaranteed to be possible by the C++ + compiler. A more reliable scheme is used by |nsShared[C]String|s, see + http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsSharedString.h#174 + */ + size += aString.Length() * sizeof(char); + AtomImpl* ii = NS_STATIC_CAST(AtomImpl*, ::operator new(size)); + + char* toBegin = &ii->mString[0]; + nsACString::const_iterator fromBegin, fromEnd; + *copy_string(aString.BeginReading(fromBegin), aString.EndReading(fromEnd), toBegin) = '\0'; + return ii; +} + +void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) CPP_THROW_NEW { + NS_ASSERTION(!aAtom->IsPermanent(), + "converting atom that's already permanent"); + + // Just let the constructor overwrite the vtable pointer. + return aAtom; +} + +NS_IMETHODIMP +AtomImpl::ToString(nsAString& aBuf) +{ + CopyUTF8toUTF16(nsDependentCString(mString), aBuf); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::ToUTF8String(nsACString& aBuf) +{ + aBuf.Assign(mString); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::GetUTF8String(const char **aResult) +{ + NS_PRECONDITION(aResult, "null out param"); + *aResult = mString; + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::EqualsUTF8(const nsACString& aString, PRBool* aResult) +{ + *aResult = aString.Equals(mString); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::Equals(const nsAString& aString, PRBool* aResult) +{ + *aResult = NS_ConvertUTF16toUTF8(aString).Equals(mString); + return NS_OK; +} + +//---------------------------------------------------------------------- + +// wrapper class for the nsStaticAtom struct + +NS_IMETHODIMP_(nsrefcnt) +nsStaticAtomWrapper::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) +nsStaticAtomWrapper::Release() +{ + return 1; +} + +NS_IMPL_QUERY_INTERFACE1(nsStaticAtomWrapper, nsIAtom) + +NS_IMETHODIMP +nsStaticAtomWrapper::GetUTF8String(const char** aResult) +{ + *aResult = mStaticAtom->mString; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::ToString(nsAString& aBuf) +{ + // static should always be always ASCII, to allow tools like gperf + // to generate the tables, and to avoid unnecessary conversion + NS_ASSERTION(nsCRT::IsAscii(mStaticAtom->mString), + "Data loss - atom should be ASCII"); + CopyASCIItoUCS2(nsDependentCString(mStaticAtom->mString), aBuf); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::ToUTF8String(nsACString& aBuf) +{ + aBuf.Assign(mStaticAtom->mString); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::EqualsUTF8(const nsACString& aString, PRBool* aResult) +{ + *aResult = aString.Equals(mStaticAtom->mString); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::Equals(const nsAString& aString, PRBool* aResult) +{ + *aResult = NS_ConvertUCS2toUTF8(aString).Equals(mStaticAtom->mString); + return NS_OK; +} +//---------------------------------------------------------------------- + +NS_COM nsIAtom* NS_NewAtom(const char* isolatin1) +{ + return NS_NewAtom(nsDependentCString(isolatin1)); +} + +NS_COM nsIAtom* NS_NewPermanentAtom(const char* isolatin1) +{ + return NS_NewPermanentAtom(NS_ConvertASCIItoUCS2(isolatin1)); +} + +static nsStaticAtomWrapper* +WrapStaticAtom(const nsStaticAtom* aAtom) +{ + if (!gStaticAtomArena) { + gStaticAtomArena = new PLArenaPool; + if (!gStaticAtomArena) + return nsnull; + + PL_INIT_ARENA_POOL(gStaticAtomArena, "nsStaticAtomArena", 4096); + } + + void* mem; + PL_ARENA_ALLOCATE(mem, gStaticAtomArena, sizeof(nsStaticAtom)); + + nsStaticAtomWrapper* wrapper = + new (mem) nsStaticAtomWrapper(aAtom); + + return wrapper; +} + +static AtomTableEntry* GetAtomHashEntry(const char* aString) +{ + if (!gAtomTable.ops && + !PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0, + sizeof(AtomTableEntry), 2048)) { + gAtomTable.ops = nsnull; + return nsnull; + } + return NS_STATIC_CAST(AtomTableEntry*, + PL_DHashTableOperate(&gAtomTable, + aString, + PL_DHASH_ADD)); +} + +NS_COM nsresult +NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, PRUint32 aAtomCount) +{ + // this does two things: + // 1) wraps each static atom in a wrapper, if necessary + // 2) initializes the address pointed to by each mAtom slot + + for (PRUint32 i=0; i<aAtomCount; i++) { + NS_ASSERTION(nsCRT::IsAscii(aAtoms[i].mString), + "Static atoms must be ASCII!"); + AtomTableEntry *he = + GetAtomHashEntry(aAtoms[i].mString); + + if (he->HasValue() && aAtoms[i].mAtom) { + // there already is an atom with this name in the table.. but we + // still have to update mAtom + if (!he->IsStaticAtom() && !he->GetAtomImpl()->IsPermanent()) { + // since we wanted to create a static atom but there is + // already one there, we convert it to a non-refcounting + // permanent atom + PromoteToPermanent(he->GetAtomImpl()); + } + + // and now, if the consumer wants to remember this value in a + // slot, we do so + if (aAtoms[i].mAtom) + *aAtoms[i].mAtom = he->GetAtom(); + } + + else { + nsStaticAtomWrapper* atom = WrapStaticAtom(&aAtoms[i]); + NS_ASSERTION(atom, "Failed to wrap static atom"); + + // but even if atom is null, no real difference in code.. + he->SetStaticAtomWrapper(atom); + if (aAtoms[i].mAtom) + *aAtoms[i].mAtom = atom; + } + } + return NS_OK; +} + +NS_COM nsIAtom* NS_NewAtom( const nsAString& aString ) +{ + NS_ConvertUCS2toUTF8 utf8String(aString); + + return NS_NewAtom(utf8String); +} + +NS_COM +nsIAtom* +NS_NewAtom( const nsACString& aString ) +{ + AtomTableEntry *he = GetAtomHashEntry(PromiseFlatCString(aString).get()); + + if (he->HasValue()) + return he->GetAtom(); + + AtomImpl* atom = new (aString) AtomImpl(); + he->SetAtomImpl(atom); + if (!atom) { + PL_DHashTableRawRemove(&gAtomTable, he); + return nsnull; + } + + NS_ADDREF(atom); + return atom; +} + +NS_COM nsIAtom* NS_NewPermanentAtom( const nsAString& aString ) +{ + return NS_NewPermanentAtom(NS_ConvertUCS2toUTF8(aString)); +} + +NS_COM +nsIAtom* NS_NewPermanentAtom( const nsACString& aString ) +{ + AtomTableEntry *he = GetAtomHashEntry(PromiseFlatCString(aString).get()); + + if (he->HasValue() && he->IsStaticAtom()) + return he->GetStaticAtomWrapper(); + + // either there is no atom and we'll create an AtomImpl, + // or there is an existing AtomImpl + AtomImpl* atom = he->GetAtomImpl(); + + if (atom) { + // ensure that it's permanent + if (!atom->IsPermanent()) { + PromoteToPermanent(atom); + } + } else { + // otherwise, make a new atom + atom = new (aString) PermanentAtomImpl(); + he->SetAtomImpl(atom); + if ( !atom ) { + PL_DHashTableRawRemove(&gAtomTable, he); + return nsnull; + } + } + + NS_ADDREF(atom); + return atom; +} + +NS_COM nsIAtom* NS_NewAtom( const PRUnichar* str ) +{ + return NS_NewAtom(NS_ConvertUCS2toUTF8(str)); +} + +NS_COM nsIAtom* NS_NewPermanentAtom( const PRUnichar* str ) +{ + return NS_NewPermanentAtom(nsDependentString(str)); +} + +NS_COM nsrefcnt NS_GetNumberOfAtoms(void) +{ + return gAtomTable.entryCount; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h new file mode 100644 index 00000000..d8971cf7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsAtomTable_h__ +#define nsAtomTable_h__ + +#include "nsIAtom.h" + +/** + * A threadsafely-refcounted implementation of nsIAtom. Note that + * AtomImpl objects are sometimes converted into PermanentAtomImpl + * objects using placement new and just overwriting the vtable pointer. + */ + +class AtomImpl : public nsIAtom { +public: + AtomImpl(); + +protected: + // We don't need a virtual destructor here because PermanentAtomImpl + // deletions aren't handled through Release(). + ~AtomImpl(); + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIATOM + + virtual PRBool IsPermanent(); + + void* operator new(size_t size, const nsACString& aString) CPP_THROW_NEW; + + void operator delete(void* ptr) { + ::operator delete(ptr); + } + + // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count + nsrefcnt GetRefCount() { return mRefCnt; } + + // Actually more; 0 terminated. This slot is reserved for the + // terminating zero. + char mString[1]; +}; + +/** + * A non-refcounted implementation of nsIAtom. + */ + +class PermanentAtomImpl : public AtomImpl { +public: +#ifdef AIX + PermanentAtomImpl() : AtomImpl() {} +#endif + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool IsPermanent(); + + void* operator new(size_t size, const nsACString& aString) CPP_THROW_NEW { + return AtomImpl::operator new(size, aString); + } + void* operator new(size_t size, AtomImpl* aAtom) CPP_THROW_NEW; + +}; + +void NS_PurgeAtomTable(); + +#endif // nsAtomTable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h new file mode 100644 index 00000000..84011369 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is auto buffer template. + * + * The Initial Developer of the Original Code is + * Conrad Carlen <ccarlen@mac.com>. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jungshik Shin <jshin@mailaps.org> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsAutoBuffer_h__ +#define nsAutoBuffer_h__ + +#ifndef nsMemory_h__ +#include "nsMemory.h" +#endif + +/** + * A buffer which will use stack space if the requested size will + * fit in the stack buffer and allocate from the heap if not. + * + * Below is a usage example : + * + * typedef nsAutoBuffer<PRUnichar, 256> nsAutoUnicharBuffer; + * + * nsAutoUnicharBuffer buffer; + * + * if (!buffer.EnsureElemCapacity(initialLength)) + * return NS_ERROR_OUT_OF_MEMORY; + * + * PRUnichar *unicharPtr = buffer.get(); + * + * // add PRUnichar's to the buffer pointed to by |unicharPtr| as long as + * // the number of PRUnichar's is less than |intialLength| + * + * // increase the capacity + * if (!buffer.AddElemCapacity(extraLength)) + * return NS_ERROR_OUT_OF_MEMORY + * + * unicharPtr = buffer.get() + initialLength; + * + * //continue to add PRUnichar's.... + */ + +template <class T, PRInt32 sz> +class nsAutoBuffer +{ +public: + nsAutoBuffer() : + mBufferPtr(mStackBuffer), + mCurElemCapacity(sz) + { + } + + ~nsAutoBuffer() + { + if (mBufferPtr != mStackBuffer) + nsMemory::Free(mBufferPtr); + } + + PRBool EnsureElemCapacity(PRInt32 inElemCapacity) + { + if (inElemCapacity <= mCurElemCapacity) + return PR_TRUE; + + T* newBuffer; + + if (mBufferPtr != mStackBuffer) + newBuffer = (T*)nsMemory::Realloc((void *)mBufferPtr, inElemCapacity * sizeof(T)); + else + newBuffer = (T*)nsMemory::Alloc(inElemCapacity * sizeof(T)); + + if (!newBuffer) + return PR_FALSE; + + if (mBufferPtr != mStackBuffer) + nsMemory::Free(mBufferPtr); + + mBufferPtr = newBuffer; + mCurElemCapacity = inElemCapacity; + return PR_TRUE; + } + + PRBool AddElemCapacity(PRInt32 inElemCapacity) + { + return EnsureElemCapacity(mCurElemCapacity + inElemCapacity); + } + + T* get() const { return mBufferPtr; } + PRInt32 GetElemCapacity() const { return mCurElemCapacity; } + +protected: + + T *mBufferPtr; + T mStackBuffer[sz]; + PRInt32 mCurElemCapacity; +}; + +#endif // nsAutoBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h new file mode 100644 index 00000000..92300c2f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h @@ -0,0 +1,458 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsBaseHashtable_h__ +#define nsBaseHashtable_h__ + +#include "nsTHashtable.h" +#include "prlock.h" +#include "nsDebug.h" + +template<class KeyClass,class DataType,class UserDataType> +class nsBaseHashtable; // forward declaration + +/** + * the private nsTHashtable::EntryType class used by nsBaseHashtable + * @see nsTHashtable for the specification of this class + * @see nsBaseHashtable for template parameters + */ +template<class KeyClass,class DataType> +class nsBaseHashtableET : public KeyClass +{ +public: + DataType mData; + friend class nsTHashtable< nsBaseHashtableET<KeyClass,DataType> >; + +private: + typedef typename KeyClass::KeyType KeyType; + typedef typename KeyClass::KeyTypePointer KeyTypePointer; + + nsBaseHashtableET(KeyTypePointer aKey); + nsBaseHashtableET(nsBaseHashtableET<KeyClass,DataType>& toCopy); + ~nsBaseHashtableET(); +}; + +/** + * templated hashtable for simple data types + * This class manages simple data types that do not need construction or + * destruction. Thread-safety is optional, via a flag in Init() + * + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param DataType the datatype stored in the hashtable, + * for example, PRUint32 or nsCOMPtr. If UserDataType is not the same, + * DataType must implicitly cast to UserDataType + * @param UserDataType the user sees, for example PRUint32 or nsISupports* + */ +template<class KeyClass,class DataType,class UserDataType> +class nsBaseHashtable : + protected nsTHashtable< nsBaseHashtableET<KeyClass,DataType> > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef nsBaseHashtableET<KeyClass,DataType> EntryType; + + // default constructor+destructor are fine + + /** + * Initialize the object. + * @param initSize the initial number of buckets in the hashtable, + * default 16 + * @param threadSafe whether to provide read/write + * locking on all class methods + * @return PR_TRUE if the object was initialized properly. + */ + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE) + { return nsTHashtable<EntryType>::Init(initSize); } + + /** + * Check whether the table has been initialized. + * This function is especially useful for static hashtables. + * @return PR_TRUE if the table has been initialized. + */ + PRBool IsInitialized() const { return this->mTable.entrySize; } + + /** + * Return the number of entries in the table. + * @return number of entries + */ + PRUint32 Count() const + { return nsTHashtable<EntryType>::Count(); } + + /** + * retrieve the value for a key. + * @param aKey the key to retreive + * @param pData data associated with this key will be placed at this + * pointer. If you only need to check if the key exists, pData + * may be null. + * @return PR_TRUE if the key exists. If key does not exist, pData is not + * modified. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const + { + EntryType* ent = this->GetEntry(aKey); + + if (!ent) + return PR_FALSE; + + if (pData) + *pData = ent->mData; + + return PR_TRUE; + } + + /** + * put a new value for the associated key + * @param aKey the key to put + * @param aData the new data + * @return always PR_TRUE, unless memory allocation failed + */ + PRBool Put(KeyType aKey, UserDataType aData) + { + EntryType* ent = this->PutEntry(aKey); + + if (!ent) + return PR_FALSE; + + ent->mData = aData; + + return PR_TRUE; + } + + /** + * remove the data for the associated key + * @param aKey the key to remove from the hashtable + */ + void Remove(KeyType aKey) { this->RemoveEntry(aKey); } + + /** + * function type provided by the application for enumeration. + * @param aKey the key being enumerated + * @param aData data being enumerated + * @parm userArg passed unchanged from Enumerate + * @return either + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink + */ + typedef PLDHashOperator + (*PR_CALLBACK EnumReadFunction)(KeyType aKey, + UserDataType aData, + void* userArg); + + /** + * enumerate entries in the hashtable, without allowing changes + * this function read-locks the hashtable, so other threads may read keys + * at the same time in multi-thread environments. + * @param enumFunc enumeration callback + * @param userArg passed unchanged to the EnumReadFunction + */ + PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const + { + NS_ASSERTION(this->mTable.entrySize, + "nsBaseHashtable was not initialized properly."); + + s_EnumReadArgs enumData = { enumFunc, userArg }; + return PL_DHashTableEnumerate(NS_CONST_CAST(PLDHashTable*, &this->mTable), + s_EnumReadStub, + &enumData); + } + + /** + * function type provided by the application for enumeration. + * @param aKey the key being enumerated + * @param aData Reference to data being enumerated, may be altered. e.g. for + * nsInterfaceHashtable this is an nsCOMPtr reference... + * @parm userArg passed unchanged from Enumerate + * @return bitflag combination of + * @link PLDHashOperator::PL_DHASH_REMOVE @endlink, + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink + */ + typedef PLDHashOperator + (*PR_CALLBACK EnumFunction)(KeyType aKey, + DataType& aData, + void* userArg); + + /** + * enumerate entries in the hashtable, allowing changes. This + * functions write-locks the hashtable. + * @param enumFunc enumeration callback + * @param userArg passed unchanged to the EnumFunction + */ + PRUint32 Enumerate(EnumFunction enumFunc, void* userArg) + { + NS_ASSERTION(this->mTable.entrySize, + "nsBaseHashtable was not initialized properly."); + + s_EnumArgs enumData = { enumFunc, userArg }; + return PL_DHashTableEnumerate(&this->mTable, + s_EnumStub, + &enumData); + } + + /** + * reset the hashtable, removing all entries + */ + void Clear() { nsTHashtable<EntryType>::Clear(); } + +protected: + /** + * used internally during EnumerateRead. Allocated on the stack. + * @param func the enumerator passed to EnumerateRead + * @param userArg the userArg passed to EnumerateRead + */ + struct s_EnumReadArgs + { + EnumReadFunction func; + void* userArg; + }; + + static PLDHashOperator s_EnumReadStub(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg); + + struct s_EnumArgs + { + EnumFunction func; + void* userArg; + }; + + static PLDHashOperator s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg); +}; + +/** + * This class is a thread-safe version of nsBaseHashtable. + */ +template<class KeyClass,class DataType,class UserDataType> +class nsBaseHashtableMT : + protected nsBaseHashtable<KeyClass,DataType,UserDataType> +{ +public: + typedef typename + nsBaseHashtable<KeyClass,DataType,UserDataType>::EntryType EntryType; + typedef typename + nsBaseHashtable<KeyClass,DataType,UserDataType>::KeyType KeyType; + typedef typename + nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumFunction EnumFunction; + typedef typename + nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumReadFunction EnumReadFunction; + + nsBaseHashtableMT() : mLock(nsnull) { } + ~nsBaseHashtableMT(); + + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); + PRBool IsInitialized() const { return (PRBool) mLock; } + PRUint32 Count() const; + PRBool Get(KeyType aKey, UserDataType* pData) const; + PRBool Put(KeyType aKey, UserDataType aData); + void Remove(KeyType aKey); + + PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const; + PRUint32 Enumerate(EnumFunction enumFunc, void* userArg); + void Clear(); + +protected: + PRLock* mLock; +}; + + +// +// nsBaseHashtableET definitions +// + +template<class KeyClass,class DataType> +nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET(KeyTypePointer aKey) : + KeyClass(aKey) +{ } + +template<class KeyClass,class DataType> +nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET + (nsBaseHashtableET<KeyClass,DataType>& toCopy) : + KeyClass(toCopy), + mData(toCopy.mData) +{ } + +template<class KeyClass,class DataType> +nsBaseHashtableET<KeyClass,DataType>::~nsBaseHashtableET() +{ } + + +// +// nsBaseHashtable definitions +// + +template<class KeyClass,class DataType,class UserDataType> +PLDHashOperator +nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumReadStub + (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) +{ + EntryType* ent = NS_STATIC_CAST(EntryType*, hdr); + s_EnumReadArgs* eargs = (s_EnumReadArgs*) arg; + + PLDHashOperator res = (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); + + NS_ASSERTION( !(res & PL_DHASH_REMOVE ), + "PL_DHASH_REMOVE return during const enumeration; ignoring."); + + if (res & PL_DHASH_STOP) + return PL_DHASH_STOP; + + return PL_DHASH_NEXT; +} + +template<class KeyClass,class DataType,class UserDataType> +PLDHashOperator +nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumStub + (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) +{ + EntryType* ent = NS_STATIC_CAST(EntryType*, hdr); + s_EnumArgs* eargs = (s_EnumArgs*) arg; + + return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); +} + + +// +// nsBaseHashtableMT definitions +// + +template<class KeyClass,class DataType,class UserDataType> +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::~nsBaseHashtableMT() +{ + if (this->mLock) + PR_DestroyLock(this->mLock); +} + +template<class KeyClass,class DataType,class UserDataType> +PRBool +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Init(PRUint32 initSize) +{ + if (!nsTHashtable<EntryType>::IsInitialized() && !nsTHashtable<EntryType>::Init(initSize)) + return PR_FALSE; + + this->mLock = PR_NewLock(); + NS_WARN_IF_FALSE(this->mLock, "Error creating lock during nsBaseHashtableL::Init()"); + + return (this->mLock != nsnull); +} + +template<class KeyClass,class DataType,class UserDataType> +PRUint32 +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Count() const +{ + PR_Lock(this->mLock); + PRUint32 count = nsTHashtable<EntryType>::Count(); + PR_Unlock(this->mLock); + + return count; +} + +template<class KeyClass,class DataType,class UserDataType> +PRBool +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Get(KeyType aKey, + UserDataType* pData) const +{ + PR_Lock(this->mLock); + PRBool res = + nsBaseHashtable<KeyClass,DataType,UserDataType>::Get(aKey, pData); + PR_Unlock(this->mLock); + + return res; +} + +template<class KeyClass,class DataType,class UserDataType> +PRBool +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Put(KeyType aKey, + UserDataType aData) +{ + PR_Lock(this->mLock); + PRBool res = + nsBaseHashtable<KeyClass,DataType,UserDataType>::Put(aKey, aData); + PR_Unlock(this->mLock); + + return res; +} + +template<class KeyClass,class DataType,class UserDataType> +void +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Remove(KeyType aKey) +{ + PR_Lock(this->mLock); + nsBaseHashtable<KeyClass,DataType,UserDataType>::Remove(aKey); + PR_Unlock(this->mLock); +} + +template<class KeyClass,class DataType,class UserDataType> +PRUint32 +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::EnumerateRead + (EnumReadFunction fEnumCall, void* userArg) const +{ + PR_Lock(this->mLock); + PRUint32 count = + nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumerateRead(fEnumCall, userArg); + PR_Unlock(this->mLock); + + return count; +} + +template<class KeyClass,class DataType,class UserDataType> +PRUint32 +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Enumerate + (EnumFunction fEnumCall, void* userArg) +{ + PR_Lock(this->mLock); + PRUint32 count = + nsBaseHashtable<KeyClass,DataType,UserDataType>::Enumerate(fEnumCall, userArg); + PR_Unlock(this->mLock); + + return count; +} + +template<class KeyClass,class DataType,class UserDataType> +void +nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Clear() +{ + PR_Lock(this->mLock); + nsBaseHashtable<KeyClass,DataType,UserDataType>::Clear(); + PR_Unlock(this->mLock); +} + +#endif // nsBaseHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp new file mode 100644 index 00000000..a51ff9d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf <pp@ludusdesign.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsByteBuffer.h" +#include "nsIInputStream.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +ByteBufferImpl::ByteBufferImpl(void) + : mBuffer(NULL), mSpace(0), mLength(0) +{ +} + +NS_IMETHODIMP +ByteBufferImpl::Init(PRUint32 aBufferSize) +{ + if (aBufferSize < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mLength = 0; + mBuffer = new char[aBufferSize]; + return mBuffer ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_ISUPPORTS1(ByteBufferImpl,nsIByteBuffer) + +ByteBufferImpl::~ByteBufferImpl() +{ + if (nsnull != mBuffer) { + delete[] mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +NS_METHOD +ByteBufferImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + ByteBufferImpl* it = new ByteBufferImpl(); + if (nsnull == it) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(it); + nsresult rv = it->QueryInterface(aIID, (void**)aResult); + NS_RELEASE(it); + return rv; +} + +NS_IMETHODIMP_(PRUint32) +ByteBufferImpl::GetLength(void) const +{ + return mLength; +} + +NS_IMETHODIMP_(PRUint32) +ByteBufferImpl::GetBufferSize(void) const +{ + return mSpace; +} + +NS_IMETHODIMP_(char*) +ByteBufferImpl::GetBuffer(void) const +{ + return mBuffer; +} + +NS_IMETHODIMP_(PRBool) +ByteBufferImpl::Grow(PRUint32 aNewSize) +{ + if (aNewSize < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + char* newbuf = new char[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + memcpy(newbuf, mBuffer, mLength); + } + delete[] mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRInt32) +ByteBufferImpl::Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep) +{ + NS_PRECONDITION(nsnull != aStream, "null stream"); + NS_PRECONDITION(aKeep <= mLength, "illegal keep count"); + if ((nsnull == aStream) || (PRUint32(aKeep) > PRUint32(mLength))) { + // whoops + *aErrorCode = NS_BASE_STREAM_ILLEGAL_ARGS; + return -1; + } + + if (0 != aKeep) { + // Slide over kept data + memmove(mBuffer, mBuffer + (mLength - aKeep), aKeep); + } + + // Read in some new data + mLength = aKeep; + PRUint32 nb; + *aErrorCode = aStream->Read(mBuffer + aKeep, mSpace - aKeep, &nb); + if (NS_SUCCEEDED(*aErrorCode)) { + mLength += nb; + } + else + nb = 0; + return nb; +} + +NS_COM nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize) +{ + nsresult rv; + nsIByteBuffer* buf; + rv = ByteBufferImpl::Create(aOuter, NS_GET_IID(nsIByteBuffer), (void**)&buf); + if (NS_FAILED(rv)) return rv; + + rv = buf->Init(aBufferSize); + if (NS_FAILED(rv)) { + NS_RELEASE(buf); + return rv; + } + *aInstancePtrResult = buf; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h new file mode 100644 index 00000000..0a474570 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsByteBuffer_h__ +#define nsByteBuffer_h__ + +#include "nsIByteBuffer.h" + +class ByteBufferImpl : public nsIByteBuffer { +public: + ByteBufferImpl(void); + + NS_DECL_ISUPPORTS + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_IMETHOD Init(PRUint32 aBufferSize); + NS_IMETHOD_(PRUint32) GetLength(void) const; + NS_IMETHOD_(PRUint32) GetBufferSize(void) const; + NS_IMETHOD_(char*) GetBuffer() const; + NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize); + NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep); + + char* mBuffer; + PRUint32 mSpace; + PRUint32 mLength; +private: + ~ByteBufferImpl(); +}; + +#endif // nsByteBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp new file mode 100644 index 00000000..9a270223 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a COM aware array class. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsCOMArray.h" +#include "nsCOMPtr.h" + +PR_STATIC_CALLBACK(PRBool) ReleaseObjects(void* aElement, void*); + +// implementations of non-trivial methods in nsCOMArray_base + +// copy constructor - we can't just memcpy here, because +// we have to make sure we own our own array buffer, and that each +// object gets another AddRef() +nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) +{ + // make sure we do only one allocation + mArray.SizeTo(aOther.Count()); + AppendObjects(aOther); +} + +nsCOMArray_base::~nsCOMArray_base() +{ + PRInt32 count = Count(), i; + for (i = 0; i < count; ++i) { + nsISupports* obj = ObjectAt(i); + NS_IF_RELEASE(obj); + } +} + +PRInt32 +nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { + NS_ENSURE_TRUE(aObject, -1); + nsCOMPtr<nsISupports> supports = do_QueryInterface(aObject); + NS_ENSURE_TRUE(supports, -1); + + PRInt32 i, count; + PRInt32 retval = -1; + count = mArray.Count(); + for (i = 0; i < count; ++i) { + nsCOMPtr<nsISupports> arrayItem = + do_QueryInterface(NS_REINTERPRET_CAST(nsISupports*,mArray.ElementAt(i))); + if (arrayItem == supports) { + retval = i; + break; + } + } + return retval; +} + +PRBool +nsCOMArray_base::InsertObjectAt(nsISupports* aObject, PRInt32 aIndex) { + PRBool result = mArray.InsertElementAt(aObject, aIndex); + if (result) + NS_IF_ADDREF(aObject); + return result; +} + +PRBool +nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, PRInt32 aIndex) { + PRBool result = mArray.InsertElementsAt(aObjects.mArray, aIndex); + if (result) { + // need to addref all these + PRInt32 count = aObjects.Count(); + for (PRInt32 i = 0; i < count; ++i) { + NS_IF_ADDREF(aObjects.ObjectAt(i)); + } + } + return result; +} + +PRBool +nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, PRInt32 aIndex) +{ + // its ok if oldObject is null here + nsISupports *oldObject = + NS_REINTERPRET_CAST(nsISupports*, mArray.SafeElementAt(aIndex)); + + PRBool result = mArray.ReplaceElementAt(aObject, aIndex); + + // ReplaceElementAt could fail, such as if the array grows + // so only release the existing object if the replacement succeeded + if (result) { + // Make sure to addref first, in case aObject == oldObject + NS_IF_ADDREF(aObject); + NS_IF_RELEASE(oldObject); + } + return result; +} + +PRBool +nsCOMArray_base::RemoveObject(nsISupports *aObject) +{ + PRBool result = mArray.RemoveElement(aObject); + if (result) + NS_IF_RELEASE(aObject); + return result; +} + +PRBool +nsCOMArray_base::RemoveObjectAt(PRInt32 aIndex) +{ + nsISupports* element = ObjectAt(aIndex); + if (element) { + PRBool result = mArray.RemoveElementAt(aIndex); + if (result) + NS_IF_RELEASE(element); + return result; + } + return PR_FALSE; +} + +// useful for destructors +PRBool +ReleaseObjects(void* aElement, void*) +{ + nsISupports* element = NS_STATIC_CAST(nsISupports*, aElement); + NS_IF_RELEASE(element); + return PR_TRUE; +} + +void +nsCOMArray_base::Clear() +{ + mArray.EnumerateForwards(ReleaseObjects, nsnull); + mArray.Clear(); +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h new file mode 100644 index 00000000..cbb728c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a COM aware array class. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsCOMArray_h__ +#define nsCOMArray_h__ + +#include "nsVoidArray.h" +#include "nsISupports.h" + +// See below for the definition of nsCOMArray<T> + +// a class that's nsISupports-specific, so that we can contain the +// work of this class in the XPCOM dll +class NS_COM nsCOMArray_base +{ + friend class nsArray; +protected: + nsCOMArray_base() {} + nsCOMArray_base(PRInt32 aCount) : mArray(aCount) {} + nsCOMArray_base(const nsCOMArray_base& other); + ~nsCOMArray_base(); + + PRInt32 IndexOf(nsISupports* aObject) const { + return mArray.IndexOf(aObject); + } + + PRInt32 IndexOfObject(nsISupports* aObject) const; + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) { + return mArray.EnumerateForwards(aFunc, aData); + } + + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) { + return mArray.EnumerateBackwards(aFunc, aData); + } + + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData) { + mArray.Sort(aFunc, aData); + } + + // any method which is not a direct forward to mArray should + // avoid inline bodies, so that the compiler doesn't inline them + // all over the place + void Clear(); + PRBool InsertObjectAt(nsISupports* aObject, PRInt32 aIndex); + PRBool InsertObjectsAt(const nsCOMArray_base& aObjects, PRInt32 aIndex); + PRBool ReplaceObjectAt(nsISupports* aObject, PRInt32 aIndex); + PRBool AppendObject(nsISupports *aObject) { + return InsertObjectAt(aObject, Count()); + } + PRBool AppendObjects(const nsCOMArray_base& aObjects) { + return InsertObjectsAt(aObjects, Count()); + } + PRBool RemoveObject(nsISupports *aObject); + PRBool RemoveObjectAt(PRInt32 aIndex); + +public: + // override nsVoidArray stuff so that they can be accessed by + // consumers of nsCOMArray + PRInt32 Count() const { + return mArray.Count(); + } + + nsISupports* ObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(nsISupports*, mArray.FastElementAt(aIndex)); + } + + nsISupports* SafeObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(nsISupports*, mArray.SafeElementAt(aIndex)); + } + + nsISupports* operator[](PRInt32 aIndex) const { + return ObjectAt(aIndex); + } + +private: + + // the actual storage + nsVoidArray mArray; + + // don't implement these, defaults will muck with refcounts! + nsCOMArray_base& operator=(const nsCOMArray_base& other); +}; + +// a non-XPCOM, refcounting array of XPCOM objects +// used as a member variable or stack variable - this object is NOT +// refcounted, but the objects that it holds are +// +// most of the read-only accessors like ObjectAt()/etc do NOT refcount +// on the way out. This means that you can do one of two things: +// +// * does an addref, but holds onto a reference +// nsCOMPtr<T> foo = array[i]; +// +// * avoids the refcount, but foo might go stale if array[i] is ever +// * modified/removed. Be careful not to NS_RELEASE(foo)! +// T* foo = array[i]; +// +// This array will accept null as an argument for any object, and will +// store null in the array, just like nsVoidArray. But that also means +// that methods like ObjectAt() may return null when referring to an +// existing, but null entry in the array. +template <class T> +class nsCOMArray : public nsCOMArray_base +{ + public: + nsCOMArray() {} + nsCOMArray(PRInt32 aCount) : nsCOMArray_base(aCount) {} + + // only to be used by trusted classes who are going to pass us the + // right type! + nsCOMArray(const nsCOMArray<T>& aOther) : nsCOMArray_base(aOther) { } + + ~nsCOMArray() {} + + // these do NOT refcount on the way out, for speed + T* ObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(T*,nsCOMArray_base::ObjectAt(aIndex)); + } + + // these do NOT refcount on the way out, for speed + T* SafeObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(T*,nsCOMArray_base::SafeObjectAt(aIndex)); + } + + // indexing operator for syntactic sugar + T* operator[](PRInt32 aIndex) const { + return ObjectAt(aIndex); + } + + // index of the element in question.. does NOT refcount + // note: this does not check COM object identity. Use + // IndexOfObject() for that purpose + PRInt32 IndexOf(T* aObject) const { + return nsCOMArray_base::IndexOf(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // index of the element in question.. be careful! + // this is much slower than IndexOf() because it uses + // QueryInterface to determine actual COM identity of the object + // if you need to do this frequently then consider enforcing + // COM object identity before adding/comparing elements + PRInt32 IndexOfObject(T* aObject) const { + return nsCOMArray_base::IndexOfObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // inserts aObject at aIndex, shifting the objects at aIndex and + // later to make space + PRBool InsertObjectAt(T* aObject, PRInt32 aIndex) { + return nsCOMArray_base::InsertObjectAt(NS_STATIC_CAST(nsISupports*, aObject), aIndex); + } + + // inserts the objects from aObject at aIndex, shifting the + // objects at aIndex and later to make space + PRBool InsertObjectsAt(const nsCOMArray<T>& aObjects, PRInt32 aIndex) { + return nsCOMArray_base::InsertObjectsAt(aObjects, aIndex); + } + + // replaces an existing element. Warning: if the array grows, + // the newly created entries will all be null + PRBool ReplaceObjectAt(T* aObject, PRInt32 aIndex) { + return nsCOMArray_base::ReplaceObjectAt(NS_STATIC_CAST(nsISupports*, aObject), aIndex); + } + + // override nsVoidArray stuff so that they can be accessed by + // other methods + + // elements in the array (including null elements!) + PRInt32 Count() const { + return nsCOMArray_base::Count(); + } + + // remove all elements in the array, and call NS_RELEASE on each one + void Clear() { + nsCOMArray_base::Clear(); + } + + // Enumerator callback function. Return PR_FALSE to stop + // Here's a more readable form: + // PRBool PR_CALLBACK enumerate(T* aElement, void* aData) + typedef PRBool (* PR_CALLBACK nsCOMArrayEnumFunc) + (T* aElement, void *aData); + + // enumerate through the array with a callback. + PRBool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) { + return nsCOMArray_base::EnumerateForwards(nsVoidArrayEnumFunc(aFunc), + aData); + } + + PRBool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) { + return nsCOMArray_base::EnumerateBackwards(nsVoidArrayEnumFunc(aFunc), + aData); + } + + typedef int (* PR_CALLBACK nsCOMArrayComparatorFunc) + (T* aElement1, T* aElement2, void* aData); + + void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) { + nsCOMArray_base::Sort(nsVoidArrayComparatorFunc(aFunc), aData); + } + + // append an object, growing the array as necessary + PRBool AppendObject(T *aObject) { + return nsCOMArray_base::AppendObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // append objects, growing the array as necessary + PRBool AppendObjects(const nsCOMArray<T>& aObjects) { + return nsCOMArray_base::AppendObjects(aObjects); + } + + // remove the first instance of the given object and shrink the + // array as necessary + // Warning: if you pass null here, it will remove the first null element + PRBool RemoveObject(T *aObject) { + return nsCOMArray_base::RemoveObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // remove an element at a specific position, shrinking the array + // as necessary + PRBool RemoveObjectAt(PRInt32 aIndex) { + return nsCOMArray_base::RemoveObjectAt(aIndex); + } + +private: + + // don't implement these! + nsCOMArray<T>& operator=(const nsCOMArray<T>& other); +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp new file mode 100644 index 00000000..23392f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp @@ -0,0 +1,534 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/** + * MODULE NOTES: + * @update gess7/30/98 + * + * Much as I hate to do it, we were using string compares wrong. + * Often, programmers call functions like strcmp(s1,s2), and pass + * one or more null strings. Rather than blow up on these, I've + * added quick checks to ensure that cases like this don't cause + * us to fail. + * + * In general, if you pass a null into any of these string compare + * routines, we simply return 0. + */ + + +#include "nsCRT.h" +#include "nsIServiceManager.h" + +// XXX Bug: These tables don't lowercase the upper 128 characters properly + +// This table maps uppercase characters to lower case characters; +// characters that are neither upper nor lower case are unaffected. +static const unsigned char kUpper2Lower[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + // upper band mapped to lower [A-Z] => [a-z] + 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const unsigned char kLower2Upper[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, + + // lower band mapped to upper [a-z] => [A-Z] + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + + 123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +//---------------------------------------------------------------------- + +char nsCRT::ToUpper(char aChar) +{ + return (char)kLower2Upper[(unsigned char)aChar]; +} + +char nsCRT::ToLower(char aChar) +{ + return (char)kUpper2Lower[(unsigned char)aChar]; +} + +PRBool nsCRT::IsUpper(char aChar) +{ + return aChar != nsCRT::ToLower(aChar); +} + +PRBool nsCRT::IsLower(char aChar) +{ + return aChar != nsCRT::ToUpper(aChar); +} + +//////////////////////////////////////////////////////////////////////////////// +// My lovely strtok routine + +#define IS_DELIM(m, c) ((m)[(c) >> 3] & (1 << ((c) & 7))) +#define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7))) +#define DELIM_TABLE_SIZE 32 + +char* nsCRT::strtok(char* string, const char* delims, char* *newStr) +{ + NS_ASSERTION(string, "Unlike regular strtok, the first argument cannot be null."); + + char delimTable[DELIM_TABLE_SIZE]; + PRUint32 i; + char* result; + char* str = string; + + for (i = 0; i < DELIM_TABLE_SIZE; i++) + delimTable[i] = '\0'; + + for (i = 0; delims[i]; i++) { + SET_DELIM(delimTable, NS_STATIC_CAST(PRUint8, delims[i])); + } + NS_ASSERTION(delims[i] == '\0', "too many delimiters"); + + // skip to beginning + while (*str && IS_DELIM(delimTable, NS_STATIC_CAST(PRUint8, *str))) { + str++; + } + result = str; + + // fix up the end of the token + while (*str) { + if (IS_DELIM(delimTable, NS_STATIC_CAST(PRUint8, *str))) { + *str++ = '\0'; + break; + } + str++; + } + *newStr = str; + + return str == result ? NULL : result; +} + +//////////////////////////////////////////////////////////////////////////////// + +PRUint32 nsCRT::strlen(const PRUnichar* s) +{ + PRUint32 len = 0; + if(s) { + while (*s++ != 0) { + len++; + } + } + return len; +} + + +/** + * Compare unichar string ptrs, stopping at the 1st null + * NOTE: If both are null, we return 0. + * NOTE: We terminate the search upon encountering a NULL + * + * @update gess 11/10/99 + * @param s1 and s2 both point to unichar strings + * @return 0 if they match, -1 if s1<s2; 1 if s1>s2 + */ +PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2) { + if(s1 && s2) { + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if ((0==c1) || (0==c2)) break; + } + } + else { + if (s1) // s2 must have been null + return -1; + if (s2) // s1 must have been null + return 1; + } + return 0; +} + +/** + * Compare unichar string ptrs, stopping at the 1st null or nth char. + * NOTE: If either is null, we return 0. + * NOTE: We DO NOT terminate the search upon encountering NULL's before N + * + * @update gess 11/10/99 + * @param s1 and s2 both point to unichar strings + * @return 0 if they match, -1 if s1<s2; 1 if s1>s2 + */ +PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRUint32 n) { + if(s1 && s2) { + if(n != 0) { + do { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } while (--n != 0); + } + } + return 0; +} + +PRUnichar* nsCRT::strdup(const PRUnichar* str) +{ + PRUint32 len = nsCRT::strlen(str); + return strndup(str, len); +} + +PRUnichar* nsCRT::strndup(const PRUnichar* str, PRUint32 len) +{ + nsCppSharedAllocator<PRUnichar> shared_allocator; + PRUnichar* rslt = shared_allocator.allocate(len + 1); // add one for the null + // PRUnichar* rslt = new PRUnichar[len + 1]; + + if (rslt == NULL) return NULL; + memcpy(rslt, str, len * sizeof(PRUnichar)); + rslt[len] = 0; + return rslt; +} + + /** + * |nsCRT::HashCode| is identical to |PL_HashString|, which tests + * (http://bugzilla.mozilla.org/showattachment.cgi?attach_id=26596) + * show to be the best hash among several other choices. + * + * We re-implement it here rather than calling it for two reasons: + * (1) in this interface, we also calculate the length of the + * string being hashed; and (2) the narrow and wide and `buffer' versions here + * will hash equivalent strings to the same value, e.g., "Hello" and L"Hello". + */ +PRUint32 nsCRT::HashCode(const char* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const char* s = str; + + if (!str) return h; + + unsigned char c; + while ( (c = *s++) ) + h = (h>>28) ^ (h<<4) ^ c; + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::HashCode(const PRUnichar* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const PRUnichar* s = str; + + if (!str) return h; + + PRUnichar c; + while ( (c = *s++) ) + h = (h>>28) ^ (h<<4) ^ c; + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::HashCodeAsUTF8(const PRUnichar* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const PRUnichar* s = str; + + { + PRUint16 W1 = 0; // the first UTF-16 word in a two word tuple + PRUint32 U = 0; // the current char as UCS-4 + int code_length = 0; // the number of bytes in the UTF-8 sequence for the current char + + PRUint16 W; + while ( (W = *s++) ) + { + /* + * On the fly, decoding from UTF-16 (and/or UCS-2) into UTF-8 as per + * http://www.ietf.org/rfc/rfc2781.txt + * http://www.ietf.org/rfc/rfc2279.txt + */ + + if ( !W1 ) + { + if ( W < 0xD800 || 0xDFFF < W ) + { + U = W; + if ( W <= 0x007F ) + code_length = 1; + else if ( W <= 0x07FF ) + code_length = 2; + else + code_length = 3; + } + else if ( /* 0xD800 <= W1 && */ W <= 0xDBFF ) + W1 = W; + } + else + { + // as required by the standard, this code is careful to + // throw out illegal sequences + + if ( 0xDC00 <= W && W <= 0xDFFF ) + { + U = PRUint32( (W1&0x03FF)<<10 | (W&0x3FFF) ); + if ( U <= 0x001FFFFF ) + code_length = 4; + else if ( U <= 0x3FFFFFF ) + code_length = 5; + else + code_length = 6; + } + W1 = 0; + } + + + if ( code_length > 0 ) + { + static const PRUint16 sBytePrefix[7] = { 0x0000, 0x0000, 0x00C0, 0x00E0, 0x00F0, 0x00F8, 0x00FC }; + static const PRUint16 sShift[7] = { 0, 0, 6, 12, 18, 24, 30 }; + + /* + * Unlike the algorithm in http://www.ietf.org/rfc/rfc2279.txt + * we must calculate the bytes in left to right order so that + * our hash result matches what the narrow version would calculate + * on an already UTF-8 string. + */ + + // hash the first (and often, only, byte) + h = (h>>28) ^ (h<<4) ^ (sBytePrefix[code_length] | (U>>sShift[code_length])); + + // an unrolled loop for hashing any remaining bytes in this sequence + switch ( code_length ) + { // falling through in each case + case 6: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>24) & 0x003F)); + case 5: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>18) & 0x003F)); + case 4: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>12) & 0x003F)); + case 3: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>6 ) & 0x003F)); + case 2: h = (h>>28) ^ (h<<4) ^ (0x80 | ( U & 0x003F)); + default: code_length = 0; + break; + } + } + } + } + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::BufferHashCode(const char* s, PRUint32 len) +{ + PRUint32 h = 0; + const char* done = s + len; + + while ( s < done ) + h = (h>>28) ^ (h<<4) ^ PRUint8(*s++); // cast to unsigned to prevent possible sign extension + + return h; +} + +PRUint32 nsCRT::BufferHashCode(const PRUnichar* s, PRUint32 len) +{ + PRUint32 h = 0; + const PRUnichar* done = s + len; + + while ( s < done ) + h = (h>>28) ^ (h<<4) ^ PRUint16(*s++); // cast to unsigned to prevent possible sign extension + + return h; +} + +// This should use NSPR but NSPR isn't exporting its PR_strtoll function +// Until then... +PRInt64 nsCRT::atoll(const char *str) +{ + if (!str) + return LL_Zero(); + + PRInt64 ll = LL_Zero(), digitll = LL_Zero(); + + while (*str && *str >= '0' && *str <= '9') { + LL_MUL(ll, ll, 10); + LL_UI2L(digitll, (*str - '0')); + LL_ADD(ll, ll, digitll); + str++; + } + + return ll; +} + +/** + * Determine if given char in valid ascii range + * + * @update ftang 04.27.2000 + * @param aChar is character to be tested + * @return TRUE if in ASCII range + */ +PRBool nsCRT::IsAscii(PRUnichar aChar) { + return (0x0080 > aChar); +} +/** + * Determine if given char in valid ascii range + * + * @update ftang 10.02.2001 + * @param aString is null terminated to be tested + * @return TRUE if all characters aare in ASCII range + */ +PRBool nsCRT::IsAscii(const PRUnichar *aString) { + while(*aString) { + if( 0x0080 <= *aString) + return PR_FALSE; + aString++; + } + return PR_TRUE; +} +/** + * Determine if given char in valid ascii range + * + * @update ftang 10.02.2001 + * @param aString is null terminated to be tested + * @return TRUE if all characters aare in ASCII range + */ +PRBool nsCRT::IsAscii(const char *aString) { + while(*aString) { + if( 0x80 & *aString) + return PR_FALSE; + aString++; + } + return PR_TRUE; +} +/** + * Determine whether the given string consists of valid ascii chars + * + * @param aString is null terminated + * @param aLength is the number of chars to test. This must be at most + * the number of chars in aString before the null terminator + * @return PR_TRUE if all chars are valid ASCII chars, PR_FALSE otherwise + */ +PRBool nsCRT::IsAscii(const char* aString, PRUint32 aLength) +{ + const char* end = aString + aLength; + while (aString < end) { + NS_ASSERTION(*aString, "Null byte before end of data!"); + if (0x80 & *aString) + return PR_FALSE; + ++aString; + } + return PR_TRUE; +} + +/** + * Determine if given char in valid alpha range + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if in alpha range + */ +PRBool nsCRT::IsAsciiAlpha(PRUnichar aChar) { + // XXX i18n + if (((aChar >= 'A') && (aChar <= 'Z')) || ((aChar >= 'a') && (aChar <= 'z'))) { + return PR_TRUE; + } + return PR_FALSE; +} + +/** + * Determine if given char is a valid space character + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if is valid space char + */ +PRBool nsCRT::IsAsciiSpace(PRUnichar aChar) { + // XXX i18n + if ((aChar == ' ') || (aChar == '\r') || (aChar == '\n') || (aChar == '\t')) { + return PR_TRUE; + } + return PR_FALSE; +} + + + +/** + * Determine if given char is valid digit + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if char is a valid digit + */ +PRBool nsCRT::IsAsciiDigit(PRUnichar aChar) { + // XXX i18n + return PRBool((aChar >= '0') && (aChar <= '9')); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCRT.h b/src/libs/xpcom18a4/xpcom/ds/nsCRT.h new file mode 100644 index 00000000..c168a0a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCRT.h @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsCRT_h___ +#define nsCRT_h___ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "plstr.h" +#include "nscore.h" +#include "prtypes.h" +#include "nsCppSharedAllocator.h" + +#ifdef XP_MAC +# define NS_LINEBREAK "\015" +# define NS_LINEBREAK_LEN 1 +#else +# if defined(XP_WIN) || defined(XP_OS2) +# define NS_LINEBREAK "\015\012" +# define NS_LINEBREAK_LEN 2 +# else +# if defined(XP_UNIX) || defined(XP_BEOS) +# define NS_LINEBREAK "\012" +# define NS_LINEBREAK_LEN 1 +# endif /* XP_UNIX */ +# endif /* XP_WIN || XP_OS2 */ +#endif /* XP_MAC */ + +extern const PRUnichar kIsoLatin1ToUCS2[256]; + +// This macro can be used in a class declaration for classes that want +// to ensure that their instance memory is zeroed. +#define NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW \ + void* operator new(size_t sz) CPP_THROW_NEW { \ + void* rv = ::operator new(sz); \ + if (rv) { \ + memset(rv, 0, sz); \ + } \ + return rv; \ + } \ + void operator delete(void* ptr) { \ + ::operator delete(ptr); \ + } + +// This macro works with the next macro to declare a non-inlined +// version of the above. +#define NS_DECL_ZEROING_OPERATOR_NEW \ + void* operator new(size_t sz) CPP_THROW_NEW; \ + void operator delete(void* ptr); + +#define NS_IMPL_ZEROING_OPERATOR_NEW(_class) \ + void* _class::operator new(size_t sz) CPP_THROW_NEW { \ + void* rv = ::operator new(sz); \ + if (rv) { \ + memset(rv, 0, sz); \ + } \ + return rv; \ + } \ + void _class::operator delete(void* ptr) { \ + ::operator delete(ptr); \ + } + +// Freeing helper +#define CRTFREEIF(x) if (x) { nsCRT::free(x); x = 0; } + +/// This is a wrapper class around all the C runtime functions. + +class NS_COM nsCRT { +public: + enum { + TAB='\t' /* Horizontal Tab */, + LF='\n' /* Line Feed */, + VTAB='\v' /* Vertical Tab */, + FF='\f' /* Form Feed */, + CR='\r' /* Carriage Return */ + }; + + /*** + *** The following nsCRT::mem* functions are no longer + *** supported, please use the corresponding lib C + *** functions instead. + *** + *** nsCRT::memcpy() + *** nsCRT::memcmp() + *** nsCRT::memmove() + *** nsCRT::memset() + *** nsCRT::zero() + *** + *** Additionally, the following char* string utilities + *** are no longer supported, please use the + *** corresponding lib C functions instead. + *** + *** nsCRT::strlen() + *** + ***/ + + /** Compute the string length of s + @param s the string in question + @return the length of s + */ + static PRUint32 strlen(const char* s) { + return PRUint32(::strlen(s)); + } + + /// Compare s1 and s2. + static PRInt32 strcmp(const char* s1, const char* s2) { + return PRInt32(PL_strcmp(s1, s2)); + } + + static PRInt32 strncmp(const char* s1, const char* s2, + PRUint32 aMaxLen) { + return PRInt32(PL_strncmp(s1, s2, aMaxLen)); + } + + /// Case-insensitive string comparison. + static PRInt32 strcasecmp(const char* s1, const char* s2) { + return PRInt32(PL_strcasecmp(s1, s2)); + } + + /// Case-insensitive string comparison with length + static PRInt32 strncasecmp(const char* s1, const char* s2, PRUint32 aMaxLen) { + PRInt32 result=PRInt32(PL_strncasecmp(s1, s2, aMaxLen)); + //Egads. PL_strncasecmp is returning *very* negative numbers. + //Some folks expect -1,0,1, so let's temper its enthusiasm. + if (result<0) + result=-1; + return result; + } + + static PRInt32 strncmp(const char* s1, const char* s2, PRInt32 aMaxLen) { + // inline the first test (assumes strings are not null): + PRInt32 diff = ((const unsigned char*)s1)[0] - ((const unsigned char*)s2)[0]; + if (diff != 0) return diff; + return PRInt32(PL_strncmp(s1,s2,unsigned(aMaxLen))); + } + + static char* strdup(const char* str) { + return PL_strdup(str); + } + + static char* strndup(const char* str, PRUint32 len) { + return PL_strndup(str, len); + } + + static void free(char* str) { + PL_strfree(str); + } + + /** + + How to use this fancy (thread-safe) version of strtok: + + void main(void) { + printf("%s\n\nTokens:\n", string); + // Establish string and get the first token: + char* newStr; + token = nsCRT::strtok(string, seps, &newStr); + while (token != NULL) { + // While there are tokens in "string" + printf(" %s\n", token); + // Get next token: + token = nsCRT::strtok(newStr, seps, &newStr); + } + } + * WARNING - STRTOK WHACKS str THE FIRST TIME IT IS CALLED * + * MAKE A COPY OF str IF YOU NEED TO USE IT AFTER strtok() * + */ + static char* strtok(char* str, const char* delims, char* *newStr); + + /// Like strlen except for ucs2 strings + static PRUint32 strlen(const PRUnichar* s); + + /// Like strcmp except for ucs2 strings + static PRInt32 strcmp(const PRUnichar* s1, const PRUnichar* s2); + /// Like strcmp except for ucs2 strings + static PRInt32 strncmp(const PRUnichar* s1, const PRUnichar* s2, + PRUint32 aMaxLen); + + // You must use nsCRT::free(PRUnichar*) to free memory allocated + // by nsCRT::strdup(PRUnichar*). + static PRUnichar* strdup(const PRUnichar* str); + + // You must use nsCRT::free(PRUnichar*) to free memory allocated + // by strndup(PRUnichar*, PRUint32). + static PRUnichar* strndup(const PRUnichar* str, PRUint32 len); + + static void free(PRUnichar* str) { + nsCppSharedAllocator<PRUnichar> shared_allocator; + shared_allocator.deallocate(str, 0 /*we never new or kept the size*/); + } + + // Computes the hashcode for a c-string, returns the string length as + // an added bonus. + static PRUint32 HashCode(const char* str, + PRUint32* resultingStrLen = nsnull); + + // Computes the hashcode for a ucs2 string, returns the string length + // as an added bonus. + static PRUint32 HashCode(const PRUnichar* str, + PRUint32* resultingStrLen = nsnull); + + // Computes a hashcode for a ucs2 string that returns the same thing + // as the HashCode method taking a |char*| would if the string were + // converted to UTF8. Returns the string length as an added bonus. + static PRUint32 HashCodeAsUTF8(const PRUnichar* str, + PRUint32* resultingStrLen = nsnull); + + // Computes the hashcode for a buffer with a specified length. + static PRUint32 BufferHashCode(const char* str, PRUint32 strLen); + + // Computes the hashcode for a buffer with a specified length. + static PRUint32 BufferHashCode(const PRUnichar* str, PRUint32 strLen); + + // String to longlong + static PRInt64 atoll(const char *str); + + static char ToUpper(char aChar); + + static char ToLower(char aChar); + + static PRBool IsUpper(char aChar); + + static PRBool IsLower(char aChar); + + static PRBool IsAscii(PRUnichar aChar); + static PRBool IsAscii(const PRUnichar* aString); + static PRBool IsAsciiAlpha(PRUnichar aChar); + static PRBool IsAsciiDigit(PRUnichar aChar); + static PRBool IsAsciiSpace(PRUnichar aChar); + static PRBool IsAscii(const char* aString); + static PRBool IsAscii(const char* aString, PRUint32 aLength); +}; + +#define FF '\014' +#define TAB '\011' + +#define CRSTR "\015" +#define LFSTR "\012" +#define CRLF "\015\012" /* A CR LF equivalent string */ + + +#if defined(XP_MAC) + #define FILE_PATH_SEPARATOR ":" + #define FILE_ILLEGAL_CHARACTERS "" +#elif defined(XP_WIN) || defined(XP_OS2) + #define FILE_PATH_SEPARATOR "\\" + #define FILE_ILLEGAL_CHARACTERS "/:*?\"<>|" +#elif defined(XP_UNIX) || defined(XP_BEOS) + #define FILE_PATH_SEPARATOR "/" + #define FILE_ILLEGAL_CHARACTERS "" +#else + #error need_to_define_your_file_path_separator_and_illegal_characters +#endif + +#define NS_IS_SPACE(VAL) \ + (((((intn)(VAL)) & 0x7f) == ((intn)(VAL))) && isspace((intn)(VAL)) ) + +#define NS_IS_CNTRL(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : iscntrl(i)) +#define NS_IS_DIGIT(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : isdigit(i)) +#if defined(XP_WIN) || defined(XP_OS2) +#define NS_IS_ALPHA(VAL) (isascii((int)(VAL)) && isalpha((int)(VAL))) +#else +#define NS_IS_ALPHA(VAL) ((((unsigned int) (VAL)) > 0x7f) ? (int) 0 : isalpha((int)(VAL))) +#endif + + +#endif /* nsCRT_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp new file mode 100644 index 00000000..954de2d1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsCheapSets.h" + +nsCheapStringSet::~nsCheapStringSet() +{ + nsStringHashSet* set = GetHash(); + if (set) { + delete set; + } else { + delete GetStr(); + } +} + +/** + * Put a string into the table + */ +nsresult +nsCheapStringSet::Put(const nsAString& aVal) +{ + // Add the value to the hash if it is there + nsStringHashSet* set = GetHash(); + if (set) { + return set->Put(aVal); + } + + // If a string is already there, create a hashtable and both of these to it + if (GetStr()) { + nsAString* oldStr = GetStr(); + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + rv = set->Put(*oldStr); + delete oldStr; + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Nothing exists in the hash right now, so just set the single string + return SetStr(aVal); +} + +void +nsCheapStringSet::Remove(const nsAString& aVal) +{ + // Remove from the hash if the hash is there + nsStringHashSet* set = GetHash(); + if (set) { + set->Remove(aVal); + return; + } + + // Remove the string if there is just a string + nsAString* str = GetStr(); + if (str && str->Equals(aVal)) { + delete str; + mValOrHash = nsnull; + } +} + +nsresult +nsCheapStringSet::InitHash(nsStringHashSet** aSet) +{ + nsStringHashSet* newSet = new nsStringHashSet(); + if (!newSet) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = newSet->Init(10); + NS_ENSURE_SUCCESS(rv, rv); + + mValOrHash = newSet; + *aSet = newSet; + return NS_OK; +} + + +nsCheapInt32Set::~nsCheapInt32Set() +{ + delete GetHash(); +} + +nsresult +nsCheapInt32Set::Put(PRInt32 aVal) +{ + // Add the value to the hash or set the pointer as an int + nsInt32HashSet* set = GetHash(); + if (set) { + return set->Put(aVal); + } + + // Create the hash and add the value to it if there is an int already + if (IsInt()) { + PRInt32 oldInt = GetInt(); + + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + rv = set->Put(oldInt); + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Create the hash anyway if the int is negative (negative numbers cannot + // fit into our PtrBits abstraction) + if (aVal < 0) { + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Finally, just set the int if we can't do anything with hashes + SetInt(aVal); + return NS_OK; +} + +void +nsCheapInt32Set::Remove(PRInt32 aVal) +{ + nsInt32HashSet* set = GetHash(); + if (set) { + set->Remove(aVal); + } else if (IsInt() && GetInt() == aVal) { + mValOrHash = nsnull; + } +} + +nsresult +nsCheapInt32Set::InitHash(nsInt32HashSet** aSet) +{ + nsInt32HashSet* newSet = new nsInt32HashSet(); + if (!newSet) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = newSet->Init(10); + NS_ENSURE_SUCCESS(rv, rv); + + mValOrHash = newSet; + *aSet = newSet; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h new file mode 100644 index 00000000..7e1c917d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nsCheapSets_h__ +#define __nsCheapSets_h__ + +#include "nsHashSets.h" + +/** + * A string set that takes up minimal size when there are 0 or 1 strings in the + * set. Use for cases where sizes of 0 and 1 are even slightly common. + */ +class NS_COM nsCheapStringSet { +public: + nsCheapStringSet() : mValOrHash(nsnull) + { + } + ~nsCheapStringSet(); + + /** + * Put a string into the set + * @param aVal the value to put in + */ + nsresult Put(const nsAString& aVal); + + /** + * Remove a string from the set + * @param aVal the string to remove + */ + void Remove(const nsAString& aVal); + + /** + * Check if the set contains a particular string + * @param aVal the string to check for + * @return whether the string is in the set + */ + PRBool Contains(const nsAString& aVal) + { + nsStringHashSet* set = GetHash(); + // Check the value from the hash if the hash is there + if (set) { + return set->Contains(aVal); + } + + // Check whether the value is equal to the string if the string is there + nsAString* str = GetStr(); + return str && str->Equals(aVal); + } + +private: + typedef PRUint64 PtrBits; + + /** Get the hash pointer (or null if we're not a hash) */ + nsStringHashSet* GetHash() + { + return (PtrBits(mValOrHash) & 0x1) ? nsnull : (nsStringHashSet*)mValOrHash; + } + /** Find out whether it is a string */ + nsAString* GetStr() + { + return (PtrBits(mValOrHash) & 0x1) + ? (nsAString*)(PtrBits(mValOrHash) & ~0x1) + : nsnull; + } + /** Set the single string */ + nsresult SetStr(const nsAString& aVal) + { + nsString* str = new nsString(aVal); + if (!str) { + return NS_ERROR_OUT_OF_MEMORY; + } + mValOrHash = (nsAString*)(PtrBits(str) | 0x1); + return NS_OK; + } + /** Initialize the hash */ + nsresult InitHash(nsStringHashSet** aSet); + +private: + /** A hash or string ptr, depending on the lower bit (0=hash, 1=string) */ + void* mValOrHash; +}; + + +/** + * An integer set that takes up only 4 bytes when there are 0 or 1 integers + * in the set. Use for cases where sizes of 0 and 1 are even slightly common. + */ +class NS_COM nsCheapInt32Set { +public: + nsCheapInt32Set() : mValOrHash(nsnull) + { + } + ~nsCheapInt32Set(); + + /** + * Put an int into the set + */ + nsresult Put(PRInt32 aVal); + + /** + * Remove a int from the set + * @param aVal the int to remove + */ + void Remove(PRInt32 aVal); + + /** + * Check if the set contains a particular int + * @param aVal the int to check for + * @return whether the int is in the set + */ + PRBool Contains(PRInt32 aVal) + { + nsInt32HashSet* set = GetHash(); + if (set) { + return set->Contains(aVal); + } + if (IsInt()) { + return GetInt() == aVal; + } + return PR_FALSE; + } + +private: + typedef PRUint64 PtrBits; + + /** Get the hash pointer (or null if we're not a hash) */ + nsInt32HashSet* GetHash() + { + return PtrBits(mValOrHash) & 0x1 ? nsnull : (nsInt32HashSet*)mValOrHash; + } + /** Find out whether it is an integer */ + PRBool IsInt() + { + return !!(PtrBits(mValOrHash) & 0x1); + } + /** Get the single integer */ + PRInt32 GetInt() + { + return PtrBits(mValOrHash) >> 1; + } + /** Set the single integer */ + void SetInt(PRInt32 aInt) + { + mValOrHash = (void*)(uintptr_t)((aInt << 1) | 0x1); + } + /** Create the hash and initialize */ + nsresult InitHash(nsInt32HashSet** aSet); + +private: + /** A hash or int, depending on the lower bit (0=hash, 1=int) */ + void* mValOrHash; +}; + + +/** + * XXX We may want an nsCheapVoidSet and nsCheapCStringSet at some point + */ + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h new file mode 100644 index 00000000..1fd73489 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsClassHashtable_h__ +#define nsClassHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsAutoPtr.h" + +/** + * templated hashtable class maps keys to C++ object pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Class the class-type being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template<class KeyClass,class T> +class nsClassHashtable : + public nsBaseHashtable< KeyClass, nsAutoPtr<T>, T* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef T* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData if the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; +}; + + +/** + * Thread-safe version of nsClassHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Class the class-type being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template<class KeyClass,class T> +class nsClassHashtableMT : + public nsBaseHashtableMT< KeyClass, nsAutoPtr<T>, T* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef T* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData if the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; +}; + + +// +// nsClassHashtable definitions +// + +template<class KeyClass,class T> +PRBool +nsClassHashtable<KeyClass,T>::Get(KeyType aKey, T** retVal) const +{ + typename nsBaseHashtable<KeyClass,nsAutoPtr<T>,T*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (retVal) + *retVal = ent->mData; + + return PR_TRUE; + } + + if (retVal) + *retVal = nsnull; + + return PR_FALSE; +} + + +// +// nsClassHashtableMT definitions +// + +template<class KeyClass,class T> +PRBool +nsClassHashtableMT<KeyClass,T>::Get(KeyType aKey, T** retVal) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT<KeyClass,nsAutoPtr<T>,T*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (retVal) + *retVal = ent->mData; + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + if (retVal) + *retVal = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsClassHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h new file mode 100644 index 00000000..55f3e19d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h @@ -0,0 +1,127 @@ +#ifndef nsCppSharedAllocator_h__ +#define nsCppSharedAllocator_h__ + +#include "nsMemory.h" // for |nsMemory| +#include "nscore.h" // for |NS_XXX_CAST| +#include NEW_H // to allow placement |new| + + + // under Metrowerks (Mac), we don't have autoconf yet +#ifdef __MWERKS__ + #define HAVE_CPP_MEMBER_TEMPLATES + #define HAVE_CPP_NUMERIC_LIMITS +#endif + + // under MSVC shut off copious warnings about unused in-lines +#ifdef _MSC_VER + #pragma warning( disable: 4514 ) +#endif + +#ifdef HAVE_CPP_NUMERIC_LIMITS +#include <limits> +#else +#include <limits.h> +#endif + + +template <class T> +class nsCppSharedAllocator + /* + ...allows Standard Library containers, et al, to use our global shared + (XP)COM-aware allocator. + */ + { + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T* pointer; + typedef const T* const_pointer; + + typedef T& reference; + typedef const T& const_reference; + + + + nsCppSharedAllocator() { } + +#ifdef HAVE_CPP_MEMBER_TEMPLATES + template <class U> + nsCppSharedAllocator( const nsCppSharedAllocator<U>& ) { } +#endif + + ~nsCppSharedAllocator() { } + + + pointer + address( reference r ) const + { + return &r; + } + + const_pointer + address( const_reference r ) const + { + return &r; + } + + pointer + allocate( size_type n, const void* /*hint*/=0 ) + { + return NS_REINTERPRET_CAST(pointer, nsMemory::Alloc(NS_STATIC_CAST(PRUint32, n*sizeof(T)))); + } + + void + deallocate( pointer p, size_type /*n*/ ) + { + nsMemory::Free(p); + } + + void + construct( pointer p, const T& val ) + { + new (p) T(val); + } + + void + destroy( pointer p ) + { + p->~T(); + } + + size_type + max_size() const + { +#ifdef HAVE_CPP_NUMERIC_LIMITS + return numeric_limits<size_type>::max() / sizeof(T); +#else + return ULONG_MAX / sizeof(T); +#endif + } + +#ifdef HAVE_CPP_MEMBER_TEMPLATES + template <class U> + struct rebind + { + typedef nsCppSharedAllocator<U> other; + }; +#endif + }; + + +template <class T> +PRBool +operator==( const nsCppSharedAllocator<T>&, const nsCppSharedAllocator<T>& ) + { + return PR_TRUE; + } + +template <class T> +PRBool +operator!=( const nsCppSharedAllocator<T>&, const nsCppSharedAllocator<T>& ) + { + return PR_FALSE; + } + +#endif /* !defined(nsCppSharedAllocator_h__) */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h new file mode 100644 index 00000000..7a14f826 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsDataHashtable_h__ +#define nsDataHashtable_h__ + +#include "nsHashKeys.h" +#include "nsBaseHashtable.h" + +/** + * templated hashtable class maps keys to simple datatypes. + * See nsBaseHashtable for complete declaration + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param DataType the simple datatype being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template<class KeyClass,class DataType> +class nsDataHashtable : + public nsBaseHashtable<KeyClass,DataType,DataType> +{ }; + +template<class KeyClass,class DataType> +class nsDataHashtableMT : + public nsBaseHashtableMT<KeyClass,DataType,DataType> +{ }; + +#endif // nsDataHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp b/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp new file mode 100644 index 00000000..d94568bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp @@ -0,0 +1,627 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsDeque.h" +#include "nsCRT.h" +#ifdef DEBUG_rickg +#include <stdio.h> +#endif + +/** + * 07/02/2001 09:17p 509,104 clangref.pdf from openwatcom's site + * Watcom C Language Reference Edition 11.0c + * page 118 of 297 + * + * The % symbol yields the remainder from the division of the first operand + * by the second operand. The operands of % must have integral type. + * + * When both operands of % are positive, the result is a positive value + * smaller than the second operand. When one or both operands is negative, + * whether the result is positive or negative is implementation-defined. + * + */ +/* Ok, so first of all, C is underspecified. joy. + * The following functions do not provide a correct implementation of modulus + * They provide functionality for x>-y. + * There are risks of 2*y being greater than max int, which is part of the + * reason no multiplication is used and other operations are avoided. + * + * modasgn + * @param x variable + * @param y expression + * approximately equivalent to x %= y + * + * modulus + * @param x expression + * @param y expression + * approximately equivalent to x % y + */ +#define modasgn(x,y) if (x<0) x+=y; x%=y +#define modulus(x,y) ((x<0)?(x+y)%(y):(x)%(y)) + +MOZ_DECL_CTOR_COUNTER(nsDeque) + +/** + * Standard constructor + * @param deallocator, called by Erase and ~nsDeque + */ +nsDeque::nsDeque(nsDequeFunctor* aDeallocator) { + MOZ_COUNT_CTOR(nsDeque); + mDeallocator=aDeallocator; + mOrigin=mSize=0; + mData=mBuffer; // don't allocate space until you must + mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]); + memset(mData, 0, mCapacity*sizeof(mBuffer[0])); +} + +/** + * Destructor + */ +nsDeque::~nsDeque() { + MOZ_COUNT_DTOR(nsDeque); + +#ifdef DEBUG_rickg + char buffer[30]; + printf("Capacity: %i\n", mCapacity); + + static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + switch(mCapacity) { + case 4: mCaps[0]++; break; + case 8: mCaps[1]++; break; + case 16: mCaps[2]++; break; + case 32: mCaps[3]++; break; + case 64: mCaps[4]++; break; + case 128: mCaps[5]++; break; + case 256: mCaps[6]++; break; + case 512: mCaps[7]++; break; + case 1024: mCaps[8]++; break; + case 2048: mCaps[9]++; break; + case 4096: mCaps[10]++; break; + default: + break; + } +#endif + + Erase(); + if (mData && (mData!=mBuffer)) { + delete [] mData; + } + mData=0; + SetDeallocator(0); +} + +/** + * Set the functor to be called by Erase() + * The deque owns the functor. + * + * @param aDeallocator functor object for use by Erase() + */ +void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ + if (mDeallocator) { + delete mDeallocator; + } + mDeallocator=aDeallocator; +} + +/** + * Remove all items from container without destroying them. + * + * @return *this + */ +nsDeque& nsDeque::Empty() { + if (mSize && mData) { + memset(mData, 0, mCapacity*sizeof(*mData)); + } + mSize=0; + mOrigin=0; + return *this; +} + +/** + * Remove and delete all items from container + * + * @return *this + */ +nsDeque& nsDeque::Erase() { + if (mDeallocator && mSize) { + ForEach(*mDeallocator); + } + return Empty(); +} + +/** + * This method quadruples the size of the deque + * Elements in the deque are resequenced so that elements + * in the deque are stored sequentially + * + * If the deque actually overflows, there's very little we can do. + * Perhaps this function should return PRBool/nsresult indicating success/failure. + * + * @return capacity of the deque + * If the deque did not grow, + * and you knew its capacity beforehand, + * then this would be a way to indicate the failure. + */ +PRInt32 nsDeque::GrowCapacity() { + PRInt32 theNewSize=mCapacity<<2; + NS_ASSERTION(theNewSize>mCapacity, "Overflow"); + if (theNewSize<=mCapacity) + return mCapacity; + void** temp=new void*[theNewSize]; + + //Here's the interesting part: You can't just move the elements + //directly (in situ) from the old buffer to the new one. + //Since capacity has changed, the old origin doesn't make + //sense anymore. It's better to resequence the elements now. + + if (temp) { + PRInt32 tempi=0; + PRInt32 i=0; + PRInt32 j=0; + for (i=mOrigin; i<mCapacity; i++) { + temp[tempi++]=mData[i]; //copy the leading elements... + } + for (j=0;j<mOrigin;j++) { + temp[tempi++]=mData[j]; //copy the trailing elements... + } + if (mData != mBuffer) { + delete [] mData; + } + mCapacity=theNewSize; + mOrigin=0; //now realign the origin... + mData=temp; + } + return mCapacity; +} + +/** + * This method adds an item to the end of the deque. + * This operation has the potential to cause the + * underlying buffer to resize. + * + * @param aItem: new item to be added to deque + * @return *this + */ +nsDeque& nsDeque::Push(void* aItem) { + if (mSize==mCapacity) { + GrowCapacity(); + } + mData[modulus(mOrigin + mSize, mCapacity)]=aItem; + mSize++; + return *this; +} + +/** + * This method adds an item to the front of the deque. + * This operation has the potential to cause the + * underlying buffer to resize. + * + * --Commments for GrowCapacity() case + * We've grown and shifted which means that the old + * final element in the deque is now the first element + * in the deque. This is temporary. + * We haven't inserted the new element at the front. + * + * To continue with the idea of having the front at zero + * after a grow, we move the old final item (which through + * the voodoo of mOrigin-- is now the first) to its final + * position which is conveniently the old length. + * + * Note that this case only happens when the deque is full. + * [And that pieces of this magic only work if the deque is full.] + * picture: + * [ABCDEFGH] @[mOrigin:3]:D. + * Task: PushFront("Z") + * shift mOrigin so, @[mOrigin:2]:C + * stretch and rearrange: (mOrigin:0) + * [CDEFGHAB ________ ________ ________] + * copy: (The second C is currently out of bounds) + * [CDEFGHAB C_______ ________ ________] + * later we will insert Z: + * [ZDEFGHAB C_______ ________ ________] + * and increment size: 9. (C is no longer out of bounds) + * -- + * @param aItem: new item to be added to deque + * @return *this + */ +nsDeque& nsDeque::PushFront(void* aItem) { + mOrigin--; + modasgn(mOrigin,mCapacity); + if (mSize==mCapacity) { + GrowCapacity(); + /* Comments explaining this are above*/ + mData[mSize]=mData[mOrigin]; + } + mData[mOrigin]=aItem; + mSize++; + return *this; +} + +/** + * Remove and return the last item in the container. + * + * @return ptr to last item in container + */ +void* nsDeque::Pop() { + void* result=0; + if (mSize>0) { + --mSize; + PRInt32 offset=modulus(mSize + mOrigin, mCapacity); + result=mData[offset]; + mData[offset]=0; + if (!mSize) { + mOrigin=0; + } + } + return result; +} + +/** + * This method gets called you want to remove and return + * the first member in the container. + * + * @return last item in container + */ +void* nsDeque::PopFront() { + void* result=0; + if (mSize>0) { + NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin"); + result=mData[mOrigin]; + mData[mOrigin++]=0; //zero it out for debugging purposes. + mSize--; + // Cycle around if we pop off the end + // and reset origin if when we pop the last element + if (mCapacity==mOrigin || !mSize) { + mOrigin=0; + } + } + return result; +} + +/** + * This method gets called you want to peek at the bottom + * member without removing it. + * + * @return last item in container + */ +void* nsDeque::Peek() { + void* result=0; + if (mSize>0) { + result = mData[modulus(mSize - 1 + mOrigin, mCapacity)]; + } + return result; +} + +/** + * This method gets called you want to peek at the topmost + * member without removing it. + * + * @return last item in container + */ +void* nsDeque::PeekFront() { + void* result=0; + if (mSize>0) { + result=mData[mOrigin]; + } + return result; +} + +/** + * Call this to retrieve the ith element from this container. + * Keep in mind that accessing the underlying elements is + * done in a relative fashion. Object 0 is not necessarily + * the first element (the first element is at mOrigin). + * + * @param aIndex : 0 relative offset of item you want + * @return void* or null + */ +void* nsDeque::ObjectAt(PRInt32 aIndex) const { + void* result=0; + if ((aIndex>=0) && (aIndex<mSize)) { + result=mData[modulus(mOrigin + aIndex, mCapacity)]; + } + return result; +} + +/** + * Create and return an iterator pointing to + * the beginning of the queue. Note that this + * takes the circular buffer semantics into account. + * + * @return new deque iterator, init'ed to 1st item + */ +nsDequeIterator nsDeque::Begin() const{ + return nsDequeIterator(*this, 0); +} + +/** + * Create and return an iterator pointing to + * the last item in the deque. + * Note that this takes the circular buffer semantics + * into account. + * + * @return new deque iterator, init'ed to the last item + */ +nsDequeIterator nsDeque::End() const{ + return nsDequeIterator(*this, mSize - 1); +} + +void* nsDeque::Last() const { + return End().GetCurrent(); +} + +/** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ +void nsDeque::ForEach(nsDequeFunctor& aFunctor) const{ + for (PRInt32 i=0; i<mSize; i++) { + aFunctor(ObjectAt(i)); + } +} + +/** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ +const void* nsDeque::FirstThat(nsDequeFunctor& aFunctor) const{ + for (PRInt32 i=0; i<mSize; i++) { + void* obj=aFunctor(ObjectAt(i)); + if (obj) { + return obj; + } + } + return 0; +} + +/****************************************************** + * Here comes the nsDequeIterator class... + ******************************************************/ + +/** + * DequeIterator is an object that knows how to iterate (forward and backward) + * through a Deque. Normally, you don't need to do this, but there are some special + * cases where it is pretty handy, so here you go. + * + * This is a standard dequeiterator constructor + * + * @param aQueue is the deque object to be iterated + * @param aIndex is the starting position for your iteration + */ +nsDequeIterator::nsDequeIterator(const nsDeque& aQueue, int aIndex) +: mIndex(aIndex), + mDeque(aQueue) +{ +} + +/** + * Create a copy of a DequeIterator + * + * @param aCopy is another iterator to copy from + */ +nsDequeIterator::nsDequeIterator(const nsDequeIterator& aCopy) +: mIndex(aCopy.mIndex), + mDeque(aCopy.mDeque) +{ +} + +/** + * Moves iterator to first element in deque + * @return *this + */ +nsDequeIterator& nsDequeIterator::First(){ + mIndex=0; + return *this; +} + +/** + * Standard assignment operator for dequeiterator + * + * @param aCopy is an iterator to be copied from + * @return *this + */ +nsDequeIterator& nsDequeIterator::operator=(const nsDequeIterator& aCopy) { + NS_ASSERTION(&mDeque==&aCopy.mDeque,"you can't change the deque that an interator is iterating over, sorry."); + mIndex=aCopy.mIndex; + return *this; +} + +/** + * preform ! operation against to iterators to test for equivalence + * (or lack thereof)! + * + * @param aIter is the object to be compared to + * @return TRUE if NOT equal. + */ +PRBool nsDequeIterator::operator!=(nsDequeIterator& aIter) { + return PRBool(!this->operator==(aIter)); +} + +/** + * Compare two iterators for increasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to an element before + * the element pointed to by aIter. + * FALSE if this and aIter are not iterating over the same deque. + */ +PRBool nsDequeIterator::operator<(nsDequeIterator& aIter) { + return PRBool(((mIndex<aIter.mIndex) && (&mDeque==&aIter.mDeque))); +} + +/** + * Compare two iterators for equivalence. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if EQUAL + */ +PRBool nsDequeIterator::operator==(nsDequeIterator& aIter) { + return PRBool(((mIndex==aIter.mIndex) && (&mDeque==&aIter.mDeque))); +} + +/** + * Compare two iterators for non strict decreasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to the same element, or + * an element after the element pointed to by aIter. + * FALSE if this and aIter are not iterating over the same deque. + */ +PRBool nsDequeIterator::operator>=(nsDequeIterator& aIter) { + return PRBool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque))); +} + +/** + * Pre-increment operator + * + * @return object at post-incremented index + */ +void* nsDequeIterator::operator++() { + NS_ASSERTION(mIndex<mDeque.mSize, + "You have reached the end of the Internet."\ + "You have seen everything there is to see. Please go back. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>=mDeque.mSize) return 0; +#endif + return mDeque.ObjectAt(++mIndex); +} + +/** + * Post-increment operator + * + * @param param is ignored + * @return object at pre-incremented index + */ +void* nsDequeIterator::operator++(int) { + NS_ASSERTION(mIndex<=mDeque.mSize, + "You have already reached the end of the Internet."\ + "You have seen everything there is to see. Please go back. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>mDeque.mSize) return 0; +#endif + return mDeque.ObjectAt(mIndex++); +} + +/** + * Pre-decrement operator + * + * @return object at pre-decremented index + */ +void* nsDequeIterator::operator--() { + NS_ASSERTION(mIndex>=0, + "You have reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif + return mDeque.ObjectAt(--mIndex); +} + +/** + * Post-decrement operator + * + * @param param is ignored + * @return object at post-decremented index + */ +void* nsDequeIterator::operator--(int) { + NS_ASSERTION(mIndex>=0, + "You have already reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif + return mDeque.ObjectAt(mIndex--); +} + +/** + * Dereference operator + * Note that the iterator floats, so you don't need to do: + * <code>++iter; aDeque.PopFront();</code> + * Unless you actually want your iterator to jump 2 spaces. + * + * Picture: [1 2I 3 4] + * PopFront() + * Picture: [2 3I 4] + * Note that I still happily points to object at the second index + * + * @return object at ith index + */ +void* nsDequeIterator::GetCurrent() { + NS_ASSERTION(mIndex<mDeque.mSize&&mIndex>=0,"Current is out of bounds"); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>=mDeque.mSize||mIndex<0) return 0; +#endif + return mDeque.ObjectAt(mIndex); +} + +/** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ +void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{ + mDeque.ForEach(aFunctor); +} + +/** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ +const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{ + return mDeque.FirstThat(aFunctor); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDeque.h b/src/libs/xpcom18a4/xpcom/ds/nsDeque.h new file mode 100644 index 00000000..7fdf7465 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDeque.h @@ -0,0 +1,405 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * MODULE NOTES: + * + * The Deque is a very small, very efficient container object + * than can hold elements of type void*, offering the following features: + * Its interface supports pushing and popping of elements. + * It can iterate (via an interator class) its elements. + * When full, it can efficiently resize dynamically. + * + * + * NOTE: The only bit of trickery here is that this deque is + * built upon a ring-buffer. Like all ring buffers, the first + * element may not be at index[0]. The mOrigin member determines + * where the first child is. This point is quietly hidden from + * customers of this class. + * + */ + +#ifndef _NSDEQUE +#define _NSDEQUE + +#include "nscore.h" + +/** + * The nsDequeFunctor class is used when you want to create + * callbacks between the deque and your generic code. + * Use these objects in a call to ForEach(); + * + */ + +class nsDequeFunctor{ +public: + virtual void* operator()(void* anObject)=0; +}; + +/****************************************************** + * Here comes the nsDeque class itself... + ******************************************************/ + +/** + * The deque (double-ended queue) class is a common container type, + * whose behavior mimics a line in your favorite checkout stand. + * Classic CS describes the common behavior of a queue as FIFO. + * A deque allows insertion and removal at both ends of + * the container. + * + * The deque stores pointers to items. + */ + +class nsDequeIterator; + +class NS_COM nsDeque { + friend class nsDequeIterator; + public: + nsDeque(nsDequeFunctor* aDeallocator); + ~nsDeque(); + + /** + * Returns the number of elements currently stored in + * this deque. + * + * @return number of elements currently in the deque + */ + inline PRInt32 GetSize() const {return mSize;} + + /** + * Appends new member at the end of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& Push(void* aItem); + + /** + * Inserts new member at the front of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& PushFront(void* aItem); + + /** + * Remove and return the last item in the container. + * + * @return the item that was the last item in container + */ + void* Pop(); + + /** + * Remove and return the first item in the container. + * + * @return the item that was first item in container + */ + void* PopFront(); + + /** + * Retrieve the bottom item without removing it. + * + * @return the first item in container + */ + + void* Peek(); + /** + * Return topmost item without removing it. + * + * @return the first item in container + */ + void* PeekFront(); + + /** + * Retrieve the i'th member from the deque without removing it. + * + * @param index of desired item + * @return i'th element in list + */ + void* ObjectAt(int aIndex) const; + + /** + * Remove all items from container without destroying them. + * + * @return *this + */ + nsDeque& Empty(); + + /** + * Remove and delete all items from container. + * Deletes are handled by the deallocator nsDequeFunctor + * which is specified at deque construction. + * + * @return *this + */ + nsDeque& Erase(); + + /** + * Creates a new iterator, pointing to the first + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator Begin() const; + + /** + * Creates a new iterator, pointing to the last + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator End() const; + + void* Last() const; + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + void SetDeallocator(nsDequeFunctor* aDeallocator); + +protected: + PRInt32 mSize; + PRInt32 mCapacity; + PRInt32 mOrigin; + nsDequeFunctor* mDeallocator; + void* mBuffer[8]; + void** mData; + +private: + + /** + * Simple default constructor (PRIVATE) + */ + nsDeque(); + + /** + * Copy constructor (PRIVATE) + * + * @param another deque + */ + nsDeque(const nsDeque& other); + + /** + * Deque assignment operator (PRIVATE) + * + * @param another deque + * @return *this + */ + nsDeque& operator=(const nsDeque& anOther); + + PRInt32 GrowCapacity(); +}; + +/****************************************************** + * Here comes the nsDequeIterator class... + ******************************************************/ + +class nsDequeIterator { +public: + /** + * DequeIterator is an object that knows how to iterate + * (forward and backward) through a Deque. Normally, + * you don't need to do this, but there are some special + * cases where it is pretty handy. + * + * One warning: the iterator is not bound to an item, + * it is bound to an index, so if you insert or remove + * from the beginning while using an iterator + * (which is not recommended) then the iterator will + * point to a different item. @see GetCurrent() + * + * Here you go. + * + * @param aQueue is the deque object to be iterated + * @param aIndex is the starting position for your iteration + */ + nsDequeIterator(const nsDeque& aQueue, int aIndex=0); + + /** + * Create a copy of a DequeIterator + * + * @param aCopy is another iterator to copy from + */ + nsDequeIterator(const nsDequeIterator& aCopy); + + /** + * Moves iterator to first element in the deque + * @return *this + */ + nsDequeIterator& First(); + + /** + * Standard assignment operator for dequeiterator + * @param aCopy is another iterator to copy from + * @return *this + */ + nsDequeIterator& operator=(const nsDequeIterator& aCopy); + + /** + * preform ! operation against two iterators to test for equivalence + * (or lack thereof)! + * + * @param aIter is the object to be compared to + * @return TRUE if NOT equal. + */ + PRBool operator!=(nsDequeIterator& aIter); + + /** + * Compare two iterators for increasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to an element before + * the element pointed to by aIter. + * FALSE if this and aIter are not iterating over + * the same deque. + */ + PRBool operator<(nsDequeIterator& aIter); + + /** + * Compare two iterators for equivalence. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if EQUAL + */ + PRBool operator==(nsDequeIterator& aIter); + + /** + * Compare two iterators for non strict decreasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to the same element, or + * an element after the element pointed to by aIter. + * FALSE if this and aIter are not iterating over + * the same deque. + */ + PRBool operator>=(nsDequeIterator& aIter); + + /** + * Pre-increment operator + * Iterator will advance one index towards the end. + * + * @return object_at(++index) + */ + void* operator++(); + + /** + * Post-increment operator + * Iterator will advance one index towards the end. + * + * @param param is ignored + * @return object_at(mIndex++) + */ + void* operator++(int); + + /** + * Pre-decrement operator + * Iterator will advance one index towards the beginning. + * + * @return object_at(--index) + */ + void* operator--(); + + /** + * Post-decrement operator + * Iterator will advance one index towards the beginning. + * + * @param param is ignored + * @return object_at(index--) + */ + void* operator--(int); + + /** + * Retrieve the the iterator's notion of current node. + * + * Note that the iterator floats, so you don't need to do: + * <code>++iter; aDeque.PopFront();</code> + * Unless you actually want your iterator to jump 2 positions + * relative to its origin. + * + * Picture: [1 2i 3 4] + * PopFront() + * Picture: [2 3i 4] + * Note that I still happily points to object at the second index. + * + * @return object at i'th index + */ + void* GetCurrent(); + + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + protected: + + PRInt32 mIndex; + const nsDeque& mDeque; +}; +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h new file mode 100644 index 00000000..27bf4ce5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h @@ -0,0 +1,505 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * nsDoubleHashtable.h is OBSOLETE. Use nsTHashtable or a derivative instead. + */ + +#ifndef __nsDoubleHashtable_h__ +#define __nsDoubleHashtable_h__ + +#include "pldhash.h" +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/* + * This file provides several major things to make PLDHashTable easier to use: + * - hash class macros for you to define a hashtable + * - default key classes to use as superclasses for your entries + * - empty maps for string, cstring, int and void + */ + +/* + * USAGE + * + * To use nsDoubleHashtable macros + * (1) Define an entry class + * (2) Create the hash class + * (3) Use the hash class + * + * EXAMPLE + * + * As an example, let's create a dictionary, a mapping from a string (the word) + * to the pronunciation and definition of those words. + * + * (1) Define an entry class + * + * What we want here is an entry class that contains the word, the + * pronunciation string, and the definition string. Since we have a string key + * we can use the standard PLDHashStringEntry class as our base, it will handle + * the key stuff for us automatically. + * + * #include "nsDoubleHashtable.h" + * + * // Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break. + * // This is because of the 4-byte pointer C++ magically prepends onto your + * // entry class. It interacts very unhappily with PLDHashTable. + * class DictionaryEntry : public PLDHashStringEntry { + * public: + * DictionaryEntry(const void* aKey) : PLDHashStringEntry(aKey) { } + * ~DictionaryEntry() { } + * nsString mPronunciation; + * nsString mDefinition; + * } + * + * (2) Create the hash class + * + * The final hash class you will use in step 3 is defined by 2 macros. + * + * DECL_DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&) + * DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&) + * + * (3) Use the hash class + * + * Here is a simple main() that might look up a string: + * + * int main(void) { + * Dictionary d; + * nsresult rv = d.Init(10); + * if (NS_FAILED(rv)) return 1; + * + * // Put an entry + * DictionaryEntry* a = d.AddEntry(NS_LITERAL_STRING("doomed")); + * if (!a) return 1; + * a->mDefinition.AssignLiteral("The state you get in when a Mozilla release is pending"); + * a->mPronunciation.AssignLiteral("doom-d"); + * + * // Get the entry + * DictionaryEntry* b = d.GetEntry(NS_LITERAL_STRING("doomed")); + * printf("doomed: %s\n", NS_ConvertUCS2toUTF8(b->mDefinition).get()); + * + * // Entries will be automagically cleaned up when the Dictionary object goes away + * return 0; + * } + * + * + * BONUS POINTS + * + * You may wish to extend this class and add helper functions like + * nsDependentString* GetDefinition(nsAString& aWord). For example: + * + * class MyDictionary : public Dictionary { + * public: + * MyDictionary() { } + * // Make SURE you have a virtual destructor + * virtual ~myDictionary() { } + * nsDependentString* GetDefinition(const nsAString& aWord) { + * DictionaryEntry* e = GetEntry(aWord); + * if (e) { + * // We're returning an nsDependentString here, callers need to delete it + * // and it doesn't last long, but at least it doesn't create a copy + * return new nsDependentString(e->mDefinition.get()); + * } else { + * return nsnull; + * } + * } + * nsresult PutDefinition(const nsAString& aWord, + * const nsAString& aDefinition, + * const nsAString& aPronunciation) { + * DictionaryEntry* e = AddEntry(aWord); + * if (!e) { + * return NS_ERROR_OUT_OF_MEMORY; + * } + * e->mDefinition = aDefinition; + * e->mPronunciation = aPronunciation; + * return NS_OK; + * } + * } + */ + +/* + * ENTRY CLASS DEFINITION + * + * The simplifications of PLDHashTable all hinge upon the idea of an entry + * class, which is a class you define, where you store the key and values that + * you will place in each hash entry. You must define six methods for an entry + * (the standard key classes, which you can extend from, define all of these + * for you except the constructor and destructor): + * + * CONSTRUCTOR(const void* aKey) + * When your entry is constructed it will only be given a pointer to the key. + * + * DESTRUCTOR + * Called when the entry is destroyed (of course). + * + * const void* GetKey() + * Must return a pointer to the key + * + * PRBool MatchEntry(const void* aKey) - return true or false depending on + * whether the key pointed to by aKey matches this entry + * + * static PLDHashNumber HashKey(const void* aKey) - get a hashcode based on the + * key (must be the same every time for the same key, but does not have + * to be unique) + * + * For a small hash that just does key->value, you will often just extend a + * standard key class and put a value member into it, and have a destructor and + * constructor--nothing else necessary. + * + * See the default key entry classes as example entry classes. + * + * NOTES: + * - Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break. + * This is because of the 4-byte pointer C++ magically prepends onto your + * entry class. It interacts very unhappily with PLDHashTable. + */ + +/* + * PRIVATE HASHTABLE MACROS + * + * These internal macros can be used to declare the callbacks for an entry + * class, but the wrapper class macros call these for you so don't call them. + */ + +// +// DHASH_CALLBACKS +// +// Define the hashtable callback functions. Do this in one place only, as you +// will have redundant symbols otherwise. +// +// ENTRY_CLASS: the classname of the entry +// +#define DHASH_CALLBACKS(ENTRY_CLASS) \ +PR_STATIC_CALLBACK(const void *) \ +ENTRY_CLASS##GetKey(PLDHashTable* table, PLDHashEntryHdr* entry) \ +{ \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, entry); \ + return e->GetKey(); \ +} \ +PR_STATIC_CALLBACK(PLDHashNumber) \ +ENTRY_CLASS##HashKey(PLDHashTable* table, const void* key) \ +{ \ + return ENTRY_CLASS::HashKey(key); \ +} \ +PR_STATIC_CALLBACK(PRBool) \ +ENTRY_CLASS##MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, \ + const void *key) \ +{ \ + const ENTRY_CLASS* e = NS_STATIC_CAST(const ENTRY_CLASS*, entry); \ + return e->MatchEntry(key); \ +} \ +PR_STATIC_CALLBACK(void) \ +ENTRY_CLASS##ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) \ +{ \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS *, entry); \ + e->~ENTRY_CLASS(); \ +} \ +PR_STATIC_CALLBACK(PRBool) \ +ENTRY_CLASS##InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, \ + const void *key) \ +{ \ + new (entry) ENTRY_CLASS(key); \ + return PR_TRUE; \ +} + +// +// DHASH_INIT +// +// Initialize hashtable to a certain class. +// +// HASHTABLE: the name of the PLDHashTable variable +// ENTRY_CLASS: the classname of the entry +// NUM_INITIAL_ENTRIES: the number of entry slots the hashtable should start +// with +// RV: an nsresult variable to hold the outcome of the initialization. +// Will be NS_ERROR_OUT_OF_MEMORY if failed, NS_OK otherwise. +// +#define DHASH_INIT(HASHTABLE,ENTRY_CLASS,NUM_INITIAL_ENTRIES,RV) \ +PR_BEGIN_MACRO \ + static PLDHashTableOps hash_table_ops = \ + { \ + PL_DHashAllocTable, \ + PL_DHashFreeTable, \ + ENTRY_CLASS##GetKey, \ + ENTRY_CLASS##HashKey, \ + ENTRY_CLASS##MatchEntry, \ + PL_DHashMoveEntryStub, \ + ENTRY_CLASS##ClearEntry, \ + PL_DHashFinalizeStub, \ + ENTRY_CLASS##InitEntry \ + }; \ + PRBool isLive = PL_DHashTableInit(&(HASHTABLE), \ + &hash_table_ops, nsnull, \ + sizeof(ENTRY_CLASS), \ + (NUM_INITIAL_ENTRIES)); \ + if (!isLive) { \ + (HASHTABLE).ops = nsnull; \ + RV = NS_ERROR_OUT_OF_MEMORY; \ + } else { \ + RV = NS_OK; \ + } \ +PR_END_MACRO + + +/* + * WRAPPER CLASS + * + * This class handles initialization and destruction of the hashtable + * (you must call Init() yourself). It defines these functions: + * + * Init(aNumInitialEntries) + * Initialize the hashtable. This must be called once, it is only separate + * from the constructor so that you can get the return value. You should pass + * in the number of entries you think the hashtable will typically hold (this + * will be the amount of space allocated initially so that it will not have to + * grow). + * + * ENTRY_CLASS* GetEntry(aKey): + * Get the entry referenced by aKey and return a pointer to it. THIS IS A + * TEMPORARY POINTER and is only guaranteed to exist until the next time you do + * an operation on the hashtable. But you can safely use it until then. + * + * Returns nsnull if the entry is not found. + * + * ENTRY_CLASS* AddEntry(aKey): + * Create a new, empty entry and return a pointer to it for you to fill values + * into. THIS IS A TEMPORARY POINTER and is only guaranteed to exist until the + * next time you do an operation on the hashtable. But you can safely fill it + * in. + * + * Returns nsnull if the entry cannot be created (usually a low memory + * constraint). + * + * void Remove(aKey) + * Remove the entry referenced by aKey. If the entry does not exist, nothing + * will happen. + * + * + * DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) + * + * Declare the hash class but do not define the functions. + * + * CLASSNAME: the name of the class to declare. + * ENTRY_CLASS: the class of the entry struct. + * KEY_TYPE: the name of the key type for GetEntry and AddEntry. + * + * + * DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) + * + * Define the functions for the hash class. + * + * CLASSNAME: the name of the class to declare. + * ENTRY_CLASS: the class of the entry struct. + * KEY_TYPE: the name of the key type for GetEntry and AddEntry. + * + * + * CAVEATS: + * - You may have only *one* wrapper class per entry class. + */ + +#define DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +class DHASH_EXPORT CLASSNAME { \ +public: \ + CLASSNAME(); \ + ~CLASSNAME(); \ + nsresult Init(PRUint32 aNumInitialEntries); \ + ENTRY_CLASS* GetEntry(const KEY_TYPE aKey); \ + ENTRY_CLASS* AddEntry(const KEY_TYPE aKey); \ + void Remove(const KEY_TYPE aKey); \ + PLDHashTable mHashTable; \ +}; + +#define DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DHASH_CALLBACKS(ENTRY_CLASS) \ +CLASSNAME::CLASSNAME() { \ + mHashTable.ops = nsnull; \ +} \ +CLASSNAME::~CLASSNAME() { \ + if (mHashTable.ops) { \ + PL_DHashTableFinish(&mHashTable); \ + } \ +} \ +nsresult CLASSNAME::Init(PRUint32 aNumInitialEntries) { \ + if (!mHashTable.ops) { \ + nsresult rv; \ + DHASH_INIT(mHashTable,ENTRY_CLASS,aNumInitialEntries,rv); \ + return rv; \ + } \ + return NS_OK; \ +} \ +ENTRY_CLASS* CLASSNAME::GetEntry(const KEY_TYPE aKey) { \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, \ + PL_DHashTableOperate(&mHashTable, &aKey, \ + PL_DHASH_LOOKUP)); \ + return PL_DHASH_ENTRY_IS_BUSY(e) ? e : nsnull; \ +} \ +ENTRY_CLASS* CLASSNAME::AddEntry(const KEY_TYPE aKey) { \ + return NS_STATIC_CAST(ENTRY_CLASS*, \ + PL_DHashTableOperate(&mHashTable, &aKey, \ + PL_DHASH_ADD)); \ +} \ +void CLASSNAME::Remove(const KEY_TYPE aKey) { \ + PL_DHashTableOperate(&mHashTable, &aKey, PL_DHASH_REMOVE); \ +} + +/* + * STANDARD KEY ENTRY CLASSES + * + * We have declared some standard key classes for you to make life a little + * easier. These include string, int and void* keys. You can extend these + * and add value data members to make a working hash entry class with your + * values. + * + * PLDHashStringEntry: nsAString + * PLDHashCStringEntry: nsACString + * PLDHashInt32Entry: PRInt32 + * PLDHashVoidEntry: void* + * + * As a short example, if you want to make a class that maps int to string, + * you could do: + * + * class MyIntStringEntry : public PLDHashInt32Entry + * { + * public: + * MyIntStringEntry(const void* aKey) : PLDHashInt32Entry(aKey) { } + * ~MyIntStringEntry() { }; + * nsString mMyStr; + * }; + * + * XXX It could be advisable (unless COW strings ever happens) to have a + * PLDHashDependentStringEntry + */ + +// +// String-key entry +// +class NS_COM PLDHashStringEntry : public PLDHashEntryHdr +{ +public: + PLDHashStringEntry(const void* aKey) : + mKey(*NS_STATIC_CAST(const nsAString*, aKey)) { } + ~PLDHashStringEntry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const nsAString*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return HashString(*NS_STATIC_CAST(const nsAString*, key)); + } + PRBool MatchEntry(const void* key) const { + return NS_STATIC_CAST(const nsAString*, key)->Equals(mKey); + } + + const nsString mKey; +}; + +// +// CString-key entry +// +class NS_COM PLDHashCStringEntry : public PLDHashEntryHdr +{ +public: + PLDHashCStringEntry(const void* aKey) : + mKey(*NS_STATIC_CAST(const nsACString*, aKey)) { } + ~PLDHashCStringEntry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const nsACString*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return HashString(*NS_STATIC_CAST(const nsACString*, key)); + } + PRBool MatchEntry(const void* key) const { + return NS_STATIC_CAST(const nsACString*, key)->Equals(mKey); + } + + const nsCString mKey; +}; + +// +// Int-key entry +// +class NS_COM PLDHashInt32Entry : public PLDHashEntryHdr +{ +public: + PLDHashInt32Entry(const void* aKey) : + mKey(*(NS_STATIC_CAST(const PRInt32*, aKey))) { } + ~PLDHashInt32Entry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const PRInt32*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return *NS_STATIC_CAST(const PRInt32*, key); + } + PRBool MatchEntry(const void* key) const { + return *(NS_STATIC_CAST(const PRInt32*, key)) == mKey; + } + + const PRInt32 mKey; +}; + + +// +// Void-key entry +// +class NS_COM PLDHashVoidEntry : public PLDHashEntryHdr +{ +public: + PLDHashVoidEntry(const void* aKey) : + mKey(*(const void**)aKey) { } + ~PLDHashVoidEntry() { } + + const void* GetKey() const { + return (const void**)&mKey; + } + static PLDHashNumber HashKey(const void* key) { + return PLDHashNumber(NS_PTR_TO_INT32(*(const void**)key)) >> 2; + } + PRBool MatchEntry(const void* key) const { + return *(const void**)key == mKey; + } + + const void* mKey; +}; + + +#define DHASH_EXPORT + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp new file mode 100644 index 00000000..c00d118c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron <dbaron@dbaron.org> + * Pierre Phaneuf <pp@ludusdesign.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + + An empty enumerator. + + */ + +#include "nsEmptyEnumerator.h" + +//////////////////////////////////////////////////////////////////////// + +MOZ_DECL_CTOR_COUNTER(EmptyEnumeratorImpl) + +EmptyEnumeratorImpl::EmptyEnumeratorImpl(void) +{ + MOZ_COUNT_CTOR(EmptyEnumeratorImpl); +} + +EmptyEnumeratorImpl::~EmptyEnumeratorImpl(void) +{ + MOZ_COUNT_DTOR(EmptyEnumeratorImpl); +} + +// nsISupports interface +NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::AddRef(void) +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::Release(void) +{ + return 1; +} + +NS_IMPL_QUERY_INTERFACE1(EmptyEnumeratorImpl, nsISimpleEnumerator) + + +// nsISimpleEnumerator interface +NS_IMETHODIMP EmptyEnumeratorImpl::HasMoreElements(PRBool* aResult) +{ + *aResult = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP EmptyEnumeratorImpl::GetNext(nsISupports** aResult) +{ + return NS_ERROR_UNEXPECTED; +} + +static EmptyEnumeratorImpl* gEmptyEnumerator = nsnull; + +extern "C" NS_COM nsresult +NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult) +{ + nsresult rv = NS_OK; + if (!gEmptyEnumerator) { + gEmptyEnumerator = new EmptyEnumeratorImpl(); + if (!gEmptyEnumerator) + rv = NS_ERROR_OUT_OF_MEMORY; + } + *aResult = gEmptyEnumerator; + return rv; +} + +/* static */ void +EmptyEnumeratorImpl::Shutdown() +{ + delete gEmptyEnumerator; + gEmptyEnumerator = nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h new file mode 100644 index 00000000..4b2feabe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron <dbaron@dbaron.org> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + + An empty enumerator. + + */ + +#include "nsIEnumerator.h" + +//////////////////////////////////////////////////////////////////////// + +class EmptyEnumeratorImpl : public nsISimpleEnumerator +{ +public: + EmptyEnumeratorImpl(void); + + // nsISupports interface + NS_DECL_ISUPPORTS_INHERITED // not really inherited, but no mRefCnt + + // nsISimpleEnumerator + NS_DECL_NSISIMPLEENUMERATOR + + static void Shutdown(); + +private: + ~EmptyEnumeratorImpl(void); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp new file mode 100644 index 00000000..e91f68e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsEnumeratorUtils.h" + + +nsArrayEnumerator::nsArrayEnumerator(nsISupportsArray* aValueArray) + : mValueArray(aValueArray), + mIndex(0) +{ + NS_IF_ADDREF(mValueArray); +} + +nsArrayEnumerator::~nsArrayEnumerator(void) +{ + NS_IF_RELEASE(mValueArray); +} + +NS_IMPL_ISUPPORTS1(nsArrayEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + *aResult = (mIndex < (PRInt32) cnt); + return NS_OK; +} + +NS_IMETHODIMP +nsArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + if (mIndex >= (PRInt32) cnt) + return NS_ERROR_UNEXPECTED; + + *aResult = mValueArray->ElementAt(mIndex++); + return NS_OK; +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsISupportsArray* array) +{ + nsArrayEnumerator* enumer = new nsArrayEnumerator(array); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + NS_ADDREF(*result); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue) + : mValue(aValue) +{ + NS_IF_ADDREF(mValue); + mConsumed = (mValue ? PR_FALSE : PR_TRUE); +} + +nsSingletonEnumerator::~nsSingletonEnumerator() +{ + NS_IF_RELEASE(mValue); +} + +NS_IMPL_ISUPPORTS1(nsSingletonEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsSingletonEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = !mConsumed; + return NS_OK; +} + + +NS_IMETHODIMP +nsSingletonEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mConsumed) + return NS_ERROR_UNEXPECTED; + + mConsumed = PR_TRUE; + + *aResult = mValue; + NS_ADDREF(*aResult); + return NS_OK; +} + +extern "C" NS_COM nsresult +NS_NewSingletonEnumerator(nsISimpleEnumerator* *result, + nsISupports* singleton) +{ + nsSingletonEnumerator* enumer = new nsSingletonEnumerator(singleton); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + NS_ADDREF(*result); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsUnionEnumerator::nsUnionEnumerator(nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator) + : mFirstEnumerator(firstEnumerator), + mSecondEnumerator(secondEnumerator), + mConsumed(PR_FALSE), mAtSecond(PR_FALSE) +{ +} + +nsUnionEnumerator::~nsUnionEnumerator() +{ +} + +NS_IMPL_ISUPPORTS1(nsUnionEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsUnionEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + + if (mConsumed) { + *aResult = PR_FALSE; + return NS_OK; + } + + if (! mAtSecond) { + rv = mFirstEnumerator->HasMoreElements(aResult); + if (NS_FAILED(rv)) return rv; + + if (*aResult) + return NS_OK; + + mAtSecond = PR_TRUE; + } + + rv = mSecondEnumerator->HasMoreElements(aResult); + if (NS_FAILED(rv)) return rv; + + if (*aResult) + return NS_OK; + + *aResult = PR_FALSE; + mConsumed = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsUnionEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mConsumed) + return NS_ERROR_UNEXPECTED; + + if (! mAtSecond) + return mFirstEnumerator->GetNext(aResult); + + return mSecondEnumerator->GetNext(aResult); +} + +extern "C" NS_COM nsresult +NS_NewUnionEnumerator(nsISimpleEnumerator* *result, + nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator) +{ + *result = nsnull; + if (! firstEnumerator) { + *result = secondEnumerator; + } else if (! secondEnumerator) { + *result = firstEnumerator; + } else { + nsUnionEnumerator* enumer = new nsUnionEnumerator(firstEnumerator, secondEnumerator); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + } + NS_ADDREF(*result); + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h new file mode 100644 index 00000000..2d8182b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsEnumeratorUtils_h__ +#define nsEnumeratorUtils_h__ + +#include "nsIEnumerator.h" +#include "nsISupportsArray.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewSingletonEnumerator VBoxNsxpNS_NewSingletonEnumerator +#define NS_NewUnionEnumerator VBoxNsxpNS_NewUnionEnumerator +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +class NS_COM nsArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + // nsArrayEnumerator methods + nsArrayEnumerator(nsISupportsArray* aValueArray); + +private: + ~nsArrayEnumerator(void); + +protected: + nsISupportsArray* mValueArray; + PRInt32 mIndex; +}; + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsISupportsArray* array); + +//////////////////////////////////////////////////////////////////////////////// + +class NS_COM nsSingletonEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator methods + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + nsSingletonEnumerator(nsISupports* aValue); + +private: + ~nsSingletonEnumerator(); + +protected: + nsISupports* mValue; + PRBool mConsumed; +}; + +extern "C" NS_COM nsresult +NS_NewSingletonEnumerator(nsISimpleEnumerator* *result, + nsISupports* singleton); + +//////////////////////////////////////////////////////////////////////// + +class NS_COM nsUnionEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator methods + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + nsUnionEnumerator(nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator); + +private: + ~nsUnionEnumerator(); + +protected: + nsCOMPtr<nsISimpleEnumerator> mFirstEnumerator, mSecondEnumerator; + PRBool mConsumed; + PRBool mAtSecond; +}; + +extern "C" NS_COM nsresult +NS_NewUnionEnumerator(nsISimpleEnumerator* *result, + nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator); + +//////////////////////////////////////////////////////////////////////// + +#endif /* nsEnumeratorUtils_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp new file mode 100644 index 00000000..1b6232f9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson <waterson@netscape.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + + Implementation for nsFixedSizeAllocator + +*/ + +#include "nsCRT.h" +#include "nsFixedSizeAllocator.h" + +nsFixedSizeAllocator::Bucket * +nsFixedSizeAllocator::AddBucket(size_t aSize) +{ + void* p; + PL_ARENA_ALLOCATE(p, &mPool, sizeof(Bucket)); + if (! p) + return nsnull; + + Bucket* bucket = NS_STATIC_CAST(Bucket*, p); + bucket->mSize = aSize; + bucket->mFirst = nsnull; + bucket->mNext = mBuckets; + + mBuckets = bucket; + return bucket; +} + +nsresult +nsFixedSizeAllocator::Init(const char* aName, + const size_t* aBucketSizes, + PRInt32 aNumBuckets, + PRInt32 aInitialSize, + PRInt32 aAlign) +{ + NS_PRECONDITION(aNumBuckets > 0, "no buckets"); + if (aNumBuckets <= 0) + return NS_ERROR_INVALID_ARG; + + // Blow away the old pool if we're being re-initialized. + if (mBuckets) + PL_FinishArenaPool(&mPool); + + PRInt32 bucketspace = aNumBuckets * sizeof(Bucket); + PL_InitArenaPool(&mPool, aName, bucketspace + aInitialSize, aAlign); + + mBuckets = nsnull; + for (PRInt32 i = 0; i < aNumBuckets; ++i) + AddBucket(aBucketSizes[i]); + + return NS_OK; +} + +nsFixedSizeAllocator::Bucket * +nsFixedSizeAllocator::FindBucket(size_t aSize) +{ + Bucket** link = &mBuckets; + Bucket* bucket; + + while ((bucket = *link) != nsnull) { + if (aSize == bucket->mSize) { + // Promote to the head of the list, under the assumption + // that we'll allocate same-sized object contemporaneously. + *link = bucket->mNext; + bucket->mNext = mBuckets; + mBuckets = bucket; + return bucket; + } + + link = &bucket->mNext; + } + return nsnull; +} + +void* +nsFixedSizeAllocator::Alloc(size_t aSize) +{ + Bucket* bucket = FindBucket(aSize); + if (! bucket) { + // Oops, we don't carry that size. Let's fix that. + bucket = AddBucket(aSize); + if (! bucket) + return nsnull; + } + + void* next; + if (bucket->mFirst) { + next = bucket->mFirst; + bucket->mFirst = bucket->mFirst->mNext; + } + else { + PL_ARENA_ALLOCATE(next, &mPool, aSize); + if (!next) + return nsnull; + } + +#ifdef DEBUG + memset(next, 0xc8, aSize); +#endif + + return next; +} + +void +nsFixedSizeAllocator::Free(void* aPtr, size_t aSize) +{ + FreeEntry* entry = NS_REINTERPRET_CAST(FreeEntry*, aPtr); + Bucket* bucket = FindBucket(aSize); + +#ifdef DEBUG + NS_ASSERTION(bucket && bucket->mSize == aSize, "ack! corruption! bucket->mSize != aSize!"); + memset(aPtr, 0xd8, bucket->mSize); +#endif + + entry->mNext = bucket->mFirst; + bucket->mFirst = entry; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h new file mode 100644 index 00000000..16708cdc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson <waterson@netscape.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + + A simple fixed-size allocator that allocates its memory from an + arena. + + Although the allocator can handle blocks of any size, its + preformance will degrade rapidly if used to allocate blocks of + arbitrary size. Ideally, it should be used to allocate and recycle a + large number of fixed-size blocks. + + Here is a typical usage pattern: + + #include NEW_H // You'll need this! + #include "nsFixedSizeAllocator.h" + + // Say this is the object you want to allocate a ton of + class Foo { + public: + // Implement placement new & delete operators that will + // use the fixed size allocator. + static Foo * + Create(nsFixedSizeAllocator &aAllocator) + { + void *place = aAllocator.Alloc(sizeof(Foo)); + return place ? ::new (place) Foo() : nsnull; + } + + static void + Destroy(nsFixedSizeAllocator &aAllocator, Foo *aFoo) + { + aFoo->~Foo(); + aAllocator.Free(aFoo, sizeof(Foo)); + } + + // ctor & dtor + Foo() {} + ~Foo() {} + }; + + + int main(int argc, char* argv[]) + { + // Somewhere in your code, you'll need to create an + // nsFixedSizeAllocator object and initialize it: + nsFixedSizeAllocator pool; + + // The fixed size allocator will support multiple fixed sizes. + // This array lists an initial set of sizes that the allocator + // should be prepared to support. In our case, there's just one, + // which is Foo. + static const size_t kBucketSizes[] + = { sizeof(Foo) } + + // This is the number of different "buckets" you'll need for + // fixed size objects. In our example, this will be "1". + static const PRInt32 kNumBuckets + = sizeof(kBucketSizes) / sizeof(size_t); + + // This is the intial size of the allocator, in bytes. We'll + // assume that we want to start with space for 1024 Foo objects. + static const PRInt32 kInitialPoolSize = + NS_SIZE_IN_HEAP(sizeof(Foo)) * 1024; + + // Initialize (or re-initialize) the pool + pool.Init("TheFooPool", kBucketSizes, kNumBuckets, kInitialPoolSize); + + // Now we can use the pool. + + // Create a new Foo object using the pool: + Foo* foo = Foo::Create(pool); + if (! foo) { + // uh oh, out of memory! + } + + // Delete the object. The memory used by `foo' is recycled in + // the pool, and placed in a freelist + Foo::Destroy(foo); + + // Create another foo: this one will be allocated from the + // free-list + foo = Foo::Create(pool); + + // When pool is destroyed, all of its memory is automatically + // freed. N.B. it will *not* call your objects' destructors! In + // this case, foo's ~Foo() method would never be called. + } + +*/ + +#ifndef nsFixedSizeAllocator_h__ +#define nsFixedSizeAllocator_h__ + +#include "nscore.h" +#include "nsError.h" +#include "plarena.h" + +#define NS_SIZE_IN_HEAP(_size) (_size) + +class NS_COM nsFixedSizeAllocator +{ +protected: + PLArenaPool mPool; + + struct Bucket; + struct FreeEntry; + + friend struct Bucket; + friend struct FreeEntry; + + struct FreeEntry { + FreeEntry* mNext; + }; + + struct Bucket { + size_t mSize; + FreeEntry* mFirst; + Bucket* mNext; + }; + + Bucket* mBuckets; + + Bucket * + AddBucket(size_t aSize); + + Bucket * + FindBucket(size_t aSize); + +public: + nsFixedSizeAllocator() : mBuckets(nsnull) {} + + ~nsFixedSizeAllocator() { + if (mBuckets) + PL_FinishArenaPool(&mPool); + } + + /** + * Initialize the fixed size allocator. 'aName' is used to tag + * the underlying PLArena object for debugging and measurement + * purposes. 'aNumBuckets' specifies the number of elements in + * 'aBucketSizes', which is an array of integral block sizes + * that this allocator should be prepared to handle. + */ + nsresult + Init(const char* aName, + const size_t* aBucketSizes, + PRInt32 aNumBuckets, + PRInt32 aInitialSize, + PRInt32 aAlign = 0); + + /** + * Allocate a block of memory 'aSize' bytes big. + */ + void* Alloc(size_t aSize); + + /** + * Free a pointer allocated using a fixed-size allocator + */ + void Free(void* aPtr, size_t aSize); +}; + + + +#endif // nsFixedSizeAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h b/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h new file mode 100644 index 00000000..8a6d272e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsTHashKeys_h__ +#define nsTHashKeys_h__ + +#include "nsAString.h" +#include "nsString.h" +#include "nsID.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" +#include "nsISupports.h" +#include "nsCOMPtr.h" +#include "pldhash.h" +#include NEW_H + +/** @file nsHashKeys.h + * standard HashKey classes for nsBaseHashtable and relatives. Each of these + * classes follows the nsTHashtable::EntryType specification + * + * Lightweight keytypes provided here: + * nsStringHashKey + * nsCStringHashKey + * nsUint32HashKey + * nsISupportsHashKey + * nsIDHashKey + * nsDepCharHashKey + */ + +/** + * hashkey wrapper using nsAString KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsStringHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsAString& KeyType; + typedef const nsAString* KeyTypePointer; + + nsStringHashKey(KeyTypePointer aStr) : mStr(*aStr) { } + nsStringHashKey(const nsStringHashKey& toCopy) : mStr(toCopy.mStr) { } + ~nsStringHashKey() { } + + KeyType GetKey() const { return mStr; } + KeyTypePointer GetKeyPointer() const { return &mStr; } + PRBool KeyEquals(const KeyTypePointer aKey) const + { + return mStr.Equals(*aKey); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(const KeyTypePointer aKey) + { + return HashString(*aKey); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsString mStr; +}; + +/** + * hashkey wrapper using nsACString KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsCStringHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsACString& KeyType; + typedef const nsACString* KeyTypePointer; + + nsCStringHashKey(const nsACString* aStr) : mStr(*aStr) { } + nsCStringHashKey(const nsCStringHashKey& toCopy) : mStr(toCopy.mStr) { } + ~nsCStringHashKey() { } + + KeyType GetKey() const { return mStr; } + KeyTypePointer GetKeyPointer() const { return &mStr; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return mStr.Equals(*aKey); } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return HashString(*aKey); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsCString mStr; +}; + +/** + * hashkey wrapper using PRUint32 KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsUint32HashKey : public PLDHashEntryHdr +{ +public: + typedef const PRUint32& KeyType; + typedef const PRUint32* KeyTypePointer; + + nsUint32HashKey(KeyTypePointer aKey) : mValue(*aKey) { } + nsUint32HashKey(const nsUint32HashKey& toCopy) : mValue(toCopy.mValue) { } + ~nsUint32HashKey() { } + + KeyType GetKey() const { return mValue; } + KeyTypePointer GetKeyPointer() const { return &mValue; } + PRBool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { return *aKey; } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const PRUint32 mValue; +}; + +/** + * hashkey wrapper using nsISupports* KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsISupportsHashKey : public PLDHashEntryHdr +{ +public: + typedef nsISupports* KeyType; + typedef const nsISupports* KeyTypePointer; + + nsISupportsHashKey(const nsISupports* key) : + mSupports(NS_CONST_CAST(nsISupports*,key)) { } + nsISupportsHashKey(const nsISupportsHashKey& toCopy) : + mSupports(toCopy.mSupports) { } + ~nsISupportsHashKey() { } + + KeyType GetKey() const { return mSupports; } + KeyTypePointer GetKeyPointer() const { return mSupports; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mSupports; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return NS_PTR_TO_INT32(aKey) >>2; + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + nsCOMPtr<nsISupports> mSupports; +}; + +/** + * hashkey wrapper using void* KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsVoidPtrHashKey : public PLDHashEntryHdr +{ +public: + typedef const void* KeyType; + typedef const void* KeyTypePointer; + + nsVoidPtrHashKey(const void* key) : + mKey(key) { } + nsVoidPtrHashKey(const nsVoidPtrHashKey& toCopy) : + mKey(toCopy.mKey) { } + ~nsVoidPtrHashKey() { } + + KeyType GetKey() const { return mKey; } + KeyTypePointer GetKeyPointer() const { return mKey; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return NS_PTR_TO_INT32(aKey) >>2; + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const void* mKey; +}; + +/** + * hashkey wrapper using nsID KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsIDHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsID& KeyType; + typedef const nsID* KeyTypePointer; + + nsIDHashKey(const nsID* id) : mID(*id) { } + nsIDHashKey(const nsIDHashKey& toCopy) : mID(toCopy.mID) { } + ~nsIDHashKey() { } + + KeyType GetKey() const { return mID; } + KeyTypePointer GetKeyPointer() const { return &mID; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey->Equals(mID); } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey); + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsID mID; +}; + +/** + * hashkey wrapper for "dependent" const char*; this class does not "own" + * its string pointer. + * + * This class must only be used if the strings have a lifetime longer than + * the hashtable they occupy. This normally occurs only for static + * strings or strings that have been arena-allocated. + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsDepCharHashKey : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + nsDepCharHashKey(const char* aKey) { mKey = aKey; } + nsDepCharHashKey(const nsDepCharHashKey& toCopy) { mKey = toCopy.mKey; } + ~nsDepCharHashKey() { } + + const char* GetKey() const { return mKey; } + const char* GetKeyPointer() const { return mKey; } + PRBool KeyEquals(const char* aKey) const + { + return !strcmp(mKey, aKey); + } + + static const char* KeyToPointer(const char* aKey) { return aKey; } + static PLDHashNumber HashKey(const char* aKey) { return nsCRT::HashCode(aKey); } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const char* mKey; +}; + +/** + * hashkey wrapper for const char*; at construction, this class duplicates + * a string pointed to by the pointer so that it doesn't matter whether or not + * the string lives longer than the hash table. + */ +class NS_COM nsCharPtrHashKey : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + nsCharPtrHashKey(const char* aKey) : mKey(strdup(aKey)) { } + nsCharPtrHashKey(const nsCharPtrHashKey& toCopy) : mKey(strdup(toCopy.mKey)) { } + ~nsCharPtrHashKey() { if (mKey) free(NS_CONST_CAST(char *, mKey)); } + + const char* GetKey() const { return mKey; } + const char* GetKeyPointer() const { return mKey; } + PRBool KeyEquals(KeyTypePointer aKey) const + { + return !strcmp(mKey, aKey); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { return nsCRT::HashCode(aKey); } + + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const char* mKey; +}; + +#endif // nsTHashKeys_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp new file mode 100644 index 00000000..3f11ba55 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nscore.h" +#include NEW_H + +#include "nsHashSets.h" + +DHASH_SET(nsStringHashSet, PLDHashStringEntry, nsAString&) +DHASH_SET(nsCStringHashSet,PLDHashCStringEntry,nsACString&) +DHASH_SET(nsInt32HashSet, PLDHashInt32Entry, PRInt32) +DHASH_SET(nsVoidHashSet, PLDHashVoidEntry, void*) diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h new file mode 100644 index 00000000..627a6a06 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __nsHashSets_h__ +#define __nsHashSets_h__ + +#include "nsDoubleHashtable.h" + +/* + * HASH SETS + * + * These hash classes describe hashtables that contain keys without values. + * This is useful when you want to store things and then just test for their + * existence later. We have defined standard ones for string, int and void. + * + * nsStringHashSet: nsAString& + * nsCStringHashSet: nsACString& + * nsInt32HashSet: PRInt32 + * nsVoidHashSet: void* + * + * USAGE: + * Put(): put a thing of the given type into the set + * Contains(): whether it contains a thing of the given type + * To use, you just do: (for example) + * + * #include "nsDoubleHashtable.h" + * nsInt32HashSet mySet; + * mySet.Init(1); + * mySet.Put(5); + * if (mySet.Contains(5)) { + * printf("yay\n"); + * } + * + * There is a nice convenient macro for declaring empty map classes: + * DECL_DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE) + * - CLASSNAME: the name of the class + * - ENTRY_CLASS: the name of the entry class with the key in it + * - KEY_TYPE: the type of key for Put() and Contains() + * + * DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE) is the companion macro + * you must put in the .cpp (implementation) code. + */ + +#define DECL_DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DECL_DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE) \ +class DHASH_EXPORT CLASSNAME : public CLASSNAME##Super { \ +public: \ + CLASSNAME() : CLASSNAME##Super() { } \ + ~CLASSNAME() { } \ + nsresult Put(const KEY_TYPE aKey) { \ + return AddEntry(aKey) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; \ + } \ + PRBool Contains(const KEY_TYPE aKey) { \ + return GetEntry(aKey) ? PR_TRUE : PR_FALSE; \ + } \ +}; + +#define DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE) + +#undef DHASH_EXPORT +#define DHASH_EXPORT NS_COM + +DECL_DHASH_SET(nsStringHashSet, PLDHashStringEntry, nsAString&) +DECL_DHASH_SET(nsCStringHashSet,PLDHashCStringEntry,nsACString&) +DECL_DHASH_SET(nsInt32HashSet, PLDHashInt32Entry, PRInt32) +DECL_DHASH_SET(nsVoidHashSet, PLDHashVoidEntry, void*) + +#undef DHASH_EXPORT +#define DHASH_EXPORT + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp new file mode 100644 index 00000000..ce74fb28 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp @@ -0,0 +1,896 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include <string.h> +#include "prmem.h" +#include "prlog.h" +#include "nsHashtable.h" +#include "nsReadableUtils.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsCRT.h" + +struct HTEntry : PLDHashEntryHdr +{ + nsHashKey* key; + void* value; +}; + +// +// Key operations +// + +PR_STATIC_CALLBACK(PRBool) +matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry, + const void* key) +{ + const HTEntry* hashEntry = + NS_STATIC_CAST(const HTEntry*, entry); + + if (hashEntry->key == key) + return PR_TRUE; + + const nsHashKey* otherKey = NS_REINTERPRET_CAST(const nsHashKey*, key); + return otherKey->Equals(hashEntry->key); +} + +PR_STATIC_CALLBACK(PLDHashNumber) +hashKey(PLDHashTable* table, const void* key) +{ + const nsHashKey* hashKey = NS_STATIC_CAST(const nsHashKey*, key); + + return hashKey->HashCode(); +} + +PR_STATIC_CALLBACK(void) +clearHashEntry(PLDHashTable* table, PLDHashEntryHdr* entry) +{ + HTEntry* hashEntry = NS_STATIC_CAST(HTEntry*, entry); + + // leave it up to the nsHashKey destructor to free the "value" + delete hashEntry->key; + hashEntry->key = nsnull; + hashEntry->value = nsnull; // probably not necessary, but for + // sanity's sake +} + + +static const PLDHashTableOps hashtableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + hashKey, + matchKeyEntry, + PL_DHashMoveEntryStub, + clearHashEntry, + PL_DHashFinalizeStub, + nsnull, +}; + + +// +// Enumerator callback +// + +struct _HashEnumerateArgs { + nsHashtableEnumFunc fn; + void* arg; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerate(PLDHashTable* table, PLDHashEntryHdr* hdr, PRUint32 i, void *arg) +{ + _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg; + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + + switch (thunk->fn(entry->key, entry->value, thunk->arg)) { + case kHashEnumerateNext: + return PL_DHASH_NEXT; + case kHashEnumerateRemove: + return PL_DHASH_REMOVE; + } + return PL_DHASH_STOP; +} + +// +// HashKey +// + +nsHashKey::~nsHashKey(void) +{ + MOZ_COUNT_DTOR(nsHashKey); +} + +nsresult +nsHashKey::Write(nsIObjectOutputStream* aStream) const +{ + NS_NOTREACHED("oops"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +MOZ_DECL_CTOR_COUNTER(nsHashtable) + +nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe) + : mLock(NULL), mEnumerating(PR_FALSE) +{ + MOZ_COUNT_CTOR(nsHashtable); + + PRBool result = PL_DHashTableInit(&mHashtable, &hashtableOps, nsnull, + sizeof(HTEntry), aInitSize); + + NS_ASSERTION(result, "Hashtable failed to initialize"); + + // make sure we detect this later + if (!result) + mHashtable.ops = nsnull; + + if (threadSafe) { + mLock = PR_NewLock(); + if (mLock == NULL) { + // Cannot create a lock. If running on a multiprocessing system + // we are sure to die. + PR_ASSERT(mLock != NULL); + } + } +} + + +nsHashtable::~nsHashtable() { + MOZ_COUNT_DTOR(nsHashtable); + if (mHashtable.ops) + PL_DHashTableFinish(&mHashtable); + if (mLock) PR_DestroyLock(mLock); +} + +PRBool nsHashtable::Exists(nsHashKey *aKey) +{ + if (mLock) PR_Lock(mLock); + + if (!mHashtable.ops) + return PR_FALSE; + + PLDHashEntryHdr *entry = + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP); + + PRBool exists = PL_DHASH_ENTRY_IS_BUSY(entry); + + if (mLock) PR_Unlock(mLock); + + return exists; +} + +void *nsHashtable::Put(nsHashKey *aKey, void *aData) +{ + void *res = NULL; + + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + // shouldn't be adding an item during enumeration + PR_ASSERT(!mEnumerating); + + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD)); + + if (entry) { // don't return early, or you'll be locked! + if (entry->key) { + // existing entry, need to boot the old value + res = entry->value; + entry->value = aData; + } else { + // new entry (leave res == null) + entry->key = aKey->Clone(); + entry->value = aData; + } + } + + if (mLock) PR_Unlock(mLock); + + return res; +} + +void *nsHashtable::Get(nsHashKey *aKey) +{ + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP)); + void *ret = PL_DHASH_ENTRY_IS_BUSY(entry) ? entry->value : nsnull; + + if (mLock) PR_Unlock(mLock); + + return ret; +} + +void *nsHashtable::Remove(nsHashKey *aKey) +{ + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + // shouldn't be adding an item during enumeration + PR_ASSERT(!mEnumerating); + + + // need to see if the entry is actually there, in order to get the + // old value for the result + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP)); + void *res; + + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + // value wasn't in the table anyway + res = nsnull; + } else { + res = entry->value; + PL_DHashTableRawRemove(&mHashtable, entry); + } + + if (mLock) PR_Unlock(mLock); + + return res; +} + +// XXX This method was called _hashEnumerateCopy, but it didn't copy the element! +// I don't know how this was supposed to work since the elements are neither copied +// nor refcounted. +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerateShare(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 i, void *arg) +{ + nsHashtable *newHashtable = (nsHashtable *)arg; + HTEntry * entry = NS_STATIC_CAST(HTEntry*, hdr); + + newHashtable->Put(entry->key, entry->value); + return PL_DHASH_NEXT; +} + +nsHashtable * nsHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = (mLock != nsnull); + nsHashtable *newHashTable = new nsHashtable(mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, hashEnumerateShare, newHashTable); + return newHashTable; +} + +void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure) +{ + if (!mHashtable.ops) return; + + PRBool wasEnumerating = mEnumerating; + mEnumerating = PR_TRUE; + _HashEnumerateArgs thunk; + thunk.fn = aEnumFunc; + thunk.arg = aClosure; + PL_DHashTableEnumerate(&mHashtable, hashEnumerate, &thunk); + mEnumerating = wasEnumerating; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerateRemove(PLDHashTable*, PLDHashEntryHdr* hdr, PRUint32 i, void *arg) +{ + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg; + if (thunk) { + return thunk->fn(entry->key, entry->value, thunk->arg) + ? PL_DHASH_REMOVE + : PL_DHASH_STOP; + } + return PL_DHASH_REMOVE; +} + +void nsHashtable::Reset() { + Reset(NULL); +} + +void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure) +{ + if (!mHashtable.ops) return; + + _HashEnumerateArgs thunk, *thunkp; + if (!destroyFunc) { + thunkp = nsnull; + } else { + thunkp = &thunk; + thunk.fn = destroyFunc; + thunk.arg = aClosure; + } + PL_DHashTableEnumerate(&mHashtable, hashEnumerateRemove, thunkp); +} + +// nsISerializable helpers + +nsHashtable::nsHashtable(nsIObjectInputStream* aStream, + nsHashtableReadEntryFunc aReadEntryFunc, + nsHashtableFreeEntryFunc aFreeEntryFunc, + nsresult *aRetVal) + : mLock(nsnull), + mEnumerating(PR_FALSE) +{ + MOZ_COUNT_CTOR(nsHashtable); + + PRBool threadSafe; + nsresult rv = aStream->ReadBoolean(&threadSafe); + if (NS_SUCCEEDED(rv)) { + if (threadSafe) { + mLock = PR_NewLock(); + if (!mLock) + rv = NS_ERROR_OUT_OF_MEMORY; + } + + if (NS_SUCCEEDED(rv)) { + PRUint32 count; + rv = aStream->Read32(&count); + + if (NS_SUCCEEDED(rv)) { + PRBool status = + PL_DHashTableInit(&mHashtable, &hashtableOps, + nsnull, sizeof(HTEntry), count); + if (!status) { + mHashtable.ops = nsnull; + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + for (PRUint32 i = 0; i < count; i++) { + nsHashKey* key; + void *data; + + rv = aReadEntryFunc(aStream, &key, &data); + if (NS_SUCCEEDED(rv)) { + if (!Put(key, data)) { + rv = NS_ERROR_OUT_OF_MEMORY; + aFreeEntryFunc(aStream, key, data); + } else { + // XXXbe must we clone key? can't we hand off + aFreeEntryFunc(aStream, key, nsnull); + } + if (NS_FAILED(rv)) + break; + } + } + } + } + } + } + *aRetVal = rv; +} + +struct WriteEntryArgs { + nsIObjectOutputStream* mStream; + nsHashtableWriteDataFunc mWriteDataFunc; + nsresult mRetVal; +}; + +PR_STATIC_CALLBACK(PRBool) +WriteEntry(nsHashKey *aKey, void *aData, void* aClosure) +{ + WriteEntryArgs* args = (WriteEntryArgs*) aClosure; + nsIObjectOutputStream* stream = args->mStream; + + nsresult rv = aKey->Write(stream); + if (NS_SUCCEEDED(rv)) + rv = args->mWriteDataFunc(stream, aData); + + args->mRetVal = rv; + return PR_TRUE; +} + +nsresult +nsHashtable::Write(nsIObjectOutputStream* aStream, + nsHashtableWriteDataFunc aWriteDataFunc) const +{ + if (!mHashtable.ops) + return NS_ERROR_OUT_OF_MEMORY; + PRBool threadSafe = (mLock != nsnull); + nsresult rv = aStream->WriteBoolean(threadSafe); + if (NS_FAILED(rv)) return rv; + + // Write the entry count first, so we know how many key/value pairs to read. + PRUint32 count = mHashtable.entryCount; + rv = aStream->Write32(count); + if (NS_FAILED(rv)) return rv; + + // Write all key/value pairs in the table. + WriteEntryArgs args = {aStream, aWriteDataFunc}; + NS_CONST_CAST(nsHashtable*, this)->Enumerate(WriteEntry, (void*) &args); + return args.mRetVal; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsISupportsKey::nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mKey(nsnull) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->ReadObject(PR_TRUE, &mKey); + *aResult = rv; +} + +nsresult +nsISupportsKey::Write(nsIObjectOutputStream* aStream) const +{ + PRBool nonnull = (mKey != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteObject(mKey, PR_TRUE); + return rv; +} + +nsIDKey::nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult) +{ + *aResult = aStream->ReadID(&mID); +} + +nsresult nsIDKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteID(mID); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Copy Constructor +// We need to free mStr if the object is passed with mOwnership as OWN. As the +// destructor here is freeing mStr in that case, mStr is NOT getting leaked here. + +nsCStringKey::nsCStringKey(const nsCStringKey& aKey) + : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership) +{ + if (mOwnership != NEVER_OWN) { + PRUint32 len = mStrLen * sizeof(char); + char* str = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(len + sizeof(char))); + if (!str) { + // Pray we don't dangle! + mOwnership = NEVER_OWN; + } else { + // Use memcpy in case there are embedded NULs. + memcpy(str, mStr, len); + str[mStrLen] = '\0'; + mStr = str; + mOwnership = OWN; + } + } +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const nsAFlatCString& str) + : mStr(NS_CONST_CAST(char*, str.get())), + mStrLen(str.Length()), + mOwnership(OWN_CLONE) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const nsACString& str) + : mStr(ToNewCString(str)), + mStrLen(str.Length()), + mOwnership(OWN) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const char* str, PRInt32 strLen, Ownership own) + : mStr((char*)str), mStrLen(strLen), mOwnership(own) +{ + NS_ASSERTION(mStr, "null string key"); + if (mStrLen == PRUint32(-1)) + mStrLen = strlen(str); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::~nsCStringKey(void) +{ + if (mOwnership == OWN) + nsMemory::Free(mStr); + MOZ_COUNT_DTOR(nsCStringKey); +} + +PRUint32 +nsCStringKey::HashCode(void) const +{ + return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen); +} + +PRBool +nsCStringKey::Equals(const nsHashKey* aKey) const +{ + NS_ASSERTION(aKey->GetKeyType() == CStringKey, "mismatched key types"); + nsCStringKey* other = (nsCStringKey*)aKey; + NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode"); + NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode"); + if (mStrLen != other->mStrLen) + return PR_FALSE; + return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0; +} + +nsHashKey* +nsCStringKey::Clone() const +{ + if (mOwnership == NEVER_OWN) + return new nsCStringKey(mStr, mStrLen, NEVER_OWN); + + // Since this might hold binary data OR a string, we ensure that the + // clone string is zero terminated, but don't assume that the source + // string was so terminated. + + PRUint32 len = mStrLen * sizeof(char); + char* str = (char*)nsMemory::Alloc(len + sizeof(char)); + if (str == NULL) + return NULL; + memcpy(str, mStr, len); + str[len] = 0; + return new nsCStringKey(str, mStrLen, OWN); +} + +nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mStr(nsnull), mStrLen(0), mOwnership(OWN) +{ + nsCAutoString str; + nsresult rv = aStream->ReadCString(str); + mStr = ToNewCString(str); + if (NS_SUCCEEDED(rv)) + mStrLen = str.Length(); + *aResult = rv; + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsresult +nsCStringKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteStringZ(mStr); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Copy Constructor +// We need to free mStr if the object is passed with mOwnership as OWN. As the +// destructor here is freeing mStr in that case, mStr is NOT getting leaked here. + +nsStringKey::nsStringKey(const nsStringKey& aKey) + : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership) +{ + if (mOwnership != NEVER_OWN) { + PRUint32 len = mStrLen * sizeof(PRUnichar); + PRUnichar* str = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc(len + sizeof(PRUnichar))); + if (!str) { + // Pray we don't dangle! + mOwnership = NEVER_OWN; + } else { + // Use memcpy in case there are embedded NULs. + memcpy(str, mStr, len); + str[mStrLen] = 0; + mStr = str; + mOwnership = OWN; + } + } +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const nsAFlatString& str) + : mStr(NS_CONST_CAST(PRUnichar*, str.get())), + mStrLen(str.Length()), + mOwnership(OWN_CLONE) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const nsAString& str) + : mStr(ToNewUnicode(str)), + mStrLen(str.Length()), + mOwnership(OWN) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const PRUnichar* str, PRInt32 strLen, Ownership own) + : mStr((PRUnichar*)str), mStrLen(strLen), mOwnership(own) +{ + NS_ASSERTION(mStr, "null string key"); + if (mStrLen == PRUint32(-1)) + mStrLen = nsCRT::strlen(str); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::~nsStringKey(void) +{ + if (mOwnership == OWN) + nsMemory::Free(mStr); + MOZ_COUNT_DTOR(nsStringKey); +} + +PRUint32 +nsStringKey::HashCode(void) const +{ + return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen); +} + +PRBool +nsStringKey::Equals(const nsHashKey* aKey) const +{ + NS_ASSERTION(aKey->GetKeyType() == StringKey, "mismatched key types"); + nsStringKey* other = (nsStringKey*)aKey; + NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode"); + NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode"); + if (mStrLen != other->mStrLen) + return PR_FALSE; + return memcmp(mStr, other->mStr, mStrLen * sizeof(PRUnichar)) == 0; +} + +nsHashKey* +nsStringKey::Clone() const +{ + if (mOwnership == NEVER_OWN) + return new nsStringKey(mStr, mStrLen, NEVER_OWN); + + PRUint32 len = (mStrLen+1) * sizeof(PRUnichar); + PRUnichar* str = (PRUnichar*)nsMemory::Alloc(len); + if (str == NULL) + return NULL; + memcpy(str, mStr, len); + return new nsStringKey(str, mStrLen, OWN); +} + +nsStringKey::nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mStr(nsnull), mStrLen(0), mOwnership(OWN) +{ + nsAutoString str; + nsresult rv = aStream->ReadString(str); + mStr = ToNewUnicode(str); + if (NS_SUCCEEDED(rv)) + mStrLen = str.Length(); + *aResult = rv; + MOZ_COUNT_CTOR(nsStringKey); +} + +nsresult +nsStringKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteWStringZ(mStr); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be +// deleted + +nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun, + void* cloneElementClosure, + nsHashtableEnumFunc destroyElementFun, + void* destroyElementClosure, + PRUint32 aSize, PRBool threadSafe) + : nsHashtable(aSize, threadSafe), + mCloneElementFun(cloneElementFun), + mCloneElementClosure(cloneElementClosure), + mDestroyElementFun(destroyElementFun), + mDestroyElementClosure(destroyElementClosure) +{ +} + +nsObjectHashtable::~nsObjectHashtable() +{ + Reset(); +} + + +PLDHashOperator PR_CALLBACK +nsObjectHashtable::CopyElement(PLDHashTable* table, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg) +{ + nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg; + HTEntry *entry = NS_STATIC_CAST(HTEntry*, hdr); + + void* newElement = + newHashtable->mCloneElementFun(entry->key, entry->value, + newHashtable->mCloneElementClosure); + if (newElement == nsnull) + return PL_DHASH_STOP; + newHashtable->Put(entry->key, newElement); + return PL_DHASH_NEXT; +} + +nsHashtable* +nsObjectHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = PR_FALSE; + if (mLock) + threadSafe = PR_TRUE; + nsObjectHashtable* newHashTable = + new nsObjectHashtable(mCloneElementFun, mCloneElementClosure, + mDestroyElementFun, mDestroyElementClosure, + mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable); + return newHashTable; +} + +void +nsObjectHashtable::Reset() +{ + nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure); +} + +PRBool +nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey) +{ + void *value = Remove(aKey); + if (value && mDestroyElementFun) + return (*mDestroyElementFun)(aKey, value, mDestroyElementClosure); + return PR_FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsSupportsHashtable: an nsHashtable where the elements are nsISupports* + +PRBool PR_CALLBACK +nsSupportsHashtable::ReleaseElement(nsHashKey *aKey, void *aData, void* aClosure) +{ + nsISupports* element = NS_STATIC_CAST(nsISupports*, aData); + NS_IF_RELEASE(element); + return PR_TRUE; +} + +nsSupportsHashtable::~nsSupportsHashtable() +{ + Enumerate(ReleaseElement, nsnull); +} + +// Return true if we overwrote something + +PRBool +nsSupportsHashtable::Put(nsHashKey *aKey, nsISupports* aData, nsISupports **value) +{ + NS_IF_ADDREF(aData); + void *prev = nsHashtable::Put(aKey, aData); + nsISupports *old = NS_REINTERPRET_CAST(nsISupports *, prev); + if (value) // pass own the ownership to the caller + *value = old; + else // the caller doesn't care, we do + NS_IF_RELEASE(old); + return prev != nsnull; +} + +nsISupports * +nsSupportsHashtable::Get(nsHashKey *aKey) +{ + void* data = nsHashtable::Get(aKey); + if (!data) + return nsnull; + nsISupports* element = NS_REINTERPRET_CAST(nsISupports*, data); + NS_IF_ADDREF(element); + return element; +} + +// Return true if we found something (useful for checks) + +PRBool +nsSupportsHashtable::Remove(nsHashKey *aKey, nsISupports **value) +{ + void* data = nsHashtable::Remove(aKey); + nsISupports* element = NS_STATIC_CAST(nsISupports*, data); + if (value) // caller wants it + *value = element; + else // caller doesn't care, we do + NS_IF_RELEASE(element); + return data != nsnull; +} + +PLDHashOperator PR_CALLBACK +nsSupportsHashtable::EnumerateCopy(PLDHashTable*, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg) +{ + nsHashtable *newHashtable = (nsHashtable *)arg; + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + + nsISupports* element = NS_STATIC_CAST(nsISupports*, entry->value); + NS_IF_ADDREF(element); + newHashtable->Put(entry->key, entry->value); + return PL_DHASH_NEXT; +} + +nsHashtable* +nsSupportsHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = (mLock != nsnull); + nsSupportsHashtable* newHashTable = + new nsSupportsHashtable(mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, EnumerateCopy, newHashTable); + return newHashTable; +} + +void +nsSupportsHashtable::Reset() +{ + Enumerate(ReleaseElement, nsnull); + nsHashtable::Reset(); +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h new file mode 100644 index 00000000..21ce9028 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h @@ -0,0 +1,454 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +/** + * nsHashtable is OBSOLETE. Use nsTHashtable or a derivative instead. + */ + +#ifndef nsHashtable_h__ +#define nsHashtable_h__ + +#include "pldhash.h" +#include "prlock.h" +#include "nscore.h" +#include "nsString.h" +#include "nsISupportsBase.h" +#include "nsTraceRefcnt.h" + +class nsIObjectInputStream; +class nsIObjectOutputStream; + +class nsHashtable; +class nsStringKey; + +class NS_COM nsHashKey { + protected: + nsHashKey(void) { +#ifdef DEBUG + mKeyType = UnknownKey; +#endif + MOZ_COUNT_CTOR(nsHashKey); + } + + + public: + // Virtual destructor because all hash keys are |delete|d via a + // nsHashKey pointer. + + virtual ~nsHashKey(void); + virtual PRUint32 HashCode(void) const = 0; + virtual PRBool Equals(const nsHashKey *aKey) const = 0; + virtual nsHashKey *Clone() const = 0; + virtual nsresult Write(nsIObjectOutputStream* aStream) const; + +#ifdef DEBUG + public: + // used for verification that we're casting to the correct key type + enum nsHashKeyType { + UnknownKey, + SupportsKey, + PRUint32Key, + VoidKey, + IDKey, + CStringKey, + StringKey + }; + nsHashKeyType GetKeyType() const { return mKeyType; } + protected: + nsHashKeyType mKeyType; +#endif +}; + +// Enumerator and Read/Write callback functions. + +// Return values for nsHashtableEnumFunc +enum { + kHashEnumerateStop = PR_FALSE, + kHashEnumerateNext = PR_TRUE, + kHashEnumerateRemove = 2 +}; + +typedef PRIntn +(*PR_CALLBACK nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure); + +typedef nsresult +(*PR_CALLBACK nsHashtableReadEntryFunc)(nsIObjectInputStream *aStream, + nsHashKey **aKey, + void **aData); + +// NB: may be called with null aKey or aData, to free just one of the two. +typedef void +(*PR_CALLBACK nsHashtableFreeEntryFunc)(nsIObjectInputStream *aStream, + nsHashKey *aKey, + void *aData); + +typedef nsresult +(*PR_CALLBACK nsHashtableWriteDataFunc)(nsIObjectOutputStream *aStream, + void *aData); + +class NS_COM nsHashtable { + protected: + // members + PRLock* mLock; + PLDHashTable mHashtable; + PRBool mEnumerating; + + public: + nsHashtable(PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE); + virtual ~nsHashtable(); + + PRInt32 Count(void) { return mHashtable.entryCount; } + PRBool Exists(nsHashKey *aKey); + void *Put(nsHashKey *aKey, void *aData); + void *Get(nsHashKey *aKey); + void *Remove(nsHashKey *aKey); + nsHashtable *Clone(); + void Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure = NULL); + void Reset(); + void Reset(nsHashtableEnumFunc destroyFunc, void* aClosure = NULL); + + nsHashtable(nsIObjectInputStream* aStream, + nsHashtableReadEntryFunc aReadEntryFunc, + nsHashtableFreeEntryFunc aFreeEntryFunc, + nsresult *aRetVal); + nsresult Write(nsIObjectOutputStream* aStream, + nsHashtableWriteDataFunc aWriteDataFunc) const; +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be +// deleted + +typedef void* (*PR_CALLBACK nsHashtableCloneElementFunc)(nsHashKey *aKey, void *aData, void* aClosure); + +class NS_COM nsObjectHashtable : public nsHashtable { + public: + nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun, + void* cloneElementClosure, + nsHashtableEnumFunc destroyElementFun, + void* destroyElementClosure, + PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE); + ~nsObjectHashtable(); + + nsHashtable *Clone(); + void Reset(); + PRBool RemoveAndDelete(nsHashKey *aKey); + + protected: + static PLDHashOperator PR_CALLBACK CopyElement(PLDHashTable* table, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg); + + nsHashtableCloneElementFunc mCloneElementFun; + void* mCloneElementClosure; + nsHashtableEnumFunc mDestroyElementFun; + void* mDestroyElementClosure; +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsSupportsHashtable: an nsHashtable where the elements are nsISupports* + +class nsISupports; + +class NS_COM nsSupportsHashtable + : private nsHashtable +{ + public: + typedef PRBool (* PR_CALLBACK EnumFunc) (nsHashKey *aKey, void *aData, void* aClosure); + + nsSupportsHashtable(PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE) + : nsHashtable(aSize, threadSafe) {} + ~nsSupportsHashtable(); + + PRInt32 Count(void) { + return nsHashtable::Count(); + } + PRBool Exists(nsHashKey *aKey) { + return nsHashtable::Exists (aKey); + } + PRBool Put(nsHashKey *aKey, + nsISupports *aData, + nsISupports **value = nsnull); + nsISupports* Get(nsHashKey *aKey); + PRBool Remove(nsHashKey *aKey, nsISupports **value = nsnull); + nsHashtable *Clone(); + void Enumerate(EnumFunc aEnumFunc, void* aClosure = NULL) { + nsHashtable::Enumerate(aEnumFunc, aClosure); + } + void Reset(); + + private: + static PRBool PR_CALLBACK ReleaseElement(nsHashKey *, void *, void *); + static PLDHashOperator PR_CALLBACK EnumerateCopy(PLDHashTable*, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg); +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsISupportsKey: Where keys are nsISupports objects that get refcounted. + +#include "nsISupports.h" + +class NS_COM nsISupportsKey : public nsHashKey { + protected: + nsISupports* mKey; + + public: + nsISupportsKey(const nsISupportsKey& aKey) : mKey(aKey.mKey) { +#ifdef DEBUG + mKeyType = SupportsKey; +#endif + NS_IF_ADDREF(mKey); + } + + nsISupportsKey(nsISupports* key) { +#ifdef DEBUG + mKeyType = SupportsKey; +#endif + mKey = key; + NS_IF_ADDREF(mKey); + } + + ~nsISupportsKey(void) { + NS_IF_RELEASE(mKey); + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mKey); + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == SupportsKey, "mismatched key types"); + return (mKey == ((nsISupportsKey *) aKey)->mKey); + } + + nsHashKey *Clone() const { + return new nsISupportsKey(mKey); + } + + nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; +}; + + +class nsPRUint32Key : public nsHashKey { +protected: + PRUint32 mKey; +public: + nsPRUint32Key(PRUint32 key) { +#ifdef DEBUG + mKeyType = PRUint32Key; +#endif + mKey = key; + } + + PRUint32 HashCode(void) const { + return mKey; + } + + PRBool Equals(const nsHashKey *aKey) const { + return mKey == ((const nsPRUint32Key *) aKey)->mKey; + } + nsHashKey *Clone() const { + return new nsPRUint32Key(mKey); + } + PRUint32 GetValue() { return mKey; } +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsVoidKey: Where keys are void* objects that don't get refcounted. + +class nsVoidKey : public nsHashKey { + protected: + void* mKey; + + public: + nsVoidKey(const nsVoidKey& aKey) : mKey(aKey.mKey) { +#ifdef DEBUG + mKeyType = aKey.mKeyType; +#endif + } + + nsVoidKey(void* key) { +#ifdef DEBUG + mKeyType = VoidKey; +#endif + mKey = key; + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mKey); + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == VoidKey, "mismatched key types"); + return (mKey == ((const nsVoidKey *) aKey)->mKey); + } + + nsHashKey *Clone() const { + return new nsVoidKey(mKey); + } + + void* GetValue() { return mKey; } +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID). + +#include "nsID.h" + +class NS_COM nsIDKey : public nsHashKey { + protected: + nsID mID; + + public: + nsIDKey(const nsIDKey& aKey) : mID(aKey.mID) { +#ifdef DEBUG + mKeyType = IDKey; +#endif + } + + nsIDKey(const nsID &aID) { +#ifdef DEBUG + mKeyType = IDKey; +#endif + mID = aID; + } + + PRUint32 HashCode(void) const { + return mID.m0; + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == IDKey, "mismatched key types"); + return (mID.Equals(((const nsIDKey *) aKey)->mID)); + } + + nsHashKey *Clone() const { + return new nsIDKey(mID); + } + + nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#include "nsString.h" + +// for null-terminated c-strings +class NS_COM nsCStringKey : public nsHashKey { + public: + + // NB: when serializing, NEVER_OWN keys are deserialized as OWN. + enum Ownership { + NEVER_OWN, // very long lived, even clones don't need to copy it. + OWN_CLONE, // as long lived as this key. But clones make a copy. + OWN // to be free'd in key dtor. Clones make their own copy. + }; + + nsCStringKey(const nsCStringKey& aStrKey); + nsCStringKey(const char* str, PRInt32 strLen = -1, Ownership own = OWN_CLONE); + nsCStringKey(const nsAFlatCString& str); + nsCStringKey(const nsACString& str); + ~nsCStringKey(void); + + PRUint32 HashCode(void) const; + PRBool Equals(const nsHashKey* aKey) const; + nsHashKey* Clone() const; + nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; + + // For when the owner of the hashtable wants to peek at the actual + // string in the key. No copy is made, so be careful. + const char* GetString() const { return mStr; } + PRUint32 GetStringLength() const { return mStrLen; } + + protected: + char* mStr; + PRUint32 mStrLen; + Ownership mOwnership; +}; + +// for null-terminated unicode strings +class NS_COM nsStringKey : public nsHashKey { + public: + + // NB: when serializing, NEVER_OWN keys are deserialized as OWN. + enum Ownership { + NEVER_OWN, // very long lived, even clones don't need to copy it. + OWN_CLONE, // as long lived as this key. But clones make a copy. + OWN // to be free'd in key dtor. Clones make their own copy. + }; + + nsStringKey(const nsStringKey& aKey); + nsStringKey(const PRUnichar* str, PRInt32 strLen = -1, Ownership own = OWN_CLONE); + nsStringKey(const nsAFlatString& str); + nsStringKey(const nsAString& str); + ~nsStringKey(void); + + PRUint32 HashCode(void) const; + PRBool Equals(const nsHashKey* aKey) const; + nsHashKey* Clone() const; + nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; + + // For when the owner of the hashtable wants to peek at the actual + // string in the key. No copy is made, so be careful. + const PRUnichar* GetString() const { return mStr; } + PRUint32 GetStringLength() const { return mStrLen; } + + protected: + PRUnichar* mStr; + PRUint32 mStrLen; + Ownership mOwnership; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl b/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl new file mode 100644 index 00000000..c937ec4b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is XPCOM Array interface. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsISimpleEnumerator; + +/** + * nsIArray + * + * An indexed collection of elements. Provides basic functionality for + * retrieving elements at a specific position, searching for + * elements. Indexes are zero-based, such that the last element in the + * array is stored at the index length-1. + * + * For an array which can be modified, see nsIMutableArray below. + * + * Neither interface makes any attempt to protect the individual + * elements from modification. The convention is that the elements of + * the array should not be modified. Documentation within a specific + * interface should describe variations from this convention. + * + * It is also convention that if an interface provides access to an + * nsIArray, that the array should not be QueryInterfaced to an + * nsIMutableArray for modification. If the interface in question had + * intended the array to be modified, it would have returned an + * nsIMutableArray! + * + * null is a valid entry in the array, and as such any nsISupports + * parameters may be null, except where noted. + * + * @status UNDER_REVIEW + */ +[scriptable, uuid(114744d9-c369-456e-b55a-52fe52880d2d)] +interface nsIArray : nsISupports +{ + /** + * length + * + * number of elements in the array. + */ + readonly attribute unsigned long length; + + /** + * queryElementAt() + * + * Retrieve a specific element of the array, and QueryInterface it + * to the specified interface. null is a valid result for + * this method, but exceptions are thrown in other circumstances + * + * @param index position of element + * @param uuid the IID of the requested interface + * @param result the object, QI'd to the requested interface + * + * @throws NS_ERROR_NO_INTERFACE when an entry exists at the + * specified index, but the requested interface is not + * available. + * @throws NS_ERROR_ILLEGAL_VALUE when index > length-1 + * + */ + void queryElementAt(in unsigned long index, + in nsIIDRef uuid, + [iid_is(uuid), retval] out nsQIResult result); + + /** + * indexOf() + * + * Get the position of a specific element. Note that since null is + * a valid input, exceptions are used to indicate that an element + * is not found. + * + * @param startIndex The initial element to search in the array + * To start at the beginning, use 0 as the + * startIndex + * @param element The element you are looking for + * @returns a number >= startIndex which is the position of the + * element in the array. + * @throws NS_ERROR_NOT_FOUND if the element was not in the array. + */ + unsigned long indexOf(in unsigned long startIndex, + in nsISupports element); + + /** + * enumerate the array + * + * @returns a new enumerator positioned at the start of the array + * @throws NS_ERROR_FAILURE if the array is empty (to make it easy + * to detect errors) + */ + nsISimpleEnumerator enumerate(); + +}; + +/** + * nsIMutableArray + * A separate set of methods that will act on the array. Consumers of + * nsIArray should not QueryInterface to nsIMutableArray unless they + * own the array. + * + * As above, it is legal to add null elements to the array. Note also + * that null elements can be created as a side effect of + * insertElementAt(). Conversely, if insertElementAt() is never used, + * and null elements are never explicitly added to the array, then it + * is guaranteed that queryElementAt() will never return a null value. + * + * Any of these methods may throw NS_ERROR_OUT_OF_MEMORY when the + * array must grow to complete the call, but the allocation fails. + * + * @status UNDER_REVIEW + */ + +[scriptable, uuid(2cd0b2f8-d4dd-48b8-87ba-b0200501f079)] +interface nsIMutableArray : nsIArray +{ + /** + * appendElement() + * + * Append an element at the end of the array. + * + * @param element The element to append. + * @param element Whether or not to store the element using a weak + * reference. + * @throws NS_ERROR_UNEXPECTED when a weak reference is requested, + * but the element does not support + * nsIWeakReference. + */ + void appendElement(in nsISupports element, in boolean weak); + + /** + * removeElementAt() + * + * Remove an element at a specific position. + * To remove a specific element, use indexOf() to find the index + * first, then call removeElementAt(). + * + * @param index the position of the item + * + */ + void removeElementAt(in unsigned long index); + + /** + * insertElementAt() + * + * Insert an element at the given position, and move all elements + * stored at a higher position up one. + * + * @param element The element to insert + * @param index The position in the array. If the position is + * greater than or equal to the length of the array + * (@see nsIArray) then the array will grow to + * exactly accomadate the index, and the new length + * will be index+1. The newly created entries will + * be null. + * + * @throws NS_ERROR_FAILURE when a weak reference is requested, + * but the element does not support + * nsIWeakReference. + */ + void insertElementAt(in nsISupports element, in unsigned long index, in boolean weak); + + /** + * clear() + * + * clear the entire array, releasing all stored objects + */ + void clear(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl b/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl new file mode 100644 index 00000000..45eecb4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "nsISupports.idl" + +%{C++ +#include "nsAString.h" +#include "nsCOMPtr.h" +%} + +/* + * Should this really be scriptable? Using atoms from script or proxies + * could be dangerous since double-wrapping could lead to loss of + * pointer identity. + */ + +[scriptable, uuid(3d1b15b0-93b4-11d1-895b-006008911b81)] +interface nsIAtom : nsISupports +{ + /** + * Get the Unicode or UTF8 value for the string + */ + AString toString(); + AUTF8String toUTF8String(); + + /** + * Return a pointer to a zero terminated UTF8 string. + */ + [noscript] void getUTF8String([shared, retval] out string aResult); + + /** + * Compare the atom to a specific string value + * Note that this will NEVER return/throw an error condition. + */ + boolean equals(in AString aString); + + boolean equalsUTF8(in AUTF8String aString); + +%{C++ + // note this is NOT virtual so this won't muck with the vtable! + inline PRBool Equals(const nsAString& s) { + PRBool result; + Equals(s, &result); + return result; + } + + inline PRBool EqualsUTF8(const nsACString& s) { + PRBool result; + EqualsUTF8(s, &result); + return result; + } +%} + +}; + + +%{C++ +/* + * The three forms of NS_NewAtom and do_GetAtom (for use with + * |nsCOMPtr<nsIAtom>|) return the atom for the string given. At any + * given time there will always be one atom representing a given string. + * Atoms are intended to make string comparison cheaper by simplifying + * it to pointer equality. A pointer to the atom that does not own a + * reference is not guaranteed to be valid. + * + * The three forms of NS_NewPermanentAtom and do_GetPermanentAtom return + * the atom for the given string and ensure that the atom is permanent. + * An atom that is permanent will exist (occupy space at a specific + * location in memory) until XPCOM is shut down. The advantage of + * permanent atoms is that they do not need to maintain a reference + * count, which requires locking and hurts performance. + */ + + +/** + * Find an atom that matches the given UTF-8 string. + * The string is assumed to be zero terminated. + */ +extern NS_COM nsIAtom* NS_NewAtom(const char* aUTF8String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const char* aUTF8String); + +inline already_AddRefed<nsIAtom> do_GetAtom(const char* aUTF8String) + { return NS_NewAtom(aUTF8String); } +inline already_AddRefed<nsIAtom> do_GetPermanentAtom(const char* aUTF8String) + { return NS_NewPermanentAtom(aUTF8String); } + +/** + * Find an atom that matches the given UTF-8 string. + */ +extern NS_COM nsIAtom* NS_NewAtom(const nsACString& aUTF8String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsACString& aUTF8String); + +inline already_AddRefed<nsIAtom> do_GetAtom(const nsACString& aUTF8String) + { return NS_NewAtom(aUTF8String); } +inline already_AddRefed<nsIAtom> do_GetPermanentAtom(const nsACString& aUTF8String) + { return NS_NewPermanentAtom(aUTF8String); } + +/** + * Find an atom that matches the given UTF-16 string. + * The string is assumed to be zero terminated. + */ +extern NS_COM nsIAtom* NS_NewAtom(const PRUnichar* aUTF16String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const PRUnichar* aUTF16String); + +inline already_AddRefed<nsIAtom> do_GetAtom(const PRUnichar* aUTF16String) + { return NS_NewAtom(aUTF16String); } +inline already_AddRefed<nsIAtom> do_GetPermanentAtom(const PRUnichar* aUTF16String) + { return NS_NewPermanentAtom(aUTF16String); } + +/** + * Find an atom that matches the given UTF-16 string. + */ +extern NS_COM nsIAtom* NS_NewAtom(const nsAString& aUTF16String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsAString& aUTF16String); + +inline already_AddRefed<nsIAtom> do_GetAtom(const nsAString& aUTF16String) + { return NS_NewAtom(aUTF16String); } +inline already_AddRefed<nsIAtom> do_GetPermanentAtom(const nsAString& aUTF16String) + { return NS_NewPermanentAtom(aUTF16String); } + +/** + * Return a count of the total number of atoms currently + * alive in the system. + */ +extern NS_COM nsrefcnt NS_GetNumberOfAtoms(void); + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl b/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl new file mode 100644 index 00000000..b3a30358 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIAtom.idl" + +%{C++ +#define NS_ATOMSERVICE_CID \ +{ /* ed3db3fc-0168-4cab-8818-98f5475a490c */ \ + 0xed3db3fc, \ + 0x0168, \ + 0x4cab, \ + {0x88, 0x18, 0x98, 0xf5, 0x47, 0x5a, 0x49, 0x0c} } + +#define NS_ATOMSERVICE_CONTRACTID "@mozilla.org/atom-service;1" +#define NS_ATOMSERVICE_CLASSNAME "Atom Service" +%} + +/* + * Should this really be scriptable? Using atoms from script or proxies + * could be dangerous since double-wrapping could lead to loss of + * pointer identity. + */ + +[scriptable, uuid(e5d0d92b-ea45-4622-ab48-302baf2094ee)] +interface nsIAtomService : nsISupports { + + /** + * Version of NS_NewAtom that doesn't require linking against the + * XPCOM library. See nsIAtom.idl. + */ + nsIAtom getAtom(in wstring value); + + /** + * Version of NS_NewPermanentAtom that doesn't require linking against + * the XPCOM library. See nsIAtom.idl. + */ + nsIAtom getPermanentAtom(in wstring value); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h new file mode 100644 index 00000000..5d02c9cb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsIByteBuffer_h___ +#define nsIByteBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsIInputStream; + +#define NS_IBYTE_BUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } +#define NS_IBYTEBUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } +#define NS_BYTEBUFFER_CONTRACTID "@mozilla.org/byte-buffer;1" +#define NS_BYTEBUFFER_CLASSNAME "Byte Buffer" + +/** Interface to a buffer that holds bytes */ +class nsIByteBuffer : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFER_IID) + + NS_IMETHOD Init(PRUint32 aBufferSize) = 0; + + /** @return length of buffer, i.e. how many bytes are currently in it. */ + NS_IMETHOD_(PRUint32) GetLength(void) const = 0; + + /** @return number of bytes allocated in the buffer */ + NS_IMETHOD_(PRUint32) GetBufferSize(void) const = 0; + + /** @return the buffer */ + NS_IMETHOD_(char*) GetBuffer(void) const = 0; + + /** Grow buffer to aNewSize bytes. */ + NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize) = 0; + + /** Fill the buffer with data from aStream. Don't grow the buffer, only + * read until length of buffer equals buffer size. */ + NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep) = 0; +}; + +#define NS_BYTEBUFFER_CID \ +{ /* a49d5280-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xa49d5280, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +/** Create a new byte buffer using the given buffer size. */ +extern NS_COM nsresult +NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize = 0); + +#endif /* nsIByteBuffer_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl b/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl new file mode 100644 index 00000000..f97bf970 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl @@ -0,0 +1,92 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins <scc@mozilla.org>: |do_QueryElementAt| + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISerializable.idl" +#include "nsIEnumerator.idl" + +[scriptable, uuid(83b6019c-cbc4-11d2-8cca-0060b0fc14a3)] +interface nsICollection : nsISerializable +{ + + PRUint32 Count(); + nsISupports GetElementAt(in PRUint32 index); + void QueryElementAt(in PRUint32 index, in nsIIDRef uuid, + [iid_is(uuid),retval] out nsQIResult result); + void SetElementAt(in PRUint32 index, in nsISupports item); + void AppendElement(in nsISupports item); + void RemoveElement(in nsISupports item); + + nsIEnumerator Enumerate(); + + void Clear(); + +}; + +%{C++ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +class NS_COM nsQueryElementAt : public nsCOMPtr_helper + { + public: + nsQueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr ) + : mCollection(aCollection), + mIndex(aIndex), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsICollection* mCollection; + PRUint32 mIndex; + nsresult* mErrorPtr; + }; + +inline +const nsQueryElementAt +do_QueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr = 0 ) + { + return nsQueryElementAt(aCollection, aIndex, aErrorPtr); + } + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl new file mode 100644 index 00000000..7f8824b2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISimpleEnumerator.idl" + +%{C++ +#define NS_ENUMERATOR_FALSE 1 + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewEmptyEnumerator VBoxNsxpNS_NewEmptyEnumerator +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +extern "C" NS_COM nsresult +NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult); +%} +/* + * DO NOT USE THIS INTERFACE. IT IS HORRIBLY BROKEN, USES NS_COMFALSE + * AND IS BASICALLY IMPOSSIBLE TO USE CORRECTLY THROUGH PROXIES OR + * XPCONNECT. IF YOU SEE NEW USES OF THIS INTERFACE IN CODE YOU ARE + * REVIEWING, YOU SHOULD INSIST ON nsISimpleEnumerator. + * + * DON'T MAKE ME COME OVER THERE. + */ +[scriptable, uuid(ad385286-cbc4-11d2-8cca-0060b0fc14a3)] +interface nsIEnumerator : nsISupports { + /** First will reset the list. will return NS_FAILED if no items + */ + void first(); + + /** Next will advance the list. will return failed if already at end + */ + void next(); + + /** CurrentItem will return the CurrentItem item it will fail if the + * list is empty + */ + nsISupports currentItem(); + + /** return if the collection is at the end. that is the beginning following + * a call to Prev and it is the end of the list following a call to next + */ + void isDone(); +}; + +[uuid(75f158a0-cadd-11d2-8cca-0060b0fc14a3)] +interface nsIBidirectionalEnumerator : nsIEnumerator { + + /** Last will reset the list to the end. will return NS_FAILED if no items + */ + void last(); + + /** Prev will decrement the list. will return failed if already at beginning + */ + void prev(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl b/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl new file mode 100644 index 00000000..ca3c6598 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XPCOM. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg <benjamin@smedbergs.us>. + * + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Mozilla Foundation <http://www.mozilla.org/>. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/** + * Represents an object that can be stored in a hashtable. + */ + +[scriptable, uuid(17e595fa-b57a-4933-bd0f-b1812e8ab188)] +interface nsIHashable : nsISupports +{ + /** + * Is this object the equivalent of the other object? + */ + boolean equals(in nsIHashable aOther); + + /** + * A generated hashcode for this object. Objects that are equivalent + * must have the same hash code. Getting this property should never + * throw an exception! + */ + readonly attribute unsigned long hashCode; +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl b/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl new file mode 100644 index 00000000..d2240f2e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/** + * This interface is implemented by an object that wants + * to observe an event corresponding to a topic. + * + * @status FROZEN + */ + +[scriptable, uuid(DB242E01-E4D9-11d2-9DDE-000064657374)] +interface nsIObserver : nsISupports { + + /** + * Observe will be called when there is a notification for the + * topic |aTopic|. This assumes that the object implementing + * this interface has been registered with an observer service + * such as the nsIObserverService. + * + * If you expect multiple topics/subjects, the impl is + * responsible for filtering. + * + * You should not modify, add, remove, or enumerate + * notifications in the implemention of observe. + * + * @param aSubject : Notification specific interface pointer. + * @param aTopic : The notification topic or subject. + * @param aData : Notification specific wide string. + * subject event. + */ + void observe( in nsISupports aSubject, + in string aTopic, + in wstring aData ); + +}; + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl b/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl new file mode 100644 index 00000000..059a903a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIObserver; +interface nsISimpleEnumerator; + +/** + * nsIObserverService + * + * Service allows a client listener (nsIObserver) to register and unregister for + * notifications of specific string referenced topic. Service also provides a + * way to notify registered listeners and a way to enumerate registered client + * listeners. + * + * @status FROZEN + */ + +[scriptable, uuid(D07F5192-E3D1-11d2-8ACD-00105A1B8860)] +interface nsIObserverService : nsISupports +{ + + /** + * AddObserver + * + * Registers a given listener for a notifications regarding the specified + * topic. + * + * @param anObserve : The interface pointer which will receive notifications. + * @param aTopic : The notification topic or subject. + * @param ownsWeak : If set to false, the nsIObserverService will hold a + * strong reference to |anObserver|. If set to true and + * |anObserver| supports the nsIWeakReference interface, + * a weak reference will be held. Otherwise an error will be + * returned. + */ + void addObserver( in nsIObserver anObserver, in string aTopic, in boolean ownsWeak); + + /** + * removeObserver + * + * Unregisters a given listener from notifications regarding the specified + * topic. + * + * @param anObserver : The interface pointer which will stop recieving + * notifications. + * @param aTopic : The notification topic or subject. + */ + void removeObserver( in nsIObserver anObserver, in string aTopic ); + + /** + * notifyObservers + * + * Notifies all registered listeners of the given topic. + * + * @param aSubject : Notification specific interface pointer. + * @param aTopic : The notification topic or subject. + * @param someData : Notification specific wide string. + */ + void notifyObservers( in nsISupports aSubject, + in string aTopic, + in wstring someData ); + + /** + * enumerateObservers + * + * Returns an enumeration of all registered listeners. + * + * @param aTopic : The notification topic or subject. + */ + nsISimpleEnumerator enumerateObservers( in string aTopic ); + + +}; + + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h new file mode 100644 index 00000000..773a52ad --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h @@ -0,0 +1,8 @@ + +#ifndef __gen_nsIPersistentProperties_h__ +#define __gen_nsIPersistentProperties_h__ + +// "soft" switch over to an IDL generated header file +#include "nsIPersistentProperties2.h" + +#endif /* __gen_nsIPersistentProperties_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl new file mode 100644 index 00000000..3d935621 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" +#include "nsIProperties.idl" +#include "nsISimpleEnumerator.idl" + +interface nsIInputStream; +interface nsIOutputStream; + +[scriptable, uuid(283EE646-1AEF-11D4-98B3-00C04fA0CE9A)] +interface nsIPropertyElement : nsISupports { + attribute AUTF8String key; + attribute AString value; +}; + +[scriptable, uuid(1A180F60-93B2-11d2-9B8B-00805F8A16D9)] +interface nsIPersistentProperties : nsIProperties +{ + /** + * load a set of name/value pairs from the input stream + * names and values should be in UTF8 + */ + void load(in nsIInputStream input); + + /** + * output the values to the stream - results will be in UTF8 + */ + void save(in nsIOutputStream output, in AUTF8String header); + + /** + * call subclass() to make future calls to load() set the properties + * in this "superclass" instead + */ + void subclass(in nsIPersistentProperties superclass); + + /** + * get an enumeration of nsIPropertyElement objects, + * which are read-only (i.e. setting properties on the element will + * not make changes back into the source nsIPersistentProperties + */ + nsISimpleEnumerator enumerate(); + + /** + * shortcut to nsIProperty's get() which retrieves a string value + * directly (and thus faster) + */ + AString getStringProperty(in AUTF8String key); + + /** + * shortcut to nsIProperty's set() which sets a string value + * directly (and thus faster) + */ + AString setStringProperty(in AUTF8String key, in AString value); +}; + + +%{C++ + +//{283EE645-1AEF-11D4-98B3-00C04fA0CE9A} +#define NS_IPROPERTYELEMENT_CID \ +{ 0x283ee645, 0x1aef, 0x11d4, \ + { 0x98, 0xb3, 0x0, 0xc0, 0x4f, 0xa0, 0xce, 0x9a } } + +#define NS_IPERSISTENTPROPERTIES_CID \ +{ 0x2245e573, 0x9464, 0x11d2, \ + { 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } } + +#define NS_PERSISTENTPROPERTIES_CONTRACTID "@mozilla.org/persistent-properties;1" +#define NS_PERSISTENTPROPERTIES_CLASSNAME "Persistent Properties" + +%} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl b/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl new file mode 100644 index 00000000..32a2a057 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl @@ -0,0 +1,79 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/* + * Simple mapping service interface. + * @status FROZEN + */ + +[scriptable, uuid(78650582-4e93-4b60-8e85-26ebd3eb14ca)] +interface nsIProperties : nsISupports +{ + /** + * Gets a property with a given name. + * + * @return NS_ERROR_FAILURE if a property with that name doesn't exist. + * @return NS_ERROR_NO_INTERFACE if the found property fails to QI to the + * given iid. + */ + void get(in string prop, in nsIIDRef iid, + [iid_is(iid),retval] out nsQIResult result); + + /** + * Sets a property with a given name to a given value. + */ + void set(in string prop, in nsISupports value); + + /** + * Returns true if the property with the given name exists. + */ + boolean has(in string prop); + + /** + * Undefines a property. + * @return NS_ERROR_FAILURE if a property with that name doesn't + * already exist. + */ + void undefine(in string prop); + + /** + * Returns an array of the keys. + */ + void getKeys(out PRUint32 count, [array, size_is(count), retval] out string keys); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl b/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl new file mode 100644 index 00000000..b54577ff --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl @@ -0,0 +1,77 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer <jband@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* nsIVariant based Property Bag support. */ + +#include "nsISupports.idl" +#include "nsIVariant.idl" +#include "nsISimpleEnumerator.idl" + +[scriptable, uuid(6dcf9030-a49f-11d5-910d-0010a4e73d9a)] +interface nsIProperty : nsISupports +{ + /** + * Get the name of the property. + */ + readonly attribute AString name; + + /** + * Get the value of the property. + */ + readonly attribute nsIVariant value; +}; + +[scriptable, uuid(bfcd37b0-a49f-11d5-910d-0010a4e73d9a)] +interface nsIPropertyBag : nsISupports +{ + /** + * Get a nsISimpleEnumerator whose elements are nsIProperty objects. + */ + readonly attribute nsISimpleEnumerator enumerator; + + /** + * Get a property value for the given name. + * @return NS_ERROR_FAILURE if a property with that name doesn't + * exist. + */ + nsIVariant getProperty(in AString name); +}; + +// We can add nsIWritableProperty and nsIWritablePropertyBag when we need them. + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl new file mode 100644 index 00000000..5402890e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi <dp@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIMemory.idl" + +/** + * + * nsIRecyclingAllocator: A wrapper for the nsRecyclingAllocator + * + * Holds allocations and reuses them for subsequent allocs. + * Thread safe and uses a timer to release freelist. + * + * @status UNDER-DEVELOPMENT + */ + +[scriptable, uuid(d064a04c-9cee-4319-be31-64d565bccba9)] +interface nsIRecyclingAllocator : nsIMemory +{ + void init(in size_t nblocks, in size_t recycleAfter, in string id); +}; + +%{C++ +#define NS_RECYCLINGALLOCATOR_CID \ +{ /* ac07ed4c-bf17-4976-a15c-d2194db3b1bf */ \ + 0xac07ed4c, \ + 0xbf17, \ + 0x4976, \ + {0xa1, 0x5c, 0xd2, 0x19, 0x4d, 0xb3, 0xb1, 0xbf} } + +#define NS_RECYCLINGALLOCATOR_CLASSNAME "Recycling Allocator" + +#define NS_RECYCLINGALLOCATOR_CONTRACTID "@mozilla.org/recycling-allocator;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl b/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl new file mode 100644 index 00000000..907c4824 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich <brendan@mozilla.org> (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIObjectInputStream; +interface nsIObjectOutputStream; + +[scriptable, uuid(91cca981-c26d-44a8-bebe-d9ed4891503a)] +interface nsISerializable : nsISupports +{ + /** + * Initialize the object implementing nsISerializable, which must have + * been freshly constructed via CreateInstance. All data members that + * can't be set to default values must have been serialized by write, + * and should be read from aInputStream in the same order by this method. + */ + void read(in nsIObjectInputStream aInputStream); + + /** + * Serialize the object implementing nsISerializable to aOutputStream, by + * writing each data member that must be recovered later to reconstitute + * a working replica of this object, in a canonical member and byte order, + * to aOutputStream. + * + * NB: a class that implements nsISerializable *must* also implement + * nsIClassInfo, in particular nsIClassInfo::GetClassID. + */ + void write(in nsIObjectOutputStream aOutputStream); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl new file mode 100644 index 00000000..3f0efbf5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/** + * Used to enumerate over elements defined by its implementor. + * Although hasMoreElements() can be called independently of getNext(), + * getNext() must be pre-ceeded by a call to hasMoreElements(). There is + * no way to "reset" an enumerator, once you obtain one. + * + * @status FROZEN + * @version 1.0 + */ + +[scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)] +interface nsISimpleEnumerator : nsISupports { + /** + * Called to determine whether or not the enumerator has + * any elements that can be returned via getNext(). This method + * is generally used to determine whether or not to initiate or + * continue iteration over the enumerator, though it can be + * called without subsequent getNext() calls. Does not affect + * internal state of enumerator. + * + * @see getNext() + * @return PR_TRUE if there are remaining elements in the enumerator. + * PR_FALSE if there are no more elements in the enumerator. + */ + boolean hasMoreElements(); + + /** + * Called to retrieve the next element in the enumerator. The "next" + * element is the first element upon the first call. Must be + * pre-ceeded by a call to hasMoreElements() which returns PR_TRUE. + * This method is generally called within a loop to iterate over + * the elements in the enumerator. + * + * @see hasMoreElements() + * @return NS_OK if the call succeeded in returning a non-null + * value through the out parameter. + * NS_ERROR_FAILURE if there are no more elements + * to enumerate. + * @return the next element in the enumeration. + */ + nsISupports getNext(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl new file mode 100644 index 00000000..a7ac9131 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl @@ -0,0 +1,58 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/** + * Used to enumerate over an ordered list of strings. + */ + +[scriptable, uuid(50d3ef6c-9380-4f06-9fb2-95488f7d141c)] +interface nsIStringEnumerator : nsISupports +{ + boolean hasMore(); + AString getNext(); +}; + +[scriptable, uuid(9bdf1010-3695-4907-95ed-83d0410ec307)] +interface nsIUTF8StringEnumerator : nsISupports +{ + boolean hasMore(); + AUTF8String getNext(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl new file mode 100644 index 00000000..bce9f4bf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "nsISupports.idl" +#include "nsICollection.idl" + +/* + * This entire interface is deprecated and should not be used. + * See nsIArray and nsIMutableArray for the new implementations. + * + * http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=3D779491.3050506%40netscape.com&rnum=2 + * http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=al8412%245ab2%40ripley.netscape.com&rnum=8 + */ + +native nsISupportsArrayEnumFunc(nsISupportsArrayEnumFunc); + +%{C++ + +class nsIBidirectionalEnumerator; + +#define NS_SUPPORTSARRAY_CID \ +{ /* bda17d50-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xbda17d50, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} +#define NS_SUPPORTSARRAY_CONTRACTID "@mozilla.org/supports-array;1" +#define NS_SUPPORTSARRAY_CLASSNAME "Supports Array" + +// Enumerator callback function. Return PR_FALSE to stop +typedef PRBool (*nsISupportsArrayEnumFunc)(nsISupports* aElement, void *aData); + +%} + +[scriptable, uuid(791eafa0-b9e6-11d1-8031-006008159b5a)] +interface nsISupportsArray : nsICollection { + + [notxpcom] boolean Equals([const] in nsISupportsArray other); + + [notxpcom] nsISupports ElementAt(in unsigned long aIndex); + + [notxpcom] long IndexOf([const] in nsISupports aPossibleElement); + [notxpcom] long IndexOfStartingAt([const] in nsISupports aPossibleElement, + in unsigned long aStartIndex); + [notxpcom] long LastIndexOf([const] in nsISupports aPossibleElement); + + // xpcom-compatible versions + long GetIndexOf(in nsISupports aPossibleElement); + long GetIndexOfStartingAt(in nsISupports aPossibleElement, + in unsigned long aStartIndex); + long GetLastIndexOf(in nsISupports aPossibleElement); + + [notxpcom] boolean InsertElementAt(in nsISupports aElement, + in unsigned long aIndex); + [notxpcom] boolean ReplaceElementAt(in nsISupports aElement, + in unsigned long aIndex); + + [notxpcom] boolean RemoveElementAt(in unsigned long aIndex); + [notxpcom] boolean RemoveLastElement([const] in nsISupports aElement); + + // xpcom-compatible versions + void DeleteLastElement(in nsISupports aElement); + void DeleteElementAt(in unsigned long aIndex); + + [notxpcom] boolean AppendElements(in nsISupportsArray aElements); + + void Compact(); + + [notxpcom, noscript] + boolean EnumerateForwards(in nsISupportsArrayEnumFunc aFunc, + in voidPtr aData); + [notxpcom, noscript] + boolean EnumerateBackwards(in nsISupportsArrayEnumFunc aFunc, + in voidPtr aData); + + nsISupportsArray clone(); + + [notxpcom] boolean MoveElement(in long aFrom, + in long aTo); + + [notxpcom] boolean InsertElementsAt(in nsISupportsArray aOther, + in unsigned long aIndex); + + [notxpcom] boolean RemoveElementsAt(in unsigned long aIndex, + in unsigned long aCount); + + [notxpcom] boolean SizeTo(in long aSize); + +}; + +%{C++ + +// Construct and return a default implementation of nsISupportsArray: +extern NS_COM nsresult +NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult); + +// Construct and return a default implementation of an enumerator for nsISupportsArrays: +extern NS_COM nsresult +NS_NewISupportsArrayEnumerator(nsISupportsArray* array, + nsIBidirectionalEnumerator* *aInstancePtrResult); + + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl new file mode 100644 index 00000000..f1d8bce1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins <scc@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* nsISupportsIterators.idl --- IDL defining general purpose iterators */ + + +#include "nsISupports.idl" + + + /* + ... + */ + + + /** + * ... + */ +[scriptable, uuid(7330650e-1dd2-11b2-a0c2-9ff86ee97bed)] +interface nsIOutputIterator : nsISupports + { + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + }; + + /** + * ... + */ +[scriptable, uuid(85585e12-1dd2-11b2-a930-f6929058269a)] +interface nsIInputIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(8da01646-1dd2-11b2-98a7-c7009045be7e)] +interface nsIForwardIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(948defaa-1dd1-11b2-89f6-8ce81f5ebda9)] +interface nsIBidirectionalIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Move this iterator to the previous position in the underlying container or sequence. + */ + void stepBackward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(9bd6fdb0-1dd1-11b2-9101-d15375968230)] +interface nsIRandomAccessIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Retrieve (and |AddRef()|) an element at some offset from where this iterator currently points. + * The offset may be negative. |getElementAt(0)| is equivalent to |getElement()|. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + * @result a new reference to the indicated element (if any) + */ + nsISupports getElementAt( in PRInt32 anOffset ); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position |anOffset| away from that currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * |putElementAt(0, obj)| is equivalent to |putElement(obj)|. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElementAt( in PRInt32 anOffset, in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Move this iterator by |anOffset| positions in the underlying container or sequence. + * |anOffset| may be negative. |stepForwardBy(1)| is equivalent to |stepForward()|. + * |stepForwardBy(0)| is a no-op. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + */ + void stepForwardBy( in PRInt32 anOffset ); + + /** + * Move this iterator to the previous position in the underlying container or sequence. + */ + void stepBackward(); + + /** + * Move this iterator backwards by |anOffset| positions in the underlying container or sequence. + * |anOffset| may be negative. |stepBackwardBy(1)| is equivalent to |stepBackward()|. + * |stepBackwardBy(n)| is equivalent to |stepForwardBy(-n)|. |stepBackwardBy(0)| is a no-op. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + */ + void stepBackwardBy( in PRInt32 anOffset ); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + +%{C++ +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl new file mode 100644 index 00000000..680e5599 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl @@ -0,0 +1,304 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen <dr@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* nsISupports wrappers for single primitive pieces of data. */ + +#include "nsISupports.idl" + +/** + * Primitive base interface. + * + * These first three are pointer types and do data copying + * using the nsIMemory. Be careful! + * + * @status FROZEN + */ + +[scriptable, uuid(d0d4b136-1dd1-11b2-9371-f0727ef827c0)] +interface nsISupportsPrimitive : nsISupports +{ + const unsigned short TYPE_ID = 1; + const unsigned short TYPE_CSTRING = 2; + const unsigned short TYPE_STRING = 3; + const unsigned short TYPE_PRBOOL = 4; + const unsigned short TYPE_PRUINT8 = 5; + const unsigned short TYPE_PRUINT16 = 6; + const unsigned short TYPE_PRUINT32 = 7; + const unsigned short TYPE_PRUINT64 = 8; + const unsigned short TYPE_PRTIME = 9; + const unsigned short TYPE_CHAR = 10; + const unsigned short TYPE_PRINT16 = 11; + const unsigned short TYPE_PRINT32 = 12; + const unsigned short TYPE_PRINT64 = 13; + const unsigned short TYPE_FLOAT = 14; + const unsigned short TYPE_DOUBLE = 15; + const unsigned short TYPE_VOID = 16; + const unsigned short TYPE_INTERFACE_POINTER = 17; + + readonly attribute unsigned short type; +}; + +/** + * Scriptable storage for nsID structures + * + * @status FROZEN + */ + +[scriptable, uuid(d18290a0-4a1c-11d3-9890-006008962422)] +interface nsISupportsID : nsISupportsPrimitive +{ + attribute nsIDPtr data; + string toString(); +}; + +/** + * Scriptable storage for ASCII strings + * + * @status FROZEN + */ + +[scriptable, uuid(d65ff270-4a1c-11d3-9890-006008962422)] +interface nsISupportsCString : nsISupportsPrimitive +{ + attribute ACString data; + string toString(); +}; + +/** + * Scriptable storage for Unicode strings + * + * @status FROZEN + */ + +[scriptable, uuid(d79dc970-4a1c-11d3-9890-006008962422)] +interface nsISupportsString : nsISupportsPrimitive +{ + attribute AString data; + wstring toString(); +}; + +/** + * The rest are truly primitive and are passed by value + */ + +/** + * Scriptable storage for booleans + * + * @status FROZEN + */ + +[scriptable, uuid(ddc3b490-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRBool : nsISupportsPrimitive +{ + attribute PRBool data; + string toString(); +}; + +/** + * Scriptable storage for 8-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(dec2e4e0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint8 : nsISupportsPrimitive +{ + attribute PRUint8 data; + string toString(); +}; + +/** + * Scriptable storage for unsigned 16-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(dfacb090-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint16 : nsISupportsPrimitive +{ + attribute PRUint16 data; + string toString(); +}; + +/** + * Scriptable storage for unsigned 32-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e01dc470-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint32 : nsISupportsPrimitive +{ + attribute PRUint32 data; + string toString(); +}; + +/** + * Scriptable storage for 64-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e13567c0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint64 : nsISupportsPrimitive +{ + attribute PRUint64 data; + string toString(); +}; + +/** + * Scriptable storage for NSPR date/time values + * + * @status FROZEN + */ + +[scriptable, uuid(e2563630-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRTime : nsISupportsPrimitive +{ + attribute PRTime data; + string toString(); +}; + +/** + * Scriptable storage for single character values + * (often used to store an ASCII character) + * + * @status FROZEN + */ + +[scriptable, uuid(e2b05e40-4a1c-11d3-9890-006008962422)] +interface nsISupportsChar : nsISupportsPrimitive +{ + attribute char data; + string toString(); +}; + +/** + * Scriptable storage for 16-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e30d94b0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt16 : nsISupportsPrimitive +{ + attribute PRInt16 data; + string toString(); +}; + +/** + * Scriptable storage for 32-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e36c5250-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt32 : nsISupportsPrimitive +{ + attribute PRInt32 data; + string toString(); +}; + +/** + * Scriptable storage for 64-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e3cb0ff0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt64 : nsISupportsPrimitive +{ + attribute PRInt64 data; + string toString(); +}; + +/** + * Scriptable storage for floating point numbers + * + * @status FROZEN + */ + +[scriptable, uuid(abeaa390-4ac0-11d3-baea-00805f8a5dd7)] +interface nsISupportsFloat : nsISupportsPrimitive +{ + attribute float data; + string toString(); +}; + +/** + * Scriptable storage for doubles + * + * @status FROZEN + */ + +[scriptable, uuid(b32523a0-4ac0-11d3-baea-00805f8a5dd7)] +interface nsISupportsDouble : nsISupportsPrimitive +{ + attribute double data; + string toString(); +}; + +/** + * Scriptable storage for generic pointers + * + * @status FROZEN + */ + +[scriptable, uuid(464484f0-568d-11d3-baf8-00805f8a5dd7)] +interface nsISupportsVoid : nsISupportsPrimitive +{ + [noscript] attribute voidPtr data; + string toString(); +}; + +/** + * Scriptable storage for other XPCOM objects + * + * @status FROZEN + */ + +[scriptable, uuid(995ea724-1dd1-11b2-9211-c21bdd3e7ed0)] +interface nsISupportsInterfacePointer : nsISupportsPrimitive +{ + attribute nsISupports data; + attribute nsIDPtr dataIID; + + string toString(); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl b/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl new file mode 100644 index 00000000..f0495a35 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl @@ -0,0 +1,242 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +%{C++ +#ifdef MOZ_TIMELINE +%} + +/** + * nsITimelineService is used to constuct a timeline of program + * execution. The timeline is output to a file, either stderr or the + * value of the environment variable NS_TIMELINE_LOG_FILE. On the + * Mac, the timeline is output to the file named "timeline.txt". The + * reason it's different on the Mac is that the Mac environment + * initialization code happens after timeline initialization code. + * + * If NS_TIMELINE_INIT_TIME is set in the environment, that will be + * used as the time of startup; otherwise the current time when mark() + * is first called will be used. + * + * mark() is used to put marks on the timeline. + * + * indent() and outdent() are used to format the timeline a bit to + * show nesting. This doesn't produce perfect results in the face of + * asychrony and multiple threads. + * + * enter() and leave() are convenience functions that add marks to the + * timeline and do indentation. + * + * startTimer() and stopTimer() control named stop watches. If + * startTimer() is called more than once, an equal number of + * stopTimer() calls are needed to actually stop the timer. This + * makes these timers slightly useful in a threaded environment. + * + * markTimer() puts a mark on the timeline containing the total for + * the named timer. + * + * Don't use nsITimelineService in C++ code; use the NS_TIMELINE + * macros instead. nsITimelineService exists so that JavaScript code + * can mark the timeline. + */ +[scriptable, uuid(93276790-3daf-11d5-b67d-000064657374)] +interface nsITimelineService : nsISupports +{ + /** + * mark() + * Print "<elapsed time>: <text>\n" in the timeline log file. + */ + void mark(in string text); + + /** + * causes subsequent marks to be indented for a more readable + * report. + */ + void indent(); + + /** + * Causes subsequent marks to be outdented. + */ + void outdent(); + + /** + * enter/leave bracket code with "<text>..." and "...<text>" as + * well as indentation. + */ + void enter(in string text); + void leave(in string text); + + void startTimer(in string timerName); + + void stopTimer(in string timerName); + + void markTimer(in string timerName); + + void resetTimer(in string timerName); + + // Mark a timer, plus an additional comment + void markTimerWithComment(in string timerName, in string comment); +}; + +%{C++ +#endif /* MOZ_TIMELINE */ +%} + + +%{C++ + +#ifdef MOZ_TIMELINE + +/* + * These are equivalent to the corresponding nsITimelineService + * methods, and can be called before XPCOM is initialized. + */ +extern "C" NS_COM nsresult NS_TimelineMark(const char *text, ...); +extern "C" NS_COM nsresult NS_TimelineForceMark(const char *text, ...); +extern "C" NS_COM nsresult NS_TimelineStartTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineStopTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineResetTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineMarkTimer(const char *timerName, const char *str=nsnull); +extern "C" NS_COM nsresult NS_TimelineIndent(); +extern "C" NS_COM nsresult NS_TimelineOutdent(); +extern "C" NS_COM nsresult NS_TimelineEnter(const char *text); +extern "C" NS_COM nsresult NS_TimelineLeave(const char *text); + +/* + * Use these macros for the above calls so we can easily compile them + * out. + */ +#define NS_TIMELINE_MARK(text) NS_TimelineMark(text) +#define NS_TIMELINE_MARKV(args) NS_TimelineMark args +#define NS_TIMELINE_INDENT() NS_TimelineIndent() +#define NS_TIMELINE_OUTDENT() NS_TimelineOutdent() +#define NS_TIMELINE_ENTER(text) NS_TimelineEnter(text) +#define NS_TIMELINE_LEAVE(text) NS_TimelineLeave(text) +#define NS_TIMELINE_START_TIMER(timerName) NS_TimelineStartTimer(timerName) +#define NS_TIMELINE_STOP_TIMER(timerName) NS_TimelineStopTimer(timerName) +#define NS_TIMELINE_MARK_TIMER(timerName) NS_TimelineMarkTimer(timerName) +#define NS_TIMELINE_RESET_TIMER(timerName) NS_TimelineResetTimer(timerName) +#define NS_TIMELINE_MARK_TIMER1(timerName, str) NS_TimelineMarkTimer(timerName, str) + +/* + * Helper class to time functions. Use only static strings. + */ +class nsFunctionTimer { +public: + const char *mTimer; + PRBool mMark; + const char *mMarkStr; + nsFunctionTimer(const char *timer, PRBool mark = PR_TRUE, const char *markStr = nsnull) + : mTimer(timer), mMark(mark), mMarkStr(markStr) + { + NS_TIMELINE_START_TIMER(mTimer); + } + + ~nsFunctionTimer() + { + NS_TIMELINE_STOP_TIMER(mTimer); + if (mMark) + if (mMarkStr) + NS_TIMELINE_MARK_TIMER1(mTimer, mMarkStr); + else + NS_TIMELINE_MARK_TIMER(mTimer); + } +}; + +/* + * NS_TIMELINE_MARK_ macros for various data types. Each of these + * macros replaces "%s" in its "text" argument with a string + * representation of its last argument. + * + * Please feel free to add more NS_TIMELINE_MARK_ macros for + * various data types so that code using NS_TIMELINE is uncluttered. + * Don't forget the empty versions in the #else section below for + * non-timeline builds. + */ +#define NS_TIMELINE_MARK_URI(text, uri) \ + { \ + nsCAutoString spec; \ + if (uri) { \ + uri->GetSpec(spec); \ + } \ + if (!spec.IsEmpty()) { \ + NS_TimelineMark(text, spec.get()); \ + } else { \ + NS_TimelineMark(text, "??"); \ + } \ + } + +#define NS_TIMELINE_MARK_CHANNEL(text, channel) \ + { \ + nsCOMPtr<nsIURI> uri; \ + if (channel) { \ + channel->GetURI(getter_AddRefs(uri)); \ + } \ + NS_TIMELINE_MARK_URI(text, uri); \ + } + +#define NS_TIMELINE_MARK_LOADER(text, loader) \ + { \ + nsCOMPtr<nsIRequest> request; \ + loader->GetRequest(getter_AddRefs(request)); \ + nsCOMPtr<nsIChannel> channel(do_QueryInterface(request)); \ + NS_TIMELINE_MARK_CHANNEL(text, channel); \ + } +#define NS_TIMELINE_MARK_FUNCTION(timer) nsFunctionTimer functionTimer(timer) +#define NS_TIMELINE_MARK_FUNCTION1(timer, str) nsFunctionTimer functionTimer(timer, PR_TRUE, str) +#define NS_TIMELINE_TIME_FUNCTION(timer) nsFunctionTimer functionTimer(timer, PR_FALSE) /* no mark, only time */ + +#else /* !defined(MOZ_TIMELINE) */ +#define NS_TIMELINE_MARK(text) +#define NS_TIMELINE_MARKV(args) +#define NS_TIMELINE_INDENT() +#define NS_TIMELINE_OUTDENT() +#define NS_TIMELINE_START_TIMER(timerName) +#define NS_TIMELINE_STOP_TIMER(timerName) +#define NS_TIMELINE_MARK_TIMER(timerName) +#define NS_TIMELINE_RESET_TIMER(timerName) +#define NS_TIMELINE_MARK_TIMER1(timerName, str) +#define NS_TIMELINE_ENTER(text) +#define NS_TIMELINE_LEAVE(text) +#define NS_TIMELINE_MARK_URI(text, uri) +#define NS_TIMELINE_MARK_FUNCTION(timer) +#define NS_TIMELINE_TIME_FUNCTION(timer) +#define NS_TIMELINE_MARK_CHANNEL(text, channel) +#define NS_TIMELINE_MARK_LOADER(text, loader); +#endif /* defined(MOZ_TIMELINE) */ +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h new file mode 100644 index 00000000..dae89021 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsIUnicharBuffer_h___ +#define nsIUnicharBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +#define NS_IUNICHARBUFFER_IID \ +{ 0x14cf6970, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/// Interface to a buffer that holds unicode characters +class nsIUnicharBuffer : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IUNICHARBUFFER_IID); + + NS_IMETHOD Init(PRUint32 aBufferSize) = 0; + NS_IMETHOD_(PRInt32) GetLength() const = 0; + NS_IMETHOD_(PRInt32) GetBufferSize() const = 0; + NS_IMETHOD_(PRUnichar*) GetBuffer() const = 0; + NS_IMETHOD_(PRBool) Grow(PRInt32 aNewSize) = 0; +}; + +/// Factory method for nsIUnicharBuffer. +extern NS_COM nsresult +NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize = 0); + +#define NS_UNICHARBUFFER_CID \ +{ /* c81fd8f0-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xc81fd8f0, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +#endif /* nsIUnicharBuffer_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl b/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl new file mode 100644 index 00000000..2c9d9e96 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl @@ -0,0 +1,188 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer <jband@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsISupports.idl" + +[scriptable,uuid(4d12e540-83d7-11d5-90ed-0010a4e73d9a)] +interface nsIDataType : nsISupports +{ + // These MUST match the declarations in xpt_struct.h. + // Otherwise the world is likely to explode. + // From xpt_struct.h ... + const PRUint16 VTYPE_INT8 = 0; // TD_INT8 = 0, + const PRUint16 VTYPE_INT16 = 1; // TD_INT16 = 1, + const PRUint16 VTYPE_INT32 = 2; // TD_INT32 = 2, + const PRUint16 VTYPE_INT64 = 3; // TD_INT64 = 3, + const PRUint16 VTYPE_UINT8 = 4; // TD_UINT8 = 4, + const PRUint16 VTYPE_UINT16 = 5; // TD_UINT16 = 5, + const PRUint16 VTYPE_UINT32 = 6; // TD_UINT32 = 6, + const PRUint16 VTYPE_UINT64 = 7; // TD_UINT64 = 7, + const PRUint16 VTYPE_FLOAT = 8; // TD_FLOAT = 8, + const PRUint16 VTYPE_DOUBLE = 9; // TD_DOUBLE = 9, + const PRUint16 VTYPE_BOOL = 10; // TD_BOOL = 10, + const PRUint16 VTYPE_CHAR = 11; // TD_CHAR = 11, + const PRUint16 VTYPE_WCHAR = 12; // TD_WCHAR = 12, + const PRUint16 VTYPE_VOID = 13; // TD_VOID = 13, + const PRUint16 VTYPE_ID = 14; // TD_PNSIID = 14, + const PRUint16 VTYPE_DOMSTRING = 15; // TD_DOMSTRING = 15, + const PRUint16 VTYPE_CHAR_STR = 16; // TD_PSTRING = 16, + const PRUint16 VTYPE_WCHAR_STR = 17; // TD_PWSTRING = 17, + const PRUint16 VTYPE_INTERFACE = 18; // TD_INTERFACE_TYPE = 18, + const PRUint16 VTYPE_INTERFACE_IS = 19; // TD_INTERFACE_IS_TYPE = 19, + const PRUint16 VTYPE_ARRAY = 20; // TD_ARRAY = 20, + const PRUint16 VTYPE_STRING_SIZE_IS = 21; // TD_PSTRING_SIZE_IS = 21, + const PRUint16 VTYPE_WSTRING_SIZE_IS = 22; // TD_PWSTRING_SIZE_IS = 22, + const PRUint16 VTYPE_UTF8STRING = 23; // TD_UTF8STRING = 23, + const PRUint16 VTYPE_CSTRING = 24; // TD_CSTRING = 24, + const PRUint16 VTYPE_ASTRING = 25; // TD_ASTRING = 25, + const PRUint16 VTYPE_EMPTY_ARRAY = 254; + const PRUint16 VTYPE_EMPTY = 255; +}; + + +/** + * XPConnect has magic to transparently convert between nsIVariant and JS types. + * We mark the interface [scriptable] so that JS can use methods + * that refer to this interface. But we mark all the methods and attributes + * [noscript] since any nsIVariant object will be automatically converted to a + * JS type anyway. + */ + +[scriptable, uuid(6c9eb060-8c6a-11d5-90f3-0010a4e73d9a)] +interface nsIVariant : nsISupports +{ + [noscript] readonly attribute PRUint16 dataType; + + [noscript] PRUint8 getAsInt8(); + [noscript] PRInt16 getAsInt16(); + [noscript] PRInt32 getAsInt32(); + [noscript] PRInt64 getAsInt64(); + [noscript] PRUint8 getAsUint8(); + [noscript] PRUint16 getAsUint16(); + [noscript] PRUint32 getAsUint32(); + [noscript] PRUint64 getAsUint64(); + [noscript] float getAsFloat(); + [noscript] double getAsDouble(); + [noscript] PRBool getAsBool(); + [noscript] char getAsChar(); + [noscript] wchar getAsWChar(); + [notxpcom] nsresult getAsID(out nsID retval); + [noscript] AString getAsAString(); + [noscript] DOMString getAsDOMString(); + [noscript] ACString getAsACString(); + [noscript] AUTF8String getAsAUTF8String(); + [noscript] string getAsString(); + [noscript] wstring getAsWString(); + [noscript] nsISupports getAsISupports(); + + [noscript] void getAsInterface(out nsIIDPtr iid, + [iid_is(iid), retval] out nsQIResult iface); + + [notxpcom] nsresult getAsArray(out PRUint16 type, out nsIID iid, + out PRUint32 count, out voidPtr ptr); + + [noscript] void getAsStringWithSize(out PRUint32 size, + [size_is(size), retval] out string str); + + [noscript] void getAsWStringWithSize(out PRUint32 size, + [size_is(size), retval] out wstring str); +}; + +/** + * An object that implements nsIVariant may or may NOT also implement this + * nsIWritableVariant. + * + * If the 'writable' attribute is false then attempts to call any of the 'set' + * methods can be expected to fail. Setting the 'writable' attribute may or + * may not succeed. + * + */ + +[scriptable, uuid(5586a590-8c82-11d5-90f3-0010a4e73d9a)] +interface nsIWritableVariant : nsIVariant +{ + attribute PRBool writable; + + void setAsInt8(in PRUint8 aValue); + void setAsInt16(in PRInt16 aValue); + void setAsInt32(in PRInt32 aValue); + void setAsInt64(in PRInt64 aValue); + void setAsUint8(in PRUint8 aValue); + void setAsUint16(in PRUint16 aValue); + void setAsUint32(in PRUint32 aValue); + void setAsUint64(in PRUint64 aValue); + void setAsFloat(in float aValue); + void setAsDouble(in double aValue); + void setAsBool(in PRBool aValue); + void setAsChar(in char aValue); + void setAsWChar(in wchar aValue); + void setAsID(in nsIDRef aValue); + void setAsAString(in AString aValue); + void setAsDOMString(in DOMString aValue); + void setAsACString(in ACString aValue); + void setAsAUTF8String(in AUTF8String aValue); + void setAsString(in string aValue); + void setAsWString(in wstring aValue); + void setAsISupports(in nsISupports aValue); + + void setAsInterface(in nsIIDRef iid, + [iid_is(iid)] in nsQIResult iface); + + [noscript] void setAsArray(in PRUint16 type, in nsIIDPtr iid, + in PRUint32 count, in voidPtr ptr); + + void setAsStringWithSize(in PRUint32 size, + [size_is(size)] in string str); + + void setAsWStringWithSize(in PRUint32 size, + [size_is(size)] in wstring str); + + void setAsVoid(); + void setAsEmpty(); + void setAsEmptyArray(); + + void setFromVariant(in nsIVariant aValue); +}; + +%{C++ +// The contractID for the generic implementation built in to xpcom. +#define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsInt64.h b/src/libs/xpcom18a4/xpcom/ds/nsInt64.h new file mode 100644 index 00000000..c7421548 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsInt64.h @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsInt64_h__ +#define nsInt64_h__ + +#include "prlong.h" +#include "nscore.h" + +/** + * This class encapsulates full 64-bit integer functionality and + * provides simple arithmetic and conversion operations. + */ + +// If you ever decide that you need to add a non-inline method to this +// class, be sure to change the class declaration to "class NS_BASE +// nsInt64". + +template<class T> +class nsTInt64 +{ +public: //XXX should be private + T mValue; + +public: + /** + * Construct a new 64-bit integer. + */ + nsTInt64(void) : mValue(LL_ZERO) { + } + + /** + * Construct a new 64-bit integer from a 32-bit signed integer + */ + nsTInt64(const PRInt32 aInt32) { + LL_I2L(mValue, aInt32); + } + + /** + * Construct a new 64-bit integer from a 32-bit unsigned integer + */ + nsTInt64(const PRUint32 aUint32) { + LL_UI2L(mValue, aUint32); + } + + /** + * Construct a new 64-bit integer from a floating point value. + */ + nsTInt64(const PRFloat64 aFloat64) { + LL_D2L(mValue, aFloat64); + } + + /** + * Construct a new 64-bit integer from a native 64-bit integer + */ + nsTInt64(const T aInt64) : mValue(aInt64) { + } + + /** + * Construct a new 64-bit integer from another 64-bit integer + */ + nsTInt64(const nsTInt64& aObject) : mValue(aObject.mValue) { + } + + // ~nsTInt64(void) -- XXX destructor unnecessary + + /** + * Assign a 64-bit integer to another 64-bit integer + */ + const nsTInt64& operator =(const nsTInt64& aObject) { + mValue = aObject.mValue; + return *this; + } + + /** + * Convert a 64-bit integer to a signed 32-bit value + */ + operator PRInt32(void) const { + PRInt32 result; + LL_L2I(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to an unsigned 32-bit value + */ + operator PRUint32(void) const { + PRUint32 result; + LL_L2UI(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to a floating point value + */ + operator PRFloat64(void) const { + PRFloat64 result; + LL_L2D(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to a native 64-bit integer. + */ + operator T() const { + return mValue; + } + + /** + * Perform unary negation on a 64-bit integer. + */ + const nsTInt64 operator -(void) { + nsTInt64 result; + LL_NEG(result.mValue, mValue); + return result; + } + + // Arithmetic operators + + /** + * Increment a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator +=(const nsTInt64& aObject) { + LL_ADD(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Decrement a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator -=(const nsTInt64& aObject) { + LL_SUB(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Multiply a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator *=(const nsTInt64& aObject) { + LL_MUL(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Divide a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator /=(const nsTInt64& aObject) { + LL_DIV(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the modulus of a 64-bit integer to a 64-bit value. + */ + nsTInt64& operator %=(const nsTInt64& aObject) { + LL_MOD(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Shift a 64-bit integer left. + */ + nsTInt64& operator <<=(int aCount) { + LL_SHL(mValue, mValue, aCount); + return *this; + } + + /** + * Shift a 64-bit signed integer right. + */ + nsTInt64& operator >>=(int aCount) { + LL_SHR(mValue, mValue, aCount); + return *this; + } + + // Comparison operators + /** + * Add two 64-bit integers. + */ + inline const nsTInt64 + operator +(const nsTInt64& aObject2) const { + return nsTInt64(*this) += aObject2; + } + + /** + * Subtract one 64-bit integer from another. + */ + inline const nsTInt64 + operator -(const nsTInt64& aObject2) const { + return nsTInt64(*this) -= aObject2; + } + + /** + * Multiply two 64-bit integers + */ + inline const nsTInt64 + operator *(const nsTInt64& aObject2) const { + return nsTInt64(*this) *= aObject2; + } + + /** + * Divide one 64-bit integer by another + */ + inline const nsTInt64 + operator /(const nsTInt64& aObject2) const { + return nsTInt64(*this) /= aObject2; + } + + /** + * Compute the modulus of two 64-bit integers + */ + inline const nsTInt64 + operator %(const nsTInt64& aObject2) const { + return nsTInt64(*this) %= aObject2; + } + + /** + * Shift left a 64-bit integer + */ + inline const nsTInt64 + operator <<(int aCount) const { + return nsTInt64(*this) <<= aCount; + } + + /** + * Shift right a signed 64-bit integer + */ + inline const nsTInt64 + operator >>(int aCount) const { + return nsTInt64(*this) >>= aCount; + } + + /** + * Determine if two 64-bit integers are equal + */ + inline PRBool + operator ==(const nsTInt64& aObject2) const { + return LL_EQ(mValue, aObject2.mValue); + } + + /** + * Determine if two 64-bit integers are not equal + */ + inline PRBool + operator !=(const nsTInt64& aObject2) const { + return LL_NE(mValue, aObject2.mValue); + } + + + /** + * Perform a bitwise AND of two 64-bit integers + */ + inline const nsTInt64 + operator &(const nsTInt64& aObject2) const { + return nsTInt64(*this) &= aObject2; + } + + /** + * Perform a bitwise OR of two 64-bit integers + */ + inline const nsTInt64 + operator |(const nsTInt64& aObject2) const { + return nsTInt64(*this) |= aObject2; + } + + /** + * Perform a bitwise XOR of two 64-bit integers + */ + inline const nsTInt64 + operator ^(const nsTInt64& aObject2) const { + return nsTInt64(*this) ^= aObject2; + } + + // Bitwise operators + + /** + * Compute the bitwise NOT of a 64-bit integer + */ + const nsTInt64 operator ~(void) const { + nsTInt64 result; + LL_NOT(result.mValue, mValue); + return result; + } + + /** + * Compute the bitwise AND with another 64-bit integer + */ + nsTInt64& operator &=(const nsTInt64& aObject) { + LL_AND(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the bitwise OR with another 64-bit integer + */ + nsTInt64& operator |=(const nsTInt64& aObject) { + LL_OR(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the bitwise XOR with another 64-bit integer + */ + nsTInt64& operator ^=(const nsTInt64& aObject) { + LL_XOR(mValue, mValue, aObject.mValue); + return *this; + } +}; + +typedef nsTInt64<PRInt64> nsInt64; +typedef nsTInt64<PRUint64> nsUint64; + +/** + * Determine if one 64-bit integer is strictly greater than another, using signed values + */ +inline PRBool +operator >(const nsInt64& aObject1, const nsInt64& aObject2) { + return LL_CMP(aObject1.mValue, >, aObject2.mValue); +} + +inline PRBool +operator >(const nsUint64& aObject1, const nsUint64& aObject2) { + return LL_UCMP(aObject1.mValue, >, aObject2.mValue); +} + +/** + * Determine if one 64-bit integer is greater than or equal to another, using signed values + */ +inline PRBool +operator >=(const nsInt64& aObject1, const nsInt64& aObject2) { + return ! LL_CMP(aObject1.mValue, <, aObject2.mValue); +} + +inline PRBool +operator >=(const nsUint64& aObject1, const nsUint64& aObject2) { + return ! LL_UCMP(aObject1.mValue, <, aObject2.mValue); +} + +/** + * Determine if one 64-bit integer is strictly less than another, using signed values + */ +inline PRBool +operator <(const nsInt64& aObject1, const nsInt64& aObject2) { + return LL_CMP(aObject1.mValue, <, aObject2.mValue); +} + +inline PRBool +operator <(const nsUint64& aObject1, const nsUint64& aObject2) { + return LL_UCMP(aObject1.mValue, <, aObject2.mValue); +} + +/** + * Determine if one 64-bit integers is less than or equal to another, using signed values + */ +inline PRBool +operator <=(const nsInt64& aObject1, const nsInt64& aObject2) { + return ! LL_CMP(aObject1.mValue, >, aObject2.mValue); +} + +inline PRBool +operator <=(const nsUint64& aObject1, const nsUint64& aObject2) { + return ! LL_UCMP(aObject1.mValue, >, aObject2.mValue); +} + +#endif // nsInt64_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h new file mode 100644 index 00000000..68b06d66 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsInterfaceHashtable_h__ +#define nsInterfaceHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsCOMPtr.h" + +/** + * templated hashtable class maps keys to interface pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Interface the interface-type being wrapped + * @see nsDataHashtable, nsClassHashtable + */ +template<class KeyClass,class Interface> +class nsInterfaceHashtable : + public nsBaseHashtable< KeyClass, nsCOMPtr<Interface> , Interface* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef Interface* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + /** + * Gets a weak reference to the hashtable entry. + * @param aFound If not nsnull, will be set to PR_TRUE if the entry is found, + * to PR_FALSE otherwise. + * @return The entry, or nsnull if not found. Do not release this pointer! + */ + Interface* GetWeak(KeyType aKey, PRBool* aFound = nsnull) const; +}; + +/** + * Thread-safe version of nsInterfaceHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Interface the interface-type being wrapped + */ +template<class KeyClass,class Interface> +class nsInterfaceHashtableMT : + public nsBaseHashtableMT< KeyClass, nsCOMPtr<Interface> , Interface* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef Interface* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + // GetWeak does not make sense on a multi-threaded hashtable, where another + // thread may remove the entry (and hence release it) as soon as GetWeak + // returns +}; + + +// +// nsInterfaceHashtable definitions +// + +template<class KeyClass,class Interface> +PRBool +nsInterfaceHashtable<KeyClass,Interface>::Get + (KeyType aKey, UserDataType* pInterface) const +{ + typename nsBaseHashtable<KeyClass, nsCOMPtr<Interface>, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pInterface) + { + *pInterface = ent->mData; + + NS_IF_ADDREF(*pInterface); + } + + return PR_TRUE; + } + + // if the key doesn't exist, set *pInterface to null + // so that it is a valid XPCOM getter + if (pInterface) + *pInterface = nsnull; + + return PR_FALSE; +} + +template<class KeyClass,class Interface> +Interface* +nsInterfaceHashtable<KeyClass,Interface>::GetWeak + (KeyType aKey, PRBool* aFound) const +{ + typename nsBaseHashtable<KeyClass, nsCOMPtr<Interface>, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (aFound) + *aFound = PR_TRUE; + + return ent->mData; + } + + // Key does not exist, return nsnull and set aFound to PR_FALSE + if (aFound) + *aFound = PR_FALSE; + return nsnull; +} + +// +// nsInterfaceHashtableMT definitions +// + +template<class KeyClass,class Interface> +PRBool +nsInterfaceHashtableMT<KeyClass,Interface>::Get + (KeyType aKey, UserDataType* pInterface) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT<KeyClass, nsCOMPtr<Interface>, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pInterface) + { + *pInterface = ent->mData; + + NS_IF_ADDREF(*pInterface); + } + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + // if the key doesn't exist, set *pInterface to null + // so that it is a valid XPCOM getter + if (pInterface) + *pInterface = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsInterfaceHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h b/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h new file mode 100644 index 00000000..761c28c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsManifestLineReader_h__ +#define nsManifestLineReader_h__ + +#include "nspr.h" +#include "nsDebug.h" + +class nsManifestLineReader +{ +public: + nsManifestLineReader() : mBase(nsnull) {} + ~nsManifestLineReader() {} + + void Init(char* base, PRUint32 flen) + { + mBase = mCur = mNext = base; + mLength = 0; + mLimit = base + flen; + } + + PRBool NextLine() + { + if(mNext >= mLimit) + return PR_FALSE; + + mCur = mNext; + mLength = 0; + + while(mNext < mLimit) + { + if(IsEOL(*mNext)) + { + *mNext = '\0'; + for(++mNext; mNext < mLimit; ++mNext) + if(!IsEOL(*mNext)) + break; + return PR_TRUE; + } + ++mNext; + ++mLength; + } + return PR_FALSE; + } + + int ParseLine(char** chunks, int* lengths, int maxChunks) + { + NS_ASSERTION(mCur && maxChunks && chunks, "bad call to ParseLine"); + int found = 0; + chunks[found++] = mCur; + + if(found < maxChunks) + { + char *lastchunk = mCur; + int *lastlength = lengths; + for(char* cur = mCur; *cur; cur++) + { + if(*cur == ',') + { + *cur = 0; + // always fill in the previous chunk's length + *lastlength++ = cur - lastchunk; + chunks[found++] = lastchunk = cur+1; + if(found == maxChunks) + break; + } + } + // crazy pointer math - calculate the length of the final chunk + *lastlength = (mCur + mLength) - lastchunk; + } + return found; + } + + char* LinePtr() {return mCur;} + PRUint32 LineLength() {return mLength;} + + PRBool IsEOL(char c) {return c == '\n' || c == '\r';} +private: + char* mCur; + PRUint32 mLength; + char* mNext; + char* mBase; + char* mLimit; +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp new file mode 100644 index 00000000..51fb04b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#define NS_WEAK_OBSERVERS + +#include "pratom.h" +#include "nsString.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsIWeakReference.h" +#include "nsEnumeratorUtils.h" +#include "nsObserverList.h" + +nsObserverList::nsObserverList() +{ + MOZ_COUNT_CTOR(nsObserverList); + mLock = PR_NewLock(); +} + +nsObserverList::~nsObserverList(void) +{ + MOZ_COUNT_DTOR(nsObserverList); + PR_DestroyLock(mLock); +} + +nsresult +nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak) +{ + nsresult rv; + PRBool inserted; + + NS_ENSURE_ARG(anObserver); + + nsAutoLock lock(mLock); + + if (!mObserverList) { + rv = NS_NewISupportsArray(getter_AddRefs(mObserverList)); + if (NS_FAILED(rv)) return rv; + } + +#ifdef NS_WEAK_OBSERVERS + nsCOMPtr<nsISupports> observerRef; + if (ownsWeak) { + nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(anObserver); + NS_ASSERTION(weakRefFactory, "AddObserver: trying weak object that doesnt support nsIWeakReference"); + if ( weakRefFactory ) + observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + } else { +#if DEBUG_dougt_xxx + // if you are hitting this assertion, contact dougt@netscape.com. There may be a ownership problem caused by his checkin to freeze nsIObserver + nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(anObserver); + NS_ASSERTION(!weakRefFactory, "Your object supports weak references, but is being added with a strong reference"); +#endif + observerRef = anObserver; + } + if (!observerRef) + return NS_ERROR_FAILURE; + + inserted = mObserverList->AppendElement(observerRef); +#else + if (*anObserver) + inserted = mObserverList->AppendElement(*anObserver); +#endif + return inserted ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsObserverList::RemoveObserver(nsIObserver* anObserver) +{ + PRBool removed = PR_FALSE; + + NS_ENSURE_ARG(anObserver); + + nsAutoLock lock(mLock); + + if (!mObserverList) + return NS_ERROR_FAILURE; + +#ifdef NS_WEAK_OBSERVERS + nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(anObserver); + nsCOMPtr<nsISupports> observerRef; + if (weakRefFactory) { + observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + if (observerRef) + removed = mObserverList->RemoveElement(observerRef); + if (!removed) + observerRef = anObserver; + } else + observerRef = anObserver; + + if (!removed && observerRef) + removed = mObserverList->RemoveElement(observerRef); +#else + if (*anObserver) + removed = mObserverList->RemoveElement(*anObserver); +#endif + return removed ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) +{ + nsAutoLock lock(mLock); + + ObserverListEnumerator * enumerator= new ObserverListEnumerator(mObserverList); + *anEnumerator = enumerator; + if (!enumerator) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(enumerator); + return NS_OK; +} + + +ObserverListEnumerator::ObserverListEnumerator(nsISupportsArray* aValueArray) + : mValueArray(aValueArray), mIndex(0) +{ + if (mValueArray) { + NS_ADDREF(mValueArray); + PRUint32 total; + mValueArray->Count(&total); + mIndex = PRInt32(total); + } +} + +ObserverListEnumerator::~ObserverListEnumerator(void) +{ + NS_IF_RELEASE(mValueArray); +} + +NS_IMPL_ISUPPORTS1(ObserverListEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +ObserverListEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + *aResult = (mIndex > 0); + return NS_OK; +} + +NS_IMETHODIMP +ObserverListEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + if (mIndex <= 0 ) + return NS_ERROR_UNEXPECTED; + + mValueArray->GetElementAt(--mIndex, aResult); + if (*aResult) { + nsCOMPtr<nsIWeakReference> weakRefFactory = do_QueryInterface(*aResult); + if ( weakRefFactory ) { + nsCOMPtr<nsISupports> weakref = do_QueryReferent(weakRefFactory); + NS_RELEASE(*aResult); + NS_IF_ADDREF(*aResult = weakref); + + return NS_OK; + } + } + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h new file mode 100644 index 00000000..521ce1c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsObserverList_h___ +#define nsObserverList_h___ + +#include "nsIObserver.h" +#include "nsIEnumerator.h" +#include "nsISupportsArray.h" +#include "nsISimpleEnumerator.h" + +class ObserverListEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + ObserverListEnumerator(nsISupportsArray* aValueArray); + +private: + ~ObserverListEnumerator(void); + +protected: + nsISupportsArray* mValueArray; + PRInt32 mIndex; +}; + +class nsObserverList +{ +public: + nsObserverList(); + ~nsObserverList(); + + nsresult AddObserver(nsIObserver* anObserver, PRBool ownsWeak); + nsresult RemoveObserver(nsIObserver* anObserver); + nsresult GetObserverList(nsISimpleEnumerator** anEnumerator); + +protected: + PRLock* mLock; + nsCOMPtr<nsISupportsArray> mObserverList; +}; + + +#endif /* nsObserverList_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp new file mode 100644 index 00000000..f4c66bcc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf <pp@ludusdesign.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prlog.h" +#include "prlock.h" +#include "nsIFactory.h" +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include "nsIObserverService.h" +#include "nsObserverService.h" +#include "nsObserverList.h" +#include "nsHashtable.h" +#include "nsIWeakReference.h" + +#define NS_WEAK_OBSERVERS + + + +#if defined(PR_LOGGING) +// Log module for nsObserverService logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=ObserverService:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +PRLogModuleInfo* observerServiceLog = nsnull; +#endif /* PR_LOGGING */ + +//////////////////////////////////////////////////////////////////////////////// +// nsObserverService Implementation + + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsObserverService, nsIObserverService) + +nsObserverService::nsObserverService() + : mObserverTopicTable(nsnull) +{ +} + +nsObserverService::~nsObserverService(void) +{ + if(mObserverTopicTable) + delete mObserverTopicTable; +} + +NS_METHOD +nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ +#if defined(PR_LOGGING) + if (!observerServiceLog) + observerServiceLog = PR_NewLogModule("ObserverService"); +#endif + + nsresult rv; + nsObserverService* os = new nsObserverService(); + if (os == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(os); + rv = os->QueryInterface(aIID, aInstancePtr); + NS_RELEASE(os); + return rv; +} + +static PRBool PR_CALLBACK +ReleaseObserverList(nsHashKey *aKey, void *aData, void* closure) +{ + nsObserverList* observerList = NS_STATIC_CAST(nsObserverList*, aData); + delete(observerList); + return PR_TRUE; +} + +nsresult nsObserverService::GetObserverList(const char* aTopic, nsObserverList** anObserverList) +{ + if (anObserverList == nsnull) + return NS_ERROR_NULL_POINTER; + + if(mObserverTopicTable == nsnull) + { + mObserverTopicTable = new nsObjectHashtable(nsnull, + nsnull, // should never be cloned + ReleaseObserverList, + nsnull, + 256, + PR_TRUE); + if (mObserverTopicTable == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + + + nsCStringKey key(aTopic); + + nsObserverList *topicObservers; + topicObservers = (nsObserverList *) mObserverTopicTable->Get(&key); + + if (topicObservers) + { + *anObserverList = topicObservers; + return NS_OK; + } + + topicObservers = new nsObserverList(); + if (!topicObservers) + return NS_ERROR_OUT_OF_MEMORY; + + *anObserverList = topicObservers; + mObserverTopicTable->Put(&key, topicObservers); + + return NS_OK; +} + +NS_IMETHODIMP nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, PRBool ownsWeak) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anObserver == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->AddObserver(anObserver, ownsWeak); +} + +NS_IMETHODIMP nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anObserver == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->RemoveObserver(anObserver); +} + +NS_IMETHODIMP nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anEnumerator == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->GetObserverList(anEnumerator); +} + +// Enumerate observers of aTopic and call Observe on each. +NS_IMETHODIMP nsObserverService::NotifyObservers( nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData ) { + nsresult rv = NS_OK; + nsCOMPtr<nsISimpleEnumerator> observers; + nsCOMPtr<nsISupports> observerRef; + + rv = EnumerateObservers( aTopic, getter_AddRefs(observers) ); + if ( NS_FAILED( rv ) ) + return rv; + PRBool loop = PR_TRUE; + while( NS_SUCCEEDED(observers->HasMoreElements(&loop)) && loop) + { + observers->GetNext(getter_AddRefs(observerRef)); + nsCOMPtr<nsIObserver> observer = do_QueryInterface(observerRef); + if ( observer ) + observer->Observe( aSubject, aTopic, someData ); +#ifdef NS_WEAK_OBSERVERS + else + { // check for weak reference. + nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(observerRef); + if ( weakRef ) + weakRef->QueryReferent(NS_GET_IID(nsIObserver), getter_AddRefs(observer)); + + if ( observer ) + observer->Observe( aSubject, aTopic, someData ); + + PR_LOG(observerServiceLog, PR_LOG_DEBUG, ("Notification - %s\n", aTopic ? aTopic : "undefined")); + + } +#endif + } + return NS_OK; +} +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h new file mode 100644 index 00000000..0a08f2ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsObserverService_h___ +#define nsObserverService_h___ + +#include "nsIObserverService.h" + +#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1" +#define NS_OBSERVERSERVICE_CLASSNAME "Observer Service" + +class nsObserverList; +class nsObjectHashtable; + +// {D07F5195-E3D1-11d2-8ACD-00105A1B8860} +#define NS_OBSERVERSERVICE_CID \ + { 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } } + +class nsObserverService : public nsIObserverService { +public: + NS_DEFINE_STATIC_CID_ACCESSOR( NS_OBSERVERSERVICE_CID ) + + nsObserverService(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVERSERVICE + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsObserverService(void); + + nsObjectHashtable* mObserverTopicTable; + + nsresult GetObserverList(const char* aTopic, nsObserverList** anObserverList); + + +}; + +#endif /* nsObserverService_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp new file mode 100644 index 00000000..0bdef252 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp @@ -0,0 +1,492 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf <pp@ludusdesign.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsID.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "pratom.h" +#include "nsEnumeratorUtils.h" +#include "nsReadableUtils.h" +#include "nsPrintfCString.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "nsPersistentProperties.h" +#include "nsIProperties.h" +#include "nsProperties.h" + +struct PropertyTableEntry : public PLDHashEntryHdr +{ + // both of these are arena-allocated + const char *mKey; + const PRUnichar *mValue; +}; + +static PRUnichar* +ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena) +{ + void *mem; + // add one to include the null terminator + PRInt32 len = (aString.Length()+1) * sizeof(PRUnichar); + PL_ARENA_ALLOCATE(mem, aArena, len); + NS_ASSERTION(mem, "Couldn't allocate space!\n"); + if (mem) { + memcpy(mem, aString.get(), len); + } + return NS_STATIC_CAST(PRUnichar*, mem); +} + +static char* +ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena) +{ + void *mem; + // add one to include the null terminator + PRInt32 len = (aString.Length()+1) * sizeof(char); + PL_ARENA_ALLOCATE(mem, aArena, len); + NS_ASSERTION(mem, "Couldn't allocate space!\n"); + if (mem) + memcpy(mem, aString.get(), len); + return NS_STATIC_CAST(char*, mem); +} + +static const struct PLDHashTableOps property_HashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + nsnull, +}; + +nsPersistentProperties::nsPersistentProperties() +: mIn(nsnull) +{ + mSubclass = NS_STATIC_CAST(nsIPersistentProperties*, this); + mTable.ops = nsnull; + PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048); +} + +nsPersistentProperties::~nsPersistentProperties() +{ + PL_FinishArenaPool(&mArena); + if (mTable.ops) + PL_DHashTableFinish(&mTable); +} + +nsresult +nsPersistentProperties::Init() +{ + if (!PL_DHashTableInit(&mTable, &property_HashTableOps, nsnull, + sizeof(PropertyTableEntry), 20)) { + mTable.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +NS_METHOD +nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + nsPersistentProperties* props = new nsPersistentProperties(); + if (props == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(props); + nsresult rv = props->Init(); + if (NS_SUCCEEDED(rv)) + rv = props->QueryInterface(aIID, aResult); + + NS_RELEASE(props); + return rv; +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsPersistentProperties, nsIPersistentProperties, nsIProperties) + +NS_IMETHODIMP +nsPersistentProperties::Load(nsIInputStream *aIn) +{ + PRInt32 c; + nsresult ret = NS_NewUTF8ConverterStream(&mIn, aIn, 0); + + if (ret != NS_OK) { + NS_WARNING("NS_NewUTF8ConverterStream failed"); + return NS_ERROR_FAILURE; + } + c = Read(); + while (1) { + c = SkipWhiteSpace(c); + if (c < 0) { + break; + } + else if ((c == '#') || (c == '!')) { + c = SkipLine(c); + continue; + } + else { + nsAutoString key; + while ((c >= 0) && (c != '=') && (c != ':')) { + key.Append(PRUnichar(c)); + c = Read(); + } + if (c < 0) { + break; + } + static const char trimThese[] = " \t"; + key.Trim(trimThese, PR_FALSE, PR_TRUE); + c = Read(); + nsAutoString value; + PRUint32 state = 0; + PRUnichar uchar = 0; + while ((c >= 0) && (c != '\r') && (c != '\n')) { + switch(state) { + case 0: + if (c == '\\') { + c = Read(); + switch(c) { + case '\r': + case '\n': + // Only skip first EOL characters and then next line's + // whitespace characters. Skipping all EOL characters + // and all upcoming whitespace is too agressive. + if (c == '\r') + c = Read(); + if (c == '\n') + c = Read(); + while (c == ' ' || c == '\t') + c = Read(); + continue; + case 'u': + case 'U': + state = 1; + uchar=0; + break; + case 't': + value.Append(PRUnichar('\t')); + break; + case 'n': + value.Append(PRUnichar('\n')); + break; + case 'r': + value.Append(PRUnichar('\r')); + break; + default: + value.Append((PRUnichar) c); + } // switch(c) + } else { + value.Append((PRUnichar) c); + } + c = Read(); + break; + case 1: + case 2: + case 3: + case 4: + if (('0' <= c) && (c <= '9')) { + uchar = (uchar << 4) | (c - '0'); + state++; + c = Read(); + } else if (('a' <= c) && (c <= 'f')) { + uchar = (uchar << 4) | (c - 'a' + 0x0a); + state++; + c = Read(); + } else if (('A' <= c) && (c <= 'F')) { + uchar = (uchar << 4) | (c - 'A' + 0x0a); + state++; + c = Read(); + } else { + value.Append((PRUnichar) uchar); + state = 0; + } + break; + case 5: + value.Append((PRUnichar) uchar); + state = 0; + } + } + if (state != 0) { + value.Append((PRUnichar) uchar); + state = 0; + } + + value.Trim(trimThese, PR_TRUE, PR_TRUE); + nsAutoString oldValue; + mSubclass->SetStringProperty(NS_ConvertUCS2toUTF8(key), value, oldValue); + } + } + mIn->Close(); + NS_RELEASE(mIn); + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::SetStringProperty(const nsACString& aKey, + const nsAString& aNewValue, + nsAString& aOldValue) +{ +#if 0 + cout << "will add " << aKey.get() << "=" << + NS_LossyConvertUCS2ToASCII(aNewValue).get() << endl; +#endif + + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); + PropertyTableEntry *entry = + NS_STATIC_CAST(PropertyTableEntry*, + PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD)); + + if (entry->mKey) { + aOldValue = entry->mValue; + NS_WARNING(nsPrintfCString(aKey.Length() + 30, + "the property %s already exists\n", + flatKey.get()).get()); + } + + entry->mKey = ArenaStrdup(flatKey, &mArena); + entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena); + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Subclass(nsIPersistentProperties* aSubclass) +{ + if (aSubclass) { + mSubclass = aSubclass; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::GetStringProperty(const nsACString& aKey, + nsAString& aValue) +{ + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); + + PropertyTableEntry *entry = + NS_STATIC_CAST(PropertyTableEntry*, + PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return NS_ERROR_FAILURE; + + aValue = entry->mValue; + return NS_OK; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +AddElemToArray(PLDHashTable* table, PLDHashEntryHdr *hdr, + PRUint32 i, void *arg) +{ + nsISupportsArray *propArray = (nsISupportsArray *) arg; + PropertyTableEntry* entry = + NS_STATIC_CAST(PropertyTableEntry*, hdr); + + nsPropertyElement *element = + new nsPropertyElement(nsDependentCString(entry->mKey), + nsDependentString(entry->mValue)); + if (!element) + return PL_DHASH_STOP; + + NS_ADDREF(element); + propArray->InsertElementAt(element, i); + + return PL_DHASH_NEXT; +} + + +NS_IMETHODIMP +nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult) +{ + nsCOMPtr<nsIBidirectionalEnumerator> iterator; + + nsISupportsArray* propArray; + nsresult rv = NS_NewISupportsArray(&propArray); + if (rv != NS_OK) + return rv; + + // Step through hash entries populating a transient array + PRUint32 n = + PL_DHashTableEnumerate(&mTable, AddElemToArray, (void *)propArray); + if (n < mTable.entryCount) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_NewArrayEnumerator(aResult, propArray); +} + + +PRInt32 +nsPersistentProperties::Read() +{ + PRUnichar c; + PRUint32 nRead; + nsresult ret; + + ret = mIn->Read(&c, 1, &nRead); + if (ret == NS_OK && nRead == 1) { + return c; + } + + return -1; +} + +#define IS_WHITE_SPACE(c) \ + (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n')) + +PRInt32 +nsPersistentProperties::SkipWhiteSpace(PRInt32 c) +{ + while (IS_WHITE_SPACE(c)) { + c = Read(); + } + + return c; +} + +PRInt32 +nsPersistentProperties::SkipLine(PRInt32 c) +{ + while ((c >= 0) && (c != '\r') && (c != '\n')) { + c = Read(); + } + if (c == '\r') { + c = Read(); + } + if (c == '\n') { + c = Read(); + } + + return c; +} + +//////////////////////////////////////////////////////////////////////////////// +// XXX Some day we'll unify the nsIPersistentProperties interface with +// nsIProperties, but until now... + +NS_IMETHODIMP +nsPersistentProperties::Get(const char* prop, const nsIID & uuid, void* *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Set(const char* prop, nsISupports* value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP +nsPersistentProperties::Undefine(const char* prop) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Has(const char* prop, PRBool *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// +// PropertyElement +//////////////////////////////////////////////////////////////////////////////// + + +NS_METHOD +nsPropertyElement::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + nsPropertyElement* propElem = new nsPropertyElement(); + if (propElem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(propElem); + nsresult rv = propElem->QueryInterface(aIID, aResult); + NS_RELEASE(propElem); + return rv; +} + +NS_IMPL_ISUPPORTS1(nsPropertyElement, nsIPropertyElement) + +NS_IMETHODIMP +nsPropertyElement::GetKey(nsACString& aReturnKey) +{ + aReturnKey = mKey; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::GetValue(nsAString& aReturnValue) +{ + aReturnValue = mValue; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::SetKey(const nsACString& aKey) +{ + mKey = aKey; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::SetValue(const nsAString& aValue) +{ + mValue = aValue; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h new file mode 100644 index 00000000..020ff82d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsPersistentProperties_h___ +#define nsPersistentProperties_h___ + +#include "nsIPersistentProperties2.h" +#include "pldhash.h" +#include "plarena.h" +#include "nsString.h" + +class nsIUnicharInputStream; + + +class nsPersistentProperties : public nsIPersistentProperties +{ +public: + nsPersistentProperties(); + nsresult Init(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROPERTIES + NS_DECL_NSIPERSISTENTPROPERTIES + + + // nsPersistentProperties methods: + PRInt32 Read(); + PRInt32 SkipLine(PRInt32 c); + PRInt32 SkipWhiteSpace(PRInt32 c); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsPersistentProperties(); + +protected: + nsIUnicharInputStream* mIn; + PRUint32 mBufferPos; + PRUint32 mBufferLength; + nsIPersistentProperties* mSubclass; + struct PLDHashTable mTable; + PLArenaPool mArena; +}; + +class nsPropertyElement : public nsIPropertyElement +{ +public: + nsPropertyElement() + { + } + + nsPropertyElement(const nsACString& aKey, const nsAString& aValue) + : mKey(aKey), mValue(aValue) + { + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROPERTYELEMENT + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsPropertyElement() {} + +protected: + nsCString mKey; + nsString mValue; +}; + +#endif /* nsPersistentProperties_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp b/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp new file mode 100644 index 00000000..8276e4a5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsProperties.h" + +//#include <iostream.h> + +//////////////////////////////////////////////////////////////////////////////// + +nsProperties::nsProperties(nsISupports* outer) +{ + NS_INIT_AGGREGATED(outer); +} + +NS_METHOD +nsProperties::Create(nsISupports *outer, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_PROPER_AGGREGATION(outer, aIID); + + nsProperties* props = new nsProperties(outer); + if (props == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = props->AggregatedQueryInterface(aIID, aResult); + if (NS_FAILED(rv)) + delete props; + return rv; +} + +PRBool PR_CALLBACK +nsProperties::ReleaseValues(nsHashKey* key, void* data, void* closure) +{ + nsISupports* value = (nsISupports*)data; + NS_IF_RELEASE(value); + return PR_TRUE; +} + +nsProperties::~nsProperties() +{ + Enumerate(ReleaseValues); +} + +NS_IMPL_AGGREGATED(nsProperties) + +NS_METHOD +nsProperties::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + + if (aIID.Equals(NS_GET_IID(nsISupports))) + *aInstancePtr = GetInner(); + else if (aIID.Equals(NS_GET_IID(nsIProperties))) + *aInstancePtr = NS_STATIC_CAST(nsIProperties*, this); + else { + *aInstancePtr = nsnull; + return NS_NOINTERFACE; + } + + NS_ADDREF((nsISupports*)*aInstancePtr); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Get(const char* prop, const nsIID & uuid, void* *result) +{ + nsresult rv; + nsCStringKey key(prop); + nsISupports* value = (nsISupports*)nsHashtable::Get(&key); + if (value) { + rv = value->QueryInterface(uuid, result); + } + else { + rv = NS_ERROR_FAILURE; + } + return rv; +} + +NS_IMETHODIMP +nsProperties::Set(const char* prop, nsISupports* value) +{ + nsCStringKey key(prop); + + nsISupports* prevValue = (nsISupports*)Put(&key, value); + NS_IF_RELEASE(prevValue); + NS_IF_ADDREF(value); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Undefine(const char* prop) +{ + nsCStringKey key(prop); + if (!Exists(&key)) + return NS_ERROR_FAILURE; + + nsISupports* prevValue = (nsISupports*)Remove(&key); + NS_IF_RELEASE(prevValue); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Has(const char* prop, PRBool *result) +{ + nsCStringKey key(prop); + *result = nsHashtable::Exists(&key); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/ds/nsProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsProperties.h new file mode 100644 index 00000000..ee225547 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsProperties.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsProperties_h___ +#define nsProperties_h___ + +#include "nsIProperties.h" +#include "nsHashtable.h" +#include "nsAgg.h" + +#define NS_PROPERTIES_CID \ +{ /* 4de2bc90-b1bf-11d3-93b6-00104ba0fd40 */ \ + 0x4de2bc90, \ + 0xb1bf, \ + 0x11d3, \ + {0x93, 0xb6, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +class nsIUnicharInputStream; + +class nsProperties : public nsIProperties, public nsHashtable { +public: + + NS_DECL_AGGREGATED + NS_DECL_NSIPROPERTIES + + nsProperties(nsISupports* outer); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + static PRBool PR_CALLBACK ReleaseValues(nsHashKey* key, void* data, void* closure); + +private: + ~nsProperties(); +}; + +#endif /* nsProperties_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp new file mode 100644 index 00000000..0a71d25d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* We need this because Solaris' version of qsort is broken and + * causes array bounds reads. + */ + +#include <stdlib.h> +#include "prtypes.h" +#include "nsQuickSort.h" + +PR_BEGIN_EXTERN_C + +#if !defined(DEBUG) && (defined(__cplusplus) || defined(__gcc)) +# ifndef INLINE +# define INLINE inline +# endif +#else +# define INLINE +#endif + +typedef int cmp_t(const void *, const void *, void *); +static INLINE char *med3(char *, char *, char *, cmp_t *, void *); +static INLINE void swapfunc(char *, char *, int, int); + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static INLINE void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc((char *)a, (char*)b, (int)es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc((char *)a, (char *)b, (int)n, swaptype) + +static INLINE char * +med3(char *a, char *b, char *c, cmp_t* cmp, void *data) +{ + return cmp(a, b, data) < 0 ? + (cmp(b, c, data) < 0 ? b : (cmp(a, c, data) < 0 ? c : a )) + :(cmp(b, c, data) > 0 ? b : (cmp(a, c, data) < 0 ? a : c )); +} + +void NS_QuickSort ( + void *a, + unsigned int n, + unsigned int es, + cmp_t *cmp, + void *data + ) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp, data); + pm = med3(pm - d, pm, pm + d, cmp, data); + pn = med3(pn - 2 * d, pn - d, pn, cmp, data); + } + pm = med3(pl, pm, pn, cmp, data); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a, data)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a, data)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = PR_MIN(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = PR_MIN(pd - pc, (int)(pn - pd - es)); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + NS_QuickSort(a, r / es, es, cmp, data); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* NS_QuickSort(pn - r, r / es, es, cmp, data);*/ +} + +PR_END_EXTERN_C diff --git a/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h new file mode 100644 index 00000000..0dd16385 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +/* We need this because Solaris' version of qsort is broken and + * causes array bounds reads. + */ + +#ifndef nsQuickSort_h___ +#define nsQuickSort_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_QuickSort VBoxNsxpNS_QuickSort +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/** + * Parameters: + * 1. the array to sort + * 2. the number of elements in the array + * 3. the size of each array element + * 4. comparison function taking two elements and parameter #5 and + * returning an integer: + * + less than zero if the first element should be before the second + * + 0 if the order of the elements does not matter + * + greater than zero if the second element should be before the first + * 5. extra data to pass to comparison function + */ +PR_EXTERN(void) NS_QuickSort(void *, unsigned int, unsigned int, + int (*)(const void *, const void *, void *), + void *); + +PR_END_EXTERN_C + +#endif /* nsQuickSort_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp new file mode 100644 index 00000000..241f795c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp @@ -0,0 +1,443 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi <dp@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * nsRecyclingAllocator + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "nsRecyclingAllocator.h" +#include "nsIMemory.h" +#include "nsAutoLock.h" +#include "prprf.h" +#include "nsITimer.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include <iprt/mem.h> +#endif + +#define NS_SEC_TO_MS(s) ((s) * 1000) + +void +nsRecyclingAllocator::nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure) +{ + nsRecyclingAllocator *obj = (nsRecyclingAllocator *) aClosure; + if (!obj->mTouched) + { + if (obj->mFreeList) + obj->FreeUnusedBuckets(); + + // If we are holding no more memory, there is no need for the timer. + // We will revive the timer on the next allocation. + // XXX Unfortunately there is no way to Cancel and restart the same timer. + // XXX So we pretty much kill it and create a new one later. + if (!obj->mFreeList && obj->mRecycleTimer) + { + obj->mRecycleTimer->Cancel(); + NS_RELEASE(obj->mRecycleTimer); + } + } + else + { + // Clear touched so the next time the timer fires we can test whether + // the allocator was used or not. + obj->Untouch(); + } +} + + +nsRecyclingAllocator::nsRecyclingAllocator(PRUint32 nbucket, PRUint32 recycleAfter, const char *id) : + mMaxBlocks(nbucket), mBlocks(nsnull), mFreeList(nsnull), mNotUsedList(nsnull), + mRecycleTimer(nsnull), mRecycleAfter(recycleAfter), mTouched(0), mId(id) +#ifdef DEBUG + ,mNAllocated(0) +#endif +{ + NS_ASSERTION(mMaxBlocks <= NS_MAX_BLOCKS, "Too many blocks. This will affect the allocator's performance."); + + mLock = PR_NewLock(); + NS_ASSERTION(mLock, "Recycling allocator cannot get lock"); + + Init(nbucket, recycleAfter, id); +} + +nsresult +nsRecyclingAllocator::Init(PRUint32 nbucket, PRUint32 recycleAfter, const char *id) +{ + nsAutoLock lock(mLock); + + // Free all memory held, if any + while(mFreeList) + { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mFreeList->block); +#else + free(mFreeList->block); +#endif + mFreeList = mFreeList->next; + } + mFreeList = nsnull; + + if (mBlocks) + delete [] mBlocks; + + // Reinitialize everything + mMaxBlocks = nbucket; + if (nbucket) + { + // Create memory for our bookkeeping + mBlocks = new BlockStoreNode[mMaxBlocks]; + if (!mBlocks) + return NS_ERROR_OUT_OF_MEMORY; + // Link them together + mNotUsedList = mBlocks; + for (PRUint32 i=0; i < mMaxBlocks-1; i++) + mBlocks[i].next = &(mBlocks[i+1]); + } + + mRecycleAfter = recycleAfter; + mId = id; + + return NS_OK; +} + +nsRecyclingAllocator::~nsRecyclingAllocator() +{ + // Cancel and destroy recycle timer + if (mRecycleTimer) + { + mRecycleTimer->Cancel(); + NS_RELEASE(mRecycleTimer); + } + + // Free all memory held, if any + while(mFreeList) + { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mFreeList->block); +#else + free(mFreeList->block); +#endif + mFreeList = mFreeList->next; + } + mFreeList = nsnull; + + if (mBlocks) + delete [] mBlocks; + + if (mLock) + { + PR_DestroyLock(mLock); + mLock = nsnull; + } +} + +// Allocation and free routines +void* +nsRecyclingAllocator::Malloc(PRSize bytes, PRBool zeroit) +{ + // Mark that we are using. This will prevent any + // timer based release of unused memory. + Touch(); + + Block* freeBlock = FindFreeBlock(bytes); + if (freeBlock) + { + void *data = DATA(freeBlock); + + if (zeroit) + memset(data, 0, bytes); + return data; + } + + // We need to do an allocation + // Add 4 bytes to what we allocate to hold the bucket index + PRSize allocBytes = bytes + NS_ALLOCATOR_OVERHEAD_BYTES; + + // We dont have that memory already. Allocate. +#ifdef VBOX_USE_IPRT_IN_XPCOM + Block *ptr = (Block *) (zeroit ? RTMemAllocZ(allocBytes) : RTMemAlloc(allocBytes)); +#else + Block *ptr = (Block *) (zeroit ? calloc(1, allocBytes) : malloc(allocBytes)); +#endif + + // Deal with no memory situation + if (!ptr) + return ptr; + + // This is the first allocation we are holding. + // Setup timer for releasing memory + // If this fails, then we wont have a timer to release unused + // memory. We can live with that. Also, the next allocation + // will try again to set the timer. + if (mRecycleAfter && !mRecycleTimer) + { + // known only to stuff in xpcom. + extern nsresult NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure, + PRUint32 aDelay, PRUint32 aType); + + (void) NS_NewTimer(&mRecycleTimer, nsRecycleTimerCallback, this, + NS_SEC_TO_MS(mRecycleAfter), + nsITimer::TYPE_REPEATING_SLACK); + NS_ASSERTION(mRecycleTimer, "nsRecyclingAllocator: Creating timer failed.\n"); + } + +#ifdef DEBUG + mNAllocated++; +#endif + + // Store size and return data portion + ptr->bytes = bytes; + return DATA(ptr); +} + +void +nsRecyclingAllocator::Free(void *ptr) +{ + // Mark that we are using the allocator. This will prevent any + // timer based release of unused memory. + Touch(); + + Block* block = DATA_TO_BLOCK(ptr); + + if (!AddToFreeList(block)) + { + // We are holding more than max. Failover to free +#ifdef DEBUG_dp + char buf[1024]; + // Warn if we are failing over to malloc/free and not storing it + // This says we have a misdesigned memory pool. The intent was + // once the pool was full, we would never fail over to calloc. + PR_snprintf(buf, sizeof(buf), "nsRecyclingAllocator(%s) FAILOVER 0x%p (%d) - %d allocations, %d max\n", + mId, (char *)ptr, block->bytes, mNAllocated, mMaxBlocks); + NS_WARNING(buf); + mNAllocated--; +#endif +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(block); +#else + free(block); +#endif + } +} + +/* FreeUnusedBuckets + * + * Frees any bucket memory that isn't in use + */ + +void +nsRecyclingAllocator::FreeUnusedBuckets() +{ +#ifdef DEBUG_dp + printf("DEBUG: nsRecyclingAllocator(%s) FreeUnusedBuckets: ", mId); +#endif + nsAutoLock lock(mLock); + + // We will run through the freelist and free all blocks + BlockStoreNode* node = mFreeList; + while (node) + { + // Free the allocated block +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(node->block); +#else + free(node->block); +#endif + +#ifdef DEBUG_dp + printf("%d ", node->bytes); +#endif + // Clear Node + node->block = nsnull; + node->bytes = 0; + node = node->next; + } + + // remake the lists + mNotUsedList = mBlocks; + for (PRUint32 i=0; i < mMaxBlocks-1; i++) + mBlocks[i].next = &(mBlocks[i+1]); + mBlocks[mMaxBlocks-1].next = nsnull; + mFreeList = nsnull; + +#ifdef DEBUG + mNAllocated = 0; +#endif +#ifdef DEBUG_dp + printf("\n"); +#endif +} + +nsRecyclingAllocator::Block* +nsRecyclingAllocator::FindFreeBlock(PRSize bytes) +{ + // We dont enter lock for this check. This is intentional. + // Here is my logic: we are checking if (!mFreeList). Doing this check + // without locking can lead to unpredictable results. YES. But the effect + // of the unpredictedness are ok. here is why: + // + // a) if the check returned NULL when there is stuff in freelist + // We would just end up reallocating. + // + // b) if the check returned nonNULL when our freelist is empty + // This is the more likely and dangerous case. The code for + // FindFreeBlock() will enter lock, while (null) and return null. + // + // The reason why I chose to not enter lock for this check was that when + // the allocator is full, we dont want to impose any more overhead than + // we already are for failing over to malloc/free. + + if (!mFreeList) + return NULL; + + Block *block = nsnull; + + nsAutoLock lock(mLock); + BlockStoreNode* freeNode = mFreeList; + BlockStoreNode** prevp = &mFreeList; + + while (freeNode) + { + if (freeNode->bytes >= bytes) + { + // Found the best fit free block + block = freeNode->block; + + // Clear the free node + freeNode->block = nsnull; + freeNode->bytes = 0; + + // Remove free node from free list + *prevp = freeNode->next; + + // Add removed BlockStoreNode to not used list + freeNode->next = mNotUsedList; + mNotUsedList = freeNode; + + break; + } + + prevp = &(freeNode->next); + freeNode = freeNode->next; + } + return block; +} + +PRInt32 +nsRecyclingAllocator::AddToFreeList(Block* block) +{ + nsAutoLock lock(mLock); + + if (!mNotUsedList) + return PR_FALSE; + + // Pick a node from the not used list + BlockStoreNode *node = mNotUsedList; + mNotUsedList = mNotUsedList->next; + + // Initialize the node + node->bytes = block->bytes; + node->block = block; + + // Find the right spot in the sorted list. + BlockStoreNode* freeNode = mFreeList; + BlockStoreNode** prevp = &mFreeList; + while (freeNode) + { + if (freeNode->bytes >= block->bytes) + break; + prevp = &(freeNode->next); + freeNode = freeNode->next; + } + + // Needs to be inserted between *prevp and freeNode + *prevp = node; + node->next = freeNode; + + return PR_TRUE; +} + + +// ---------------------------------------------------------------------- +// Wrapping the recyling allocator with nsIMemory +// ---------------------------------------------------------------------- + +// nsIMemory methods +NS_IMPL_THREADSAFE_ISUPPORTS2(nsRecyclingAllocatorImpl, nsIMemory, nsIRecyclingAllocator) + +NS_IMETHODIMP_(void *) +nsRecyclingAllocatorImpl::Alloc(PRSize size) +{ + return nsRecyclingAllocatorImpl::Malloc(size, PR_FALSE); +} + +NS_IMETHODIMP_(void *) +nsRecyclingAllocatorImpl::Realloc(void *ptr, PRSize size) +{ + // XXX Not yet implemented + return NULL; +} + +NS_IMETHODIMP_(void) +nsRecyclingAllocatorImpl::Free(void *ptr) +{ + nsRecyclingAllocator::Free(ptr); +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::Init(size_t nbuckets, size_t recycleAfter, const char *id) +{ + return nsRecyclingAllocator::Init((PRUint32) nbuckets, (PRUint32) recycleAfter, id); +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::HeapMinimize(PRBool immediate) +{ + // XXX Not yet implemented + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::IsLowMemory(PRBool *lowmemoryb_ptr) +{ + // XXX Not yet implemented + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h new file mode 100644 index 00000000..4266b1b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h @@ -0,0 +1,208 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi <dp@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * nsRecyclingAllocator + * + * This allocator is useful when we cycle through a small set of allocations + * repeatedly with minimal overlap. For eg. something we do for every gif + * file read (or) buffers required for decompression of every file from jar. + * + * What this does is keeps around the first set of memory allocated and + * reuses it subsequently. If all buckets are full, this falls back to + * malloc/free + * + * Uses a timer to release all memory allocated if not used for more than + * 10 secs automatically. + * + * Also there is a 4 byte maintenance overhead on every allocation. + * + * This allocator is thread safe. + * + * CAVEATS: As the number of buckets increases, this allocators performance + * will drop. As a general guideline, dont use this for more + * than NS_MAX_BLOCKS + */ + +#ifndef nsRecyclingAllocator_h__ +#define nsRecyclingAllocator_h__ + +#include "nscore.h" +#include "pratom.h" +#include "prlock.h" +#include "nsIRecyclingAllocator.h" +#include "nsIGenericFactory.h" + +#define NS_DEFAULT_RECYCLE_TIMEOUT 10 // secs +#define NS_MAX_BLOCKS 24 +#define NS_ALLOCATOR_OVERHEAD_BYTES (sizeof(Block)) // bytes + +class nsITimer; +class nsIMemory; + +class NS_COM nsRecyclingAllocator { + protected: + struct Block { + PRSize bytes; + }; + + // Make |BlockStoreNode| a |friend| so it can access |Block|. + struct BlockStoreNode; + friend struct BlockStoreNode; + + struct BlockStoreNode { + BlockStoreNode() : bytes(0), block(nsnull), next(nsnull) {}; + PRSize bytes; + Block *block; + BlockStoreNode *next; + }; + +#define DATA(block) ((void *)(((char *)block) + NS_ALLOCATOR_OVERHEAD_BYTES)) +#define DATA_TO_BLOCK(data) ((Block *)((char *)(data) - NS_ALLOCATOR_OVERHEAD_BYTES)) + + // mMaxBlocks: Maximum number of blocks that can be allocated + PRUint32 mMaxBlocks; + + // mBlocks: + // All blocks used or not. + BlockStoreNode *mBlocks; + + // mFreeList + // A linked list of free blocks sorted by increasing order of size + BlockStoreNode* mFreeList; + + // mNotUsedList + // A linked list of BlockStoreNodes that are not used to store + // any block information. When we add blocks into mFreeList, we + // take BlockStoreNode from here. + BlockStoreNode* mNotUsedList; + + // mLock: Thread safety of mFreeList and mNotUsedList + PRLock *mLock; + + // Timer for freeing unused memory + nsITimer *mRecycleTimer; + + // mRecycleAfter: + // Allocator should be untouched for this many seconds for freeing + // unused Blocks. + PRUint32 mRecycleAfter; + + // mTouched: + // says if the allocator touched any bucket. If allocator didn't touch + // any bucket over a time time interval, timer will call FreeUnusedBuckets() + PRInt32 mTouched; + + // mId: + // a string for identifying the user of nsRecyclingAllocator + // User mainly for debug prints + const char *mId; + +#ifdef DEBUG + // mNAllocated: Number of blocks allocated + PRInt32 mNAllocated; +#endif + + public: + + // nbucket : number of buckets to hold. Capped at NS_MAX_BUCKET + // recycleAfter : Try recycling allocated buckets after this many seconds + // id : a string used to identify debug prints. Will not be released. + nsRecyclingAllocator(PRUint32 nbucket = 0, PRUint32 recycleAfter = NS_DEFAULT_RECYCLE_TIMEOUT, + const char *id = NULL); + ~nsRecyclingAllocator(); + + nsresult Init(PRUint32 nbucket, PRUint32 recycleAfter, const char *id); + + // Allocation and free routines + void* Malloc(PRSize size, PRBool zeroit = PR_FALSE); + void Free(void *ptr); + + void* Calloc(PRUint32 items, PRSize size) + { + return Malloc(items * size, PR_TRUE); + } + + // FreeUnusedBuckets - Frees any bucket memory that isn't in use + void FreeUnusedBuckets(); + + protected: + + // Timer callback to trigger unused memory + static void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure); + + // Freelist management + // FindFreeBlock: return a free block that can hold bytes (best fit) + Block* FindFreeBlock(PRSize bytes); + // AddToFreeList: adds block into our freelist for future retrieval. + // Returns PR_TRUE is addition was successful. PR_FALSE otherewise. + PRBool AddToFreeList(Block* block); + + // Touch will mark that someone used this allocator + // Timer based release will free unused memory only if allocator + // was not touched for mRecycleAfter seconds. + void Touch() { + if (!mTouched) + PR_AtomicSet(&mTouched, 1); + } + void Untouch() { + PR_AtomicSet(&mTouched, 0); + } + + friend void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure); +}; + +// ---------------------------------------------------------------------- +// Wrapping the recyling allocator with nsIMemory +// ---------------------------------------------------------------------- + +// Wrapping the nsRecyclingAllocator with nsIMemory +class nsRecyclingAllocatorImpl : public nsRecyclingAllocator, public nsIRecyclingAllocator { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORY + NS_DECL_NSIRECYCLINGALLOCATOR + + nsRecyclingAllocatorImpl() + { + } + +private: + ~nsRecyclingAllocatorImpl() {} +}; +#endif // nsRecyclingAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h new file mode 100644 index 00000000..69cdbe88 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Neil Rashbrook <neil@parkwaycc.co.uk> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsRefPtrHashtable_h__ +#define nsRefPtrHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsAutoPtr.h" + +/** + * templated hashtable class maps keys to reference pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param RefPtr the reference-type being wrapped + * @see nsDataHashtable, nsClassHashtable + */ +template<class KeyClass, class RefPtr> +class nsRefPtrHashtable : + public nsBaseHashtable< KeyClass, nsRefPtr<RefPtr> , RefPtr* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef RefPtr* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + /** + * Gets a weak reference to the hashtable entry. + * @param aFound If not nsnull, will be set to PR_TRUE if the entry is found, + * to PR_FALSE otherwise. + * @return The entry, or nsnull if not found. Do not release this pointer! + */ + RefPtr* GetWeak(KeyType aKey, PRBool* aFound = nsnull) const; +}; + +/** + * Thread-safe version of nsRefPtrHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param RefPtr the reference-type being wrapped + */ +template<class KeyClass, class RefPtr> +class nsRefPtrHashtableMT : + public nsBaseHashtableMT< KeyClass, nsRefPtr<RefPtr> , RefPtr* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef RefPtr* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + // GetWeak does not make sense on a multi-threaded hashtable, where another + // thread may remove the entry (and hence release it) as soon as GetWeak + // returns +}; + + +// +// nsRefPtrHashtable definitions +// + +template<class KeyClass, class RefPtr> +PRBool +nsRefPtrHashtable<KeyClass,RefPtr>::Get + (KeyType aKey, UserDataType* pRefPtr) const +{ + typename nsBaseHashtable<KeyClass, nsRefPtr<RefPtr>, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pRefPtr) + { + *pRefPtr = ent->mData; + + NS_IF_ADDREF(*pRefPtr); + } + + return PR_TRUE; + } + + // if the key doesn't exist, set *pRefPtr to null + // so that it is a valid XPCOM getter + if (pRefPtr) + *pRefPtr = nsnull; + + return PR_FALSE; +} + +template<class KeyClass, class RefPtr> +RefPtr* +nsRefPtrHashtable<KeyClass,RefPtr>::GetWeak + (KeyType aKey, PRBool* aFound) const +{ + typename nsBaseHashtable<KeyClass, nsRefPtr<RefPtr>, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (aFound) + *aFound = PR_TRUE; + + return ent->mData; + } + + // Key does not exist, return nsnull and set aFound to PR_FALSE + if (aFound) + *aFound = PR_FALSE; + return nsnull; +} + +// +// nsRefPtrHashtableMT definitions +// + +template<class KeyClass, class RefPtr> +PRBool +nsRefPtrHashtableMT<KeyClass,RefPtr>::Get + (KeyType aKey, UserDataType* pRefPtr) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT<KeyClass, nsRefPtr<RefPtr>, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pRefPtr) + { + *pRefPtr = ent->mData; + + NS_IF_ADDREF(*pRefPtr); + } + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + // if the key doesn't exist, set *pRefPtr to null + // so that it is a valid XPCOM getter + if (pRefPtr) + *pRefPtr = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsRefPtrHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h b/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h new file mode 100644 index 00000000..6c76d016 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Static Atom classes. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsStaticAtom_h__ +#define nsStaticAtom_h__ + +#include "nsIAtom.h" + +// see http://www.mozilla.org/projects/xpcom/atoms.html to use this stuff + +// class for declaring a static list of atoms, for use with gperf +// Keep this VERY simple +// mString: the value of the atom - the policy is that this is only +// ASCII, in order to avoid unnecessary conversions if +// someone asks for this in unicode +// mAtom: a convienience pointer - if you want to store the value of +// the atom created by this structure somewhere, put its +// address here +struct nsStaticAtom { + const char* mString; + nsIAtom ** mAtom; +}; + + +// register your lookup function with the atom table. Your function +// will be called when at atom is not found in the main atom table. +NS_COM nsresult +NS_RegisterStaticAtoms(const nsStaticAtom*, PRUint32 aAtomCount); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp new file mode 100644 index 00000000..35489c6a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Class to manage lookup of static names in a table. */ + +#include "nsCRT.h" + +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "nsStaticNameTable.h" + +struct NameTableEntry : public PLDHashEntryHdr +{ + // no ownership here! + const char *mKey; + PRInt32 mIndex; +}; + +PR_STATIC_CALLBACK(PRBool) +matchNameKeysCaseInsensitive(PLDHashTable*, const PLDHashEntryHdr* aHdr, + const void* key) +{ + const NameTableEntry* entry = + NS_STATIC_CAST(const NameTableEntry *, aHdr); + const char *keyValue = NS_STATIC_CAST(const char*, key); + + return (nsCRT::strcasecmp(entry->mKey, keyValue)==0); +} + +/* + * caseInsensitiveHashKey is just like PL_DHashStringKey except it + * uses (*s & ~0x20) instead of simply *s. This means that "aFOO" and + * "afoo" and "aFoo" will all hash to the same thing. It also means + * that some strings that aren't case-insensensitively equal will hash + * to the same value, but it's just a hash function so it doesn't + * matter. + */ +PR_STATIC_CALLBACK(PLDHashNumber) +caseInsensitiveStringHashKey(PLDHashTable *table, const void *key) +{ + PLDHashNumber h = 0; + for (const unsigned char* s = + NS_STATIC_CAST(const unsigned char*, key); + *s != '\0'; + s++) + h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ (*s & ~0x20); + return h; +} + +static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + caseInsensitiveStringHashKey, + matchNameKeysCaseInsensitive, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + nsnull, +}; + +nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable() + : mNameArray(nsnull), mNullStr("") +{ + MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable); + mNameTable.ops = nsnull; +} + +nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable() +{ + if (mNameArray) { + // manually call the destructor on placement-new'ed objects + for (PRUint32 index = 0; index < mNameTable.entryCount; index++) { + mNameArray[index].~nsDependentCString(); + } + nsMemory::Free((void*)mNameArray); + } + if (mNameTable.ops) + PL_DHashTableFinish(&mNameTable); + MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable); +} + +PRBool +nsStaticCaseInsensitiveNameTable::Init(const char* const aNames[], PRInt32 Count) +{ + NS_ASSERTION(!mNameArray, "double Init"); + NS_ASSERTION(!mNameTable.ops, "double Init"); + NS_ASSERTION(aNames, "null name table"); + NS_ASSERTION(Count, "0 count"); + + mNameArray = (nsDependentCString*) + nsMemory::Alloc(Count * sizeof(nsDependentCString)); + if (!mNameArray) + return PR_FALSE; + + if (!PL_DHashTableInit(&mNameTable, + &nametable_CaseInsensitiveHashTableOps, + nsnull, sizeof(NameTableEntry), Count)) { + mNameTable.ops = nsnull; + return PR_FALSE; + } + + for (PRInt32 index = 0; index < Count; ++index) { + const char* raw = aNames[index]; +#ifdef DEBUG + { + // verify invariants of contents + nsCAutoString temp1(raw); + nsDependentCString temp2(raw); + ToLowerCase(temp1); + NS_ASSERTION(temp1.Equals(temp2), "upper case char in table"); + NS_ASSERTION(nsCRT::IsAscii(raw), + "non-ascii string in table -- " + "case-insensitive matching won't work right"); + } +#endif + // use placement-new to initialize the string object + new (&mNameArray[index]) nsDependentCString(raw); + + NameTableEntry *entry = + NS_STATIC_CAST(NameTableEntry*, + PL_DHashTableOperate(&mNameTable, raw, PL_DHASH_ADD)); + + if (!entry) continue; + + NS_ASSERTION(entry->mKey == 0, "Entry already exists!"); + + entry->mKey = raw; // not owned! + entry->mIndex = index; + } + return PR_TRUE; +} + +inline PRInt32 +LookupFlatKeyword(const nsAFlatCString& aKeyword, + PLDHashTable& aTable) +{ + NameTableEntry *entry = + NS_STATIC_CAST(NameTableEntry*, + PL_DHashTableOperate(&aTable, aKeyword.get(), PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return nsStaticCaseInsensitiveNameTable::NOT_FOUND; + + return entry->mIndex; +} + +PRInt32 +nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + return LookupFlatKeyword(PromiseFlatCString(aName), mNameTable); +} + +PRInt32 +nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + nsCAutoString cstring; + cstring.AssignWithConversion(aName); + return LookupFlatKeyword(cstring, mNameTable); +} + +const nsAFlatCString& +nsStaticCaseInsensitiveNameTable::GetStringValue(PRInt32 index) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + if ((NOT_FOUND < index) && ((PRUint32)index < mNameTable.entryCount)) { + return mNameArray[index]; + } + return mNullStr; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h new file mode 100644 index 00000000..154a1c9d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Classes to manage lookup of static names in a table. */ + +#ifndef nsStaticNameTable_h___ +#define nsStaticNameTable_h___ + +#include "pldhash.h" +/* This class supports case insensitive lookup. + * + * It differs from atom tables: + * - It supports case insensitive lookup. + * - It has minimal footprint by not copying the string table. + * - It does no locking. + * - It returns zero based indexes and const nsCString& as required by its + * callers in the parser. + * - It is not an xpcom interface - meant for fast lookup in static tables. + * + * ***REQUIREMENTS*** + * - It *requires* that all entries in the table be lowercase only. + * - It *requires* that the table of strings be in memory that lives at least + * as long as this table object - typically a static string array. + */ + +class NS_COM nsStaticCaseInsensitiveNameTable +{ +public: + enum { NOT_FOUND = -1 }; + + PRBool Init(const char* const aNames[], PRInt32 Count); + PRInt32 Lookup(const nsACString& aName); + PRInt32 Lookup(const nsAString& aName); + const nsAFlatCString& GetStringValue(PRInt32 index); + + nsStaticCaseInsensitiveNameTable(); + ~nsStaticCaseInsensitiveNameTable(); + +private: + nsDependentCString* mNameArray; + PLDHashTable mNameTable; + nsDependentCString mNullStr; +}; + +#endif /* nsStaticNameTable_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp new file mode 100644 index 00000000..8a10b18c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp @@ -0,0 +1,261 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "nsStringEnumerator.h" +#include "prtypes.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsISimpleEnumerator.h" +#include "nsSupportsPrimitives.h" + +// +// nsStringEnumerator +// + +class nsStringEnumerator : public nsIStringEnumerator, + public nsIUTF8StringEnumerator, + public nsISimpleEnumerator +{ +public: + nsStringEnumerator(const nsStringArray* aArray, PRBool aOwnsArray) : + mArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(PR_TRUE) + {} + + nsStringEnumerator(const nsCStringArray* aArray, PRBool aOwnsArray) : + mCArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(PR_FALSE) + {} + + nsStringEnumerator(const nsStringArray* aArray, nsISupports* aOwner) : + mArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(PR_FALSE), mIsUnicode(PR_TRUE) + {} + + nsStringEnumerator(const nsCStringArray* aArray, nsISupports* aOwner) : + mCArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(PR_FALSE), mIsUnicode(PR_FALSE) + {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIUTF8STRINGENUMERATOR + + // have to declare nsIStringEnumerator manually, because of + // overlapping method names + NS_IMETHOD GetNext(nsAString& aResult); + NS_DECL_NSISIMPLEENUMERATOR + +private: + ~nsStringEnumerator() { + if (mOwnsArray) { + // const-casting is safe here, because the NS_New* + // constructors make sure mOwnsArray is consistent with + // the constness of the objects + if (mIsUnicode) + delete NS_CONST_CAST(nsStringArray*,mArray); + else + delete NS_CONST_CAST(nsCStringArray*,mCArray); + } + } + + union { + const nsStringArray* mArray; + const nsCStringArray* mCArray; + }; + + inline PRUint32 Count() { + return mIsUnicode ? mArray->Count() : mCArray->Count(); + } + + PRUint32 mIndex; + + // the owner allows us to hold a strong reference to the object + // that owns the array. Having a non-null value in mOwner implies + // that mOwnsArray is PR_FALSE, because we rely on the real owner + // to release the array + nsCOMPtr<nsISupports> mOwner; + PRPackedBool mOwnsArray; + PRPackedBool mIsUnicode; +}; + +NS_IMPL_ISUPPORTS3(nsStringEnumerator, + nsIStringEnumerator, + nsIUTF8StringEnumerator, + nsISimpleEnumerator) + +NS_IMETHODIMP +nsStringEnumerator::HasMore(PRBool* aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = mIndex < Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::HasMoreElements(PRBool* aResult) +{ + return HasMore(aResult); +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsISupports** aResult) +{ + if (mIsUnicode) { + nsSupportsStringImpl* stringImpl = new nsSupportsStringImpl(); + if (!stringImpl) return NS_ERROR_OUT_OF_MEMORY; + + stringImpl->SetData(*mArray->StringAt(mIndex++)); + *aResult = stringImpl; + } + else { + nsSupportsCStringImpl* cstringImpl = new nsSupportsCStringImpl(); + if (!cstringImpl) return NS_ERROR_OUT_OF_MEMORY; + + cstringImpl->SetData(*mCArray->CStringAt(mIndex++)); + *aResult = cstringImpl; + } + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsAString& aResult) +{ + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + + if (mIsUnicode) + aResult = *mArray->StringAt(mIndex++); + else + CopyUTF8toUTF16(*mCArray->CStringAt(mIndex++), aResult); + + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsACString& aResult) +{ + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + + if (mIsUnicode) + CopyUTF16toUTF8(*mArray->StringAt(mIndex++), aResult); + else + aResult = *mCArray->CStringAt(mIndex++); + + return NS_OK; +} + +template<class T> +static inline nsresult +StringEnumeratorTail(T** aResult) +{ + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*aResult); + return NS_OK; +} + +// +// constructors +// + +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray, nsISupports* aOwner) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, aOwner); + return StringEnumeratorTail(aResult); +} + + +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray, nsISupports* aOwner) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, aOwner); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, + nsStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_TRUE); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + nsCStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_TRUE); + return StringEnumeratorTail(aResult); +} + +// const ones internally just forward to the non-const equivalents +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_FALSE); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_FALSE); + return StringEnumeratorTail(aResult); +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h new file mode 100644 index 00000000..d0080005 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett <alecf@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIStringEnumerator.h" +#include "nsVoidArray.h" + +// nsIStringEnumerator/nsIUTF8StringEnumerator implementations +// +// Currently all implementations support both interfaces. The +// constructors below provide the most common interface for the given +// type (i.e. nsIStringEnumerator for PRUnichar* strings, and so +// forth) but any resulting enumerators can be queried to the other +// type. Internally, the enumerators will hold onto the type that was +// passed in and do conversion if GetNext() for the other type of +// string is called. + +// There are a few different types of enumerators: + +// +// These enumerators hold a pointer to the array. Be careful +// because modifying the array may confuse the iterator, especially if +// you insert or remove elements in the middle of the array. +// + +// The non-adopting enumerator requires that the array sticks around +// at least as long as the enumerator does. These are for constant +// string arrays that the enumerator does not own, this could be used +// in VERY specialized cases such as when the provider KNOWS that the +// string enumerator will be consumed immediately, or will at least +// outlast the array. +// For example: +// +// nsCStringArray array; +// array.AppendCString("abc"); +// array.AppendCString("def"); +// NS_NewStringEnumerator(&enumerator, &array, PR_TRUE); +// +// // call some internal method which iterates the enumerator +// InternalMethod(enumerator); +// NS_RELEASE(enumerator); +// +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray); + +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray); + +// Adopting string enumerators assume ownership of the array and will +// call |operator delete| on the array when the enumerator is destroyed +// this is useful when the provider creates an array soley for the +// purpose of creating the enumerator. +// For example: +// +// nsCStringArray* array = new nsCStringArray; +// array->AppendString("abcd"); +// NS_NewAdoptingStringEnumerator(&result, array); +NS_COM nsresult +NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, + nsStringArray* aArray); + +NS_COM nsresult +NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + nsCStringArray* aArray); + + +// these versions take a refcounted "owner" which will be addreffed +// when the enumerator is created, and destroyed when the enumerator +// is released. This allows providers to give non-owning pointers to +// ns*StringArray member variables without worrying about lifetime +// issues +// For example: +// +// nsresult MyClass::Enumerate(nsIUTF8StringEnumerator** aResult) { +// mCategoryList->AppendString("abcd"); +// return NS_NewStringEnumerator(aResult, mCategoryList, this); +// } +// +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray, + nsISupports* aOwner); +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray, + nsISupports* aOwner); diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp new file mode 100644 index 00000000..e0774083 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp @@ -0,0 +1,684 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins <scc@mozilla.org>: |do_QueryElementAt| + * Pierre Phaneuf <pp@ludusdesign.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <string.h> +#include "prbit.h" +#include "nsSupportsArray.h" +#include "nsSupportsArrayEnumerator.h" +#include "nsAString.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" + +#if DEBUG_SUPPORTSARRAY +#define MAXSUPPORTS 20 + +class SupportsStats { +public: + SupportsStats(); + ~SupportsStats(); + +}; + +static int sizesUsed; // number of the elements of the arrays used +static int sizesAlloced[MAXSUPPORTS]; // sizes of the allocations. sorted +static int NumberOfSize[MAXSUPPORTS]; // number of this allocation size (1 per array) +static int AllocedOfSize[MAXSUPPORTS]; // number of this allocation size (each size for array used) +static int GrowInPlace[MAXSUPPORTS]; + +// these are per-allocation +static int MaxElements[3000]; + +// very evil +#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])++; break; } \ + } \ + if (i >= sizesUsed && sizesUsed < MAXSUPPORTS) \ + { sizesAlloced[sizesUsed] = (size); \ + ((x)[sizesUsed++])++; break; \ + } \ + } while (0); + +#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])--; break; } \ + } \ + } while (0); + + +SupportsStats::SupportsStats() +{ + sizesUsed = 1; + sizesAlloced[0] = 0; +} + +SupportsStats::~SupportsStats() +{ + int i; + for (i = 0; i < sizesUsed; i++) + { + printf("Size %d:\n",sizesAlloced[i]); + printf("\tNumber of SupportsArrays this size (max): %d\n",NumberOfSize[i]); + printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]); + printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]); + } + printf("Max Size of SupportsArray:\n"); + for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++) + { + if (MaxElements[i]) + printf("\t%d: %d\n",i,MaxElements[i]); + } +} + +// Just so constructor/destructor get called +SupportsStats gSupportsStats; +#endif + +nsresult +nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const + { + nsresult status = mCollection + ? mCollection->QueryElementAt(mIndex, aIID, aResult) + : NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + + return status; + } + +static const PRInt32 kGrowArrayBy = 8; +static const PRInt32 kLinearThreshold = 16 * sizeof(nsISupports *); + +nsSupportsArray::nsSupportsArray() +{ + mArray = mAutoArray; + mArraySize = kAutoArraySize; + mCount = 0; +#if DEBUG_SUPPORTSARRAY + mMaxCount = 0; + mMaxSize = 0; + ADD_TO_STATS(NumberOfSize,kAutoArraySize*sizeof(mArray[0])); + MaxElements[0]++; +#endif +} + +nsSupportsArray::~nsSupportsArray() +{ + DeleteArray(); +} + +PRBool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy) +{ + // 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; + + PRUint32 newCount = mArraySize + aGrowBy; // Minimum increase + PRUint32 newSize = sizeof(mArray[0]) * newCount; + + if (newSize >= (PRUint32) 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 & (newSize - 1)) + newSize = PR_BIT(PR_CeilingLog2(newSize)); + + 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]; + if (!mArray) { // ran out of memory + mArray = oldArray; + return PR_FALSE; + } + mArraySize = newCount; + +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,mCount); + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); + if (mArraySize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,mArraySize*sizeof(mArray[0])); + if (oldArray != &(mAutoArray[0])) + SUB_FROM_STATS(NumberOfSize,mCount*sizeof(mArray[0])); + mMaxSize = mArraySize; + } +#endif + if (oldArray) { // need to move old data + if (0 < mCount) { + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + } + if (oldArray != &(mAutoArray[0])) { + delete[] oldArray; + } + } + + return PR_TRUE; +} + +NS_METHOD +nsSupportsArray::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsCOMPtr<nsISupportsArray> it = new nsSupportsArray(); + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + return it->QueryInterface(aIID, aResult); +} + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsSupportsArray, nsISupportsArray, nsICollection, nsISerializable) + +NS_IMETHODIMP +nsSupportsArray::Read(nsIObjectInputStream *aStream) +{ + nsresult rv; + + PRUint32 newArraySize; + rv = aStream->Read32(&newArraySize); + + 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 (!array) + return NS_ERROR_OUT_OF_MEMORY; + if (mArray != mAutoArray) + delete[] mArray; + mArray = array; + } + } + mArraySize = newArraySize; + + rv = aStream->Read32(&mCount); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!"); + if (mCount > mArraySize) + mCount = mArraySize; + + for (PRUint32 i = 0; i < mCount; i++) { + rv = aStream->ReadObject(PR_TRUE, &mArray[i]); + if (NS_FAILED(rv)) return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArray::Write(nsIObjectOutputStream *aStream) +{ + nsresult rv; + + rv = aStream->Write32(mArraySize); + if (NS_FAILED(rv)) return rv; + + rv = aStream->Write32(mCount); + if (NS_FAILED(rv)) return rv; + + for (PRUint32 i = 0; i < mCount; i++) { + rv = aStream->WriteObject(mArray[i], PR_TRUE); + if (NS_FAILED(rv)) return rv; + } + + return NS_OK; +} + +void nsSupportsArray::DeleteArray(void) +{ + Clear(); + if (mArray != &(mAutoArray[0])) { + delete[] mArray; + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } +} + + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::Equals(const nsISupportsArray* aOther) +{ + if (aOther) { + PRUint32 countOther; + nsISupportsArray* other = NS_CONST_CAST(nsISupportsArray*, aOther); + nsresult rv = other->Count(&countOther); + if (NS_FAILED( rv )) + return PR_FALSE; + + if (mCount == countOther) { + PRUint32 index = mCount; + nsCOMPtr<nsISupports> otherElem; + while (index--) { + if (NS_FAILED(other->GetElementAt(index, getter_AddRefs(otherElem)))) + return PR_FALSE; + if (mArray[index] != otherElem) + return PR_FALSE; + } + return PR_TRUE; + } + } + return PR_FALSE; +} + +NS_IMETHODIMP_(nsISupports*) +nsSupportsArray::ElementAt(PRUint32 aIndex) +{ + if (aIndex < mCount) { + nsISupports* element = mArray[aIndex]; + NS_IF_ADDREF(element); + return element; + } + return 0; +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::IndexOf(const nsISupports* aPossibleElement) +{ + return IndexOfStartingAt(aPossibleElement, 0); +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::IndexOfStartingAt(const nsISupports* aPossibleElement, + PRUint32 aStartIndex) +{ + if (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; +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement) +{ + 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; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex) +{ + if (aIndex <= mCount) { + if (mArraySize < (mCount + 1)) { + // need to grow the array + if (!GrowArrayBy(1)) + return PR_FALSE; + } + + // Could be slightly more efficient if GrowArrayBy knew about the + // split, but the difference is trivial. + PRUint32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*)); + } + + mArray[aIndex] = aElement; + NS_IF_ADDREF(aElement); + mCount++; + +#if DEBUG_SUPPORTSARRAY + if (mCount > mMaxCount && + mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mCount; + } +#endif + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::InsertElementsAt(nsISupportsArray* aElements, PRUint32 aIndex) +{ + if (!aElements) { + return PR_FALSE; + } + PRUint32 countElements; + if (NS_FAILED( aElements->Count( &countElements ) )) + return PR_FALSE; + + if (aIndex <= mCount) { + if (mArraySize < (mCount + countElements)) { + // need to grow the array + if (!GrowArrayBy(countElements)) + return PR_FALSE; + } + + // Could be slightly more efficient if GrowArrayBy knew about the + // split, but the difference is trivial. + PRUint32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex + countElements, mArray + aIndex, + slide * sizeof(nsISupports*)); + } + + for (PRUint32 i = 0; i < countElements; ++i, ++mCount) { + // use GetElementAt to copy and do AddRef for us + if (NS_FAILED( aElements->GetElementAt( i, mArray + aIndex + i) )) + return PR_FALSE; + } + +#if DEBUG_SUPPORTSARRAY + if (mCount > mMaxCount && + mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mCount; + } +#endif + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 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; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount) +{ + if (aIndex + aCount <= mCount) { + for (PRUint32 i = 0; i < aCount; i++) + NS_IF_RELEASE(mArray[aIndex+i]); + mCount -= aCount; + PRInt32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex, mArray + aIndex + aCount, + slide * sizeof(nsISupports*)); + } + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex) +{ + PRInt32 theIndex = IndexOfStartingAt(aElement,aStartIndex); + if (theIndex >= 0) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveLastElement(const nsISupports* aElement) +{ + PRInt32 theIndex = LastIndexOf(aElement); + if (theIndex >= 0) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::MoveElement(PRInt32 aFrom, PRInt32 aTo) +{ + nsISupports *tempElement; + + if (aTo == aFrom) + return PR_TRUE; + + if (aTo < 0 || aFrom < 0 || + (PRUint32) aTo >= mCount || (PRUint32) aFrom >= mCount) + { + // can't extend the array when moving an element. Also catches mImpl = null + return PR_FALSE; + } + tempElement = mArray[aFrom]; + + if (aTo < aFrom) + { + // Moving one element closer to the head; the elements inbetween move down + ::memmove(mArray + aTo + 1, mArray + aTo, + (aFrom-aTo) * sizeof(mArray[0])); + mArray[aTo] = tempElement; + } + else // already handled aFrom == aTo + { + // Moving one element closer to the tail; the elements inbetween move up + ::memmove(mArray + aFrom, mArray + aFrom + 1, + (aTo-aFrom) * sizeof(mArray[0])); + mArray[aTo] = tempElement; + } + + return PR_TRUE; +} + +NS_IMETHODIMP +nsSupportsArray::Clear(void) +{ + if (0 < mCount) { + do { + --mCount; + NS_IF_RELEASE(mArray[mCount]); + } while (0 != mCount); + } + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArray::Compact(void) +{ +#if DEBUG_SUPPORTSARRAY + PRUint32 oldArraySize = mArraySize; +#endif + if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) { + nsISupports** oldArray = mArray; + if (mCount <= kAutoArraySize) { + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } + else { + mArray = new nsISupports*[mCount]; + if (!mArray) { + mArray = oldArray; + return NS_OK; + } + mArraySize = mCount; + } +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray && + oldArray != &(mAutoArray[0])) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,oldArraySize); + if (oldArray != &(mAutoArray[0])) + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); +#endif + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + delete[] oldArray; + } + return NS_OK; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::SizeTo(PRInt32 aSize) +{ +#if DEBUG_SUPPORTSARRAY + PRUint32 oldArraySize = mArraySize; +#endif + NS_ASSERTION(aSize >= 0, "negative aSize!"); + + // XXX for aSize < mCount we could resize to mCount + if (mArraySize == (PRUint32) aSize || (PRUint32) aSize < mCount) + return PR_TRUE; // nothing to do + + // switch back to autoarray if possible + nsISupports** oldArray = mArray; + if ((PRUint32) aSize <= kAutoArraySize) { + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } + else { + mArray = new nsISupports*[aSize]; + if (!mArray) { + mArray = oldArray; + return PR_FALSE; + } + mArraySize = aSize; + } +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray && + oldArray != &(mAutoArray[0])) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,oldArraySize); + if (oldArray != &(mAutoArray[0])) + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); +#endif + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + if (oldArray != mAutoArray) + delete[] oldArray; + + return PR_TRUE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) +{ + PRInt32 aIndex = -1; + PRBool running = PR_TRUE; + + while (running && (++aIndex < (PRInt32)mCount)) { + running = (*aFunc)(mArray[aIndex], aData); + } + return running; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) +{ + PRUint32 aIndex = mCount; + PRBool running = PR_TRUE; + + while (running && (0 < aIndex--)) { + running = (*aFunc)(mArray[aIndex], aData); + } + return running; +} + +NS_IMETHODIMP +nsSupportsArray::Enumerate(nsIEnumerator* *result) +{ + nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this); + if (!e) + return NS_ERROR_OUT_OF_MEMORY; + *result = e; + NS_ADDREF(e); + return NS_OK; +} + +static PRBool +CopyElement(nsISupports* aElement, void *aData) +{ + nsresult rv; + nsISupportsArray* newArray = (nsISupportsArray*)aData; + rv = newArray->AppendElement(aElement); + return NS_SUCCEEDED(rv); +} + +NS_IMETHODIMP +nsSupportsArray::Clone(nsISupportsArray* *result) +{ + nsresult rv; + nsISupportsArray* newArray; + rv = NS_NewISupportsArray(&newArray); + PRBool ok = EnumerateForwards(CopyElement, newArray); + if (!ok) return NS_ERROR_OUT_OF_MEMORY; + *result = newArray; + return NS_OK; +} + +NS_COM nsresult +NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult) +{ + nsresult rv; + rv = nsSupportsArray::Create(NULL, NS_GET_IID(nsISupportsArray), + (void**)aInstancePtrResult); + return rv; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h new file mode 100644 index 00000000..0f9c9601 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsSupportsArray_h__ +#define nsSupportsArray_h__ + +//#define DEBUG_SUPPORTSARRAY 1 + +#include "nsISupportsArray.h" + +static const PRUint32 kAutoArraySize = 8; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + +class NS_COM nsSupportsArray : public nsISupportsArray { +public: + nsSupportsArray(void); + ~nsSupportsArray(void); // nonvirtual since we're not subclassed + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_DECL_ISUPPORTS + + NS_DECL_NSISERIALIZABLE + + // nsICollection methods: + NS_IMETHOD Count(PRUint32 *result) { *result = mCount; return NS_OK; } + NS_IMETHOD GetElementAt(PRUint32 aIndex, nsISupports* *result) { + *result = ElementAt(aIndex); + return NS_OK; + } + NS_IMETHOD QueryElementAt(PRUint32 aIndex, const nsIID & aIID, void * *aResult) { + if (aIndex < mCount) { + nsISupports* element = mArray[aIndex]; + if (nsnull != element) + return element->QueryInterface(aIID, aResult); + } + return NS_ERROR_FAILURE; + } + NS_IMETHOD SetElementAt(PRUint32 aIndex, nsISupports* value) { + return ReplaceElementAt(value, aIndex) ? NS_OK : NS_ERROR_FAILURE; + } + NS_IMETHOD AppendElement(nsISupports *aElement) { + return InsertElementAt(aElement, mCount)/* ? NS_OK : NS_ERROR_FAILURE*/; + } + // XXX this is badly named - should be RemoveFirstElement + NS_IMETHOD RemoveElement(nsISupports *aElement) { + return RemoveElement(aElement, 0)/* ? NS_OK : NS_ERROR_FAILURE*/; + } + NS_IMETHOD_(PRBool) MoveElement(PRInt32 aFrom, PRInt32 aTo); + NS_IMETHOD Enumerate(nsIEnumerator* *result); + NS_IMETHOD Clear(void); + + // nsISupportsArray methods: + NS_IMETHOD_(PRBool) Equals(const nsISupportsArray* aOther); + + NS_IMETHOD_(nsISupports*) ElementAt(PRUint32 aIndex); + + NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement); + NS_IMETHOD_(PRInt32) IndexOfStartingAt(const nsISupports* aPossibleElement, + PRUint32 aStartIndex = 0); + NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement); + + NS_IMETHOD GetIndexOf(nsISupports *aPossibleElement, PRInt32 *_retval) { + *_retval = IndexOf(aPossibleElement); + return NS_OK; + } + + NS_IMETHOD GetIndexOfStartingAt(nsISupports *aPossibleElement, + PRUint32 aStartIndex, PRInt32 *_retval) { + *_retval = IndexOfStartingAt(aPossibleElement, aStartIndex); + return NS_OK; + } + + NS_IMETHOD GetLastIndexOf(nsISupports *aPossibleElement, PRInt32 *_retval) { + *_retval = LastIndexOf(aPossibleElement); + return NS_OK; + } + + NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) RemoveElementAt(PRUint32 aIndex) { + return RemoveElementsAt(aIndex,1); + } + NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex = 0); + NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement); + + NS_IMETHOD DeleteLastElement(nsISupports *aElement) { + return (RemoveLastElement(aElement) ? NS_OK : NS_ERROR_FAILURE); + } + + NS_IMETHOD DeleteElementAt(PRUint32 aIndex) { + return (RemoveElementAt(aIndex) ? NS_OK : NS_ERROR_FAILURE); + } + + NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements) { + return InsertElementsAt(aElements,mCount); + } + + NS_IMETHOD Compact(void); + + NS_IMETHOD_(PRBool) EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData); + NS_IMETHOD_(PRBool) EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData); + + NS_IMETHOD Clone(nsISupportsArray **_retval); + + NS_IMETHOD_(PRBool) InsertElementsAt(nsISupportsArray *aOther, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount); + + NS_IMETHOD_(PRBool) SizeTo(PRInt32 aSize); +protected: + void DeleteArray(void); + + NS_IMETHOD_(PRBool) GrowArrayBy(PRInt32 aGrowBy); + + nsISupports** mArray; + PRUint32 mArraySize; + PRUint32 mCount; + nsISupports* mAutoArray[kAutoArraySize]; +#if DEBUG_SUPPORTSARRAY + PRUint32 mMaxCount; + PRUint32 mMaxSize; +#endif + +private: + // Copy constructors are not allowed + nsSupportsArray(const nsISupportsArray& other); +}; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +#endif // nsSupportsArray_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp new file mode 100644 index 00000000..38d7d728 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsSupportsArrayEnumerator.h" +#include "nsISupportsArray.h" + +nsSupportsArrayEnumerator::nsSupportsArrayEnumerator(nsISupportsArray* array) + : mArray(array), mCursor(0) +{ + NS_ASSERTION(array, "null array"); + NS_ADDREF(mArray); +} + +nsSupportsArrayEnumerator::~nsSupportsArrayEnumerator() +{ + NS_RELEASE(mArray); +} + +NS_IMPL_ISUPPORTS2(nsSupportsArrayEnumerator, nsIBidirectionalEnumerator, nsIEnumerator) + +NS_IMETHODIMP +nsSupportsArrayEnumerator::First() +{ + mCursor = 0; + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + PRInt32 end = (PRInt32)cnt; + if (mCursor < end) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Next() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + PRInt32 end = (PRInt32)cnt; + if (mCursor < end) // don't count upward forever + mCursor++; + if (mCursor < end) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::CurrentItem(nsISupports **aItem) +{ + NS_ASSERTION(aItem, "null out parameter"); + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + if (mCursor >= 0 && mCursor < (PRInt32)cnt) { + *aItem = mArray->ElementAt(mCursor); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::IsDone() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + return (mCursor >= 0 && mCursor < (PRInt32)cnt) + ? NS_ENUMERATOR_FALSE : NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Last() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + mCursor = cnt - 1; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Prev() +{ + if (mCursor >= 0) + --mCursor; + if (mCursor >= 0) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_NewISupportsArrayEnumerator(nsISupportsArray* array, + nsIBidirectionalEnumerator* *aInstancePtrResult) +{ + if (aInstancePtrResult == 0) + return NS_ERROR_NULL_POINTER; + nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(array); + if (e == 0) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(e); + *aInstancePtrResult = e; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h new file mode 100644 index 00000000..e987709f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsSupportsArrayEnumerator_h___ +#define nsSupportsArrayEnumerator_h___ + +#include "nsIEnumerator.h" + +class nsISupportsArray; + +class nsSupportsArrayEnumerator : public nsIBidirectionalEnumerator { +public: + NS_DECL_ISUPPORTS + + nsSupportsArrayEnumerator(nsISupportsArray* array); + + // nsIEnumerator methods: + NS_DECL_NSIENUMERATOR + + // nsIBidirectionalEnumerator methods: + NS_DECL_NSIBIDIRECTIONALENUMERATOR + +private: + ~nsSupportsArrayEnumerator(); + +protected: + nsISupportsArray* mArray; + PRInt32 mCursor; + +}; + +#endif // __nsSupportsArrayEnumerator_h + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp new file mode 100644 index 00000000..7fe5502a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp @@ -0,0 +1,880 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen <dr@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsSupportsPrimitives.h" +#include "nsCRT.h" +#include "nsMemory.h" +#include "prprf.h" +#include "nsIInterfaceInfoManager.h" +#include "nsDependentString.h" +#include "nsReadableUtils.h" +#include "nsPromiseFlatString.h" + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsIDImpl, nsISupportsID, nsISupportsPrimitive) + +nsSupportsIDImpl::nsSupportsIDImpl() + : mData(nsnull) +{ +} + +NS_IMETHODIMP nsSupportsIDImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_ID; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::GetData(nsID **aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + if(mData) + { + *aData = (nsID*) nsMemory::Clone(mData, sizeof(nsID)); + return *aData ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + *aData = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::SetData(const nsID *aData) +{ + if(mData) + nsMemory::Free(mData); + if(aData) + mData = (nsID*) nsMemory::Clone(aData, sizeof(nsID)); + else + mData = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::ToString(char **_retval) +{ + char* result; + NS_ASSERTION(_retval, "Bad pointer"); + if(mData) + { + result = mData->ToString(); + } + else + { + static const char nullStr[] = "null"; + result = (char*) nsMemory::Clone(nullStr, sizeof(nullStr)); + } + + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************** + * nsSupportsCStringImpl + *****************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsCStringImpl, nsISupportsCString, + nsISupportsPrimitive) + +NS_IMETHODIMP nsSupportsCStringImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + + *aType = TYPE_CSTRING; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::GetData(nsACString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::ToString(char **_retval) +{ + *_retval = ToNewCString(mData); + + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::SetData(const nsACString& aData) +{ + mData = aData; + return NS_OK; +} + +/***************************************************************************** + * nsSupportsStringImpl + *****************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsStringImpl, nsISupportsString, + nsISupportsPrimitive) + +NS_IMETHODIMP nsSupportsStringImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + + *aType = TYPE_STRING; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::GetData(nsAString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::ToString(PRUnichar **_retval) +{ + *_retval = ToNewUnicode(mData); + + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::SetData(const nsAString& aData) +{ + mData = aData; + return NS_OK; +} + +/***************************************************************************/ + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsPRBoolImpl, nsISupportsPRBool, + nsISupportsPrimitive) + +nsSupportsPRBoolImpl::nsSupportsPRBoolImpl() + : mData(PR_FALSE) +{ +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRBOOL; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::GetData(PRBool *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::SetData(PRBool aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + const char * str = mData ? "true" : "false"; + char* result = (char*) nsMemory::Clone(str, + (strlen(str)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint8Impl, nsISupportsPRUint8, + nsISupportsPrimitive) + +nsSupportsPRUint8Impl::nsSupportsPRUint8Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT8; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::GetData(PRUint8 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::SetData(PRUint8 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%u", (PRUint16) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint16Impl, nsISupportsPRUint16, + nsISupportsPrimitive) + +nsSupportsPRUint16Impl::nsSupportsPRUint16Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT16; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::GetData(PRUint16 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::SetData(PRUint16 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%u", (int) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint32Impl, nsISupportsPRUint32, + nsISupportsPrimitive) + +nsSupportsPRUint32Impl::nsSupportsPRUint32Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT32; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::GetData(PRUint32 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::SetData(PRUint32 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 16; + char buf[size]; + + PR_snprintf(buf, size, "%lu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint64Impl, nsISupportsPRUint64, + nsISupportsPrimitive) + +nsSupportsPRUint64Impl::nsSupportsPRUint64Impl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT64; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::GetData(PRUint64 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::SetData(PRUint64 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%llu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRTimeImpl, nsISupportsPRTime, + nsISupportsPrimitive) + +nsSupportsPRTimeImpl::nsSupportsPRTimeImpl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRTIME; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::GetData(PRTime *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::SetData(PRTime aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%llu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsCharImpl, nsISupportsChar, + nsISupportsPrimitive) + +nsSupportsCharImpl::nsSupportsCharImpl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsCharImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_CHAR; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::GetData(char *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::SetData(char aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::ToString(char **_retval) +{ + char* result; + NS_ASSERTION(_retval, "Bad pointer"); + + if(nsnull != (result = (char*) nsMemory::Alloc(2*sizeof(char)))) + { + result[0] = mData; + result[1] = '\0'; + } + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt16Impl, nsISupportsPRInt16, + nsISupportsPrimitive) + +nsSupportsPRInt16Impl::nsSupportsPRInt16Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT16; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::GetData(PRInt16 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::SetData(PRInt16 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%d", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt32Impl, nsISupportsPRInt32, + nsISupportsPrimitive) + +nsSupportsPRInt32Impl::nsSupportsPRInt32Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT32; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::GetData(PRInt32 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::SetData(PRInt32 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 16; + char buf[size]; + + PR_snprintf(buf, size, "%ld", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt64Impl, nsISupportsPRInt64, + nsISupportsPrimitive) + +nsSupportsPRInt64Impl::nsSupportsPRInt64Impl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT64; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::GetData(PRInt64 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::SetData(PRInt64 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%lld", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsFloatImpl, nsISupportsFloat, + nsISupportsPrimitive) + +nsSupportsFloatImpl::nsSupportsFloatImpl() + : mData(float(0.0)) +{ +} + +NS_IMETHODIMP nsSupportsFloatImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_FLOAT; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::GetData(float *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::SetData(float aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%f", (double) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsDoubleImpl, nsISupportsDouble, + nsISupportsPrimitive) + +nsSupportsDoubleImpl::nsSupportsDoubleImpl() + : mData(double(0.0)) +{ +} + +NS_IMETHODIMP nsSupportsDoubleImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_DOUBLE; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::GetData(double *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::SetData(double aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%f", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsVoidImpl, nsISupportsVoid, + nsISupportsPrimitive) + +nsSupportsVoidImpl::nsSupportsVoidImpl() + : mData(nsnull) +{ +} + +NS_IMETHODIMP nsSupportsVoidImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_VOID; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::GetData(void * *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::SetData(void * aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + + static const char str[] = "[raw data]"; + char* result = (char*) nsMemory::Clone(str, sizeof(str)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsInterfacePointerImpl, + nsISupportsInterfacePointer, + nsISupportsPrimitive) + +nsSupportsInterfacePointerImpl::nsSupportsInterfacePointerImpl() + : mIID(nsnull) +{ +} + +nsSupportsInterfacePointerImpl::~nsSupportsInterfacePointerImpl() +{ + if (mIID) { + nsMemory::Free(mIID); + } +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_INTERFACE_POINTER; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetData(nsISupports **aData) +{ + NS_ASSERTION(aData,"Bad pointer"); + + *aData = mData; + NS_IF_ADDREF(*aData); + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::SetData(nsISupports * aData) +{ + mData = aData; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetDataIID(nsID **aIID) +{ + NS_ASSERTION(aIID,"Bad pointer"); + + if(mIID) + { + *aIID = (nsID*) nsMemory::Clone(mIID, sizeof(nsID)); + return *aIID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + *aIID = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::SetDataIID(const nsID *aIID) +{ + if(mIID) + nsMemory::Free(mIID); + if(aIID) + mIID = (nsID*) nsMemory::Clone(aIID, sizeof(nsID)); + else + mIID = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + + static const char str[] = "[interface pointer]"; + + // jband sez: think about asking nsIInterfaceInfoManager whether + // the interface has a known human-readable name + char* result = (char*) nsMemory::Clone(str, sizeof(str)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsDependentCString,nsISupportsCString,nsISupportsPrimitive) + +nsSupportsDependentCString::nsSupportsDependentCString(const char* aStr) + : mData(aStr) +{ } + +NS_IMETHODIMP +nsSupportsDependentCString::GetType(PRUint16 *aType) +{ + NS_ENSURE_ARG_POINTER(aType); + + *aType = TYPE_CSTRING; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::GetData(nsACString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::ToString(char **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = ToNewCString(mData); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::SetData(const nsACString& aData) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h new file mode 100644 index 00000000..81e83fa3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h @@ -0,0 +1,358 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen <dr@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsSupportsPrimitives_h__ +#define nsSupportsPrimitives_h__ + +#include "nsISupportsPrimitives.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsDependentString.h" + +class nsSupportsIDImpl : public nsISupportsID +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSID + + nsSupportsIDImpl(); + +private: + ~nsSupportsIDImpl() { } + + nsID *mData; +}; + +/***************************************************************************/ + +class nsSupportsCStringImpl : public nsISupportsCString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCSTRING + + nsSupportsCStringImpl() {} + +private: + ~nsSupportsCStringImpl() {} + + nsCString mData; +}; + +/***************************************************************************/ + +class nsSupportsStringImpl : public nsISupportsString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSSTRING + + nsSupportsStringImpl() {} + +private: + ~nsSupportsStringImpl() {} + + nsString mData; +}; + +/***************************************************************************/ + +class nsSupportsPRBoolImpl : public nsISupportsPRBool +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRBOOL + + nsSupportsPRBoolImpl(); + +private: + ~nsSupportsPRBoolImpl() {} + + PRBool mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint8Impl : public nsISupportsPRUint8 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT8 + + nsSupportsPRUint8Impl(); + +private: + ~nsSupportsPRUint8Impl() {} + + PRUint8 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint16Impl : public nsISupportsPRUint16 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT16 + + nsSupportsPRUint16Impl(); + +private: + ~nsSupportsPRUint16Impl() {} + + PRUint16 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint32Impl : public nsISupportsPRUint32 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT32 + + nsSupportsPRUint32Impl(); + +private: + ~nsSupportsPRUint32Impl() {} + + PRUint32 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint64Impl : public nsISupportsPRUint64 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT64 + + nsSupportsPRUint64Impl(); + +private: + ~nsSupportsPRUint64Impl() {} + + PRUint64 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRTimeImpl : public nsISupportsPRTime +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRTIME + + nsSupportsPRTimeImpl(); + +private: + ~nsSupportsPRTimeImpl() {} + + PRTime mData; +}; + +/***************************************************************************/ + +class nsSupportsCharImpl : public nsISupportsChar +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCHAR + + nsSupportsCharImpl(); + +private: + ~nsSupportsCharImpl() {} + + char mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt16Impl : public nsISupportsPRInt16 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT16 + + nsSupportsPRInt16Impl(); + +private: + ~nsSupportsPRInt16Impl() {} + + PRInt16 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt32Impl : public nsISupportsPRInt32 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT32 + + nsSupportsPRInt32Impl(); + +private: + ~nsSupportsPRInt32Impl() {} + + PRInt32 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt64Impl : public nsISupportsPRInt64 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT64 + + nsSupportsPRInt64Impl(); + +private: + ~nsSupportsPRInt64Impl() {} + + PRInt64 mData; +}; + +/***************************************************************************/ + +class nsSupportsFloatImpl : public nsISupportsFloat +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSFLOAT + + nsSupportsFloatImpl(); + +private: + ~nsSupportsFloatImpl() {} + + float mData; +}; + +/***************************************************************************/ + +class nsSupportsDoubleImpl : public nsISupportsDouble +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSDOUBLE + + nsSupportsDoubleImpl(); + +private: + ~nsSupportsDoubleImpl() {} + + double mData; +}; + +/***************************************************************************/ + +class nsSupportsVoidImpl : public nsISupportsVoid +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSVOID + + nsSupportsVoidImpl(); + +private: + ~nsSupportsVoidImpl() {} + + void* mData; +}; + +/***************************************************************************/ + +class nsSupportsInterfacePointerImpl : public nsISupportsInterfacePointer +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSINTERFACEPOINTER + + nsSupportsInterfacePointerImpl(); + +private: + ~nsSupportsInterfacePointerImpl(); + + nsCOMPtr<nsISupports> mData; + nsID *mIID; +}; + +/***************************************************************************/ + +/** + * Wraps a static const char* buffer for use with nsISupportsCString + * + * Only use this class with static buffers, or arena-allocated buffers of + * permanent lifetime! + */ +class nsSupportsDependentCString : public nsISupportsCString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCSTRING + + nsSupportsDependentCString(const char* aStr); + +private: + ~nsSupportsDependentCString() {} + + nsDependentCString mData; +}; + +#endif /* nsSupportsPrimitives_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp new file mode 100644 index 00000000..37fa998f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsTHashtable.h" +#include "nsHashKeys.h" + +PR_IMPLEMENT(PLDHashOperator) +PL_DHashStubEnumRemove(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 ordinal, + void *userarg) +{ + return PL_DHASH_REMOVE; +} + +PRUint32 nsIDHashKey::HashKey(const nsID* id) +{ + PRUint32 h = id->m0; + PRUint32 i; + + h = (h>>28) ^ (h<<4) ^ id->m1; + h = (h>>28) ^ (h<<4) ^ id->m2; + + for (i = 0; i < 8; i++) + h = (h>>28) ^ (h<<4) ^ id->m3[i]; + + return h; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h new file mode 100644 index 00000000..1e55ada6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h @@ -0,0 +1,429 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsTHashtable_h__ +#define nsTHashtable_h__ + +#include "nscore.h" +#include "pldhash.h" +#include "nsDebug.h" +#include NEW_H + +// helper function for nsTHashtable::Clear() +PR_EXTERN(PLDHashOperator) PR_CALLBACK +PL_DHashStubEnumRemove(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 ordinal, + void *userArg); + + +/** + * a base class for templated hashtables. + * + * Clients will rarely need to use this class directly. Check the derived + * classes first, to see if they will meet your needs. + * + * @param EntryType the templated entry-type class that is managed by the + * hashtable. <code>EntryType</code> must extend the following declaration, + * and <strong>must not declare any virtual functions or derive from classes + * with virtual functions.</strong> Any vtable pointer would break the + * PLDHashTable code. + *<pre> class EntryType : public PLDHashEntryHdr + * { + * public: or friend nsTHashtable<EntryType>; + * // KeyType is what we use when Get()ing or Put()ing this entry + * // this should either be a simple datatype (PRUint32, nsISupports*) or + * // a const reference (const nsAString&) + * typedef something KeyType; + * // KeyTypePointer is the pointer-version of KeyType, because pldhash.h + * // requires keys to cast to <code>const void*</code> + * typedef const something* KeyTypePointer; + * + * EntryType(KeyTypePointer aKey); + * + * // the copy constructor must be defined, even if AllowMemMove() == true + * // or you will cause link errors! + * EntryType(const EntryType& aEnt); + * + * // the destructor must be defined... or you will cause link errors! + * ~EntryType(); + * + * // return the key of this entry + * const KeyTypePointer GetKeyPointer() const; + * + * // KeyEquals(): does this entry match this key? + * PRBool KeyEquals(KeyTypePointer aKey) const; + * + * // KeyToPointer(): Convert KeyType to KeyTypePointer + * static KeyTypePointer KeyToPointer(KeyType aKey); + * + * // HashKey(): calculate the hash number + * static PLDHashNumber HashKey(KeyTypePointer aKey); + * + * // ALLOW_MEMMOVE can we move this class with memmove(), or do we have + * // to use the copy constructor? + * enum { ALLOW_MEMMOVE = PR_(TRUE or FALSE) }; + * }</pre> + * + * @see nsInterfaceHashtable + * @see nsDataHashtable + * @see nsClassHashtable + * @author "Benjamin Smedberg <bsmedberg@covad.net>" + */ + +template<class EntryType> +class nsTHashtable +{ +public: + /** + * A dummy constructor; you must call Init() before using this class. + */ + nsTHashtable(); + + /** + * destructor, cleans up and deallocates + */ + ~nsTHashtable(); + + /** + * Initialize the table. This function must be called before any other + * class operations. This can fail due to OOM conditions. + * @param initSize the initial number of buckets in the hashtable, default 16 + * @return PR_TRUE if the class was initialized properly. + */ + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); + + /** + * Check whether the table has been initialized. This can be useful for static hashtables. + * @return the initialization state of the class. + */ + PRBool IsInitialized() const { return mTable.entrySize; } + + /** + * KeyType is typedef'ed for ease of use. + */ + typedef typename EntryType::KeyType KeyType; + + /** + * KeyTypePointer is typedef'ed for ease of use. + */ + typedef typename EntryType::KeyTypePointer KeyTypePointer; + + /** + * Return the number of entries in the table. + * @return number of entries + */ + PRUint32 Count() const { return mTable.entryCount; } + + /** + * Get the entry associated with a key. + * @param aKey the key to retrieve + * @return pointer to the entry class, if the key exists; nsnull if the + * key doesn't exist + */ + EntryType* GetEntry(KeyType aKey) const + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + EntryType* entry = + NS_REINTERPRET_CAST(EntryType*, + PL_DHashTableOperate( + NS_CONST_CAST(PLDHashTable*,&mTable), + EntryType::KeyToPointer(aKey), + PL_DHASH_LOOKUP)); + return PL_DHASH_ENTRY_IS_BUSY(entry) ? entry : nsnull; + } + + /** + * Get the entry associated with a key, or create a new entry, + * @param aKey the key to retrieve + * @return pointer to the entry class retreived; nsnull only if memory + can't be allocated + */ + EntryType* PutEntry(KeyType aKey) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + return NS_STATIC_CAST(EntryType*, + PL_DHashTableOperate( + &mTable, + EntryType::KeyToPointer(aKey), + PL_DHASH_ADD)); + } + + /** + * Remove the entry associated with a key. + * @param aKey of the entry to remove + */ + void RemoveEntry(KeyType aKey) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + PL_DHashTableOperate(&mTable, + EntryType::KeyToPointer(aKey), + PL_DHASH_REMOVE); + } + + /** + * Remove the entry associated with a key, but don't resize the hashtable. + * This is a low-level method, and is not recommended unless you know what + * you're doing and you need the extra performance. This method can be used + * during enumeration, while RemoveEntry() cannot. + * @param aEntry the entry-pointer to remove (obtained from GetEntry or + * the enumerator + */ + void RawRemoveEntry(EntryType* aEntry) + { + PL_DHashTableRawRemove(&mTable, aEntry); + } + + /** + * client must provide an <code>Enumerator</code> function for + * EnumerateEntries + * @param aEntry the entry being enumerated + * @param userArg passed unchanged from <code>EnumerateEntries</code> + * @return combination of flags + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink , + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink , + * @link PLDHashOperator::PL_DHASH_REMOVE PL_DHASH_REMOVE @endlink + */ + typedef PLDHashOperator (*PR_CALLBACK Enumerator)(EntryType* aEntry, void* userArg); + + /** + * Enumerate all the entries of the function. + * @param enumFunc the <code>Enumerator</code> function to call + * @param userArg a pointer to pass to the + * <code>Enumerator</code> function + * @return the number of entries actually enumerated + */ + PRUint32 EnumerateEntries(Enumerator enumFunc, void* userArg) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + s_EnumArgs args = { enumFunc, userArg }; + return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args); + } + + /** + * remove all entries, return hashtable to "pristine" state ;) + */ + void Clear() + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull); + } + +protected: + PLDHashTable mTable; + + static const void* PR_CALLBACK s_GetKey(PLDHashTable *table, + PLDHashEntryHdr *entry); + + static PLDHashNumber PR_CALLBACK s_HashKey(PLDHashTable *table, + const void *key); + + static PRBool PR_CALLBACK s_MatchEntry(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + + static void PR_CALLBACK s_CopyEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + + static void PR_CALLBACK s_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry); + + static PRBool PR_CALLBACK s_InitEntry(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key); + + /** + * passed internally during enumeration. Allocated on the stack. + * + * @param userFunc the Enumerator function passed to + * EnumerateEntries by the client + * @param userArg the userArg passed unaltered + */ + struct s_EnumArgs + { + Enumerator userFunc; + void* userArg; + }; + + static PLDHashOperator PR_CALLBACK s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 number, + void *arg); +private: + // copy constructor, not implemented + nsTHashtable(nsTHashtable<EntryType>& toCopy); + + // assignment operator, not implemented + nsTHashtable<EntryType>& operator= (nsTHashtable<EntryType>& toEqual); +}; + +// +// template definitions +// + +template<class EntryType> +nsTHashtable<EntryType>::nsTHashtable() +{ + // entrySize is our "I'm initialized" indicator + mTable.entrySize = 0; +} + +template<class EntryType> +nsTHashtable<EntryType>::~nsTHashtable() +{ + if (mTable.entrySize) + PL_DHashTableFinish(&mTable); +} + +template<class EntryType> +PRBool +nsTHashtable<EntryType>::Init(PRUint32 initSize) +{ + if (mTable.entrySize) + { + NS_ERROR("nsTHashtable::Init() should not be called twice."); + return PR_TRUE; + } + + static PLDHashTableOps sOps = + { + ::PL_DHashAllocTable, + ::PL_DHashFreeTable, + s_GetKey, + s_HashKey, + s_MatchEntry, + ::PL_DHashMoveEntryStub, + s_ClearEntry, + ::PL_DHashFinalizeStub, + s_InitEntry + }; + + if (!EntryType::ALLOW_MEMMOVE) + { + sOps.moveEntry = s_CopyEntry; + } + + if (!PL_DHashTableInit(&mTable, &sOps, nsnull, sizeof(EntryType), initSize)) + { + // if failed, reset "flag" + mTable.entrySize = 0; + return PR_FALSE; + } + + return PR_TRUE; +} + +// static definitions + +template<class EntryType> +const void* +nsTHashtable<EntryType>::s_GetKey(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + return ((EntryType*) entry)->GetKeyPointer(); +} + +template<class EntryType> +PLDHashNumber +nsTHashtable<EntryType>::s_HashKey(PLDHashTable *table, + const void *key) +{ + return EntryType::HashKey(NS_REINTERPRET_CAST(const KeyTypePointer, key)); +} + +template<class EntryType> +PRBool +nsTHashtable<EntryType>::s_MatchEntry(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + return ((const EntryType*) entry)->KeyEquals( + NS_REINTERPRET_CAST(const KeyTypePointer, key)); +} + +template<class EntryType> +void +nsTHashtable<EntryType>::s_CopyEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + EntryType* fromEntry = + NS_CONST_CAST(EntryType*, NS_REINTERPRET_CAST(const EntryType*, from)); + + new(to) EntryType(*fromEntry); + + fromEntry->~EntryType(); +} + +template<class EntryType> +void +nsTHashtable<EntryType>::s_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + NS_REINTERPRET_CAST(EntryType*,entry)->~EntryType(); +} + +template<class EntryType> +PRBool +nsTHashtable<EntryType>::s_InitEntry(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key) +{ + new(entry) EntryType(NS_REINTERPRET_CAST(KeyTypePointer,key)); + return PR_TRUE; +} + +template<class EntryType> +PLDHashOperator +nsTHashtable<EntryType>::s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 number, + void *arg) +{ + // dereferences the function-pointer to the user's enumeration function + return (* NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userFunc)( + NS_REINTERPRET_CAST(EntryType*,entry), + NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userArg); +} + +#endif // nsTHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp new file mode 100644 index 00000000..a5f2dde0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp @@ -0,0 +1,1557 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Portable safe sprintf code. + * + * Code based on mozilla/nsprpub/src/io/prprf.c rev 3.7 + * + * Contributor(s): + * Kipp E.B. Hickman <kipp@netscape.com> (original author) + * Frank Yung-Fong Tang <ftang@netscape.com> + * Daniele Nicolodi <daniele@grinta.net> + */ + +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include "prdtoa.h" +#include "prlong.h" +#include "prlog.h" +#include "prmem.h" +#include "prprf.h" +#include "nsCRT.h" +#include "nsTextFormatter.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/* +** Note: on some platforms va_list is defined as an array, +** and requires array notation. +*/ + +#ifdef HAVE_VA_COPY +#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar) +#elif defined(HAVE_VA_LIST_AS_ARRAY) +#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0] +#else +#define VARARGS_ASSIGN(foo, bar) (foo) = (bar) +#endif + +typedef struct SprintfStateStr SprintfState; + +struct SprintfStateStr { + int (*stuff)(SprintfState *ss, const PRUnichar *sp, PRUint32 len); + + PRUnichar *base; + PRUnichar *cur; + PRUint32 maxlen; + + void *stuffclosure; +}; + +/* +** Numbered Arguement State +*/ +struct NumArgState{ + int type; /* type of the current ap */ + va_list ap; /* point to the corresponding position on ap */ +}; + +#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */ + +#define TYPE_INT16 0 +#define TYPE_UINT16 1 +#define TYPE_INTN 2 +#define TYPE_UINTN 3 +#define TYPE_INT32 4 +#define TYPE_UINT32 5 +#define TYPE_INT64 6 +#define TYPE_UINT64 7 +#define TYPE_STRING 8 +#define TYPE_DOUBLE 9 +#define TYPE_INTSTR 10 +#define TYPE_UNISTRING 11 +#define TYPE_UNKNOWN 20 + +#define _LEFT 0x1 +#define _SIGNED 0x2 +#define _SPACED 0x4 +#define _ZEROS 0x8 +#define _NEG 0x10 + +#define ELEMENTS_OF(array_) (sizeof(array_) / sizeof(array_[0])) + +// Warning: if aDest isn't big enough this function returns the converted +// string in allocated memory which must be freed using PR_FREE(). +// May return nsnull if memory couldn't be allocated. +static PRUnichar* UTF8ToUCS2(const char *aSrc, PRUint32 aSrcLen, + PRUnichar* aDest, PRUint32 aDestLen) +{ + const char *in, *inend; + inend = aSrc + aSrcLen; + PRUnichar *out; + PRUint32 state; + PRUint32 ucs4; + // decide the length of the UCS2 first. + PRUint32 needLen = 0; + + for (in = aSrc, state = 0, ucs4 = 0; in < inend; in++) { + if (0 == state) { + if (0 == (0x80 & (*in))) { + needLen++; + } else if (0xC0 == (0xE0 & (*in))) { + needLen++; + state = 1; + } else if (0xE0 == (0xF0 & (*in))) { + needLen++; + state = 2; + } else if (0xF0 == (0xF8 & (*in))) { + needLen+=2; + state = 3; + } else if (0xF8 == (0xFC & (*in))) { + needLen+=2; + state = 4; + } else if (0xFC == (0xFE & (*in))) { + needLen+=2; + state = 5; + } else { + needLen++; + state = 0; + } + } else { + NS_ASSERTION((0x80 == (0xC0 & (*in))), "The input string is not in utf8"); + if(0x80 == (0xC0 & (*in))) { + state--; + } else { + state = 0; + } + } + } + needLen++; // add null termination. + + // allocates sufficient memory if aDest is not big enough. + if (needLen > aDestLen) { + aDest = (PRUnichar*)PR_MALLOC(sizeof(PRUnichar) * needLen); + } + if (nsnull == aDest) { + return nsnull; + } + out = aDest; + + for (in = aSrc, state = 0, ucs4 = 0; in < inend; in++) { + if (0 == state) { + if (0 == (0x80 & (*in))) { + // ASCII + *out++ = (PRUnichar)*in; + } else if (0xC0 == (0xE0 & (*in))) { + // 2 bytes UTF8 + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 6) & 0x000007C0L; + state=1; + } else if (0xE0 == (0xF0 & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 12) & 0x0000F000L; + state=2; + } else if (0xF0 == (0xF8 & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 18) & 0x001F0000L; + state=3; + } else if (0xF8 == (0xFC & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 24) & 0x03000000L; + state=4; + } else if (0xFC == (0xFE & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 30) & 0x40000000L; + state=5; + } else { + NS_ASSERTION(0, "The input string is not in utf8"); + state=0; + ucs4=0; + } + } else { + NS_ASSERTION((0x80 == (0xC0 & (*in))), "The input string is not in utf8"); + if (0x80 == (0xC0 & (*in))) { + PRUint32 tmp = (*in); + int shift = --state * 6; + tmp = (tmp << shift) & (0x0000003FL << shift); + ucs4 |= tmp; + if (0 == state) { + if (ucs4 >= 0x00010000) { + if (ucs4 >= 0x00110000) { + *out++ = 0xFFFD; + } else { + ucs4 -= 0x00010000; + *out++ = 0xD800 | (0x000003FF & (ucs4 >> 10)); + *out++ = 0xDC00 | (0x000003FF & ucs4); + } + } else { + *out++ = ucs4; + } + ucs4 = 0; + } + } else { + state = 0; + ucs4 = 0; + } + } + } + *out = 0x0000; + return aDest; +} + +/* +** Fill into the buffer using the data in src +*/ +static int fill2(SprintfState *ss, const PRUnichar *src, int srclen, + int width, int flags) +{ + PRUnichar space = ' '; + int rv; + + width -= srclen; + /* Right adjusting */ + if ((width > 0) && ((flags & _LEFT) == 0)) { + if (flags & _ZEROS) { + space = '0'; + } + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Copy out the source data */ + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + + /* Left adjusting */ + if ((width > 0) && ((flags & _LEFT) != 0)) { + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + return 0; +} + +/* +** Fill a number. The order is: optional-sign zero-filling conversion-digits +*/ +static int fill_n(SprintfState *ss, const PRUnichar *src, int srclen, + int width, int prec, int type, int flags) +{ + int zerowidth = 0; + int precwidth = 0; + int signwidth = 0; + int leftspaces = 0; + int rightspaces = 0; + int cvtwidth; + int rv; + PRUnichar sign; + PRUnichar space = ' '; + PRUnichar zero = '0'; + + if ((type & 1) == 0) { + if (flags & _NEG) { + sign = '-'; + signwidth = 1; + } else if (flags & _SIGNED) { + sign = '+'; + signwidth = 1; + } else if (flags & _SPACED) { + sign = ' '; + signwidth = 1; + } + } + cvtwidth = signwidth + srclen; + + if (prec > 0) { + if (prec > srclen) { + /* Need zero filling */ + precwidth = prec - srclen; + cvtwidth += precwidth; + } + } + + if ((flags & _ZEROS) && (prec < 0)) { + if (width > cvtwidth) { + /* Zero filling */ + zerowidth = width - cvtwidth; + cvtwidth += zerowidth; + } + } + + if (flags & _LEFT) { + if (width > cvtwidth) { + /* Space filling on the right (i.e. left adjusting) */ + rightspaces = width - cvtwidth; + } + } else { + if (width > cvtwidth) { + /* Space filling on the left (i.e. right adjusting) */ + leftspaces = width - cvtwidth; + } + } + while (--leftspaces >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + if (signwidth) { + rv = (*ss->stuff)(ss, &sign, 1); + if (rv < 0) { + return rv; + } + } + while (--precwidth >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + while (--zerowidth >= 0) { + rv = (*ss->stuff)(ss, &zero, 1); + if (rv < 0) { + return rv; + } + } + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + while (--rightspaces >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + return 0; +} + +/* +** Convert a long into its printable form +*/ +static int cvt_l(SprintfState *ss, long num, int width, int prec, + int radix, int type, int flags, const PRUnichar *hexp) +{ + PRUnichar cvtbuf[100]; + PRUnichar *cvt; + int digits; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (num == 0)) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); + digits = 0; + while (num) { + int digit = (((unsigned long)num) % radix) & 0xF; + *--cvt = hexp[digit]; + digits++; + num = (long)(((unsigned long)num) / radix); + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a 64-bit integer into its printable form +*/ +static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, + int radix, int type, int flags, const PRUnichar *hexp) +{ + PRUnichar cvtbuf[100]; + PRUnichar *cvt; + int digits; + PRInt64 rad; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (LL_IS_ZERO(num))) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + LL_I2L(rad, radix); + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); + digits = 0; + while (!LL_IS_ZERO(num)) { + PRInt32 digit; + PRInt64 quot, rem; + LL_UDIVMOD(", &rem, num, rad); + LL_L2I(digit, rem); + *--cvt = hexp[digit & 0xf]; + digits++; + num = quot; + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a double precision floating point number into its printable +** form. +*/ +static int cvt_f(SprintfState *ss, double d, int width, int prec, + const PRUnichar type, int flags) +{ + int mode = 2; + int decpt; + int sign; + char buf[256]; + char * bufp = buf; + int bufsz = 256; + char num[256]; + char * nump; + char * endnum; + int numdigits = 0; + char exp = 'e'; + + if (prec == -1) { + prec = 6; + } else if (prec > 50) { + // limit precision to avoid PR_dtoa bug 108335 + // and to prevent buffers overflows + prec = 50; + } + + switch (type) { + case 'f': + numdigits = prec; + mode = 3; + break; + case 'E': + exp = 'E'; + // no break + case 'e': + numdigits = prec + 1; + mode = 2; + break; + case 'G': + exp = 'E'; + // no break + case 'g': + if (prec == 0) { + prec = 1; + } + numdigits = prec; + mode = 2; + break; + default: + NS_ERROR("invalid type passed to cvt_f"); + } + + if (PR_dtoa(d, mode, numdigits, &decpt, &sign, &endnum, num, bufsz) == PR_FAILURE) { + buf[0] = '\0'; + return -1; + } + numdigits = endnum - num; + nump = num; + + if (sign) { + *bufp++ = '-'; + } else if (flags & _SIGNED) { + *bufp++ = '+'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++)) { } + } else { + + switch (type) { + + case 'E': + case 'e': + + *bufp++ = *nump++; + if (prec > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + prec--; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + *bufp++ = exp; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); + break; + + case 'f': + + if (decpt < 1) { + *bufp++ = '0'; + if (prec > 0) { + *bufp++ = '.'; + while (decpt++ && prec-- > 0) { + *bufp++ = '0'; + } + while (*nump && prec-- > 0) { + *bufp++ = *nump++; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + } else { + while (*nump && decpt-- > 0) { + *bufp++ = *nump++; + } + while (decpt-- > 0) { + *bufp++ = '0'; + } + if (prec > 0) { + *bufp++ = '.'; + while (*nump && prec-- > 0) { + *bufp++ = *nump++; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + } + *bufp = '\0'; + break; + + case 'G': + case 'g': + + if ((decpt < -3) || ((decpt - 1) >= prec)) { + *bufp++ = *nump++; + numdigits--; + if (numdigits > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + } + } + *bufp++ = exp; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); + } else { + if (decpt < 1) { + *bufp++ = '0'; + if (prec > 0) { + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + while (*nump) { + *bufp++ = *nump++; + } + } + } else { + while (*nump && decpt-- > 0) { + *bufp++ = *nump++; + numdigits--; + } + while (decpt-- > 0) { + *bufp++ = '0'; + } + if (numdigits > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + } + } + } + *bufp = '\0'; + } + } + } + + PRUnichar rbuf[256]; + PRUnichar *rbufp = rbuf; + bufp = buf; + // cast to PRUnichar + while ((*rbufp++ = *bufp++)) { } + *rbufp = '\0'; + + return fill2(ss, rbuf, nsCRT::strlen(rbuf), width, flags); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_S(SprintfState *ss, const PRUnichar *s, int width, + int prec, int flags) +{ + int slen; + + if (prec == 0) { + return 0; + } + + /* Limit string length by precision value */ + slen = s ? nsCRT::strlen(s) : 6; + if (prec > 0) { + if (prec < slen) { + slen = prec; + } + } + + /* and away we go */ + NS_NAMED_LITERAL_STRING(nullstr, "(null)"); + + return fill2(ss, s ? s : nullstr.get(), slen, width, flags); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_s(SprintfState *ss, const char *s, int width, + int prec, int flags) +{ + // convert s from UTF8 to PRUnichar* + // Fix me !!! + PRUnichar buf[256]; + PRUnichar *retbuf = nsnull; + + if (s) { + retbuf = UTF8ToUCS2(s, strlen(s), buf, 256); + if(nsnull == retbuf) { + return -1; + } + } + int ret = cvt_S(ss, retbuf, width, prec, flags); + + if (retbuf != buf) { + PR_DELETE(retbuf); + } + return ret; +} + +/* +** BiuldArgArray stands for Numbered Argument list Sprintf +** for example, +** fmp = "%4$i, %2$d, %3s, %1d"; +** the number must start from 1, and no gap among them +*/ + +static struct NumArgState* BuildArgArray(const PRUnichar *fmt, + va_list ap, int * rv, + struct NumArgState * nasArray) +{ + int number = 0, cn = 0, i; + const PRUnichar* p; + PRUnichar c; + struct NumArgState* nas; + + /* + ** first pass: + ** detemine how many legal % I have got, then allocate space + */ + p = fmt; + *rv = 0; + i = 0; + while ((c = *p++) != 0) { + if (c != '%') { + continue; + } + /* skip %% case */ + if ((c = *p++) == '%') { + continue; + } + + while( c != 0 ){ + if (c > '9' || c < '0') { + /* numbered argument csae */ + if (c == '$') { + if (i > 0) { + *rv = -1; + return NULL; + } + number++; + break; + + } else { + /* non-numbered argument case */ + if (number > 0) { + *rv = -1; + return NULL; + } + i = 1; + break; + } + } + c = *p++; + } + } + + if (number == 0) { + return NULL; + } + + if (number > NAS_DEFAULT_NUM) { + nas = (struct NumArgState*)PR_MALLOC(number * sizeof(struct NumArgState)); + if (!nas) { + *rv = -1; + return NULL; + } + } else { + nas = nasArray; + } + + for (i = 0; i < number; i++) { + nas[i].type = TYPE_UNKNOWN; + } + + /* + ** second pass: + ** set nas[].type + */ + p = fmt; + while ((c = *p++) != 0) { + if (c != '%') { + continue; + } + c = *p++; + if (c == '%') { + continue; + } + cn = 0; + /* should imporve error check later */ + while (c && c != '$') { + cn = cn*10 + c - '0'; + c = *p++; + } + + if (!c || cn < 1 || cn > number) { + *rv = -1; + break; + } + + /* nas[cn] starts from 0, and make sure + nas[cn].type is not assigned */ + cn--; + if (nas[cn].type != TYPE_UNKNOWN) { + continue; + } + + c = *p++; + + /* width */ + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } else { + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + + /* precision */ + if (c == '.') { + c = *p++; + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } else { + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + } + + /* size */ + nas[cn].type = TYPE_INTN; + if (c == 'h') { + nas[cn].type = TYPE_INT16; + c = *p++; + } else if (c == 'L') { + /* XXX not quite sure here */ + nas[cn].type = TYPE_INT64; + c = *p++; + } else if (c == 'l') { + nas[cn].type = TYPE_INT32; + c = *p++; + if (c == 'l') { + nas[cn].type = TYPE_INT64; + c = *p++; + } + } + + /* format */ + switch (c) { + case 'd': + case 'c': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + break; + + case 'e': + case 'f': + case 'g': + nas[cn].type = TYPE_DOUBLE; + break; + + case 'p': + /* XXX should use cpp */ + if (sizeof(void *) == sizeof(PRInt32)) { + nas[cn].type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + nas[cn].type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(PRIntn)) { + nas[cn].type = TYPE_UINTN; + } else { + nas[cn].type = TYPE_UNKNOWN; + } + break; + + case 'C': + /* XXX not supported I suppose */ + PR_ASSERT(0); + nas[cn].type = TYPE_UNKNOWN; + break; + + case 'S': + nas[cn].type = TYPE_UNISTRING; + break; + + case 's': + nas[cn].type = TYPE_STRING; + break; + + case 'n': + nas[cn].type = TYPE_INTSTR; + break; + + default: + PR_ASSERT(0); + nas[cn].type = TYPE_UNKNOWN; + break; + } + + /* get a legal para. */ + if (nas[cn].type == TYPE_UNKNOWN) { + *rv = -1; + break; + } + } + + + /* + ** third pass + ** fill the nas[cn].ap + */ + if (*rv < 0) { + if( nas != nasArray ) { + PR_DELETE(nas); + } + return NULL; + } + + cn = 0; + while (cn < number) { + if (nas[cn].type == TYPE_UNKNOWN) { + cn++; + continue; + } + + VARARGS_ASSIGN(nas[cn].ap, ap); + + switch (nas[cn].type) { + case TYPE_INT16: + case TYPE_UINT16: + case TYPE_INTN: + case TYPE_UINTN: (void)va_arg(ap, PRIntn); break; + + case TYPE_INT32: (void)va_arg(ap, PRInt32); break; + + case TYPE_UINT32: (void)va_arg(ap, PRUint32); break; + + case TYPE_INT64: (void)va_arg(ap, PRInt64); break; + + case TYPE_UINT64: (void)va_arg(ap, PRUint64); break; + + case TYPE_STRING: (void)va_arg(ap, char*); break; + + case TYPE_INTSTR: (void)va_arg(ap, PRIntn*); break; + + case TYPE_DOUBLE: (void)va_arg(ap, double); break; + + case TYPE_UNISTRING: (void)va_arg(ap, PRUnichar*); break; + + default: + if( nas != nasArray ) { + PR_DELETE( nas ); + } + *rv = -1; + return NULL; + } + cn++; + } + return nas; +} + +/* +** The workhorse sprintf code. +*/ +static int dosprintf(SprintfState *ss, const PRUnichar *fmt, va_list ap) +{ + PRUnichar c; + int flags, width, prec, radix, type; + union { + PRUnichar ch; + int i; + long l; + PRInt64 ll; + double d; + const char *s; + const PRUnichar *S; + int *ip; + } u; + PRUnichar space = ' '; + const PRUnichar *fmt0; + + nsAutoString hex; + hex.AssignLiteral("0123456789abcdef"); + + nsAutoString HEX; + HEX.AssignLiteral("0123456789ABCDEF"); + + const PRUnichar *hexp; + int rv, i; + struct NumArgState* nas = NULL; + struct NumArgState nasArray[NAS_DEFAULT_NUM]; + /* in "%4$.2f" dolPt will point to . */ + const PRUnichar* dolPt = NULL; + + + /* + ** build an argument array, IF the fmt is numbered argument + ** list style, to contain the Numbered Argument list pointers + */ + nas = BuildArgArray (fmt, ap, &rv, nasArray); + if (rv < 0) { + /* the fmt contains error Numbered Argument format, jliu@netscape.com */ + PR_ASSERT(0); + return rv; + } + + while ((c = *fmt++) != 0) { + if (c != '%') { + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + fmt0 = fmt - 1; + + /* + ** Gobble up the % format string. Hopefully we have handled all + ** of the strange cases! + */ + flags = 0; + c = *fmt++; + if (c == '%') { + /* quoting a % with %% */ + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + + if (nas != NULL) { + /* the fmt contains the Numbered Arguments feature */ + i = 0; + /* should imporve error check later */ + while (c && c != '$') { + i = (i * 10) + (c - '0'); + c = *fmt++; + } + + if (nas[i-1].type == TYPE_UNKNOWN) { + if (nas && (nas != nasArray)) { + PR_DELETE(nas); + } + return -1; + } + + ap = nas[i-1].ap; + dolPt = fmt; + c = *fmt++; + } + + /* + * Examine optional flags. Note that we do not implement the + * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is + * somewhat ambiguous and not ideal, which is perhaps why + * the various sprintf() implementations are inconsistent + * on this feature. + */ + while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { + if (c == '-') flags |= _LEFT; + if (c == '+') flags |= _SIGNED; + if (c == ' ') flags |= _SPACED; + if (c == '0') flags |= _ZEROS; + c = *fmt++; + } + if (flags & _SIGNED) flags &= ~_SPACED; + if (flags & _LEFT) flags &= ~_ZEROS; + + /* width */ + if (c == '*') { + c = *fmt++; + width = va_arg(ap, int); + } else { + width = 0; + while ((c >= '0') && (c <= '9')) { + width = (width * 10) + (c - '0'); + c = *fmt++; + } + } + + /* precision */ + prec = -1; + if (c == '.') { + c = *fmt++; + if (c == '*') { + c = *fmt++; + prec = va_arg(ap, int); + } else { + prec = 0; + while ((c >= '0') && (c <= '9')) { + prec = (prec * 10) + (c - '0'); + c = *fmt++; + } + } + } + + /* size */ + type = TYPE_INTN; + if (c == 'h') { + type = TYPE_INT16; + c = *fmt++; + } else if (c == 'L') { + /* XXX not quite sure here */ + type = TYPE_INT64; + c = *fmt++; + } else if (c == 'l') { + type = TYPE_INT32; + c = *fmt++; + if (c == 'l') { + type = TYPE_INT64; + c = *fmt++; + } + } + + /* format */ + hexp = hex.get(); + switch (c) { + case 'd': + case 'i': /* decimal/integer */ + radix = 10; + goto fetch_and_convert; + + case 'o': /* octal */ + radix = 8; + type |= 1; + goto fetch_and_convert; + + case 'u': /* unsigned decimal */ + radix = 10; + type |= 1; + goto fetch_and_convert; + + case 'x': /* unsigned hex */ + radix = 16; + type |= 1; + goto fetch_and_convert; + + case 'X': /* unsigned HEX */ + radix = 16; + hexp = HEX.get(); + type |= 1; + goto fetch_and_convert; + + fetch_and_convert: + switch (type) { + case TYPE_INT16: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINT16: + u.l = va_arg(ap, int) & 0xffff; + goto do_long; + case TYPE_INTN: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINTN: + u.l = (long)va_arg(ap, unsigned int); + goto do_long; + + case TYPE_INT32: + u.l = va_arg(ap, PRInt32); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINT32: + u.l = (long)va_arg(ap, PRUint32); + do_long: + rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + + case TYPE_INT64: + u.ll = va_arg(ap, PRInt64); + if (!LL_GE_ZERO(u.ll)) { + LL_NEG(u.ll, u.ll); + flags |= _NEG; + } + goto do_longlong; + case TYPE_UINT64: + u.ll = va_arg(ap, PRUint64); + do_longlong: + rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + } + break; + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + u.d = va_arg(ap, double); + rv = cvt_f(ss, u.d, width, prec, c, flags); + if (rv < 0) { + return rv; + } + break; + + case 'c': + u.ch = va_arg(ap, int); + if ((flags & _LEFT) == 0) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + rv = (*ss->stuff)(ss, &u.ch, 1); + if (rv < 0) { + return rv; + } + if (flags & _LEFT) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + break; + + case 'p': + if (sizeof(void *) == sizeof(PRInt32)) { + type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(int)) { + type = TYPE_UINTN; + } else { + PR_ASSERT(0); + break; + } + radix = 16; + goto fetch_and_convert; + +#if 0 + case 'C': + /* XXX not supported I suppose */ + PR_ASSERT(0); + break; +#endif + + case 'S': + u.S = va_arg(ap, const PRUnichar*); + rv = cvt_S(ss, u.S, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 's': + u.s = va_arg(ap, const char*); + rv = cvt_s(ss, u.s, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 'n': + u.ip = va_arg(ap, int*); + if (u.ip) { + *u.ip = ss->cur - ss->base; + } + break; + + default: + /* Not a % token after all... skip it */ +#if 0 + PR_ASSERT(0); +#endif + PRUnichar perct = '%'; + rv = (*ss->stuff)(ss, &perct, 1); + if (rv < 0) { + return rv; + } + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Stuff trailing NUL */ + PRUnichar null = '\0'; + + rv = (*ss->stuff)(ss, &null, 1); + + if( nas && ( nas != nasArray ) ){ + PR_DELETE( nas ); + } + + return rv; +} + +/************************************************************************/ + +static int +StringStuff(SprintfState* ss, const PRUnichar* sp, PRUint32 len) +{ + ptrdiff_t off = ss->cur - ss->base; + + nsAString* str = NS_STATIC_CAST(nsAString*,ss->stuffclosure); + str->Append(sp, len); + + // we can assume contiguous storage + nsAString::iterator begin; + str->BeginWriting(begin); + ss->base = begin.get(); + ss->cur = ss->base + off; + + return 0; +} + +/* +** Stuff routine that automatically grows the malloc'd output buffer +** before it overflows. +*/ +static int GrowStuff(SprintfState *ss, const PRUnichar *sp, PRUint32 len) +{ + ptrdiff_t off; + PRUnichar *newbase; + PRUint32 newlen; + + off = ss->cur - ss->base; + if (off + len >= ss->maxlen) { + /* Grow the buffer */ + newlen = ss->maxlen + ((len > 32) ? len : 32); + if (ss->base) { + newbase = (PRUnichar*) PR_REALLOC(ss->base, newlen*sizeof(PRUnichar)); + } else { + newbase = (PRUnichar*) PR_MALLOC(newlen*sizeof(PRUnichar)); + } + if (!newbase) { + /* Ran out of memory */ + return -1; + } + ss->base = newbase; + ss->maxlen = newlen; + ss->cur = ss->base + off; + } + + /* Copy data */ + while (len) { + --len; + *ss->cur++ = *sp++; + } + PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen); + return 0; +} + +/* +** sprintf into a malloc'd buffer +*/ +PRUnichar * nsTextFormatter::smprintf(const PRUnichar *fmt, ...) +{ + va_list ap; + PRUnichar *rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vsmprintf(fmt, ap); + va_end(ap); + return rv; +} + +PRUint32 nsTextFormatter::ssprintf(nsAString& out, const PRUnichar* fmt, ...) +{ + va_list ap; + PRUint32 rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vssprintf(out, fmt, ap); + va_end(ap); + return rv; +} + +/* +** Free memory allocated, for the caller, by smprintf +*/ +void nsTextFormatter::smprintf_free(PRUnichar *mem) +{ + PR_DELETE(mem); +} + +PRUint32 nsTextFormatter::vssprintf(nsAString& out, const PRUnichar* fmt, va_list ap) +{ + SprintfState ss; + ss.stuff = StringStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + ss.stuffclosure = &out; + + out.Truncate(); + int n = dosprintf(&ss, fmt, ap); + return n ? n - 1 : n; +} + +PRUnichar * nsTextFormatter::vsmprintf(const PRUnichar *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} + +/* +** Stuff routine that discards overflow data +*/ +static int LimitStuff(SprintfState *ss, const PRUnichar *sp, PRUint32 len) +{ + PRUint32 limit = ss->maxlen - (ss->cur - ss->base); + + if (len > limit) { + len = limit; + } + while (len) { + --len; + *ss->cur++ = *sp++; + } + return 0; +} + +/* +** sprintf into a fixed size buffer. Make sure there is a NUL at the end +** when finished. +*/ +PRUint32 nsTextFormatter::snprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + va_start(ap, fmt); + rv = nsTextFormatter::vsnprintf(out, outlen, fmt, ap); + va_end(ap); + return rv; +} + +PRUint32 nsTextFormatter::vsnprintf(PRUnichar *out, PRUint32 outlen,const PRUnichar *fmt, + va_list ap) +{ + SprintfState ss; + PRUint32 n; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + ss.stuff = LimitStuff; + ss.base = out; + ss.cur = out; + ss.maxlen = outlen; + (void) dosprintf(&ss, fmt, ap); + + /* If we added chars, and we didn't append a null, do it now. */ + if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') ) + *(--ss.cur) = '\0'; + + n = ss.cur - ss.base; + return n ? n - 1 : n; +} + +PRUnichar * nsTextFormatter::sprintf_append(PRUnichar *last, const PRUnichar *fmt, ...) +{ + va_list ap; + PRUnichar *rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vsprintf_append(last, fmt, ap); + va_end(ap); + return rv; +} + +PRUnichar * nsTextFormatter::vsprintf_append(PRUnichar *last, const PRUnichar *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + if (last) { + int lastlen = nsCRT::strlen(last); + ss.base = last; + ss.cur = last + lastlen; + ss.maxlen = lastlen; + } else { + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + } + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} +#ifdef DEBUG +PRBool nsTextFormatter::SelfTest() +{ + PRBool passed = PR_TRUE ; + nsAutoString fmt(NS_LITERAL_STRING("%3$s %4$S %1$d %2$d")); + + char utf8[] = "Hello"; + PRUnichar ucs2[]={'W', 'o', 'r', 'l', 'd', 0x4e00, 0xAc00, 0xFF45, 0x0103}; + int d=3; + + + PRUnichar buf[256]; + int ret; + ret = nsTextFormatter::snprintf(buf, 256, fmt.get(), d, 333, utf8, ucs2); + printf("ret = %d\n", ret); + nsAutoString out(buf); + printf("%s \n", NS_LossyConvertUCS2toASCII(out).get()); + const PRUnichar *uout = out.get(); + for(PRUint32 i=0;i<out.Length();i++) + printf("%2X ", uout[i]); + + return passed; +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.h b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.h new file mode 100644 index 00000000..903ac195 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsTextFormatter_h___ +#define nsTextFormatter_h___ + +/* +** API for PR printf like routines. Supports the following formats +** %d - decimal +** %u - unsigned decimal +** %x - unsigned hex +** %X - unsigned uppercase hex +** %o - unsigned octal +** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above +** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above +** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above +** %s - utf8 string +** %S - PRUnichar string +** %c - character +** %p - pointer (deals with machine dependent pointer size) +** %f - float +** %g - float +*/ +#include "prtypes.h" +#include "prio.h" +#include <stdio.h> +#include <stdarg.h> +#include "nscore.h" +#include "nsAString.h" + + +class NS_COM nsTextFormatter { + +public: + +/* +** sprintf into a fixed size buffer. Guarantees that a NUL is at the end +** of the buffer. Returns the length of the written output, NOT including +** the NUL, or (PRUint32)-1 if an error occurs. +*/ +static PRUint32 snprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, ...); + +/* +** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "smprintf_free" to release +** the memory returned. +*/ +static PRUnichar* smprintf(const PRUnichar *fmt, ...); + + +static PRUint32 ssprintf(nsAString& out, const PRUnichar* fmt, ...); +/* +** Free the memory allocated, for the caller, by smprintf +*/ +static void smprintf_free(PRUnichar *mem); + +/* +** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of +** the PR_MALLOC'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, PR_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +static PRUnichar* sprintf_append(PRUnichar *last, const PRUnichar *fmt, ...); + +/* +** va_list forms of the above. +*/ +static PRUint32 vsnprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, va_list ap); +static PRUnichar* vsmprintf(const PRUnichar *fmt, va_list ap); +static PRUint32 vssprintf(nsAString& out, const PRUnichar *fmt, va_list ap); +static PRUnichar* vsprintf_append(PRUnichar *last, const PRUnichar *fmt, va_list ap); + +#ifdef DEBUG +static PRBool SelfTest(); +#endif + + +}; + +#endif /* nsTextFormatter_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTime.h b/src/libs/xpcom18a4/xpcom/ds/nsTime.h new file mode 100644 index 00000000..f5c3a0ab --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTime.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsTime_h__ +#define nsTime_h__ + +#include "prtime.h" +#include "nsInt64.h" +#include "nscore.h" + +/** + * This class encapsulates full 64-bit time functionality and + * provides simple arithmetic and conversion operations. + */ + +// If you ever decide that you need to add a non-inline method to this +// class, be sure to change the class declaration to "class NS_BASE +// nsTime". + +class nsTime : public nsInt64 +{ +public: + /** + * Construct the current time. + */ + nsTime(void) : nsInt64(PR_Now()) { + } + + /** + * Construct the time from a string. + */ + nsTime(const char* dateStr, PRBool defaultToGMT) { + PRInt64 theTime; + PRStatus status = PR_ParseTimeString(dateStr, defaultToGMT, &theTime); + if (status == PR_SUCCESS) + mValue = theTime; + else + mValue = LL_ZERO; + } + + /** + * Construct a time from a PRTime. + */ + nsTime(const PRTime aTime) : nsInt64(aTime) { + } + + /** + * Construct a time from a 64-bit value. + */ + nsTime(const nsInt64& aTime) : nsInt64(aTime) { + } + + /** + * Construct a time from another time. + */ + nsTime(const nsTime& aTime) : nsInt64(aTime.mValue) { + } + + // ~nsTime(void) -- XXX destructor unnecessary + + /** + * Assign one time to another. + */ + const nsTime& operator =(const nsTime& aTime) { + mValue = aTime.mValue; + return *this; + } + + /** + * Convert a nsTime object to a PRTime + */ + operator PRTime(void) const { + return mValue; + } +}; + +/** + * Determine if one time is strictly less than another + */ +inline const PRBool +operator <(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue < aTime2.mValue; +} + +/** + * Determine if one time is less than or equal to another + */ +inline const PRBool +operator <=(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue <= aTime2.mValue; +} + +/** + * Determine if one time is strictly greater than another + */ +inline const PRBool +operator >(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue > aTime2.mValue; +} + +/** + * Determine if one time is greater than or equal to another + */ +inline const PRBool +operator >=(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue >= aTime2.mValue; +} + +#endif // nsTime_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp new file mode 100644 index 00000000..4974f562 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsTimelineService.h" +#include "prlong.h" +#include "prprf.h" +#include "prenv.h" +#include "plhash.h" +#include "prlock.h" +#include "prinit.h" +#include "prinrval.h" +#include "prthread.h" + +#ifdef MOZ_TIMELINE + +#define MAXINDENT 20 + +#ifdef XP_MAC +static PRIntervalTime initInterval = 0; +#endif + +static PRFileDesc *timelineFD = PR_STDERR; +static PRBool gTimelineDisabled = PR_TRUE; + +// Notes about threading: +// We avoid locks as we always use thread-local-storage. +// This means every other thread has its own private copy of +// data, and this thread can't re-enter (as our implemenation +// doesn't call back out anywhere). Thus, we can avoid locks! +// TLS index +static const PRUintn BAD_TLS_INDEX = (PRUintn) -1; +static PRUintn gTLSIndex = BAD_TLS_INDEX; + +class TimelineThreadData { +public: + TimelineThreadData() : initTime(0), indent(0), + disabled(PR_TRUE), timers(nsnull) {} + ~TimelineThreadData() {if (timers) PL_HashTableDestroy(timers);} + PRTime initTime; + PRHashTable *timers; + int indent; + PRBool disabled; +}; + +/* Implementation file */ +NS_IMPL_THREADSAFE_ISUPPORTS1(nsTimelineService, nsITimelineService) + +static PRTime Now(void); + +/* + * Timer structure stored in a hash table to keep track of named + * timers. + */ +class nsTimelineServiceTimer { + public: + nsTimelineServiceTimer(); + ~nsTimelineServiceTimer(); + void start(); + + /* + * Caller passes in "now" rather than having us calculate it so + * that we can avoid including timer overhead in the time being + * measured. + */ + void stop(PRTime now); + void reset(); + PRTime getAccum(); + PRTime getAccum(PRTime now); + + private: + PRTime mAccum; + PRTime mStart; + PRInt32 mRunning; + PRThread *mOwnerThread; // only used for asserts - could be #if MOZ_DEBUG +}; + +#define TIMER_CHECK_OWNER() \ + NS_ABORT_IF_FALSE(PR_GetCurrentThread() == mOwnerThread, \ + "Timer used by non-owning thread") + + +nsTimelineServiceTimer::nsTimelineServiceTimer() +: mAccum(LL_ZERO), mStart(LL_ZERO), mRunning(0), + mOwnerThread(PR_GetCurrentThread()) +{ +} + +nsTimelineServiceTimer::~nsTimelineServiceTimer() +{ +} + +void nsTimelineServiceTimer::start() +{ + TIMER_CHECK_OWNER(); + if (!mRunning) { + mStart = Now(); + } + mRunning++; +} + +void nsTimelineServiceTimer::stop(PRTime now) +{ + TIMER_CHECK_OWNER(); + mRunning--; + if (mRunning == 0) { + PRTime delta, accum; + LL_SUB(delta, now, mStart); + LL_ADD(accum, mAccum, delta); + mAccum = accum; + } +} + +void nsTimelineServiceTimer::reset() +{ + TIMER_CHECK_OWNER(); + mStart = 0; + mAccum = 0; +} + +PRTime nsTimelineServiceTimer::getAccum() +{ + TIMER_CHECK_OWNER(); + PRTime accum; + + if (!mRunning) { + accum = mAccum; + } else { + PRTime delta; + LL_SUB(delta, Now(), mStart); + LL_ADD(accum, mAccum, delta); + } + return accum; +} + +PRTime nsTimelineServiceTimer::getAccum(PRTime now) +{ + TIMER_CHECK_OWNER(); + PRTime accum; + + if (!mRunning) { + accum = mAccum; + } else { + PRTime delta; + LL_SUB(delta, now, mStart); + LL_ADD(accum, mAccum, delta); + } + return accum; +} + +#ifdef XP_MAC +/* + * PR_Now() on the Mac only gives us a resolution of seconds. Using + * PR_IntervalNow() gives us better resolution. with the drawback that + * the timeline is only good for about six hours. + * + * PR_IntervalNow() occasionally exhibits discontinuities on Windows, + * so we only use it on the Mac. Bleah! + */ +static PRTime Now(void) +{ + PRIntervalTime numTicks = PR_IntervalNow() - initInterval; + PRTime now; + LL_ADD(now, initTime, PR_IntervalToMilliseconds(numTicks) * 1000); + return now; +} +#else +static PRTime Now(void) +{ + return PR_Now(); +} +#endif + +static TimelineThreadData *GetThisThreadData() +{ + NS_ABORT_IF_FALSE(gTLSIndex!=BAD_TLS_INDEX, "Our TLS not initialized"); + TimelineThreadData *new_data = nsnull; + TimelineThreadData *data = (TimelineThreadData *)PR_GetThreadPrivate(gTLSIndex); + if (data == nsnull) { + // First request for this thread - allocate it. + new_data = new TimelineThreadData(); + if (!new_data) + goto done; + + // Fill it + new_data->timers = PL_NewHashTable(100, PL_HashString, PL_CompareStrings, + PL_CompareValues, NULL, NULL); + if (new_data->timers==NULL) + goto done; + new_data->initTime = PR_Now(); + NS_WARN_IF_FALSE(!gTimelineDisabled, + "Why are we creating new state when disabled?"); + new_data->disabled = PR_FALSE; + data = new_data; + new_data = nsnull; + PR_SetThreadPrivate(gTLSIndex, data); + } +done: + if (new_data) // eeek - error during creation! + delete new_data; + NS_WARN_IF_FALSE(data, "TimelineService could not get thread-local data"); + return data; +} + +extern "C" { + static void ThreadDestruct (void *data); + static PRStatus TimelineInit(void); +}; + +void ThreadDestruct( void *data ) +{ + if (data) + delete (TimelineThreadData *)data; +} + +/* +* PRCallOnceFN that initializes stuff for the timing service. +*/ +static PRCallOnceType initonce; + +PRStatus TimelineInit(void) +{ + char *timeStr; + char *fileName; + PRInt32 secs, msecs; + PRFileDesc *fd; + PRInt64 tmp1, tmp2; + + PRStatus status = PR_NewThreadPrivateIndex( &gTLSIndex, ThreadDestruct ); + NS_WARN_IF_FALSE(status==0, "TimelineService could not allocate TLS storage."); + + timeStr = PR_GetEnv("NS_TIMELINE_INIT_TIME"); +#ifdef XP_MAC + initInterval = PR_IntervalNow(); +#endif + // NS_TIMELINE_INIT_TIME only makes sense for the main thread, so if it + // exists, set it there. If not, let normal thread management code take + // care of setting the init time. + if (timeStr != NULL && 2 == PR_sscanf(timeStr, "%d.%d", &secs, &msecs)) { + PRTime &initTime = GetThisThreadData()->initTime; + LL_MUL(tmp1, (PRInt64)secs, 1000000); + LL_MUL(tmp2, (PRInt64)msecs, 1000); + LL_ADD(initTime, tmp1, tmp2); +#ifdef XP_MAC + initInterval -= PR_MicrosecondsToInterval( + (PRUint32)(PR_Now() - initTime)); +#endif + } + // Get the log file. +#ifdef XP_MAC + fileName = "timeline.txt"; +#else + fileName = PR_GetEnv("NS_TIMELINE_LOG_FILE"); +#endif + if (fileName != NULL + && (fd = PR_Open(fileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666)) != NULL) { + timelineFD = fd; + PR_fprintf(fd, + "NOTE: due to asynchrony, the indentation that you see does" + " not necessarily correspond to nesting in the code.\n\n"); + } + + // Runtime disable of timeline + if (PR_GetEnv("NS_TIMELINE_ENABLE")) + gTimelineDisabled = PR_FALSE; + return PR_SUCCESS; +} + +static void ParseTime(PRTime tm, PRInt32& secs, PRInt32& msecs) +{ + PRTime llsecs, llmsecs, tmp; + + LL_DIV(llsecs, tm, 1000000); + LL_MOD(tmp, tm, 1000000); + LL_DIV(llmsecs, tmp, 1000); + + LL_L2I(secs, llsecs); + LL_L2I(msecs, llmsecs); +} + +static char *Indent(char *buf) +{ + int &indent = GetThisThreadData()->indent; + int amount = indent; + if (amount > MAXINDENT) { + amount = MAXINDENT; + } + if (amount < 0) { + amount = 0; + indent = 0; + PR_Write(timelineFD, "indent underflow!\n", 18); + } + while (amount--) { + *buf++ = ' '; + } + return buf; +} + +static void PrintTime(PRTime tm, const char *text, va_list args) +{ + PRInt32 secs, msecs; + char pbuf[550], *pc, tbuf[550]; + + ParseTime(tm, secs, msecs); + + // snprintf/write rather than fprintf because we don't want + // messages from multiple threads to garble one another. + pc = Indent(pbuf); + PR_vsnprintf(pc, sizeof pbuf - (pc - pbuf), text, args); + PR_snprintf(tbuf, sizeof tbuf, "%05d.%03d (%08p): %s\n", + secs, msecs, PR_GetCurrentThread(), pbuf); + PR_Write(timelineFD, tbuf, strlen(tbuf)); +} + +/* + * Make this public if we need it. + */ +static nsresult NS_TimelineMarkV(const char *text, va_list args) +{ + PRTime elapsed,tmp; + + PR_CallOnce(&initonce, TimelineInit); + + TimelineThreadData *thread = GetThisThreadData(); + + tmp = Now(); + LL_SUB(elapsed, tmp, thread->initTime); + + PrintTime(elapsed, text, args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineForceMark(const char *text, ...) +{ + va_list args; + va_start(args, text); + NS_TimelineMarkV(text, args); + va_end(args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineMark(const char *text, ...) +{ + va_list args; + + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + + va_start(args, text); + NS_TimelineMarkV(text, args); + va_end(args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineStartTimer(const char *timerName) +{ + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + timer = new nsTimelineServiceTimer; + if (!timer) + return NS_ERROR_OUT_OF_MEMORY; + + PL_HashTableAdd(thread->timers, timerName, timer); + } + timer->start(); + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineStopTimer(const char *timerName) +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + /* + * Strange-looking now/timer->stop() interaction is to avoid + * including time spent in TLS and PL_HashTableLookup in the + * timer. + */ + PRTime now = Now(); + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + + timer->stop(now); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineMarkTimer(const char *timerName, const char *str) +{ + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + PRTime accum = timer->getAccum(); + + char buf[500]; + PRInt32 sec, msec; + ParseTime(accum, sec, msec); + if (!str) + PR_snprintf(buf, sizeof buf, "%s total: %d.%03d", + timerName, sec, msec); + else + PR_snprintf(buf, sizeof buf, "%s total: %d.%03d (%s)", + timerName, sec, msec, str); + NS_TimelineMark(buf); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineResetTimer(const char *timerName) +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + + timer->reset(); + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineIndent() +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + thread->indent++; + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineOutdent() +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + thread->indent--; + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineEnter(const char *text) +{ + nsresult rv = NS_TimelineMark("%s...", text); + if (NS_FAILED(rv)) { + return rv; + } + return NS_TimelineIndent(); +} + +PR_IMPLEMENT(nsresult) NS_TimelineLeave(const char *text) +{ + nsresult rv = NS_TimelineOutdent(); + if (NS_FAILED(rv)) { + return rv; + } + return NS_TimelineMark("...%s", text); +} + +nsTimelineService::nsTimelineService() +{ + /* member initializers and constructor code */ +} + +/* void mark (in string text); */ +NS_IMETHODIMP nsTimelineService::Mark(const char *text) +{ + return NS_TimelineMark(text); +} + +/* void startTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::StartTimer(const char *timerName) +{ + return NS_TimelineStartTimer(timerName); +} + +/* void stopTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::StopTimer(const char *timerName) +{ + return NS_TimelineStopTimer(timerName); +} + +/* void markTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::MarkTimer(const char *timerName) +{ + return NS_TimelineMarkTimer(timerName); +} + +/* void markTimerWithComment(in string timerName, in string comment); */ +NS_IMETHODIMP nsTimelineService::MarkTimerWithComment(const char *timerName, const char *comment) +{ + return NS_TimelineMarkTimer(timerName, comment); +} + +/* void resetTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::ResetTimer(const char *timerName) +{ + return NS_TimelineResetTimer(timerName); +} + +/* void indent (); */ +NS_IMETHODIMP nsTimelineService::Indent() +{ + return NS_TimelineIndent(); +} + +/* void outdent (); */ +NS_IMETHODIMP nsTimelineService::Outdent() +{ + return NS_TimelineOutdent(); +} + +/* void enter (in string text); */ +NS_IMETHODIMP nsTimelineService::Enter(const char *text) +{ + return NS_TimelineEnter(text); +} + +/* void leave (in string text); */ +NS_IMETHODIMP nsTimelineService::Leave(const char *text) +{ + return NS_TimelineLeave(text); +} + +#endif /* MOZ_TIMELINE */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h new file mode 100644 index 00000000..bb579755 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsITimelineService.h" + +#ifdef MOZ_TIMELINE + +#define NS_TIMELINESERVICE_CID \ +{ /* a335edf0-3daf-11d5-b67d-000064657374 */ \ + 0xa335edf0, \ + 0x3daf, \ + 0x11d5, \ + {0xb6, 0x7d, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}} + +#define NS_TIMELINESERVICE_CONTRACTID "@mozilla.org;timeline-service;1" +#define NS_TIMELINESERVICE_CLASSNAME "Timeline Service" + +class nsTimelineService : public nsITimelineService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSITIMELINESERVICE + + nsTimelineService(); + +private: + ~nsTimelineService() {} +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp new file mode 100644 index 00000000..12033da0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf <pp@ludusdesign.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsUnicharBuffer.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +UnicharBufferImpl::UnicharBufferImpl() + : mBuffer(NULL), mSpace(0), mLength(0) +{ +} + +NS_METHOD +UnicharBufferImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + UnicharBufferImpl* it = new UnicharBufferImpl(); + if (it == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(it); + nsresult rv = it->QueryInterface(aIID, aResult); + NS_RELEASE(it); + return rv; +} + +NS_IMETHODIMP +UnicharBufferImpl::Init(PRUint32 aBufferSize) +{ + if (aBufferSize < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mLength = 0; + mBuffer = new PRUnichar[aBufferSize]; + return mBuffer ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_ISUPPORTS1(UnicharBufferImpl, nsIUnicharBuffer) + +UnicharBufferImpl::~UnicharBufferImpl() +{ + if (nsnull != mBuffer) { + delete[] mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +NS_IMETHODIMP_(PRInt32) +UnicharBufferImpl::GetLength() const +{ + return mLength; +} + +NS_IMETHODIMP_(PRInt32) +UnicharBufferImpl::GetBufferSize() const +{ + return mSpace; +} + +NS_IMETHODIMP_(PRUnichar*) +UnicharBufferImpl::GetBuffer() const +{ + return mBuffer; +} + +NS_IMETHODIMP_(PRBool) +UnicharBufferImpl::Grow(PRInt32 aNewSize) +{ + if (PRUint32(aNewSize) < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + PRUnichar* newbuf = new PRUnichar[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + memcpy(newbuf, mBuffer, mLength * sizeof(PRUnichar)); + } + delete[] mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_COM nsresult +NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize) +{ + nsresult rv; + nsIUnicharBuffer* buf; + rv = UnicharBufferImpl::Create(aOuter, NS_GET_IID(nsIUnicharBuffer), + (void**)&buf); + if (NS_FAILED(rv)) return rv; + rv = buf->Init(aBufferSize); + if (NS_FAILED(rv)) { + NS_RELEASE(buf); + return rv; + } + *aInstancePtrResult = buf; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h new file mode 100644 index 00000000..d57a48ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsUnicharBuffer_h__ +#define nsUnicharBuffer_h__ + +#include "nsIUnicharBuffer.h" + +class UnicharBufferImpl : public nsIUnicharBuffer { +public: + UnicharBufferImpl(); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_DECL_ISUPPORTS + NS_IMETHOD Init(PRUint32 aBufferSize); + NS_IMETHOD_(PRInt32) GetLength() const; + NS_IMETHOD_(PRInt32) GetBufferSize() const; + NS_IMETHOD_(PRUnichar*) GetBuffer() const; + NS_IMETHOD_(PRBool) Grow(PRInt32 aNewSize); + + PRUnichar* mBuffer; + PRUint32 mSpace; + PRUint32 mLength; + +private: + ~UnicharBufferImpl(); +}; + +#endif // nsUnicharBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h b/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h new file mode 100644 index 00000000..07825385 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsUnitConversion_h__ +#define nsUnitConversion_h__ + +#include "nscore.h" +#include "nsCoord.h" +#include <math.h> +#include <float.h> + +#ifndef FLT_EPSILON +// Not an ANSI compiler... oh, well. Use an IEEE value. +#define FLT_EPSILON 1.19209290e-7f +#endif +/// handy constants +#define TWIPS_PER_POINT_INT 20 +#define TWIPS_PER_POINT_FLOAT 20.0f +#define CEIL_CONST_FLOAT (1.0f - 0.5f*FLT_EPSILON) +#define ROUND_EXCLUSIVE_CONST_FLOAT (0.5f*CEIL_CONST_FLOAT) +#define ROUND_CONST_FLOAT 0.5f + + +/* + * Coord Rounding Functions + */ +inline nscoord NSToCoordFloor(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue) : nscoord(aValue - CEIL_CONST_FLOAT)); +} + +inline nscoord NSToCoordCeil(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + CEIL_CONST_FLOAT) : nscoord(aValue)); +} + +inline nscoord NSToCoordRound(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + ROUND_CONST_FLOAT) : nscoord(aValue - ROUND_CONST_FLOAT)); +} + +inline nscoord NSToCoordRoundExclusive(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + ROUND_EXCLUSIVE_CONST_FLOAT) : + nscoord(aValue - ROUND_EXCLUSIVE_CONST_FLOAT)); +} + + +/* + * Int Rounding Functions + */ +inline PRInt32 NSToIntFloor(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue) : PRInt32(aValue - CEIL_CONST_FLOAT)); +} + +inline PRInt32 NSToIntCeil(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + CEIL_CONST_FLOAT) : PRInt32(aValue)); +} + +inline PRInt32 NSToIntRound(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + ROUND_CONST_FLOAT) : PRInt32(aValue - ROUND_CONST_FLOAT)); +} + +inline PRInt32 NSToIntRoundExclusive(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + ROUND_EXCLUSIVE_CONST_FLOAT) : + PRInt32(aValue - ROUND_EXCLUSIVE_CONST_FLOAT)); +} + + +/* + * Twips/Points conversions + */ +inline nscoord NSFloatPointsToTwips(float aPoints) +{ + return NSToCoordRound(aPoints * TWIPS_PER_POINT_FLOAT); +} + +inline nscoord NSIntPointsToTwips(PRInt32 aPoints) +{ + return nscoord(aPoints * TWIPS_PER_POINT_INT); +} + +inline PRInt32 NSTwipsToIntPoints(nscoord aTwips) +{ + return NSToIntRound(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline PRInt32 NSTwipsToFloorIntPoints(nscoord aTwips) +{ + return NSToIntFloor(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline PRInt32 NSTwipsToCeilIntPoints(nscoord aTwips) +{ + return NSToIntCeil(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline float NSTwipsToFloatPoints(nscoord aTwips) +{ + return (float(aTwips) / TWIPS_PER_POINT_FLOAT); +} + +/* + * Twips/Pixel conversions + */ +inline nscoord NSFloatPixelsToTwips(float aPixels, float aTwipsPerPixel) +{ + return NSToCoordRound(aPixels * aTwipsPerPixel); +} + +inline nscoord NSIntPixelsToTwips(PRInt32 aPixels, float aTwipsPerPixel) +{ + return NSToCoordRound(float(aPixels) * aTwipsPerPixel); +} + +inline float NSTwipsToFloatPixels(nscoord aTwips, float aPixelsPerTwip) +{ + return (float(aTwips) * aPixelsPerTwip); +} + +inline PRInt32 NSTwipsToIntPixels(nscoord aTwips, float aPixelsPerTwip) +{ + return NSToIntRound(float(aTwips) * aPixelsPerTwip); +} + +/* + * Twips/unit conversions + */ +inline nscoord NSUnitsToTwips(float aValue, float aPointsPerUnit) +{ + return NSToCoordRound(aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT); +} + +inline float NSTwipsToUnits(nscoord aTwips, float aUnitsPerPoint) +{ + return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT)); +} + + +/// Unit conversion macros +//@{ +#define NS_INCHES_TO_TWIPS(x) NSUnitsToTwips((x), 72.0f) // 72 points per inch +#define NS_FEET_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 12.0f)) // 12 inches per foot +#define NS_MILES_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 12.0f * 5280.0f)) // 5280 feet per mile + +#define NS_MILLIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 0.03937f)) +#define NS_CENTIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 0.3937f)) +#define NS_METERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 39.37f)) +#define NS_KILOMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 39370.0f)) + +#define NS_PICAS_TO_TWIPS(x) NSUnitsToTwips((x), 12.0f) // 12 points per pica +#define NS_DIDOTS_TO_TWIPS(x) NSUnitsToTwips((x), (16.0f / 15.0f)) // 15 didots per 16 points +#define NS_CICEROS_TO_TWIPS(x) NSUnitsToTwips((x), (12.0f * (16.0f / 15.0f))) // 12 didots per cicero + + +#define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / 72.0f) +#define NS_TWIPS_TO_FEET(x) NSTwipsToUnits((x), 1.0f / (72.0f * 12.0f)) +#define NS_TWIPS_TO_MILES(x) NSTwipsToUnits((x), 1.0f / (72.0f * 12.0f * 5280.0f)) + +#define NS_TWIPS_TO_MILLIMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 0.03937f)) +#define NS_TWIPS_TO_CENTIMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 0.3937f)) +#define NS_TWIPS_TO_METERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 39.37f)) +#define NS_TWIPS_TO_KILOMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 39370.0f)) + +#define NS_TWIPS_TO_PICAS(x) NSTwipsToUnits((x), 1.0f / 12.0f) +#define NS_TWIPS_TO_DIDOTS(x) NSTwipsToUnits((x), 1.0f / (16.0f / 15.0f)) +#define NS_TWIPS_TO_CICEROS(x) NSTwipsToUnits((x), 1.0f / (12.0f * (16.0f / 15.0f))) +//@} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp new file mode 100644 index 00000000..4660ccec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp @@ -0,0 +1,304 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is nsValueArray.h/nsValueArray.cpp code, released + * Dec 28, 2001. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Garrett Arch Blythe, 20-December-2001 + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// +// nsValueArray.cpp +// +// Implement an array class to store unsigned integer values. +// The maximum value must be known up front. Once known, the +// smallest memory representation will be attempted; i.e. if the +// maximum value was 1275, then 2 bytes (uint16) would represent each value +// in the array instead of 4 bytes (uint32). +// +#include "nsValueArray.h" +#include "nsCRT.h" +#include "prmem.h" +#include "prbit.h" + +#define NSVALUEARRAY_LINEAR_GROWBY 8 +#define NSVALUEARRAY_LINEAR_THRESHOLD 128 + +nsValueArray::nsValueArray(nsValueArrayValue aMaxValue, nsValueArrayCount aInitialCapacity) { + mCount = 0; + mCapacity = 0; + mValueArray = nsnull; + + PRUint8 test8 = (PRUint8)aMaxValue; + PRUint16 test16 = (PRUint16)aMaxValue; + PRUint32 test32 = (PRUint32)aMaxValue; + if ((nsValueArrayValue)test8 == aMaxValue) { + mBytesPerValue = sizeof(test8); + } + else if ((nsValueArrayValue)test16 == aMaxValue) { + mBytesPerValue = sizeof(test16); + } + else if ((nsValueArrayValue)test32 == aMaxValue) { + mBytesPerValue = sizeof(test32); + } + else { + NS_ASSERTION(0, "not supported yet, add it yourself..."); + mBytesPerValue = 0; + } + + if (aInitialCapacity) { + mValueArray = (PRUint8*)PR_Malloc(aInitialCapacity * mBytesPerValue); + if (nsnull != mValueArray) { + mCapacity = aInitialCapacity; + } + } +} + +nsValueArray::~nsValueArray() { + if (nsnull != mValueArray) { + PR_Free(mValueArray); + mValueArray = nsnull; + } +} + +// +// Copy it. +// +nsValueArray& nsValueArray::operator=(const nsValueArray& aOther) { + // + // Free off what you know if not enough space, or units differ. + // + if ((mBytesPerValue != aOther.mBytesPerValue || mCapacity < aOther.mCount) && nsnull != mValueArray) { + PR_Free(mValueArray); + mValueArray = nsnull; + mCount = mCapacity = 0; + } + + // + // Copy some attribs. + // + mBytesPerValue = aOther.mBytesPerValue; + mCount = aOther.mCount; + + // + // Anything to do? + // + if (0 != mCount) { + // + // May need to allocate our buffer. + // + if (0 == mCapacity) { + mValueArray = (PRUint8*)PR_Malloc(mCount * mBytesPerValue); + mCapacity = mCount; + } + + NS_ASSERTION(nsnull != mValueArray, "loss of value array assignment and original data."); + if (nsnull != mValueArray) { + memcpy(mValueArray, aOther.mValueArray, mCount * mBytesPerValue); + } + else { + mCount = mCapacity = 0; + } + } + + return *this; +} + +// +// Insert a value into the array. +// No validity checking other than index is done. +// +PRBool nsValueArray::InsertValueAt(nsValueArrayValue aValue, nsValueArrayIndex aIndex) { + PRBool retval = PR_FALSE; + + nsValueArrayCount count = Count(); + if (aIndex <= count) { + // + // If we're at capacity, then we'll need to grow a little. + // + if (Capacity() == count) { + PRUint8* reallocRes = nsnull; + nsValueArrayCount growBy = NSVALUEARRAY_LINEAR_GROWBY; + + // + // Up to a particular limit we grow in small increments. + // Otherwise, grow exponentially. + // + if (count >= NSVALUEARRAY_LINEAR_THRESHOLD) { + growBy = PR_BIT(PR_CeilingLog2(count + 1)) - count; + } + + if (nsnull == mValueArray) { + reallocRes = (PRUint8*)PR_Malloc((count + growBy) * mBytesPerValue); + } + else { + reallocRes = (PRUint8*)PR_Realloc(mValueArray, (count + growBy) * mBytesPerValue); + } + if (nsnull != reallocRes) { + mValueArray = reallocRes; + mCapacity += growBy; + } + } + + // + // Only if we are below capacity do we continue. + // + if (Capacity() > count) { + // + // All those at and beyond the insertion point need to move. + // + if (aIndex < count) { + memmove(&mValueArray[(aIndex + 1) * mBytesPerValue], &mValueArray[aIndex * mBytesPerValue], (count - aIndex) * mBytesPerValue); + } + + // + // Do the assignment. + // + switch (mBytesPerValue) { + case sizeof(PRUint8): + *((PRUint8*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint8)aValue; + NS_ASSERTION(*((PRUint8*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + case sizeof(PRUint16): + *((PRUint16*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint16)aValue; + NS_ASSERTION(*((PRUint16*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + case sizeof(PRUint32): + *((PRUint32*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint32)aValue; + NS_ASSERTION(*((PRUint32*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + default: + NS_ASSERTION(0, "surely you've been warned prior to this!"); + break; + } + + // + // Up the count by 1. + // + mCount++; + } + } + + return retval; +} + +// +// Remove the index from the value array. +// The array does not shrink until Compact() is invoked. +// +PRBool nsValueArray::RemoveValueAt(nsValueArrayIndex aIndex) { + PRBool retval = PR_FALSE; + + nsValueArrayCount count = Count(); + if (aIndex < count) { + // + // Move memory around if appropriate. + // + if (aIndex != (count - 1)) { + memmove(&mValueArray[aIndex * mBytesPerValue], &mValueArray[(aIndex + 1) * mBytesPerValue], (count - aIndex - 1) * mBytesPerValue); + } + + // + // Update our count. + // + mCount--; + } + + return retval; +} + +// +// Shrink as much as possible. +// +void nsValueArray::Compact() { + nsValueArrayCount count = Count(); + if (Capacity() != count) + { + if (0 == count) { + PR_Free(mValueArray); + mValueArray = nsnull; + mCapacity = 0; + } + else { + PRUint8* reallocRes = (PRUint8*)PR_Realloc(mValueArray, count * mBytesPerValue); + if (nsnull != reallocRes) { + mValueArray = reallocRes; + mCapacity = count; + } + } + } +} + +// +// Return the value at the index. +// +nsValueArrayValue nsValueArray::ValueAt(nsValueArrayIndex aIndex) const { + nsValueArrayValue retval = NSVALUEARRAY_INVALID; + + if (aIndex < Count()) { + switch (mBytesPerValue) { + case sizeof(PRUint8): + retval = (nsValueArrayIndex)*((PRUint8*)&mValueArray[aIndex * mBytesPerValue]); + break; + case sizeof(PRUint16): + retval = (nsValueArrayIndex)*((PRUint16*)&mValueArray[aIndex * mBytesPerValue]); + break; + case sizeof(PRUint32): + retval = (nsValueArrayIndex)*((PRUint32*)&mValueArray[aIndex * mBytesPerValue]); + break; + default: + NS_ASSERTION(0, "unexpected for sure."); + break; + } + } + + return retval; +} + +// +// Return the first encountered index of the value. +// +nsValueArrayIndex nsValueArray::IndexOf(nsValueArrayValue aPossibleValue) const { + nsValueArrayIndex retval = NSVALUEARRAY_INVALID; + nsValueArrayIndex traverse; + + for (traverse = 0; traverse < Count(); traverse++) { + if (aPossibleValue == ValueAt(traverse)) { + retval = traverse; + break; + } + } + + return retval; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h new file mode 100644 index 00000000..6437ca60 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is nsValueArray.h/nsValueArray.cpp code, released + * Dec 28, 2001. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Garrett Arch Blythe, 20-December-2001 + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsValueArray_h___ +#define nsValueArray_h___ + +// +// nsValueArray.h +// +// Implement an array class to store unsigned integer values. +// The maximum value must be known up front. Once known, the +// smallest memory representation will be attempted; i.e. if the +// maximum value was 1275, then 2 bytes (uint16) would represent each value +// in the array instead of 4 bytes (uint32). +// +#include "nscore.h" + +typedef PRUint32 nsValueArrayCount; +typedef PRUint32 nsValueArrayIndex; +typedef PRUint32 nsValueArrayValue; +#define NSVALUEARRAY_INVALID ((nsValueArrayValue)-1) + +class NS_COM nsValueArray { + public: + nsValueArray(nsValueArrayValue aMaxValue, + nsValueArrayCount aInitialCapacity = 0); + ~nsValueArray(); + + // + // Assignment. + // + public: + nsValueArray& operator=(const nsValueArray& other); + + // + // Array size information. + // Ability to add more values without growing is Capacity - Count. + // + public: + inline nsValueArrayCount Count() const { + return mCount; + } + + inline nsValueArrayCount Capacity() const { + return mCapacity; + } + + void Compact(); + + // Removes all elements from this array + inline void Clear() { + mCount = 0; + } + + // + // Array access. + // + public: + nsValueArrayValue ValueAt(nsValueArrayIndex aIndex) const; + + inline nsValueArrayValue operator[](nsValueArrayIndex aIndex) const { + return ValueAt(aIndex); + } + + nsValueArrayIndex IndexOf(nsValueArrayValue aPossibleValue) const; + + inline PRBool AppendValue(nsValueArrayValue aValue) { + return InsertValueAt(aValue, Count()); + } + + inline PRBool RemoveValue(nsValueArrayValue aValue) { + return RemoveValueAt(IndexOf(aValue)); + } + + PRBool InsertValueAt(nsValueArrayValue aValue, nsValueArrayIndex aIndex); + + PRBool RemoveValueAt(nsValueArrayIndex aIndex); + + // + // Data members. + // + private: + nsValueArrayCount mCount; + nsValueArrayCount mCapacity; + PRUint8* mValueArray; + PRUint8 mBytesPerValue; +}; + +#endif /* nsValueArray_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp b/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp new file mode 100644 index 00000000..09a4cda5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp @@ -0,0 +1,2092 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer <jband@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsVariant.h" +#include "nsString.h" +#include "prprf.h" +#include "prdtoa.h" +#include <math.h> +#include "nsCRT.h" + +/***************************************************************************/ +// Helpers for static convert functions... + +static nsresult String2Double(const char* aString, double* retval) +{ + char* next; + double value = PR_strtod(aString, &next); + if(next == aString) + return NS_ERROR_CANNOT_CONVERT_DATA; + *retval = value; + return NS_OK; +} + +static nsresult AString2Double(const nsAString& aString, double* retval) +{ + char* pChars = ToNewCString(aString); + if(!pChars) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = String2Double(pChars, retval); + nsMemory::Free(pChars); + return rv; +} + +static nsresult AUTF8String2Double(const nsAUTF8String& aString, double* retval) +{ + return String2Double(PromiseFlatUTF8String(aString).get(), retval); +} + +static nsresult ACString2Double(const nsACString& aString, double* retval) +{ + return String2Double(PromiseFlatCString(aString).get(), retval); +} + +// Fills outVariant with double, PRUint32, or PRInt32. +// Returns NS_OK, an error code, or a non-NS_OK success code +static nsresult ToManageableNumber(const nsDiscriminatedUnion& inData, + nsDiscriminatedUnion* outData) +{ + nsresult rv; + + switch(inData.mType) + { + // This group results in a PRInt32... + +#define CASE__NUMBER_INT32(type_, member_) \ + case nsIDataType :: type_ : \ + outData->u.mInt32Value = inData.u. member_ ; \ + outData->mType = nsIDataType::VTYPE_INT32; \ + return NS_OK; + + CASE__NUMBER_INT32(VTYPE_INT8, mInt8Value) + CASE__NUMBER_INT32(VTYPE_INT16, mInt16Value) + CASE__NUMBER_INT32(VTYPE_INT32, mInt32Value) + CASE__NUMBER_INT32(VTYPE_UINT8, mUint8Value) + CASE__NUMBER_INT32(VTYPE_UINT16, mUint16Value) + CASE__NUMBER_INT32(VTYPE_BOOL, mBoolValue) + CASE__NUMBER_INT32(VTYPE_CHAR, mCharValue) + CASE__NUMBER_INT32(VTYPE_WCHAR, mWCharValue) + +#undef CASE__NUMBER_INT32 + + // This group results in a PRUint32... + + case nsIDataType::VTYPE_UINT32: + outData->u.mInt32Value = inData.u.mUint32Value; + outData->mType = nsIDataType::VTYPE_INT32; + return NS_OK; + + // This group results in a double... + + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT64: + // XXX Need boundary checking here. + // We may need to return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA + LL_L2D(outData->u.mDoubleValue, inData.u.mInt64Value); + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_FLOAT: + outData->u.mDoubleValue = inData.u.mFloatValue; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_DOUBLE: + outData->u.mDoubleValue = inData.u.mDoubleValue; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + rv = String2Double(inData.u.str.mStringValue, &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_ASTRING: + rv = AString2Double(*inData.u.mAStringValue, &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + rv = AUTF8String2Double(*inData.u.mUTF8StringValue, + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + rv = ACString2Double(*inData.u.mCStringValue, + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + rv = AString2Double(nsDependentString(inData.u.wstr.mWStringValue), + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + + // This group fails... + + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ID: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/***************************************************************************/ +// Array helpers... + +static void FreeArray(nsDiscriminatedUnion* data) +{ + NS_ASSERTION(data->mType == nsIDataType::VTYPE_ARRAY, "bad FreeArray call"); + NS_ASSERTION(data->u.array.mArrayValue, "bad array"); + NS_ASSERTION(data->u.array.mArrayCount, "bad array count"); + +#define CASE__FREE_ARRAY_PTR(type_, ctype_) \ + case nsIDataType:: type_ : \ + { \ + ctype_ ** p = (ctype_ **) data->u.array.mArrayValue; \ + for(PRUint32 i = data->u.array.mArrayCount; i > 0; p++, i--) \ + if(*p) \ + nsMemory::Free((char*)*p); \ + break; \ + } + +#define CASE__FREE_ARRAY_IFACE(type_, ctype_) \ + case nsIDataType:: type_ : \ + { \ + ctype_ ** p = (ctype_ **) data->u.array.mArrayValue; \ + for(PRUint32 i = data->u.array.mArrayCount; i > 0; p++, i--) \ + if(*p) \ + (*p)->Release(); \ + break; \ + } + + switch(data->u.array.mArrayType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + break; + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + CASE__FREE_ARRAY_PTR(VTYPE_ID, nsID) + CASE__FREE_ARRAY_PTR(VTYPE_CHAR_STR, char) + CASE__FREE_ARRAY_PTR(VTYPE_WCHAR_STR, PRUnichar) + CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE, nsISupports) + CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE_IS, nsISupports) + + // The rest are illegal. + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + NS_ERROR("bad type in array!"); + break; + } + + // Free the array memory. + nsMemory::Free((char*)data->u.array.mArrayValue); + +#undef CASE__FREE_ARRAY_PTR +#undef CASE__FREE_ARRAY_IFACE +} + +static nsresult CloneArray(PRUint16 inType, const nsIID* inIID, + PRUint32 inCount, void* inValue, + PRUint16* outType, nsIID* outIID, + PRUint32* outCount, void** outValue) +{ + NS_ASSERTION(inCount, "bad param"); + NS_ASSERTION(inValue, "bad param"); + NS_ASSERTION(outType, "bad param"); + NS_ASSERTION(outCount, "bad param"); + NS_ASSERTION(outValue, "bad param"); + + PRUint32 allocatedValueCount = 0; + nsresult rv = NS_OK; + PRUint32 i; + + // First we figure out the size of the elements for the new u.array. + + size_t elementSize; + size_t allocSize; + + switch(inType) + { + case nsIDataType::VTYPE_INT8: + elementSize = sizeof(PRInt8); + break; + case nsIDataType::VTYPE_INT16: + elementSize = sizeof(PRInt16); + break; + case nsIDataType::VTYPE_INT32: + elementSize = sizeof(PRInt32); + break; + case nsIDataType::VTYPE_INT64: + elementSize = sizeof(PRInt64); + break; + case nsIDataType::VTYPE_UINT8: + elementSize = sizeof(PRUint8); + break; + case nsIDataType::VTYPE_UINT16: + elementSize = sizeof(PRUint16); + break; + case nsIDataType::VTYPE_UINT32: + elementSize = sizeof(PRUint32); + break; + case nsIDataType::VTYPE_UINT64: + elementSize = sizeof(PRUint64); + break; + case nsIDataType::VTYPE_FLOAT: + elementSize = sizeof(float); + break; + case nsIDataType::VTYPE_DOUBLE: + elementSize = sizeof(double); + break; + case nsIDataType::VTYPE_BOOL: + elementSize = sizeof(PRBool); + break; + case nsIDataType::VTYPE_CHAR: + elementSize = sizeof(char); + break; + case nsIDataType::VTYPE_WCHAR: + elementSize = sizeof(PRUnichar); + break; + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + case nsIDataType::VTYPE_ID: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + elementSize = sizeof(void*); + break; + + // The rest are illegal. + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + NS_ERROR("bad type in array!"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + + // Alloc the u.array. + + allocSize = inCount * elementSize; + *outValue = nsMemory::Alloc(allocSize); + if(!*outValue) + return NS_ERROR_OUT_OF_MEMORY; + + // Clone the elements. + + switch(inType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + memcpy(*outValue, inValue, allocSize); + break; + + case nsIDataType::VTYPE_INTERFACE_IS: + if(outIID) + *outIID = *inIID; + // fall through... + case nsIDataType::VTYPE_INTERFACE: + { + memcpy(*outValue, inValue, allocSize); + + nsISupports** p = (nsISupports**) *outValue; + for(i = inCount; i > 0; p++, i--) + if(*p) + (*p)->AddRef(); + break; + } + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + case nsIDataType::VTYPE_ID: + { + nsID** inp = (nsID**) inValue; + nsID** outp = (nsID**) *outValue; + for(i = inCount; i > 0; i--) + { + nsID* idp = *(inp++); + if(idp) + { + if(nsnull == (*(outp++) = (nsID*) + nsMemory::Clone((char*)idp, sizeof(nsID)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + case nsIDataType::VTYPE_CHAR_STR: + { + char** inp = (char**) inValue; + char** outp = (char**) *outValue; + for(i = inCount; i > 0; i--) + { + char* str = *(inp++); + if(str) + { + if(nsnull == (*(outp++) = (char*) + nsMemory::Clone(str, (strlen(str)+1)*sizeof(char)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + case nsIDataType::VTYPE_WCHAR_STR: + { + PRUnichar** inp = (PRUnichar**) inValue; + PRUnichar** outp = (PRUnichar**) *outValue; + for(i = inCount; i > 0; i--) + { + PRUnichar* str = *(inp++); + if(str) + { + if(nsnull == (*(outp++) = (PRUnichar*) + nsMemory::Clone(str, + (nsCRT::strlen(str)+1)*sizeof(PRUnichar)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + // The rest are illegal. + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + default: + NS_ERROR("bad type in array!"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + *outType = inType; + *outCount = inCount; + return NS_OK; + +bad: + if(*outValue) + { + char** p = (char**) *outValue; + for(i = allocatedValueCount; i > 0; p++, i--) + if(*p) + nsMemory::Free(*p); + nsMemory::Free((char*)*outValue); + *outValue = nsnull; + } + return rv; +} + +/***************************************************************************/ + +#define TRIVIAL_DATA_CONVERTER(type_, data_, member_, retval_) \ + if(data_.mType == nsIDataType :: type_) { \ + *retval_ = data_.u.member_; \ + return NS_OK; \ + } + +#define NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \ +/* static */ nsresult \ +nsVariant::ConvertTo##name_ (const nsDiscriminatedUnion& data, \ + Ctype_ *_retval) \ +{ \ + TRIVIAL_DATA_CONVERTER(type_, data, m##name_##Value, _retval) \ + nsDiscriminatedUnion tempData; \ + nsVariant::Initialize(&tempData); \ + nsresult rv = ToManageableNumber(data, &tempData); \ + /* */ \ + /* NOTE: rv may indicate a success code that we want to preserve */ \ + /* For the final return. So all the return cases below should return */ \ + /* this rv when indicating success. */ \ + /* */ \ + if(NS_FAILED(rv)) \ + return rv; \ + switch(tempData.mType) \ + { + +#define CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_INT32: \ + *_retval = ( Ctype_ ) tempData.u.mInt32Value; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_INT32: \ + { \ + PRInt32 value = tempData.u.mInt32Value; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_UINT32: \ + *_retval = ( Ctype_ ) tempData.u.mUint32Value; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \ + case nsIDataType::VTYPE_UINT32: \ + { \ + PRUint32 value = tempData.u.mUint32Value; \ + if(value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_DOUBLE: \ + *_retval = ( Ctype_ ) tempData.u.mDoubleValue; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_DOUBLE: \ + { \ + double value = tempData.u.mDoubleValue; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_DOUBLE: \ + { \ + double value = tempData.u.mDoubleValue; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return (0.0 == fmod(value,1.0)) ? \ + rv : NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA; \ + } + +#define CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \ + CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \ + CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \ + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) + +#define NUMERIC_CONVERSION_METHOD_END \ + default: \ + NS_ERROR("bad type returned from ToManageableNumber"); \ + return NS_ERROR_CANNOT_CONVERT_DATA; \ + } \ +} + +#define NUMERIC_CONVERSION_METHOD_NORMAL(type_, Ctype_, name_, min_, max_) \ + NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \ + CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \ + NUMERIC_CONVERSION_METHOD_END + +/***************************************************************************/ +// These expand into full public methods... + +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT8, PRUint8, Int8, (-127-1), 127) +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT16, PRInt16, Int16, (-32767-1), 32767) + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_INT32, PRInt32, Int32) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(PRInt32) + CASE__NUMERIC_CONVERSION_UINT32_MAX(PRInt32, 2147483647) + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(PRInt32, (-2147483647-1), 2147483647) +NUMERIC_CONVERSION_METHOD_END + +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT8, PRUint8, Uint8, 0, 255) +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT16, PRUint16, Uint16, 0, 65535) + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_UINT32, PRUint32, Uint32) + CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(PRUint32, 0, 2147483647) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(PRUint32) + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(PRUint32, 0, 4294967295U) +NUMERIC_CONVERSION_METHOD_END + +// XXX toFloat convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_FLOAT, float, Float) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(float) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(float) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(float) +NUMERIC_CONVERSION_METHOD_END + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_DOUBLE, double, Double) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(double) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(double) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(double) +NUMERIC_CONVERSION_METHOD_END + +// XXX toChar convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_CHAR, char, Char) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(char) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(char) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(char) +NUMERIC_CONVERSION_METHOD_END + +// XXX toWChar convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_WCHAR, PRUnichar, WChar) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(PRUnichar) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(PRUnichar) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(PRUnichar) +NUMERIC_CONVERSION_METHOD_END + +#undef NUMERIC_CONVERSION_METHOD_BEGIN +#undef CASE__NUMERIC_CONVERSION_INT32_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_INT32_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_UINT32_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT +#undef CASES__NUMERIC_CONVERSION_NORMAL +#undef NUMERIC_CONVERSION_METHOD_END +#undef NUMERIC_CONVERSION_METHOD_NORMAL + +/***************************************************************************/ + +// Just leverage a numeric converter for bool (but restrict the values). +// XXX Is this really what we want to do? + +/* static */ nsresult +nsVariant::ConvertToBool(const nsDiscriminatedUnion& data, PRBool *_retval) +{ + TRIVIAL_DATA_CONVERTER(VTYPE_BOOL, data, mBoolValue, _retval) + + double val; + nsresult rv = nsVariant::ConvertToDouble(data, &val); + if(NS_FAILED(rv)) + return rv; + *_retval = 0.0 != val; + return rv; +} + +/***************************************************************************/ + +/* static */ nsresult +nsVariant::ConvertToInt64(const nsDiscriminatedUnion& data, PRInt64 *_retval) +{ + TRIVIAL_DATA_CONVERTER(VTYPE_INT64, data, mInt64Value, _retval) + TRIVIAL_DATA_CONVERTER(VTYPE_UINT64, data, mUint64Value, _retval) + + nsDiscriminatedUnion tempData; + nsVariant::Initialize(&tempData); + nsresult rv = ToManageableNumber(data, &tempData); + if(NS_FAILED(rv)) + return rv; + switch(tempData.mType) + { + case nsIDataType::VTYPE_INT32: + LL_I2L(*_retval, tempData.u.mInt32Value); + return rv; + case nsIDataType::VTYPE_UINT32: + LL_UI2L(*_retval, tempData.u.mUint32Value); + return rv; + case nsIDataType::VTYPE_DOUBLE: + // XXX should check for data loss here! + LL_D2L(*_retval, tempData.u.mDoubleValue); + return rv; + default: + NS_ERROR("bad type returned from ToManageableNumber"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/* static */ nsresult +nsVariant::ConvertToUint64(const nsDiscriminatedUnion& data, PRUint64 *_retval) +{ + return nsVariant::ConvertToInt64(data, (PRInt64 *)_retval); +} + +/***************************************************************************/ + +static PRBool String2ID(const nsDiscriminatedUnion& data, nsID* pid) +{ + nsAutoString tempString; + nsAString* pString; + + switch(data.mType) + { + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + return pid->Parse(data.u.str.mStringValue); + case nsIDataType::VTYPE_CSTRING: + return pid->Parse(PromiseFlatCString(*data.u.mCStringValue).get()); + case nsIDataType::VTYPE_UTF8STRING: + return pid->Parse(PromiseFlatUTF8String(*data.u.mUTF8StringValue).get()); + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + pString = data.u.mAStringValue; + break; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + tempString.Assign(data.u.wstr.mWStringValue); + pString = &tempString; + break; + default: + NS_ERROR("bad type in call to String2ID"); + return PR_FALSE; + } + + char* pChars = ToNewCString(*pString); + if(!pChars) + return PR_FALSE; + PRBool result = pid->Parse(pChars); + nsMemory::Free(pChars); + return result; +} + +/* static */ nsresult +nsVariant::ConvertToID(const nsDiscriminatedUnion& data, nsID * _retval) +{ + nsID id; + + switch(data.mType) + { + case nsIDataType::VTYPE_ID: + *_retval = data.u.mIDValue; + return NS_OK; + case nsIDataType::VTYPE_INTERFACE: + *_retval = NS_GET_IID(nsISupports); + return NS_OK; + case nsIDataType::VTYPE_INTERFACE_IS: + *_retval = data.u.iface.mInterfaceID; + return NS_OK; + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + if(!String2ID(data, &id)) + return NS_ERROR_CANNOT_CONVERT_DATA; + *_retval = id; + return NS_OK; + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/***************************************************************************/ + +static nsresult ToString(const nsDiscriminatedUnion& data, + nsACString & outString) +{ + char* ptr; + + switch(data.mType) + { + // all the stuff we don't handle... + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_WCHAR: + NS_ERROR("ToString being called for a string type - screwy logic!"); + // fall through... + + // XXX We might want stringified versions of these... ??? + + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + + // nsID has its own text formater. + + case nsIDataType::VTYPE_ID: + ptr = data.u.mIDValue.ToString(); + if(!ptr) + return NS_ERROR_OUT_OF_MEMORY; + outString.Assign(ptr); + nsMemory::Free(ptr); + return NS_OK; + + // the rest can be PR_smprintf'd and use common code. + +#define CASE__SMPRINTF_NUMBER(type_, format_, cast_, member_) \ + case nsIDataType :: type_ : \ + ptr = PR_smprintf( format_ , (cast_) data.u. member_ ); \ + break; + + CASE__SMPRINTF_NUMBER(VTYPE_INT8, "%d", int, mInt8Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT16, "%d", int, mInt16Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT32, "%d", int, mInt32Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT64, "%lld", PRInt64, mInt64Value) + + CASE__SMPRINTF_NUMBER(VTYPE_UINT8, "%u", unsigned, mUint8Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT16, "%u", unsigned, mUint16Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT32, "%u", unsigned, mUint32Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT64, "%llu", PRInt64, mUint64Value) + + CASE__SMPRINTF_NUMBER(VTYPE_FLOAT, "%f", float, mFloatValue) + CASE__SMPRINTF_NUMBER(VTYPE_DOUBLE, "%f", double, mDoubleValue) + + // XXX Would we rather print "true" / "false" ? + CASE__SMPRINTF_NUMBER(VTYPE_BOOL, "%d", int, mBoolValue) + + CASE__SMPRINTF_NUMBER(VTYPE_CHAR, "%c", char, mCharValue) + +#undef CASE__SMPRINTF_NUMBER + } + + if(!ptr) + return NS_ERROR_OUT_OF_MEMORY; + outString.Assign(ptr); + PR_smprintf_free(ptr); + return NS_OK; +} + +/* static */ nsresult +nsVariant::ConvertToAString(const nsDiscriminatedUnion& data, + nsAString & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + _retval.Assign(*data.u.mAStringValue); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + CopyASCIItoUCS2(*data.u.mCStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + CopyUTF8toUTF16(*data.u.mUTF8StringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + CopyASCIItoUTF16(data.u.str.mStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + _retval.Assign(data.u.wstr.mWStringValue); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + CopyASCIItoUCS2(nsDependentCString(data.u.str.mStringValue, + data.u.str.mStringLength), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + _retval.Assign(data.u.wstr.mWStringValue, data.u.wstr.mWStringLength); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + _retval.Assign(data.u.mWCharValue); + return NS_OK; + default: + { + nsCAutoString tempCString; + nsresult rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + CopyASCIItoUTF16(tempCString, _retval); + return NS_OK; + } + } +} + +/* static */ nsresult +nsVariant::ConvertToACString(const nsDiscriminatedUnion& data, + nsACString & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + CopyUCS2toASCII(*data.u.mAStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + _retval.Assign(*data.u.mCStringValue); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + // XXX This is an extra copy that should be avoided + // once Jag lands support for UTF8String and associated + // conversion methods. + CopyUCS2toASCII(NS_ConvertUTF8toUCS2(*data.u.mUTF8StringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + _retval.Assign(*data.u.str.mStringValue); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + CopyUCS2toASCII(nsDependentString(data.u.wstr.mWStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + _retval.Assign(data.u.str.mStringValue, data.u.str.mStringLength); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CopyUCS2toASCII(nsDependentString(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength), _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + { + const PRUnichar* str = &data.u.mWCharValue; + CopyUCS2toASCII(Substring(str, str + 1), _retval); + return NS_OK; + } + default: + return ToString(data, _retval); + } +} + +/* static */ nsresult +nsVariant::ConvertToAUTF8String(const nsDiscriminatedUnion& data, + nsAUTF8String & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + CopyUTF16toUTF8(*data.u.mAStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + // XXX Extra copy, can be removed if we're sure CSTRING can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(*data.u.mCStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + _retval.Assign(*data.u.mUTF8StringValue); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + // XXX Extra copy, can be removed if we're sure CHAR_STR can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(data.u.str.mStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + CopyUTF16toUTF8(data.u.wstr.mWStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + // XXX Extra copy, can be removed if we're sure CHAR_STR can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16( + nsDependentCString(data.u.str.mStringValue, + data.u.str.mStringLength)), _retval); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CopyUTF16toUTF8(nsDependentString(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + { + const PRUnichar* str = &data.u.mWCharValue; + CopyUTF16toUTF8(Substring(str, str + 1), _retval); + return NS_OK; + } + default: + { + nsCAutoString tempCString; + nsresult rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + // XXX Extra copy, can be removed if we're sure tempCString can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(tempCString), _retval); + return NS_OK; + } + } +} + +/* static */ nsresult +nsVariant::ConvertToString(const nsDiscriminatedUnion& data, char **_retval) +{ + PRUint32 ignored; + return nsVariant::ConvertToStringWithSize(data, &ignored, _retval); +} + +/* static */ nsresult +nsVariant::ConvertToWString(const nsDiscriminatedUnion& data, PRUnichar **_retval) +{ + PRUint32 ignored; + return nsVariant::ConvertToWStringWithSize(data, &ignored, _retval); +} + +/* static */ nsresult +nsVariant::ConvertToStringWithSize(const nsDiscriminatedUnion& data, + PRUint32 *size, char **str) +{ + nsAutoString tempString; + nsCAutoString tempCString; + nsresult rv; + + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + *size = data.u.mAStringValue->Length(); + *str = ToNewCString(*data.u.mAStringValue); + break; + case nsIDataType::VTYPE_CSTRING: + *size = data.u.mCStringValue->Length(); + *str = ToNewCString(*data.u.mCStringValue); + break; + case nsIDataType::VTYPE_UTF8STRING: + { + // XXX This is doing 1 extra copy. Need to fix this + // when Jag lands UTF8String + // we want: + // *size = *data.mUTF8StringValue->Length(); + // *str = ToNewCString(*data.mUTF8StringValue); + // But this will have to do for now. + NS_ConvertUTF8toUCS2 tempString(*data.u.mUTF8StringValue); + *size = tempString.Length(); + *str = ToNewCString(tempString); + break; + } + case nsIDataType::VTYPE_CHAR_STR: + { + nsDependentCString cString(data.u.str.mStringValue); + *size = cString.Length(); + *str = ToNewCString(cString); + break; + } + case nsIDataType::VTYPE_WCHAR_STR: + { + nsDependentString string(data.u.wstr.mWStringValue); + *size = string.Length(); + *str = ToNewCString(string); + break; + } + case nsIDataType::VTYPE_STRING_SIZE_IS: + { + nsDependentCString cString(data.u.str.mStringValue, + data.u.str.mStringLength); + *size = cString.Length(); + *str = ToNewCString(cString); + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + { + nsDependentString string(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength); + *size = string.Length(); + *str = ToNewCString(string); + break; + } + case nsIDataType::VTYPE_WCHAR: + tempString.Assign(data.u.mWCharValue); + *size = tempString.Length(); + *str = ToNewCString(tempString); + break; + default: + rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + *size = tempCString.Length(); + *str = ToNewCString(tempCString); + break; + } + + return *str ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} +/* static */ nsresult +nsVariant::ConvertToWStringWithSize(const nsDiscriminatedUnion& data, + PRUint32 *size, PRUnichar **str) +{ + nsAutoString tempString; + nsCAutoString tempCString; + nsresult rv; + + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + *size = data.u.mAStringValue->Length(); + *str = ToNewUnicode(*data.u.mAStringValue); + break; + case nsIDataType::VTYPE_CSTRING: + *size = data.u.mCStringValue->Length(); + *str = ToNewUnicode(*data.u.mCStringValue); + break; + case nsIDataType::VTYPE_UTF8STRING: + { + *str = UTF8ToNewUnicode(*data.u.mUTF8StringValue, size); + break; + } + case nsIDataType::VTYPE_CHAR_STR: + { + nsDependentCString cString(data.u.str.mStringValue); + *size = cString.Length(); + *str = ToNewUnicode(cString); + break; + } + case nsIDataType::VTYPE_WCHAR_STR: + { + nsDependentString string(data.u.wstr.mWStringValue); + *size = string.Length(); + *str = ToNewUnicode(string); + break; + } + case nsIDataType::VTYPE_STRING_SIZE_IS: + { + nsDependentCString cString(data.u.str.mStringValue, + data.u.str.mStringLength); + *size = cString.Length(); + *str = ToNewUnicode(cString); + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + { + nsDependentString string(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength); + *size = string.Length(); + *str = ToNewUnicode(string); + break; + } + case nsIDataType::VTYPE_WCHAR: + tempString.Assign(data.u.mWCharValue); + *size = tempString.Length(); + *str = ToNewUnicode(tempString); + break; + default: + rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + *size = tempCString.Length(); + *str = ToNewUnicode(tempCString); + break; + } + + return *str ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/* static */ nsresult +nsVariant::ConvertToISupports(const nsDiscriminatedUnion& data, + nsISupports **_retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + if (data.u.iface.mInterfaceValue) { + return data.u.iface.mInterfaceValue-> + QueryInterface(NS_GET_IID(nsISupports), (void**)_retval); + } else { + *_retval = nsnull; + return NS_OK; + } + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/* static */ nsresult +nsVariant::ConvertToInterface(const nsDiscriminatedUnion& data, nsIID * *iid, + void * *iface) +{ + const nsIID* piid; + + switch(data.mType) + { + case nsIDataType::VTYPE_INTERFACE: + piid = &NS_GET_IID(nsISupports); + break; + case nsIDataType::VTYPE_INTERFACE_IS: + piid = &data.u.iface.mInterfaceID; + break; + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + *iid = (nsIID*) nsMemory::Clone(piid, sizeof(nsIID)); + if(!*iid) + return NS_ERROR_OUT_OF_MEMORY; + + if (data.u.iface.mInterfaceValue) { + return data.u.iface.mInterfaceValue->QueryInterface(*piid, iface); + } + + *iface = nsnull; + return NS_OK; +} + +/* static */ nsresult +nsVariant::ConvertToArray(const nsDiscriminatedUnion& data, PRUint16 *type, + nsIID* iid, PRUint32 *count, void * *ptr) +{ + // XXX perhaps we'd like to add support for converting each of the various + // types into an array containing one element of that type. We can leverage + // CloneArray to do this if we want to support this. + + if(data.mType == nsIDataType::VTYPE_ARRAY) + return CloneArray(data.u.array.mArrayType, &data.u.array.mArrayInterfaceID, + data.u.array.mArrayCount, data.u.array.mArrayValue, + type, iid, count, ptr); + return NS_ERROR_CANNOT_CONVERT_DATA; +} + +/***************************************************************************/ +// static setter functions... + +#define DATA_SETTER_PROLOGUE(data_) \ + nsVariant::Cleanup(data_); + +#define DATA_SETTER_EPILOGUE(data_, type_) \ + data_->mType = nsIDataType :: type_; \ + return NS_OK; + +#define DATA_SETTER(data_, type_, member_, value_) \ + DATA_SETTER_PROLOGUE(data_) \ + data_->u.member_ = value_; \ + DATA_SETTER_EPILOGUE(data_, type_) + +#define DATA_SETTER_WITH_CAST(data_, type_, member_, cast_, value_) \ + DATA_SETTER_PROLOGUE(data_) \ + data_->u.member_ = cast_ value_; \ + DATA_SETTER_EPILOGUE(data_, type_) + + +/********************************************/ + +#define CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + { \ + +#define CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \ + rv = aValue->GetAs##name_ (&(data->u. member_ )); + +#define CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \ + rv = aValue->GetAs##name_ ( cast_ &(data->u. member_ )); + +#define CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) \ + if(NS_SUCCEEDED(rv)) \ + { \ + data->mType = nsIDataType :: type_ ; \ + } \ + break; \ + } + +#define CASE__SET_FROM_VARIANT_TYPE(type_, member_, name_) \ + case nsIDataType :: type_ : \ + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \ + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) + +#define CASE__SET_FROM_VARIANT_VTYPE_CAST(type_, cast_, member_, name_) \ + case nsIDataType :: type_ : \ + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \ + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) + + +/* static */ nsresult +nsVariant::SetFromVariant(nsDiscriminatedUnion* data, nsIVariant* aValue) +{ + PRUint16 type; + nsresult rv; + + nsVariant::Cleanup(data); + + rv = aValue->GetDataType(&type); + if(NS_FAILED(rv)) + return rv; + + switch(type) + { + CASE__SET_FROM_VARIANT_VTYPE_CAST(VTYPE_INT8, (PRUint8*), mInt8Value, + Int8) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT16, mInt16Value, Int16) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT32, mInt32Value, Int32) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT8, mUint8Value, Uint8) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT16, mUint16Value, Uint16) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT32, mUint32Value, Uint32) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_FLOAT, mFloatValue, Float) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_DOUBLE, mDoubleValue, Double) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_BOOL , mBoolValue, Bool) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_CHAR, mCharValue, Char) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_WCHAR, mWCharValue, WChar) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_ID, mIDValue, ID) + + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ASTRING); + data->u.mAStringValue = new nsString(); + if(!data->u.mAStringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsAString(*data->u.mAStringValue); + if(NS_FAILED(rv)) + delete data->u.mAStringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ASTRING) + + case nsIDataType::VTYPE_CSTRING: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_CSTRING); + data->u.mCStringValue = new nsCString(); + if(!data->u.mCStringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsACString(*data->u.mCStringValue); + if(NS_FAILED(rv)) + delete data->u.mCStringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_CSTRING) + + case nsIDataType::VTYPE_UTF8STRING: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_UTF8STRING); + data->u.mUTF8StringValue = new nsUTF8String(); + if(!data->u.mUTF8StringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsAUTF8String(*data->u.mUTF8StringValue); + if(NS_FAILED(rv)) + delete data->u.mUTF8StringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_UTF8STRING) + + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_STRING_SIZE_IS); + rv = aValue->GetAsStringWithSize(&data->u.str.mStringLength, + &data->u.str.mStringValue); + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_STRING_SIZE_IS) + + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_INTERFACE_IS); + // XXX This iid handling is ugly! + nsIID* iid; + rv = aValue->GetAsInterface(&iid, (void**)&data->u.iface.mInterfaceValue); + if(NS_SUCCEEDED(rv)) + { + data->u.iface.mInterfaceID = *iid; + nsMemory::Free((char*)iid); + } + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_INTERFACE_IS) + + case nsIDataType::VTYPE_ARRAY: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ARRAY); + rv = aValue->GetAsArray(&data->u.array.mArrayType, + &data->u.array.mArrayInterfaceID, + &data->u.array.mArrayCount, + &data->u.array.mArrayValue); + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ARRAY) + + case nsIDataType::VTYPE_VOID: + rv = nsVariant::SetToVoid(data); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + rv = nsVariant::SetToEmptyArray(data); + break; + case nsIDataType::VTYPE_EMPTY: + rv = nsVariant::SetToEmpty(data); + break; + default: + NS_ERROR("bad type in variant!"); + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +/* static */ nsresult +nsVariant::SetFromInt8(nsDiscriminatedUnion* data, PRUint8 aValue) +{ + DATA_SETTER_WITH_CAST(data, VTYPE_INT8, mInt8Value, (PRUint8), aValue) +} +/* static */ nsresult +nsVariant::SetFromInt16(nsDiscriminatedUnion* data, PRInt16 aValue) +{ + DATA_SETTER(data, VTYPE_INT16, mInt16Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromInt32(nsDiscriminatedUnion* data, PRInt32 aValue) +{ + DATA_SETTER(data, VTYPE_INT32, mInt32Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromInt64(nsDiscriminatedUnion* data, PRInt64 aValue) +{ + DATA_SETTER(data, VTYPE_INT64, mInt64Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint8(nsDiscriminatedUnion* data, PRUint8 aValue) +{ + DATA_SETTER(data, VTYPE_UINT8, mUint8Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint16(nsDiscriminatedUnion* data, PRUint16 aValue) +{ + DATA_SETTER(data, VTYPE_UINT16, mUint16Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint32(nsDiscriminatedUnion* data, PRUint32 aValue) +{ + DATA_SETTER(data, VTYPE_UINT32, mUint32Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint64(nsDiscriminatedUnion* data, PRUint64 aValue) +{ + DATA_SETTER(data, VTYPE_UINT64, mUint64Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromFloat(nsDiscriminatedUnion* data, float aValue) +{ + DATA_SETTER(data, VTYPE_FLOAT, mFloatValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromDouble(nsDiscriminatedUnion* data, double aValue) +{ + DATA_SETTER(data, VTYPE_DOUBLE, mDoubleValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromBool(nsDiscriminatedUnion* data, PRBool aValue) +{ + DATA_SETTER(data, VTYPE_BOOL, mBoolValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromChar(nsDiscriminatedUnion* data, char aValue) +{ + DATA_SETTER(data, VTYPE_CHAR, mCharValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromWChar(nsDiscriminatedUnion* data, PRUnichar aValue) +{ + DATA_SETTER(data, VTYPE_WCHAR, mWCharValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromID(nsDiscriminatedUnion* data, const nsID & aValue) +{ + DATA_SETTER(data, VTYPE_ID, mIDValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromAString(nsDiscriminatedUnion* data, const nsAString & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mAStringValue = new nsString(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_ASTRING); +} + +/* static */ nsresult +nsVariant::SetFromACString(nsDiscriminatedUnion* data, + const nsACString & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mCStringValue = new nsCString(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_CSTRING); +} + +/* static */ nsresult +nsVariant::SetFromAUTF8String(nsDiscriminatedUnion* data, + const nsAUTF8String & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mUTF8StringValue = new nsUTF8String(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_UTF8STRING); +} + +/* static */ nsresult +nsVariant::SetFromString(nsDiscriminatedUnion* data, const char *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + return SetFromStringWithSize(data, strlen(aValue), aValue); +} +/* static */ nsresult +nsVariant::SetFromWString(nsDiscriminatedUnion* data, const PRUnichar *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + return SetFromWStringWithSize(data, nsCRT::strlen(aValue), aValue); +} +/* static */ nsresult +nsVariant::SetFromISupports(nsDiscriminatedUnion* data, nsISupports *aValue) +{ + return SetFromInterface(data, NS_GET_IID(nsISupports), aValue); +} +/* static */ nsresult +nsVariant::SetFromInterface(nsDiscriminatedUnion* data, const nsIID& iid, + nsISupports *aValue) +{ + DATA_SETTER_PROLOGUE(data); + NS_IF_ADDREF(aValue); + data->u.iface.mInterfaceValue = aValue; + data->u.iface.mInterfaceID = iid; + DATA_SETTER_EPILOGUE(data, VTYPE_INTERFACE_IS); +} +/* static */ nsresult +nsVariant::SetFromArray(nsDiscriminatedUnion* data, PRUint16 type, + const nsIID* iid, PRUint32 count, void * aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue || !count) + return NS_ERROR_NULL_POINTER; + + nsresult rv = CloneArray(type, iid, count, aValue, + &data->u.array.mArrayType, + &data->u.array.mArrayInterfaceID, + &data->u.array.mArrayCount, + &data->u.array.mArrayValue); + if(NS_FAILED(rv)) + return rv; + DATA_SETTER_EPILOGUE(data, VTYPE_ARRAY); +} +/* static */ nsresult +nsVariant::SetFromStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const char *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + if(!(data->u.str.mStringValue = + (char*) nsMemory::Clone(aValue, (size+1)*sizeof(char)))) + return NS_ERROR_OUT_OF_MEMORY; + data->u.str.mStringLength = size; + DATA_SETTER_EPILOGUE(data, VTYPE_STRING_SIZE_IS); +} +/* static */ nsresult +nsVariant::SetFromWStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const PRUnichar *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + if(!(data->u.wstr.mWStringValue = + (PRUnichar*) nsMemory::Clone(aValue, (size+1)*sizeof(PRUnichar)))) + return NS_ERROR_OUT_OF_MEMORY; + data->u.wstr.mWStringLength = size; + DATA_SETTER_EPILOGUE(data, VTYPE_WSTRING_SIZE_IS); +} +/* static */ nsresult +nsVariant::SetToVoid(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_VOID); +} +/* static */ nsresult +nsVariant::SetToEmpty(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_EMPTY); +} +/* static */ nsresult +nsVariant::SetToEmptyArray(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_EMPTY_ARRAY); +} + +/***************************************************************************/ + +/* static */ nsresult +nsVariant::Initialize(nsDiscriminatedUnion* data) +{ + data->mType = nsIDataType::VTYPE_EMPTY; + return NS_OK; +} + +/* static */ nsresult +nsVariant::Cleanup(nsDiscriminatedUnion* data) +{ + switch(data->mType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ID: + break; + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + delete data->u.mAStringValue; + break; + case nsIDataType::VTYPE_CSTRING: + delete data->u.mCStringValue; + break; + case nsIDataType::VTYPE_UTF8STRING: + delete data->u.mUTF8StringValue; + break; + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + nsMemory::Free((char*)data->u.str.mStringValue); + break; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + nsMemory::Free((char*)data->u.wstr.mWStringValue); + break; + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + NS_IF_RELEASE(data->u.iface.mInterfaceValue); + break; + case nsIDataType::VTYPE_ARRAY: + FreeArray(data); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + break; + default: + NS_ERROR("bad type in variant!"); + break; + } + + data->mType = nsIDataType::VTYPE_EMPTY; + return NS_OK; +} + +/***************************************************************************/ +/***************************************************************************/ +// members... + +NS_IMPL_ISUPPORTS2(nsVariant, nsIVariant, nsIWritableVariant) + +nsVariant::nsVariant() + : mWritable(PR_TRUE) +{ + nsVariant::Initialize(&mData); + +#ifdef DEBUG + { + // Assert that the nsIDataType consts match the values #defined in + // xpt_struct.h. Bad things happen somewhere if they don't. + struct THE_TYPES {PRUint16 a; PRUint16 b;}; + static const THE_TYPES array[] = { + {nsIDataType::VTYPE_INT8 , TD_INT8 }, + {nsIDataType::VTYPE_INT16 , TD_INT16 }, + {nsIDataType::VTYPE_INT32 , TD_INT32 }, + {nsIDataType::VTYPE_INT64 , TD_INT64 }, + {nsIDataType::VTYPE_UINT8 , TD_UINT8 }, + {nsIDataType::VTYPE_UINT16 , TD_UINT16 }, + {nsIDataType::VTYPE_UINT32 , TD_UINT32 }, + {nsIDataType::VTYPE_UINT64 , TD_UINT64 }, + {nsIDataType::VTYPE_FLOAT , TD_FLOAT }, + {nsIDataType::VTYPE_DOUBLE , TD_DOUBLE }, + {nsIDataType::VTYPE_BOOL , TD_BOOL }, + {nsIDataType::VTYPE_CHAR , TD_CHAR }, + {nsIDataType::VTYPE_WCHAR , TD_WCHAR }, + {nsIDataType::VTYPE_VOID , TD_VOID }, + {nsIDataType::VTYPE_ID , TD_PNSIID }, + {nsIDataType::VTYPE_DOMSTRING , TD_DOMSTRING }, + {nsIDataType::VTYPE_CHAR_STR , TD_PSTRING }, + {nsIDataType::VTYPE_WCHAR_STR , TD_PWSTRING }, + {nsIDataType::VTYPE_INTERFACE , TD_INTERFACE_TYPE }, + {nsIDataType::VTYPE_INTERFACE_IS , TD_INTERFACE_IS_TYPE}, + {nsIDataType::VTYPE_ARRAY , TD_ARRAY }, + {nsIDataType::VTYPE_STRING_SIZE_IS , TD_PSTRING_SIZE_IS }, + {nsIDataType::VTYPE_WSTRING_SIZE_IS , TD_PWSTRING_SIZE_IS }, + {nsIDataType::VTYPE_UTF8STRING , TD_UTF8STRING }, + {nsIDataType::VTYPE_CSTRING , TD_CSTRING }, + {nsIDataType::VTYPE_ASTRING , TD_ASTRING } + }; + static const int length = sizeof(array)/sizeof(array[0]); + static PRBool inited = PR_FALSE; + if(!inited) + { + for(int i = 0; i < length; i++) + NS_ASSERTION(array[i].a == array[i].b, "bad const declaration"); + inited = PR_TRUE; + } + } +#endif +} + +nsVariant::~nsVariant() +{ + nsVariant::Cleanup(&mData); +} + +// For all the data getters we just forward to the static (and sharable) +// 'ConvertTo' functions. + +/* readonly attribute PRUint16 dataType; */ +NS_IMETHODIMP nsVariant::GetDataType(PRUint16 *aDataType) +{ + *aDataType = mData.mType; + return NS_OK; +} + +/* PRUint8 getAsInt8 (); */ +NS_IMETHODIMP nsVariant::GetAsInt8(PRUint8 *_retval) +{ + return nsVariant::ConvertToInt8(mData, _retval); +} + +/* PRInt16 getAsInt16 (); */ +NS_IMETHODIMP nsVariant::GetAsInt16(PRInt16 *_retval) +{ + return nsVariant::ConvertToInt16(mData, _retval); +} + +/* PRInt32 getAsInt32 (); */ +NS_IMETHODIMP nsVariant::GetAsInt32(PRInt32 *_retval) +{ + return nsVariant::ConvertToInt32(mData, _retval); +} + +/* PRInt64 getAsInt64 (); */ +NS_IMETHODIMP nsVariant::GetAsInt64(PRInt64 *_retval) +{ + return nsVariant::ConvertToInt64(mData, _retval); +} + +/* PRUint8 getAsUint8 (); */ +NS_IMETHODIMP nsVariant::GetAsUint8(PRUint8 *_retval) +{ + return nsVariant::ConvertToUint8(mData, _retval); +} + +/* PRUint16 getAsUint16 (); */ +NS_IMETHODIMP nsVariant::GetAsUint16(PRUint16 *_retval) +{ + return nsVariant::ConvertToUint16(mData, _retval); +} + +/* PRUint32 getAsUint32 (); */ +NS_IMETHODIMP nsVariant::GetAsUint32(PRUint32 *_retval) +{ + return nsVariant::ConvertToUint32(mData, _retval); +} + +/* PRUint64 getAsUint64 (); */ +NS_IMETHODIMP nsVariant::GetAsUint64(PRUint64 *_retval) +{ + return nsVariant::ConvertToUint64(mData, _retval); +} + +/* float getAsFloat (); */ +NS_IMETHODIMP nsVariant::GetAsFloat(float *_retval) +{ + return nsVariant::ConvertToFloat(mData, _retval); +} + +/* double getAsDouble (); */ +NS_IMETHODIMP nsVariant::GetAsDouble(double *_retval) +{ + return nsVariant::ConvertToDouble(mData, _retval); +} + +/* PRBool getAsBool (); */ +NS_IMETHODIMP nsVariant::GetAsBool(PRBool *_retval) +{ + return nsVariant::ConvertToBool(mData, _retval); +} + +/* char getAsChar (); */ +NS_IMETHODIMP nsVariant::GetAsChar(char *_retval) +{ + return nsVariant::ConvertToChar(mData, _retval); +} + +/* wchar getAsWChar (); */ +NS_IMETHODIMP nsVariant::GetAsWChar(PRUnichar *_retval) +{ + return nsVariant::ConvertToWChar(mData, _retval); +} + +/* [notxpcom] nsresult getAsID (out nsID retval); */ +NS_IMETHODIMP_(nsresult) nsVariant::GetAsID(nsID *retval) +{ + return nsVariant::ConvertToID(mData, retval); +} + +/* AString getAsAString (); */ +NS_IMETHODIMP nsVariant::GetAsAString(nsAString & _retval) +{ + return nsVariant::ConvertToAString(mData, _retval); +} + +/* DOMString getAsDOMString (); */ +NS_IMETHODIMP nsVariant::GetAsDOMString(nsAString & _retval) +{ + // A DOMString maps to an AString internally, so we can re-use + // ConvertToAString here. + return nsVariant::ConvertToAString(mData, _retval); +} + +/* ACString getAsACString (); */ +NS_IMETHODIMP nsVariant::GetAsACString(nsACString & _retval) +{ + return nsVariant::ConvertToACString(mData, _retval); +} + +/* AUTF8String getAsAUTF8String (); */ +NS_IMETHODIMP nsVariant::GetAsAUTF8String(nsAUTF8String & _retval) +{ + return nsVariant::ConvertToAUTF8String(mData, _retval); +} + +/* string getAsString (); */ +NS_IMETHODIMP nsVariant::GetAsString(char **_retval) +{ + return nsVariant::ConvertToString(mData, _retval); +} + +/* wstring getAsWString (); */ +NS_IMETHODIMP nsVariant::GetAsWString(PRUnichar **_retval) +{ + return nsVariant::ConvertToWString(mData, _retval); +} + +/* nsISupports getAsISupports (); */ +NS_IMETHODIMP nsVariant::GetAsISupports(nsISupports **_retval) +{ + return nsVariant::ConvertToISupports(mData, _retval); +} + +/* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */ +NS_IMETHODIMP nsVariant::GetAsInterface(nsIID * *iid, void * *iface) +{ + return nsVariant::ConvertToInterface(mData, iid, iface); +} + +/* [notxpcom] nsresult getAsArray (out PRUint16 type, out nsIID iid, out PRUint32 count, out voidPtr ptr); */ +NS_IMETHODIMP_(nsresult) nsVariant::GetAsArray(PRUint16 *type, nsIID *iid, PRUint32 *count, void * *ptr) +{ + return nsVariant::ConvertToArray(mData, type, iid, count, ptr); +} + +/* void getAsStringWithSize (out PRUint32 size, [size_is (size), retval] out string str); */ +NS_IMETHODIMP nsVariant::GetAsStringWithSize(PRUint32 *size, char **str) +{ + return nsVariant::ConvertToStringWithSize(mData, size, str); +} + +/* void getAsWStringWithSize (out PRUint32 size, [size_is (size), retval] out wstring str); */ +NS_IMETHODIMP nsVariant::GetAsWStringWithSize(PRUint32 *size, PRUnichar **str) +{ + return nsVariant::ConvertToWStringWithSize(mData, size, str); +} + +/***************************************************************************/ + +/* attribute PRBool writable; */ +NS_IMETHODIMP nsVariant::GetWritable(PRBool *aWritable) +{ + *aWritable = mWritable; + return NS_OK; +} +NS_IMETHODIMP nsVariant::SetWritable(PRBool aWritable) +{ + if(!mWritable && aWritable) + return NS_ERROR_FAILURE; + mWritable = aWritable; + return NS_OK; +} + +/***************************************************************************/ + +// For all the data setters we just forward to the static (and sharable) +// 'SetFrom' functions. + +/* void setAsInt8 (in PRUint8 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt8(PRUint8 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt8(&mData, aValue); +} + +/* void setAsInt16 (in PRInt16 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt16(PRInt16 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt16(&mData, aValue); +} + +/* void setAsInt32 (in PRInt32 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt32(PRInt32 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt32(&mData, aValue); +} + +/* void setAsInt64 (in PRInt64 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt64(PRInt64 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt64(&mData, aValue); +} + +/* void setAsUint8 (in PRUint8 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint8(PRUint8 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint8(&mData, aValue); +} + +/* void setAsUint16 (in PRUint16 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint16(PRUint16 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint16(&mData, aValue); +} + +/* void setAsUint32 (in PRUint32 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint32(PRUint32 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint32(&mData, aValue); +} + +/* void setAsUint64 (in PRUint64 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint64(PRUint64 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint64(&mData, aValue); +} + +/* void setAsFloat (in float aValue); */ +NS_IMETHODIMP nsVariant::SetAsFloat(float aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromFloat(&mData, aValue); +} + +/* void setAsDouble (in double aValue); */ +NS_IMETHODIMP nsVariant::SetAsDouble(double aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromDouble(&mData, aValue); +} + +/* void setAsBool (in PRBool aValue); */ +NS_IMETHODIMP nsVariant::SetAsBool(PRBool aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromBool(&mData, aValue); +} + +/* void setAsChar (in char aValue); */ +NS_IMETHODIMP nsVariant::SetAsChar(char aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromChar(&mData, aValue); +} + +/* void setAsWChar (in wchar aValue); */ +NS_IMETHODIMP nsVariant::SetAsWChar(PRUnichar aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWChar(&mData, aValue); +} + +/* void setAsID (in nsIDRef aValue); */ +NS_IMETHODIMP nsVariant::SetAsID(const nsID & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromID(&mData, aValue); +} + +/* void setAsAString (in AString aValue); */ +NS_IMETHODIMP nsVariant::SetAsAString(const nsAString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromAString(&mData, aValue); +} + +/* void setAsDOMString (in DOMString aValue); */ +NS_IMETHODIMP nsVariant::SetAsDOMString(const nsAString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + + // A DOMString maps to an AString internally, so we can re-use + // SetFromAString here. + return nsVariant::SetFromAString(&mData, aValue); +} + +/* void setAsACString (in ACString aValue); */ +NS_IMETHODIMP nsVariant::SetAsACString(const nsACString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromACString(&mData, aValue); +} + +/* void setAsAUTF8String (in AUTF8String aValue); */ +NS_IMETHODIMP nsVariant::SetAsAUTF8String(const nsAUTF8String & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromAUTF8String(&mData, aValue); +} + +/* void setAsString (in string aValue); */ +NS_IMETHODIMP nsVariant::SetAsString(const char *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromString(&mData, aValue); +} + +/* void setAsWString (in wstring aValue); */ +NS_IMETHODIMP nsVariant::SetAsWString(const PRUnichar *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWString(&mData, aValue); +} + +/* void setAsISupports (in nsISupports aValue); */ +NS_IMETHODIMP nsVariant::SetAsISupports(nsISupports *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromISupports(&mData, aValue); +} + +/* void setAsInterface (in nsIIDRef iid, [iid_is (iid)] in nsQIResult iface); */ +NS_IMETHODIMP nsVariant::SetAsInterface(const nsIID & iid, void * iface) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInterface(&mData, iid, (nsISupports*)iface); +} + +/* [noscript] void setAsArray (in PRUint16 type, in nsIIDPtr iid, in PRUint32 count, in voidPtr ptr); */ +NS_IMETHODIMP nsVariant::SetAsArray(PRUint16 type, const nsIID * iid, PRUint32 count, void * ptr) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromArray(&mData, type, iid, count, ptr); +} + +/* void setAsStringWithSize (in PRUint32 size, [size_is (size)] in string str); */ +NS_IMETHODIMP nsVariant::SetAsStringWithSize(PRUint32 size, const char *str) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromStringWithSize(&mData, size, str); +} + +/* void setAsWStringWithSize (in PRUint32 size, [size_is (size)] in wstring str); */ +NS_IMETHODIMP nsVariant::SetAsWStringWithSize(PRUint32 size, const PRUnichar *str) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWStringWithSize(&mData, size, str); +} + +/* void setAsVoid (); */ +NS_IMETHODIMP nsVariant::SetAsVoid() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToVoid(&mData); +} + +/* void setAsEmpty (); */ +NS_IMETHODIMP nsVariant::SetAsEmpty() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToEmpty(&mData); +} + +/* void setAsEmptyArray (); */ +NS_IMETHODIMP nsVariant::SetAsEmptyArray() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToEmptyArray(&mData); +} + +/* void setFromVariant (in nsIVariant aValue); */ +NS_IMETHODIMP nsVariant::SetFromVariant(nsIVariant *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromVariant(&mData, aValue); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVariant.h b/src/libs/xpcom18a4/xpcom/ds/nsVariant.h new file mode 100644 index 00000000..393e745f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVariant.h @@ -0,0 +1,203 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer <jband@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsIVariant.h" +#include "nsStringFwd.h" +#include "xpt_struct.h" + +/** + * Map the nsAUTF8String, nsUTF8String classes to the nsACString and + * nsCString classes respectively for now. These defines need to be removed + * once Jag lands his nsUTF8String implementation. + */ +#define nsAUTF8String nsACString +#define nsUTF8String nsCString +#define PromiseFlatUTF8String PromiseFlatCString + +/** + * nsDiscriminatedUnion is a type that nsIVariant implementors *may* use + * to hold underlying data. It has no methods. So, its use requires no linkage + * to the xpcom module. + */ + +struct nsDiscriminatedUnion +{ + union { + PRInt8 mInt8Value; + PRInt16 mInt16Value; + PRInt32 mInt32Value; + PRInt64 mInt64Value; + PRUint8 mUint8Value; + PRUint16 mUint16Value; + PRUint32 mUint32Value; + PRUint64 mUint64Value; + float mFloatValue; + double mDoubleValue; + PRBool mBoolValue; + char mCharValue; + PRUnichar mWCharValue; + nsIID mIDValue; + nsAString* mAStringValue; + nsAUTF8String* mUTF8StringValue; + nsACString* mCStringValue; + struct { + nsISupports* mInterfaceValue; + nsIID mInterfaceID; + } iface; + struct { + nsIID mArrayInterfaceID; + void* mArrayValue; + PRUint32 mArrayCount; + PRUint16 mArrayType; + } array; + struct { + char* mStringValue; + PRUint32 mStringLength; + } str; + struct { + PRUnichar* mWStringValue; + PRUint32 mWStringLength; + } wstr; + } u; + PRUint16 mType; +}; + +/** + * nsVariant implements the generic variant support. The xpcom module registers + * a factory (see NS_VARIANT_CONTRACTID in nsIVariant.idl) that will create + * these objects. They are created 'empty' and 'writable'. + * + * nsIVariant users won't usually need to see this class. + * + * This class also has static helper methods that nsIVariant *implementors* can + * use to help them do all the 'standard' nsIVariant data conversions. + */ + +class NS_COM nsVariant : public nsIWritableVariant +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIVARIANT + NS_DECL_NSIWRITABLEVARIANT + + nsVariant(); + + static nsresult Initialize(nsDiscriminatedUnion* data); + static nsresult Cleanup(nsDiscriminatedUnion* data); + + static nsresult ConvertToInt8(const nsDiscriminatedUnion& data, PRUint8 *_retval); + static nsresult ConvertToInt16(const nsDiscriminatedUnion& data, PRInt16 *_retval); + static nsresult ConvertToInt32(const nsDiscriminatedUnion& data, PRInt32 *_retval); + static nsresult ConvertToInt64(const nsDiscriminatedUnion& data, PRInt64 *_retval); + static nsresult ConvertToUint8(const nsDiscriminatedUnion& data, PRUint8 *_retval); + static nsresult ConvertToUint16(const nsDiscriminatedUnion& data, PRUint16 *_retval); + static nsresult ConvertToUint32(const nsDiscriminatedUnion& data, PRUint32 *_retval); + static nsresult ConvertToUint64(const nsDiscriminatedUnion& data, PRUint64 *_retval); + static nsresult ConvertToFloat(const nsDiscriminatedUnion& data, float *_retval); + static nsresult ConvertToDouble(const nsDiscriminatedUnion& data, double *_retval); + static nsresult ConvertToBool(const nsDiscriminatedUnion& data, PRBool *_retval); + static nsresult ConvertToChar(const nsDiscriminatedUnion& data, char *_retval); + static nsresult ConvertToWChar(const nsDiscriminatedUnion& data, PRUnichar *_retval); + static nsresult ConvertToID(const nsDiscriminatedUnion& data, nsID * _retval); + static nsresult ConvertToAString(const nsDiscriminatedUnion& data, nsAString & _retval); + static nsresult ConvertToAUTF8String(const nsDiscriminatedUnion& data, nsAUTF8String & _retval); + static nsresult ConvertToACString(const nsDiscriminatedUnion& data, nsACString & _retval); + static nsresult ConvertToString(const nsDiscriminatedUnion& data, char **_retval); + static nsresult ConvertToWString(const nsDiscriminatedUnion& data, PRUnichar **_retval); + static nsresult ConvertToISupports(const nsDiscriminatedUnion& data, nsISupports **_retval); + static nsresult ConvertToInterface(const nsDiscriminatedUnion& data, nsIID * *iid, void * *iface); + static nsresult ConvertToArray(const nsDiscriminatedUnion& data, PRUint16 *type, nsIID* iid, PRUint32 *count, void * *ptr); + static nsresult ConvertToStringWithSize(const nsDiscriminatedUnion& data, PRUint32 *size, char **str); + static nsresult ConvertToWStringWithSize(const nsDiscriminatedUnion& data, PRUint32 *size, PRUnichar **str); + + static nsresult SetFromVariant(nsDiscriminatedUnion* data, nsIVariant* aValue); + + static nsresult SetFromInt8(nsDiscriminatedUnion* data, PRUint8 aValue); + static nsresult SetFromInt16(nsDiscriminatedUnion* data, PRInt16 aValue); + static nsresult SetFromInt32(nsDiscriminatedUnion* data, PRInt32 aValue); + static nsresult SetFromInt64(nsDiscriminatedUnion* data, PRInt64 aValue); + static nsresult SetFromUint8(nsDiscriminatedUnion* data, PRUint8 aValue); + static nsresult SetFromUint16(nsDiscriminatedUnion* data, PRUint16 aValue); + static nsresult SetFromUint32(nsDiscriminatedUnion* data, PRUint32 aValue); + static nsresult SetFromUint64(nsDiscriminatedUnion* data, PRUint64 aValue); + static nsresult SetFromFloat(nsDiscriminatedUnion* data, float aValue); + static nsresult SetFromDouble(nsDiscriminatedUnion* data, double aValue); + static nsresult SetFromBool(nsDiscriminatedUnion* data, PRBool aValue); + static nsresult SetFromChar(nsDiscriminatedUnion* data, char aValue); + static nsresult SetFromWChar(nsDiscriminatedUnion* data, PRUnichar aValue); + static nsresult SetFromID(nsDiscriminatedUnion* data, const nsID & aValue); + static nsresult SetFromAString(nsDiscriminatedUnion* data, const nsAString & aValue); + static nsresult SetFromAUTF8String(nsDiscriminatedUnion* data, const nsAUTF8String & aValue); + static nsresult SetFromACString(nsDiscriminatedUnion* data, const nsACString & aValue); + static nsresult SetFromString(nsDiscriminatedUnion* data, const char *aValue); + static nsresult SetFromWString(nsDiscriminatedUnion* data, const PRUnichar *aValue); + static nsresult SetFromISupports(nsDiscriminatedUnion* data, nsISupports *aValue); + static nsresult SetFromInterface(nsDiscriminatedUnion* data, const nsIID& iid, nsISupports *aValue); + static nsresult SetFromArray(nsDiscriminatedUnion* data, PRUint16 type, const nsIID* iid, PRUint32 count, void * aValue); + static nsresult SetFromStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const char *aValue); + static nsresult SetFromWStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const PRUnichar *aValue); + + static nsresult SetToVoid(nsDiscriminatedUnion* data); + static nsresult SetToEmpty(nsDiscriminatedUnion* data); + static nsresult SetToEmptyArray(nsDiscriminatedUnion* data); + +private: + ~nsVariant(); + +protected: + nsDiscriminatedUnion mData; + PRBool mWritable; +}; + +/** + * Users of nsIVariant should be using the contractID and not this CID. + * - see NS_VARIANT_CONTRACTID in nsIVariant.idl. + */ + +#define NS_VARIANT_CID \ +{ /* 0D6EA1D0-879C-11d5-90EF-0010A4E73D9A */ \ + 0xd6ea1d0, \ + 0x879c, \ + 0x11d5, \ + {0x90, 0xef, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a}} + +#define NS_VARIANT_CLASSNAME "Variant" + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp new file mode 100644 index 00000000..259d0bd3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp @@ -0,0 +1,1560 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "nsVoidArray.h" +#include "nsQuickSort.h" +#include "prmem.h" +#include "nsCRT.h" +#include "nsString.h" +#include "prbit.h" + +/** + * Grow the array by at least this many elements at a time. + */ +static const PRInt32 kMinGrowArrayBy = 8; +static const PRInt32 kMaxGrowArrayBy = 1024; + +/** + * This is the threshold (in bytes) of the mImpl struct, past which + * we'll force the array to grow geometrically + */ +static const PRInt32 kLinearThreshold = 24 * sizeof(void *); + +/** + * Compute the number of bytes requires for the mImpl struct that will + * hold |n| elements. + */ +#define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1)) + + +/** + * Compute the number of elements that an mImpl struct of |n| bytes + * will hold. + */ +#define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1) + +#if DEBUG_VOIDARRAY +#define MAXVOID 10 + +class VoidStats { +public: + VoidStats(); + ~VoidStats(); + +}; + +static int sizesUsed; // number of the elements of the arrays used +static int sizesAlloced[MAXVOID]; // sizes of the allocations. sorted +static int NumberOfSize[MAXVOID]; // number of this allocation size (1 per array) +static int AllocedOfSize[MAXVOID]; // number of this allocation size (each size for array used) +static int MaxAuto[MAXVOID]; // AutoArrays that maxed out at this size +static int GrowInPlace[MAXVOID]; // arrays this size that grew in-place via realloc + +// these are per-allocation +static int MaxElements[2000]; // # of arrays that maxed out at each size. + +// statistics macros +#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])++; break; } \ + } \ + if (i >= sizesUsed && sizesUsed < MAXVOID) \ + { sizesAlloced[sizesUsed] = (size); \ + ((x)[sizesUsed++])++; break; \ + } \ + } while (0) + +#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])--; break; } \ + } \ + } while (0) + + +VoidStats::VoidStats() +{ + sizesUsed = 1; + sizesAlloced[0] = 0; +} + +VoidStats::~VoidStats() +{ + int i; + for (i = 0; i < sizesUsed; i++) + { + printf("Size %d:\n",sizesAlloced[i]); + printf("\tNumber of VoidArrays this size (max): %d\n",NumberOfSize[i]-MaxAuto[i]); + printf("\tNumber of AutoVoidArrays this size (max): %d\n",MaxAuto[i]); + printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]); + printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]); + } + printf("Max Size of VoidArray:\n"); + for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++) + { + if (MaxElements[i]) + printf("\t%d: %d\n",i,MaxElements[i]); + } +} + +// Just so constructor/destructor's get called +VoidStats gVoidStats; +#endif + +inline void +nsVoidArray::SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner) +{ + // old mImpl has been realloced and so we don't free/delete it + NS_PRECONDITION(newImpl, "can't set size"); + mImpl = newImpl; + mImpl->mCount = aCount; + mImpl->mBits = PRUint32(aSize & kArraySizeMask) | + (owner ? kArrayOwnerMask : 0); +} + +// This does all allocation/reallocation of the array. +// It also will compact down to N - good for things that might grow a lot +// at times, but usually are smaller, like JS deferred GC releases. +PRBool nsVoidArray::SizeTo(PRInt32 aSize) +{ + PRUint32 oldsize = GetArraySize(); + + if (aSize == (PRInt32) oldsize) + return PR_TRUE; // no change + + if (aSize <= 0) + { + // free the array if allocated + if (mImpl) + { + if (IsArrayOwner()) + { + PR_Free(NS_REINTERPRET_CAST(char *, mImpl)); + mImpl = nsnull; + } + else + { + mImpl->mCount = 0; // nsAutoVoidArray + } + } + return PR_TRUE; + } + + if (mImpl && IsArrayOwner()) + { + // We currently own an array impl. Resize it appropriately. + if (aSize < mImpl->mCount) + { + // XXX Note: we could also just resize to mCount + return PR_TRUE; // can't make it that small, ignore request + } + + char* bytes = (char *) PR_Realloc(mImpl,SIZEOF_IMPL(aSize)); + Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes); + if (!newImpl) + return PR_FALSE; + +#if DEBUG_VOIDARRAY + if (mImpl == newImpl) + ADD_TO_STATS(GrowInPlace,oldsize); + ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); + if (aSize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); + if (oldsize) + SUB_FROM_STATS(NumberOfSize,oldsize); + mMaxSize = aSize; + if (mIsAuto) + { + ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); + SUB_FROM_STATS(MaxAuto,oldsize); + } + } +#endif + SetArray(newImpl,aSize,newImpl->mCount,PR_TRUE); + return PR_TRUE; + } + + // just allocate an array + // allocate the exact size requested + char* bytes = (char *) PR_Malloc(SIZEOF_IMPL(aSize)); + Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes); + if (!newImpl) + return PR_FALSE; + +#if DEBUG_VOIDARRAY + ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); + if (aSize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); + if (oldsize && !mImpl) + SUB_FROM_STATS(NumberOfSize,oldsize); + mMaxSize = aSize; + } +#endif + if (mImpl) + { +#if DEBUG_VOIDARRAY + ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); + SUB_FROM_STATS(MaxAuto,0); + SUB_FROM_STATS(NumberOfSize,0); + mIsAuto = PR_TRUE; +#endif + // We must be growing an nsAutoVoidArray - copy since we didn't + // realloc. + memcpy(newImpl->mArray, mImpl->mArray, + mImpl->mCount * sizeof(mImpl->mArray[0])); + } + + SetArray(newImpl,aSize,mImpl ? mImpl->mCount : 0,PR_TRUE); + // no memset; handled later in ReplaceElementAt if needed + return PR_TRUE; +} + +PRBool nsVoidArray::GrowArrayBy(PRInt32 aGrowBy) +{ + // We have to grow the array. Grow by kMinGrowArrayBy 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 < kMinGrowArrayBy) + aGrowBy = kMinGrowArrayBy; + + PRUint32 newCapacity = GetArraySize() + aGrowBy; // Minimum increase + PRUint32 newSize = SIZEOF_IMPL(newCapacity); + + if (newSize >= (PRUint32) kLinearThreshold) + { + // newCount includes enough space for at least kMinGrowArrayBy new + // slots. Select the next power-of-two size in bytes above or + // equal to that. + // Also, limit the increase in size to about a VM page or two. + if (GetArraySize() >= kMaxGrowArrayBy) + { + newCapacity = GetArraySize() + PR_MAX(kMaxGrowArrayBy,aGrowBy); + newSize = SIZEOF_IMPL(newCapacity); + } + else + { + newSize = PR_BIT(PR_CeilingLog2(newSize)); + newCapacity = CAPACITYOF_IMPL(newSize); + } + } + // frees old mImpl IF this succeeds + if (!SizeTo(newCapacity)) + return PR_FALSE; + + return PR_TRUE; +} + +nsVoidArray::nsVoidArray() + : mImpl(nsnull) +{ + MOZ_COUNT_CTOR(nsVoidArray); +#if DEBUG_VOIDARRAY + mMaxCount = 0; + mMaxSize = 0; + mIsAuto = PR_FALSE; + ADD_TO_STATS(NumberOfSize,0); + MaxElements[0]++; +#endif +} + +nsVoidArray::nsVoidArray(PRInt32 aCount) + : mImpl(nsnull) +{ + MOZ_COUNT_CTOR(nsVoidArray); +#if DEBUG_VOIDARRAY + mMaxCount = 0; + mMaxSize = 0; + mIsAuto = PR_FALSE; + MaxElements[0]++; +#endif + SizeTo(aCount); +} + +nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other) +{ + PRInt32 otherCount = other.Count(); + PRInt32 maxCount = GetArraySize(); + if (otherCount) + { + if (otherCount > maxCount) + { + // frees old mImpl IF this succeeds + if (!GrowArrayBy(otherCount-maxCount)) + return *this; // XXX The allocation failed - don't do anything + + memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0])); + mImpl->mCount = otherCount; + } + else + { + // the old array can hold the new array + memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0])); + mImpl->mCount = otherCount; + // if it shrank a lot, compact it anyways + if ((otherCount*2) < maxCount && maxCount > 100) + { + Compact(); // shrank by at least 50 entries + } + } +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + } + else + { + if (mImpl && IsArrayOwner()) + PR_Free(NS_REINTERPRET_CAST(char*, mImpl)); + + mImpl = nsnull; + } + + return *this; +} + +nsVoidArray::~nsVoidArray() +{ + MOZ_COUNT_DTOR(nsVoidArray); + if (mImpl && IsArrayOwner()) + PR_Free(NS_REINTERPRET_CAST(char*, mImpl)); +} + +PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + if (*ap == aPossibleElement) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + PRInt32 oldCount = Count(); + NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)"); + if (PRUint32(aIndex) > PRUint32(oldCount)) + { + // An invalid index causes the insertion to fail + // Invalid indexes are ones that add more than one entry to the + // array (i.e., they can append). + return PR_FALSE; + } + + if (oldCount >= GetArraySize()) + { + if (!GrowArrayBy(1)) + return PR_FALSE; + } + // else the array is already large enough + + PRInt32 slide = oldCount - aIndex; + if (0 != slide) + { + // Slide data over to make room for the insertion + memmove(mImpl->mArray + aIndex + 1, mImpl->mArray + aIndex, + slide * sizeof(mImpl->mArray[0])); + } + + mImpl->mArray[aIndex] = aElement; + mImpl->mCount++; + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + + return PR_TRUE; +} + +PRBool nsVoidArray::InsertElementsAt(const nsVoidArray& other, PRInt32 aIndex) +{ + PRInt32 oldCount = Count(); + PRInt32 otherCount = other.Count(); + + NS_ASSERTION(aIndex >= 0,"InsertElementsAt(negative index)"); + if (PRUint32(aIndex) > PRUint32(oldCount)) + { + // An invalid index causes the insertion to fail + // Invalid indexes are ones that are more than one entry past the end of + // the array (i.e., they can append). + return PR_FALSE; + } + + if (oldCount + otherCount > GetArraySize()) + { + if (!GrowArrayBy(otherCount)) + return PR_FALSE;; + } + // else the array is already large enough + + PRInt32 slide = oldCount - aIndex; + if (0 != slide) + { + // Slide data over to make room for the insertion + memmove(mImpl->mArray + aIndex + otherCount, mImpl->mArray + aIndex, + slide * sizeof(mImpl->mArray[0])); + } + + for (PRInt32 i = 0; i < otherCount; i++) + { + // copy all the elements (destroys aIndex) + mImpl->mArray[aIndex++] = other.mImpl->mArray[i]; + mImpl->mCount++; + } + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + + return PR_TRUE; +} + +PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)"); + if (aIndex < 0) + return PR_FALSE; + + // Unlike InsertElementAt, ReplaceElementAt can implicitly add more + // than just the one element to the array. + if (PRUint32(aIndex) >= PRUint32(GetArraySize())) + { + PRInt32 oldCount = Count(); + PRInt32 requestedCount = aIndex + 1; + PRInt32 growDelta = requestedCount - oldCount; + + // frees old mImpl IF this succeeds + if (!GrowArrayBy(growDelta)) + return PR_FALSE; + } + + mImpl->mArray[aIndex] = aElement; + if (aIndex >= mImpl->mCount) + { + // Make sure that any entries implicitly added to the array by this + // ReplaceElementAt are cleared to 0. Some users of this assume that. + // This code means we don't have to memset when we allocate an array. + if (aIndex > mImpl->mCount) // note: not >= + { + // For example, if mCount is 2, and we do a ReplaceElementAt for + // element[5], then we need to set three entries ([2], [3], and [4]) + // to 0. + memset(&mImpl->mArray[mImpl->mCount], 0, + (aIndex - mImpl->mCount) * sizeof(mImpl->mArray[0])); + } + + mImpl->mCount = aIndex + 1; + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + } + + return PR_TRUE; +} + +// useful for doing LRU arrays +PRBool nsVoidArray::MoveElement(PRInt32 aFrom, PRInt32 aTo) +{ + void *tempElement; + + if (aTo == aFrom) + return PR_TRUE; + + NS_ASSERTION(aTo >= 0 && aFrom >= 0,"MoveElement(negative index)"); + if (aTo >= Count() || aFrom >= Count()) + { + // can't extend the array when moving an element. Also catches mImpl = null + return PR_FALSE; + } + tempElement = mImpl->mArray[aFrom]; + + if (aTo < aFrom) + { + // Moving one element closer to the head; the elements inbetween move down + memmove(mImpl->mArray + aTo + 1, mImpl->mArray + aTo, + (aFrom-aTo) * sizeof(mImpl->mArray[0])); + mImpl->mArray[aTo] = tempElement; + } + else // already handled aFrom == aTo + { + // Moving one element closer to the tail; the elements inbetween move up + memmove(mImpl->mArray + aFrom, mImpl->mArray + aFrom + 1, + (aTo-aFrom) * sizeof(mImpl->mArray[0])); + mImpl->mArray[aTo] = tempElement; + } + + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount) +{ + PRInt32 oldCount = Count(); + NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)"); + if (PRUint32(aIndex) >= PRUint32(oldCount)) + { + // An invalid index causes the replace to fail + return PR_FALSE; + } + // Limit to available entries starting at aIndex + if (aCount + aIndex > oldCount) + aCount = oldCount - aIndex; + + // We don't need to move any elements if we're removing the + // last element in the array + if (aIndex < (oldCount - aCount)) + { + memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount, + (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0])); + } + + mImpl->mCount -= aCount; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElement(void* aElement) +{ + PRInt32 theIndex = IndexOf(aElement); + if (theIndex != -1) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +void nsVoidArray::Clear() +{ + if (mImpl) + { + mImpl->mCount = 0; + } +} + +void nsVoidArray::Compact() +{ + if (mImpl) + { + // XXX NOTE: this is quite inefficient in many cases if we're only + // compacting by a little, but some callers care more about memory use. + if (GetArraySize() > Count()) + { + SizeTo(Count()); + } + } +} + +// Needed because we want to pass the pointer to the item in the array +// to the comparator function, not a pointer to the pointer in the array. +struct VoidArrayComparatorContext { + nsVoidArrayComparatorFunc mComparatorFunc; + void* mData; +}; + +PR_STATIC_CALLBACK(int) +VoidArrayComparator(const void* aElement1, const void* aElement2, void* aData) +{ + VoidArrayComparatorContext* ctx = NS_STATIC_CAST(VoidArrayComparatorContext*, aData); + return (*ctx->mComparatorFunc)(*NS_STATIC_CAST(void* const*, aElement1), + *NS_STATIC_CAST(void* const*, aElement2), + ctx->mData); +} + +void nsVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData) +{ + if (mImpl && mImpl->mCount > 1) + { + VoidArrayComparatorContext ctx = {aFunc, aData}; + NS_QuickSort(mImpl->mArray, mImpl->mCount, sizeof(mImpl->mArray[0]), + VoidArrayComparator, &ctx); + } +} + +PRBool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = -1; + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(mImpl->mArray[index], aData); + } + } + return running; +} + +PRBool nsVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = Count(); + while (running && (0 <= --index)) + { + running = (*aFunc)(mImpl->mArray[index], aData); + } + } + return running; +} + +//---------------------------------------------------------------- +// nsAutoVoidArray + +nsAutoVoidArray::nsAutoVoidArray() + : nsVoidArray() +{ + // Don't need to clear it. Some users just call ReplaceElementAt(), + // but we'll clear it at that time if needed to save CPU cycles. +#if DEBUG_VOIDARRAY + mIsAuto = PR_TRUE; + ADD_TO_STATS(MaxAuto,0); +#endif + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); +} + +void nsAutoVoidArray::Clear() +{ + // We don't have to free on Clear, but since we have a built-in buffer, + // it's worth considering. + nsVoidArray::Clear(); + if (IsArrayOwner() && GetArraySize() > 4*kAutoBufSize) + SizeTo(0); // we override CompactTo - delete and repoint at auto array +} + +PRBool nsAutoVoidArray::SizeTo(PRInt32 aSize) +{ + if (!nsVoidArray::SizeTo(aSize)) + return PR_FALSE; + + if (!mImpl) + { + // reset the array to point to our autobuf + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); + } + return PR_TRUE; +} + +void nsAutoVoidArray::Compact() +{ + nsVoidArray::Compact(); + if (!mImpl) + { + // reset the array to point to our autobuf + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); + } +} + +//---------------------------------------------------------------- +// nsStringArray + +nsStringArray::nsStringArray(void) + : nsVoidArray() +{ +} + +nsStringArray::nsStringArray(PRInt32 aCount) + : nsVoidArray(aCount) +{ +} + +nsStringArray::~nsStringArray(void) +{ + Clear(); +} + +nsStringArray& +nsStringArray::operator=(const nsStringArray& other) +{ + // Copy the pointers + nsVoidArray::operator=(other); + + // Now copy the strings + for (PRInt32 i = Count() - 1; i >= 0; --i) + { + nsString* oldString = NS_STATIC_CAST(nsString*, other.ElementAt(i)); + mImpl->mArray[i] = new nsString(*oldString); + } + + return *this; +} + +void +nsStringArray::StringAt(PRInt32 aIndex, nsAString& aString) const +{ + nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + aString.Assign(*string); + } + else + { + aString.Truncate(); + } +} + +nsString* +nsStringArray::StringAt(PRInt32 aIndex) const +{ + return NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); +} + +PRInt32 +nsStringArray::IndexOf(const nsAString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsString* string = NS_STATIC_CAST(nsString*, *ap); + if (string->Equals(aPossibleString)) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool +nsStringArray::InsertStringAt(const nsAString& aString, PRInt32 aIndex) +{ + nsString* string = new nsString(aString); + if (nsVoidArray::InsertElementAt(string, aIndex)) + { + return PR_TRUE; + } + delete string; + return PR_FALSE; +} + +PRBool +nsStringArray::ReplaceStringAt(const nsAString& aString, + PRInt32 aIndex) +{ + nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + *string = aString; + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsStringArray::RemoveString(const nsAString& aString) +{ + PRInt32 index = IndexOf(aString); + if (-1 < index) + { + return RemoveStringAt(index); + } + return PR_FALSE; +} + +PRBool nsStringArray::RemoveStringAt(PRInt32 aIndex) +{ + nsString* string = StringAt(aIndex); + if (nsnull != string) + { + nsVoidArray::RemoveElementAt(aIndex); + delete string; + return PR_TRUE; + } + return PR_FALSE; +} + +void +nsStringArray::Clear(void) +{ + PRInt32 index = Count(); + while (0 <= --index) + { + nsString* string = NS_STATIC_CAST(nsString*, mImpl->mArray[index]); + delete string; + } + nsVoidArray::Clear(); +} + +PR_STATIC_CALLBACK(int) +CompareString(const nsString* aString1, const nsString* aString2, void*) +{ + return Compare(*aString1, *aString2); +} + +void nsStringArray::Sort(void) +{ + Sort(CompareString, nsnull); +} + +void nsStringArray::Sort(nsStringArrayComparatorFunc aFunc, void* aData) +{ + nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData); +} + +PRBool +nsStringArray::EnumerateForwards(nsStringArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = -1; + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData); + } + } + return running; +} + +PRBool +nsStringArray::EnumerateBackwards(nsStringArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = Count(); + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (0 <= --index)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData); + } + } + return running; +} + + + +//---------------------------------------------------------------- +// nsCStringArray + +nsCStringArray::nsCStringArray(void) + : nsVoidArray() +{ +} + +// Parses a given string using the delimiter passed in and appends items +// parsed to the array. +void +nsCStringArray::ParseString(const char* string, const char* delimiter) +{ + if (string && *string && delimiter && *delimiter) { + char *newStr; + char *rest = nsCRT::strdup(string); + char *token = nsCRT::strtok(rest, delimiter, &newStr); + + while (token) { + if (*token) { + /* calling AppendElement(void*) to avoid extra nsCString copy */ + AppendElement(new nsCString(token)); + } + token = nsCRT::strtok(newStr, delimiter, &newStr); + } + PR_FREEIF(rest); + } +} + +nsCStringArray::nsCStringArray(PRInt32 aCount) + : nsVoidArray(aCount) +{ +} + +nsCStringArray::~nsCStringArray(void) +{ + Clear(); +} + +nsCStringArray& +nsCStringArray::operator=(const nsCStringArray& other) +{ + // Copy the pointers + nsVoidArray::operator=(other); + + // Now copy the strings + for (PRInt32 i = Count() - 1; i >= 0; --i) + { + nsCString* oldString = NS_STATIC_CAST(nsCString*, other.ElementAt(i)); + mImpl->mArray[i] = new nsCString(*oldString); + } + + return *this; +} + +void +nsCStringArray::CStringAt(PRInt32 aIndex, nsACString& aCString) const +{ + nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + aCString = *string; + } + else + { + aCString.Truncate(); + } +} + +nsCString* +nsCStringArray::CStringAt(PRInt32 aIndex) const +{ + return NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); +} + +PRInt32 +nsCStringArray::IndexOf(const nsACString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsCString* string = NS_STATIC_CAST(nsCString*, *ap); + if (string->Equals(aPossibleString)) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRInt32 +nsCStringArray::IndexOfIgnoreCase(const nsACString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsCString* string = NS_STATIC_CAST(nsCString*, *ap); + if (string->Equals(aPossibleString, nsCaseInsensitiveCStringComparator())) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool +nsCStringArray::InsertCStringAt(const nsACString& aCString, PRInt32 aIndex) +{ + nsCString* string = new nsCString(aCString); + if (nsVoidArray::InsertElementAt(string, aIndex)) + { + return PR_TRUE; + } + delete string; + return PR_FALSE; +} + +PRBool +nsCStringArray::ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex) +{ + nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + *string = aCString; + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsCStringArray::RemoveCString(const nsACString& aCString) +{ + PRInt32 index = IndexOf(aCString); + if (-1 < index) + { + return RemoveCStringAt(index); + } + return PR_FALSE; +} + +PRBool +nsCStringArray::RemoveCStringIgnoreCase(const nsACString& aCString) +{ + PRInt32 index = IndexOfIgnoreCase(aCString); + if (-1 < index) + { + return RemoveCStringAt(index); + } + return PR_FALSE; +} + +PRBool nsCStringArray::RemoveCStringAt(PRInt32 aIndex) +{ + nsCString* string = CStringAt(aIndex); + if (nsnull != string) + { + nsVoidArray::RemoveElementAt(aIndex); + delete string; + return PR_TRUE; + } + return PR_FALSE; +} + +void +nsCStringArray::Clear(void) +{ + PRInt32 index = Count(); + while (0 <= --index) + { + nsCString* string = NS_STATIC_CAST(nsCString*, mImpl->mArray[index]); + delete string; + } + nsVoidArray::Clear(); +} + +PR_STATIC_CALLBACK(int) +CompareCString(const nsCString* aCString1, const nsCString* aCString2, void*) +{ + return Compare(*aCString1, *aCString2); +} + +PR_STATIC_CALLBACK(int) +CompareCStringIgnoreCase(const nsCString* aCString1, const nsCString* aCString2, void*) +{ + return Compare(*aCString1, *aCString2, nsCaseInsensitiveCStringComparator()); +} + +void nsCStringArray::Sort(void) +{ + Sort(CompareCString, nsnull); +} + +void nsCStringArray::SortIgnoreCase(void) +{ + Sort(CompareCStringIgnoreCase, nsnull); +} + +void nsCStringArray::Sort(nsCStringArrayComparatorFunc aFunc, void* aData) +{ + nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData); +} + +PRBool +nsCStringArray::EnumerateForwards(nsCStringArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = -1; + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData); + } + } + return running; +} + +PRBool +nsCStringArray::EnumerateBackwards(nsCStringArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = Count(); + while (running && (0 <= --index)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData); + } + } + return running; +} + + +//---------------------------------------------------------------------- +// NOTE: nsSmallVoidArray elements MUST all have the low bit as 0. +// This means that normally it's only used for pointers, and in particular +// structures or objects. +nsSmallVoidArray::nsSmallVoidArray() +{ + mChildren = nsnull; +} + +nsSmallVoidArray::~nsSmallVoidArray() +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + delete vector; + } +} + +nsSmallVoidArray& +nsSmallVoidArray::operator=(nsSmallVoidArray& other) +{ + nsVoidArray* ourArray = GetChildVector(); + nsVoidArray* otherArray = other.GetChildVector(); + + if (HasVector()) + { + if (other.HasVector()) + { + // if both are real arrays, just use array= */ + *ourArray = *otherArray; + } + else + { + // we have an array, but the other doesn't. + otherArray = other.SwitchToVector(); + if (otherArray) + *ourArray = *otherArray; + } + } + else + { + if (other.HasVector()) + { + // we have no array, but other does + ourArray = SwitchToVector(); + if (ourArray) + *ourArray = *otherArray; + } + else + { + // neither has an array (either may have 0 or 1 items) + SetSingleChild(other.GetSingleChild()); + } + } + return *this; +} + +PRInt32 +nsSmallVoidArray::GetArraySize() const +{ + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->GetArraySize(); + + return 1; +} + +PRInt32 +nsSmallVoidArray::Count() const +{ + if (HasSingleChild()) + { + return 1; + } + else { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->Count(); + } + + return 0; +} + +void* +nsSmallVoidArray::ElementAt(PRInt32 aIndex) const +{ + if (HasSingleChild()) + { + if (0 == aIndex) + return (void*)GetSingleChild(); + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->ElementAt(aIndex); + } + + return nsnull; +} + +PRInt32 +nsSmallVoidArray::IndexOf(void* aPossibleElement) const +{ + if (HasSingleChild()) + { + if (aPossibleElement == (void*)GetSingleChild()) + return 0; + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->IndexOf(aPossibleElement); + } + + return -1; +} + +PRBool +nsSmallVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + nsVoidArray* vector; + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + if (HasSingleChild()) + { + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (!vector) + { + if (0 == aIndex) + { + SetSingleChild(aElement); + return PR_TRUE; + } + return PR_FALSE; + } + } + + return vector->InsertElementAt(aElement, aIndex); +} + +PRBool nsSmallVoidArray::InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex) +{ + nsVoidArray* vector; + PRInt32 count = other.Count(); + if (count == 0) + return PR_TRUE; + +#ifdef DEBUG + for (int i = 0; i < count; i++) + { + NS_ASSERTION(!(PtrBits(other.ElementAt(i)) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(other.ElementAt(i) != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + } +#endif + + if (!HasVector()) + { + if (HasSingleChild() || count > 1 || aIndex > 0) + { + vector = SwitchToVector(); + } + else + { + // count == 1, aIndex == 0, no elements already + SetSingleChild(other[0]); + return PR_TRUE; + } + } + else + { + vector = GetChildVector(); + } + + if (vector) + { + return vector->InsertElementsAt(other,aIndex); + } + return PR_TRUE; +} + +PRBool +nsSmallVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + if (HasSingleChild()) + { + if (aIndex == 0) + { + SetSingleChild(aElement); + return PR_TRUE; + } + return PR_FALSE; + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->ReplaceElementAt(aElement, aIndex); + + return PR_FALSE; + } +} + +PRBool +nsSmallVoidArray::AppendElement(void* aElement) +{ + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + nsVoidArray* vector; + if (HasSingleChild()) + { + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (!vector) + { + SetSingleChild(aElement); + return PR_TRUE; + } + } + + return vector->AppendElement(aElement); +} + +PRBool +nsSmallVoidArray::RemoveElement(void* aElement) +{ + if (HasSingleChild()) + { + if (aElement == GetSingleChild()) + { + SetSingleChild(nsnull); + return PR_TRUE; + } + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->RemoveElement(aElement); + } + + return PR_FALSE; +} + +PRBool +nsSmallVoidArray::RemoveElementAt(PRInt32 aIndex) +{ + if (HasSingleChild()) + { + if (0 == aIndex) + { + SetSingleChild(nsnull); + return PR_TRUE; + } + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + { + return vector->RemoveElementAt(aIndex); + } + } + + return PR_FALSE; +} + +PRBool +nsSmallVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount) +{ + nsVoidArray* vector = GetChildVector(); + + if (aCount == 0) + return PR_TRUE; + + if (HasSingleChild()) + { + if (aIndex == 0) + SetSingleChild(nsnull); + return PR_TRUE; + } + + if (!vector) + return PR_TRUE; + + // complex case; remove entries from an array + return vector->RemoveElementsAt(aIndex,aCount); +} + +void +nsSmallVoidArray::Clear() +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + vector->Clear(); + } + else + { + SetSingleChild(nsnull); + } +} + +PRBool +nsSmallVoidArray::SizeTo(PRInt32 aMin) +{ + nsVoidArray* vector; + if (!HasVector()) + { + if (aMin <= 1) + return PR_TRUE; + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (aMin <= 1) + { + void *prev = nsnull; + if (vector->Count() == 1) + { + prev = vector->ElementAt(0); + } + delete vector; + SetSingleChild(prev); + return PR_TRUE; + } + } + return vector->SizeTo(aMin); +} + +void +nsSmallVoidArray::Compact() +{ + if (!HasSingleChild()) + { + nsVoidArray* vector = GetChildVector(); + if (vector) + vector->Compact(); + } +} + +void +nsSmallVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + vector->Sort(aFunc,aData); + } +} + +PRBool +nsSmallVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + return vector->EnumerateForwards(aFunc,aData); + } + if (HasSingleChild()) + { + return (*aFunc)(GetSingleChild(), aData); + } + return PR_TRUE; +} + +PRBool +nsSmallVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + return vector->EnumerateBackwards(aFunc,aData); + } + if (HasSingleChild()) + { + return (*aFunc)(GetSingleChild(), aData); + } + return PR_TRUE; +} + +void +nsSmallVoidArray::SetSingleChild(void* aChild) +{ + if (aChild) + mChildren = (void*)(PtrBits(aChild) | 0x1); + else + mChildren = nsnull; +} + +nsVoidArray* +nsSmallVoidArray::SwitchToVector() +{ + void* child = GetSingleChild(); + + mChildren = (void*)new nsAutoVoidArray(); + nsVoidArray* vector = GetChildVector(); + if (vector && child) + vector->AppendElement(child); + + return vector; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h new file mode 100644 index 00000000..28d950e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h @@ -0,0 +1,410 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsVoidArray_h___ +#define nsVoidArray_h___ + +//#define DEBUG_VOIDARRAY 1 + +#include "nscore.h" +#include "nsAString.h" + +// Comparator callback function for sorting array values. +typedef int (* PR_CALLBACK nsVoidArrayComparatorFunc) + (const void* aElement1, const void* aElement2, void* aData); + +// Enumerator callback function. Return PR_FALSE to stop +typedef PRBool (* PR_CALLBACK nsVoidArrayEnumFunc)(void* aElement, void *aData); + +/// A basic zero-based array of void*'s that manages its own memory +class NS_COM nsVoidArray { +public: + nsVoidArray(); + nsVoidArray(PRInt32 aCount); // initial count of aCount elements set to nsnull + virtual ~nsVoidArray(); + + nsVoidArray& operator=(const nsVoidArray& other); + + inline PRInt32 Count() const { + return mImpl ? mImpl->mCount : 0; + } + // returns the max number that can be held without allocating + inline PRInt32 GetArraySize() const { + return mImpl ? (PRInt32(mImpl->mBits) & kArraySizeMask) : 0; + } + + void* FastElementAt(PRInt32 aIndex) const + { + NS_ASSERTION(0 <= aIndex && aIndex < Count(), "index out of range"); + return mImpl->mArray[aIndex]; + } + + // This both asserts and bounds-checks, because (1) we don't want + // people to write bad code, but (2) we don't want to change it to + // crashing for backwards compatibility. See bug 96108. + void* ElementAt(PRInt32 aIndex) const + { + NS_ASSERTION(0 <= aIndex && aIndex < Count(), "index out of range"); + return SafeElementAt(aIndex); + } + + // bounds-checked version + void* SafeElementAt(PRInt32 aIndex) const + { + if (PRUint32(aIndex) >= PRUint32(Count())) // handles aIndex < 0 too + { + return nsnull; + } + // The bounds check ensures mImpl is non-null. + return mImpl->mArray[aIndex]; + } + + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 IndexOf(void* aPossibleElement) const; + + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex); + + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + + // useful for doing LRU arrays, sorting, etc + PRBool MoveElement(PRInt32 aFrom, PRInt32 aTo); + + PRBool AppendElement(void* aElement) { + return InsertElementAt(aElement, Count()); + } + + PRBool AppendElements(nsVoidArray& aElements) { + return InsertElementsAt(aElements, Count()); + } + + PRBool RemoveElement(void* aElement); + PRBool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount); + PRBool RemoveElementAt(PRInt32 aIndex) { return RemoveElementsAt(aIndex,1); } + + virtual void Clear(); + + virtual PRBool SizeTo(PRInt32 aMin); + // Subtly different - Compact() tries to be smart about whether we + // should reallocate the array; SizeTo() just does it. + virtual void Compact(); + + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); + +protected: + virtual PRBool GrowArrayBy(PRInt32 aGrowBy); + + struct Impl { + /** + * Packed bits. The low 31 bits are the array's size. + * The highest bit is a flag that indicates + * whether or not we "own" mArray, and must free() it when + * destroyed. + */ + PRUint32 mBits; + + /** + * The number of elements in the array + */ + PRInt32 mCount; + + /** + * Array data, padded out to the actual size of the array. + */ + void* mArray[1]; + }; + + Impl* mImpl; +#if DEBUG_VOIDARRAY + PRInt32 mMaxCount; + PRInt32 mMaxSize; + PRBool mIsAuto; +#endif + + enum { + kArrayOwnerMask = 1 << 31, + kArraySizeMask = ~kArrayOwnerMask + }; + + + // bit twiddlers + void SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner); + inline PRBool IsArrayOwner() const { + return mImpl ? (PRBool(mImpl->mBits) & kArrayOwnerMask) : PR_FALSE; + } + +private: + /// Copy constructors are not allowed + nsVoidArray(const nsVoidArray& other); +}; + + +// A zero-based array with a bit of automatic internal storage +class NS_COM nsAutoVoidArray : public nsVoidArray { +public: + nsAutoVoidArray(); + void Clear(); + + virtual PRBool SizeTo(PRInt32 aMin); + virtual void Compact(); + +protected: + // The internal storage + enum { kAutoBufSize = 8 }; + char mAutoBuf[sizeof(Impl) + (kAutoBufSize - 1) * sizeof(void*)]; +}; + + +class nsString; + +typedef int (* PR_CALLBACK nsStringArrayComparatorFunc) + (const nsString* aElement1, const nsString* aElement2, void* aData); + +typedef PRBool (*nsStringArrayEnumFunc)(nsString& aElement, void *aData); + +class NS_COM nsStringArray: protected nsVoidArray +{ +public: + nsStringArray(void); + nsStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated + virtual ~nsStringArray(void); + + nsStringArray& operator=(const nsStringArray& other); + + PRInt32 Count(void) const { + return nsVoidArray::Count(); + } + + void StringAt(PRInt32 aIndex, nsAString& aString) const; + nsString* StringAt(PRInt32 aIndex) const; + nsString* operator[](PRInt32 aIndex) const { return StringAt(aIndex); } + + PRInt32 IndexOf(const nsAString& aPossibleString) const; + + PRBool InsertStringAt(const nsAString& aString, PRInt32 aIndex); + + PRBool ReplaceStringAt(const nsAString& aString, PRInt32 aIndex); + + PRBool AppendString(const nsAString& aString) { + return InsertStringAt(aString, Count()); + } + + PRBool RemoveString(const nsAString& aString); + PRBool RemoveStringAt(PRInt32 aIndex); + void Clear(void); + + void Compact(void) { + nsVoidArray::Compact(); + } + + void Sort(void); + void Sort(nsStringArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsStringArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsStringArrayEnumFunc aFunc, void* aData); + +private: + /// Copy constructors are not allowed + nsStringArray(const nsStringArray& other); +}; + + +class nsCString; + +typedef int (* PR_CALLBACK nsCStringArrayComparatorFunc) + (const nsCString* aElement1, const nsCString* aElement2, void* aData); + +typedef PRBool (*nsCStringArrayEnumFunc)(nsCString& aElement, void *aData); + +class NS_COM nsCStringArray: protected nsVoidArray +{ +public: + nsCStringArray(void); + nsCStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated + virtual ~nsCStringArray(void); + + nsCStringArray& operator=(const nsCStringArray& other); + + // Parses a given string using the delimiter passed in. If the array + // already has some elements, items parsed from string will be appended + // to array. For example, array.ParseString("a,b,c", ","); will add strings + // "a", "b" and "c" to the array. Parsing process has the same tokenizing + // behavior as strtok(). + void ParseString(const char* string, const char* delimiter); + + PRInt32 Count(void) const { + return nsVoidArray::Count(); + } + + void CStringAt(PRInt32 aIndex, nsACString& aCString) const; + nsCString* CStringAt(PRInt32 aIndex) const; + nsCString* operator[](PRInt32 aIndex) const { return CStringAt(aIndex); } + + PRInt32 IndexOf(const nsACString& aPossibleString) const; + PRInt32 IndexOfIgnoreCase(const nsACString& aPossibleString) const; + + PRBool InsertCStringAt(const nsACString& aCString, PRInt32 aIndex); + + PRBool ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex); + + PRBool AppendCString(const nsACString& aCString) { + return InsertCStringAt(aCString, Count()); + } + + PRBool RemoveCString(const nsACString& aCString); + PRBool RemoveCStringIgnoreCase(const nsACString& aCString); + PRBool RemoveCStringAt(PRInt32 aIndex); + void Clear(void); + + void Compact(void) { + nsVoidArray::Compact(); + } + + void Sort(void); + void SortIgnoreCase(void); + void Sort(nsCStringArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsCStringArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsCStringArrayEnumFunc aFunc, void* aData); + +private: + /// Copy constructors are not allowed + nsCStringArray(const nsCStringArray& other); +}; + + +//=================================================================== +// nsSmallVoidArray is not a general-purpose replacement for +// ns(Auto)VoidArray because there is (some) extra CPU overhead for arrays +// larger than 1 element, though not a lot. It is appropriate for +// space-sensitive uses where sizes of 0 or 1 are moderately common or +// more, and where we're NOT storing arbitrary integers or arbitrary +// pointers. + +// NOTE: nsSmallVoidArray can ONLY be used for holding items that always +// have the low bit as a 0 - i.e. element & 1 == 0. This happens to be +// true for allocated and object pointers for all the architectures we run +// on, but conceivably there might be some architectures/compilers for +// which it is NOT true. We know this works for all existing architectures +// because if it didn't then nsCheapVoidArray would have failed. Also note +// that we will ASSERT if this assumption is violated in DEBUG builds. + +// XXX we're really re-implementing the whole nsVoidArray interface here - +// some form of abstract class would be useful + +// I disagree on the abstraction here. If the point of this class is to be +// as small as possible, and no one will ever derive from it, as I found +// today, there should not be any virtualness to it to avoid the vtable +// ptr overhead. + +class NS_COM nsSmallVoidArray +{ +public: + nsSmallVoidArray(); + ~nsSmallVoidArray(); + + nsSmallVoidArray& operator=(nsSmallVoidArray& other); + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 GetArraySize() const; + + PRInt32 Count() const; + void* ElementAt(PRInt32 aIndex) const; + void* SafeElementAt(PRInt32 aIndex) const { + // let compiler inline; it may be able to remove these checks + if (aIndex < 0 || aIndex >= Count()) + return nsnull; + return ElementAt(aIndex); + } + PRInt32 IndexOf(void* aPossibleElement) const; + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex); + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + PRBool MoveElement(PRInt32 aFrom, PRInt32 aTo); + PRBool AppendElement(void* aElement); + PRBool AppendElements(nsVoidArray& aElements) { + return InsertElementsAt(aElements, Count()); + } + PRBool RemoveElement(void* aElement); + PRBool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount); + PRBool RemoveElementAt(PRInt32 aIndex); + + void Clear(); + PRBool SizeTo(PRInt32 aMin); + void Compact(); + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); + +private: +#ifdef RT_OS_OS2 /* shut up a million warnings */ + typedef PRUint32 PtrBits; +#else + typedef PRUint64 PtrBits; +#endif + + PRBool HasSingleChild() const + { + return (mChildren && (PtrBits(mChildren) & 0x1)); + } + PRBool HasVector() const + { + return (mChildren && !(PtrBits(mChildren) & 0x1)); + } + void* GetSingleChild() const + { + return (mChildren ? ((void*)(PtrBits(mChildren) & ~0x1)) : nsnull); + } + void SetSingleChild(void *aChild); + nsVoidArray* GetChildVector() const + { + return (nsVoidArray*)mChildren; + } + nsVoidArray* SwitchToVector(); + + // A tagged pointer that's either a pointer to a single child + // or a pointer to a vector of multiple children. This is a space + // optimization since a large number of containers have only a + // single child. + void *mChildren; +}; + +#endif /* nsVoidArray_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/pldhash.c b/src/libs/xpcom18a4/xpcom/ds/pldhash.c new file mode 100644 index 00000000..74f8cd0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/pldhash.c @@ -0,0 +1,826 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich <brendan@mozilla.org> (Original Author) + * Chris Waterson <waterson@netscape.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Double hashing implementation. + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "prbit.h" +#include "pldhash.h" +#include "prlog.h" /* for PR_ASSERT */ + +#ifdef PL_DHASHMETER +# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan +# include "nsTraceMalloc.h" +# endif +# define METER(x) x +#else +# define METER(x) /* nothing */ +#endif +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include <iprt/mem.h> +#endif + +PR_IMPLEMENT(void *) +PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + return RTMemAlloc(nbytes); +#else + return malloc(nbytes); +#endif +} + +PR_IMPLEMENT(void) +PL_DHashFreeTable(PLDHashTable *table, void *ptr) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(ptr); +#else + free(ptr); +#endif +} + +PR_IMPLEMENT(PLDHashNumber) +PL_DHashStringKey(PLDHashTable *table, const void *key) +{ + PLDHashNumber h; + const unsigned char *s; + + h = 0; + for (s = key; *s != '\0'; s++) + h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ *s; + return h; +} + +PR_IMPLEMENT(const void *) +PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + PLDHashEntryStub *stub = (PLDHashEntryStub *)entry; + + return stub->key; +} + +PR_IMPLEMENT(PLDHashNumber) +PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key) +{ + return (PLDHashNumber)(uintptr_t)key >> 2; +} + +PR_IMPLEMENT(PRBool) +PL_DHashMatchEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + + return stub->key == key; +} + +PR_IMPLEMENT(PRBool) +PL_DHashMatchStringKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + + /* XXX tolerate null keys on account of sloppy Mozilla callers. */ + return stub->key == key || + (stub->key && key && strcmp(stub->key, key) == 0); +} + +PR_IMPLEMENT(void) +PL_DHashMoveEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + memcpy(to, from, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + memset(entry, 0, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree((void *) stub->key); +#else + free((void *) stub->key); +#endif + memset(entry, 0, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashFinalizeStub(PLDHashTable *table) +{ +} + +static const PLDHashTableOps stub_ops = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + NULL +}; + +PR_IMPLEMENT(const PLDHashTableOps *) +PL_DHashGetStubOps(void) +{ + return &stub_ops; +} + +PR_IMPLEMENT(PLDHashTable *) +PL_NewDHashTable(const PLDHashTableOps *ops, void *data, PRUint32 entrySize, + PRUint32 capacity) +{ + PLDHashTable *table; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + table = (PLDHashTable *) RTMemAlloc(sizeof *table); +#else + table = (PLDHashTable *) malloc(sizeof *table); +#endif + if (!table) + return NULL; + if (!PL_DHashTableInit(table, ops, data, entrySize, capacity)) { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(table); +#else + free(table); +#endif + return NULL; + } + return table; +} + +PR_IMPLEMENT(void) +PL_DHashTableDestroy(PLDHashTable *table) +{ + PL_DHashTableFinish(table); +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(table); +#else + free(table); +#endif +} + +PR_IMPLEMENT(PRBool) +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, + PRUint32 entrySize, PRUint32 capacity) +{ + int log2; + PRUint32 nbytes; + +#ifdef DEBUG + if (entrySize > 10 * sizeof(void *)) { + fprintf(stderr, + "pldhash: for the table at address %p, the given entrySize" + " of %lu %s favors chaining over double hashing.\n", + (void *)table, + (unsigned long) entrySize, + (entrySize > 16 * sizeof(void*)) ? "definitely" : "probably"); + } +#endif + + table->ops = ops; + table->data = data; + if (capacity < PL_DHASH_MIN_SIZE) + capacity = PL_DHASH_MIN_SIZE; + log2 = PR_CeilingLog2(capacity); + capacity = PR_BIT(log2); + if (capacity >= PL_DHASH_SIZE_LIMIT) + return PR_FALSE; + table->hashShift = PL_DHASH_BITS - log2; + table->maxAlphaFrac = 0xC0; /* .75 */ + table->minAlphaFrac = 0x40; /* .25 */ + table->entrySize = entrySize; + table->entryCount = table->removedCount = 0; + table->generation = 0; + nbytes = capacity * entrySize; + + table->entryStore = ops->allocTable(table, nbytes); + if (!table->entryStore) + return PR_FALSE; + memset(table->entryStore, 0, nbytes); + METER(memset(&table->stats, 0, sizeof table->stats)); + return PR_TRUE; +} + +/* + * Compute max and min load numbers (entry counts) from table params. + */ +#define MAX_LOAD(table, size) (((table)->maxAlphaFrac * (size)) >> 8) +#define MIN_LOAD(table, size) (((table)->minAlphaFrac * (size)) >> 8) + +PR_IMPLEMENT(void) +PL_DHashTableSetAlphaBounds(PLDHashTable *table, + float maxAlpha, + float minAlpha) +{ + PRUint32 size; + + /* + * Reject obviously insane bounds, rather than trying to guess what the + * buggy caller intended. + */ + PR_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha); + if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0) + return; + + /* + * Ensure that at least one entry will always be free. If maxAlpha at + * minimum size leaves no entries free, reduce maxAlpha based on minimum + * size and the precision limit of maxAlphaFrac's fixed point format. + */ + PR_ASSERT(PL_DHASH_MIN_SIZE - (maxAlpha * PL_DHASH_MIN_SIZE) >= 1); + if (PL_DHASH_MIN_SIZE - (maxAlpha * PL_DHASH_MIN_SIZE) < 1) { + maxAlpha = (float) + (PL_DHASH_MIN_SIZE - PR_MAX(PL_DHASH_MIN_SIZE / 256, 1)) + / PL_DHASH_MIN_SIZE; + } + + /* + * Ensure that minAlpha is strictly less than half maxAlpha. Take care + * not to truncate an entry's worth of alpha when storing in minAlphaFrac + * (8-bit fixed point format). + */ + PR_ASSERT(minAlpha < maxAlpha / 2); + if (minAlpha >= maxAlpha / 2) { + size = PL_DHASH_TABLE_SIZE(table); + minAlpha = (size * maxAlpha - PR_MAX(size / 256, 1)) / (2 * size); + } + + table->maxAlphaFrac = (uint8)(maxAlpha * 256); + table->minAlphaFrac = (uint8)(minAlpha * 256); +} + +/* + * Double hashing needs the second hash code to be relatively prime to table + * size, so we simply make hash2 odd. + */ +#define HASH1(hash0, shift) ((hash0) >> (shift)) +#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1) + +/* + * Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. Note + * that a removed-entry sentinel need be stored only if the removed entry had + * a colliding entry added after it. Therefore we can use 1 as the collision + * flag in addition to the removed-entry sentinel value. Multiplicative hash + * uses the high order bits of keyHash, so this least-significant reservation + * should not hurt the hash function's effectiveness much. + * + * If you change any of these magic numbers, also update PL_DHASH_ENTRY_IS_LIVE + * in pldhash.h. It used to be private to pldhash.c, but then became public to + * assist iterator writers who inspect table->entryStore directly. + */ +#define COLLISION_FLAG ((PLDHashNumber) 1) +#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0) +#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1) +#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1) +#define ENTRY_IS_LIVE(entry) PL_DHASH_ENTRY_IS_LIVE(entry) +#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0 + +/* Match an entry's keyHash against an unstored one computed from a key. */ +#define MATCH_ENTRY_KEYHASH(entry,hash0) \ + (((entry)->keyHash & ~COLLISION_FLAG) == (hash0)) + +/* Compute the address of the indexed entry in table. */ +#define ADDRESS_ENTRY(table, index) \ + ((PLDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize)) + +PR_IMPLEMENT(void) +PL_DHashTableFinish(PLDHashTable *table) +{ + char *entryAddr, *entryLimit; + PRUint32 entrySize; + PLDHashEntryHdr *entry; + +#ifdef DEBUG_XXXbrendan + static FILE *dumpfp = NULL; + if (!dumpfp) dumpfp = fopen("/tmp/pldhash.bigdump", "w"); + if (dumpfp) { +#ifdef MOZILLA_CLIENT + NS_TraceStack(1, dumpfp); +#endif + PL_DHashTableDumpMeter(table, NULL, dumpfp); + fputc('\n', dumpfp); + } +#endif + + /* Call finalize before clearing entries, so it can enumerate them. */ + table->ops->finalize(table); + + /* Clear any remaining live entries. */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + entryLimit = entryAddr + PL_DHASH_TABLE_SIZE(table) * entrySize; + while (entryAddr < entryLimit) { + entry = (PLDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + METER(table->stats.removeEnums++); + table->ops->clearEntry(table, entry); + } + entryAddr += entrySize; + } + + /* Free entry storage last. */ + table->ops->freeTable(table, table->entryStore); +} + +static PLDHashEntryHdr * PL_DHASH_FASTCALL +SearchTable(PLDHashTable *table, const void *key, PLDHashNumber keyHash, + PLDHashOperator op) +{ + PLDHashNumber hash1, hash2; + int hashShift, sizeLog2; + PLDHashEntryHdr *entry, *firstRemoved; + PLDHashMatchEntry matchEntry; + PRUint32 sizeMask; + + METER(table->stats.searches++); + PR_ASSERT(!(keyHash & COLLISION_FLAG)); + + /* Compute the primary hash address. */ + hashShift = table->hashShift; + hash1 = HASH1(keyHash, hashShift); + entry = ADDRESS_ENTRY(table, hash1); + + /* Miss: return space for a new entry. */ + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + + /* Hit: return entry. */ + matchEntry = table->ops->matchEntry; + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + /* Collision: double hash. */ + sizeLog2 = PL_DHASH_BITS - table->hashShift; + hash2 = HASH2(keyHash, sizeLog2, hashShift); + sizeMask = PR_BITMASK(sizeLog2); + + /* Save the first removed entry pointer so PL_DHASH_ADD can recycle it. */ + if (ENTRY_IS_REMOVED(entry)) { + firstRemoved = entry; + } else { + firstRemoved = NULL; + if (op == PL_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + + for (;;) { + METER(table->stats.steps++); + hash1 -= hash2; + hash1 &= sizeMask; + + entry = ADDRESS_ENTRY(table, hash1); + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return (firstRemoved && op == PL_DHASH_ADD) ? firstRemoved : entry; + } + + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && + matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + if (ENTRY_IS_REMOVED(entry)) { + if (!firstRemoved) + firstRemoved = entry; + } else { + if (op == PL_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + } + + /* NOTREACHED */ + return NULL; +} + +static PRBool +ChangeTable(PLDHashTable *table, int deltaLog2) +{ + int oldLog2, newLog2; + PRUint32 oldCapacity, newCapacity; + char *newEntryStore, *oldEntryStore, *oldEntryAddr; + PRUint32 entrySize, i, nbytes; + PLDHashEntryHdr *oldEntry, *newEntry; + PLDHashGetKey getKey; + PLDHashMoveEntry moveEntry; + +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PR_ASSERT(table->generation != PR_UINT32_MAX); + if (table->generation == PR_UINT32_MAX) + return PR_FALSE; +#endif + + /* Look, but don't touch, until we succeed in getting new entry store. */ + oldLog2 = PL_DHASH_BITS - table->hashShift; + newLog2 = oldLog2 + deltaLog2; + oldCapacity = PR_BIT(oldLog2); + newCapacity = PR_BIT(newLog2); + if (newCapacity >= PL_DHASH_SIZE_LIMIT) + return PR_FALSE; + entrySize = table->entrySize; + nbytes = newCapacity * entrySize; + + newEntryStore = table->ops->allocTable(table, nbytes); + if (!newEntryStore) + return PR_FALSE; + + /* We can't fail from here on, so update table parameters. */ + table->hashShift = PL_DHASH_BITS - newLog2; + table->removedCount = 0; + table->generation++; +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + if (table->generation == PR_UINT32_MAX) + table->generation++; +#endif + + /* Assign the new entry store to table. */ + memset(newEntryStore, 0, nbytes); + oldEntryAddr = oldEntryStore = table->entryStore; + table->entryStore = newEntryStore; + getKey = table->ops->getKey; + moveEntry = table->ops->moveEntry; + + /* Copy only live entries, leaving removed ones behind. */ + for (i = 0; i < oldCapacity; i++) { + oldEntry = (PLDHashEntryHdr *)oldEntryAddr; + if (ENTRY_IS_LIVE(oldEntry)) { + oldEntry->keyHash &= ~COLLISION_FLAG; + newEntry = SearchTable(table, getKey(table, oldEntry), + oldEntry->keyHash, PL_DHASH_ADD); + PR_ASSERT(PL_DHASH_ENTRY_IS_FREE(newEntry)); + moveEntry(table, oldEntry, newEntry); + newEntry->keyHash = oldEntry->keyHash; + } + oldEntryAddr += entrySize; + } + + table->ops->freeTable(table, oldEntryStore); + return PR_TRUE; +} + +PR_IMPLEMENT(PLDHashEntryHdr *) PL_DHASH_FASTCALL +PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op) +{ + PLDHashNumber keyHash; + PLDHashEntryHdr *entry; + PRUint32 size; + int deltaLog2; + + keyHash = table->ops->hashKey(table, key); + keyHash *= PL_DHASH_GOLDEN_RATIO; + + /* Avoid 0 and 1 hash codes, they indicate free and removed entries. */ + ENSURE_LIVE_KEYHASH(keyHash); + keyHash &= ~COLLISION_FLAG; + + switch (op) { + case PL_DHASH_LOOKUP: + METER(table->stats.lookups++); + entry = SearchTable(table, key, keyHash, op); + break; + + case PL_DHASH_ADD: + /* + * If alpha is >= .75, grow or compress the table. If key is already + * in the table, we may grow once more than necessary, but only if we + * are on the edge of being overloaded. + */ + size = PL_DHASH_TABLE_SIZE(table); + if (table->entryCount + table->removedCount >= MAX_LOAD(table, size)) { + /* Compress if a quarter or more of all entries are removed. */ + if (table->removedCount >= size >> 2) { + METER(table->stats.compresses++); + deltaLog2 = 0; + } else { + METER(table->stats.grows++); + deltaLog2 = 1; + } + + /* + * Grow or compress table, returning null if ChangeTable fails and + * falling through might claim the last free entry. + */ + if (!ChangeTable(table, deltaLog2) && + table->entryCount + table->removedCount == size - 1) { + METER(table->stats.addFailures++); + return NULL; + } + } + + /* + * Look for entry after possibly growing, so we don't have to add it, + * then skip it while growing the table and re-add it after. + */ + entry = SearchTable(table, key, keyHash, op); + if (!ENTRY_IS_LIVE(entry)) { + /* Initialize the entry, indicating that it's no longer free. */ + METER(table->stats.addMisses++); + if (ENTRY_IS_REMOVED(entry)) { + METER(table->stats.addOverRemoved++); + table->removedCount--; + keyHash |= COLLISION_FLAG; + } + if (table->ops->initEntry && + !table->ops->initEntry(table, entry, key)) { + /* We haven't claimed entry yet; fail with null return. */ + memset(entry + 1, 0, table->entrySize - sizeof *entry); + return NULL; + } + entry->keyHash = keyHash; + table->entryCount++; + } + METER(else table->stats.addHits++); + break; + + case PL_DHASH_REMOVE: + entry = SearchTable(table, key, keyHash, op); + if (ENTRY_IS_LIVE(entry)) { + /* Clear this entry and mark it as "removed". */ + METER(table->stats.removeHits++); + PL_DHashTableRawRemove(table, entry); + + /* Shrink if alpha is <= .25 and table isn't too small already. */ + size = PL_DHASH_TABLE_SIZE(table); + if (size > PL_DHASH_MIN_SIZE && +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + /** @todo This is where IPC screws up, avoid the assertion in ChangeTable until it's fixed. */ + table->generation != PR_UINT32_MAX && +#endif + table->entryCount <= MIN_LOAD(table, size)) { + METER(table->stats.shrinks++); + (void) ChangeTable(table, -1); + } + } + METER(else table->stats.removeMisses++); + entry = NULL; + break; + + default: + PR_ASSERT(0); + entry = NULL; + } + + return entry; +} + +PR_IMPLEMENT(void) +PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + PLDHashNumber keyHash; /* load first in case clearEntry goofs it */ + + PR_ASSERT(PL_DHASH_ENTRY_IS_LIVE(entry)); + keyHash = entry->keyHash; + table->ops->clearEntry(table, entry); + if (keyHash & COLLISION_FLAG) { + MARK_ENTRY_REMOVED(entry); + table->removedCount++; + } else { + METER(table->stats.removeFrees++); + MARK_ENTRY_FREE(entry); + } + table->entryCount--; +} + +PR_IMPLEMENT(PRUint32) +PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg) +{ + char *entryAddr, *entryLimit; + PRUint32 i, capacity, entrySize; + PRBool didRemove; + PLDHashEntryHdr *entry; + PLDHashOperator op; +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PRUint32 generation; + + /* + * The hack! Set generation to PR_UINT32_MAX during the enumeration so + * we can prevent ChangeTable from being called. + * + * This happens during ipcDConnectService::OnClientStateChange() + * / ipcDConnectService::DeleteInstance() now when running + * java clienttest list hostinfo and vboxwebsrv crashes. It's quite + * likely that the IPC code isn't following the rules here, but it + * looks more difficult to fix that just hacking this hash code. + */ + generation = table->generation; + table->generation = PR_UINT32_MAX; +#endif /* VBOX */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + capacity = PL_DHASH_TABLE_SIZE(table); + entryLimit = entryAddr + capacity * entrySize; + i = 0; + didRemove = PR_FALSE; + while (entryAddr < entryLimit) { + entry = (PLDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + op = etor(table, entry, i++, arg); +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PR_ASSERT(table->generation == PR_UINT32_MAX); +#endif + if (op & PL_DHASH_REMOVE) { + METER(table->stats.removeEnums++); + PL_DHashTableRawRemove(table, entry); + didRemove = PR_TRUE; + } + if (op & PL_DHASH_STOP) + break; + } + entryAddr += entrySize; + } +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + table->generation = generation; +#endif + + /* + * Shrink or compress if a quarter or more of all entries are removed, or + * if the table is underloaded according to the configured minimum alpha, + * and is not minimal-size already. Do this only if we removed above, so + * non-removing enumerations can count on stable table->entryStore until + * the next non-lookup-Operate or removing-Enumerate. + */ + if (didRemove && + (table->removedCount >= capacity >> 2 || + (capacity > PL_DHASH_MIN_SIZE && + table->entryCount <= MIN_LOAD(table, capacity)))) { + METER(table->stats.enumShrinks++); + capacity = table->entryCount; + capacity += capacity >> 1; + if (capacity < PL_DHASH_MIN_SIZE) + capacity = PL_DHASH_MIN_SIZE; + (void) ChangeTable(table, + PR_CeilingLog2(capacity) + - (PL_DHASH_BITS - table->hashShift)); + } + return i; +} + +#ifdef PL_DHASHMETER +#include <math.h> + +PR_IMPLEMENT(void) +PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp) +{ + char *entryAddr; + PRUint32 entrySize, entryCount; + int hashShift, sizeLog2; + PRUint32 i, tableSize, sizeMask, chainLen, maxChainLen, chainCount; + PLDHashNumber hash1, hash2, saveHash1, maxChainHash1, maxChainHash2; + double sqsum, mean, variance, sigma; + PLDHashEntryHdr *entry, *probe; + + entryAddr = table->entryStore; + entrySize = table->entrySize; + hashShift = table->hashShift; + sizeLog2 = PL_DHASH_BITS - hashShift; + tableSize = PL_DHASH_TABLE_SIZE(table); + sizeMask = PR_BITMASK(sizeLog2); + chainCount = maxChainLen = 0; + hash2 = 0; + sqsum = 0; + + for (i = 0; i < tableSize; i++) { + entry = (PLDHashEntryHdr *)entryAddr; + entryAddr += entrySize; + if (!ENTRY_IS_LIVE(entry)) + continue; + hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift); + saveHash1 = hash1; + probe = ADDRESS_ENTRY(table, hash1); + chainLen = 1; + if (probe == entry) { + /* Start of a (possibly unit-length) chain. */ + chainCount++; + } else { + hash2 = HASH2(entry->keyHash & ~COLLISION_FLAG, sizeLog2, + hashShift); + do { + chainLen++; + hash1 -= hash2; + hash1 &= sizeMask; + probe = ADDRESS_ENTRY(table, hash1); + } while (probe != entry); + } + sqsum += chainLen * chainLen; + if (chainLen > maxChainLen) { + maxChainLen = chainLen; + maxChainHash1 = saveHash1; + maxChainHash2 = hash2; + } + } + + entryCount = table->entryCount; + if (entryCount && chainCount) { + mean = (double)entryCount / chainCount; + variance = chainCount * sqsum - entryCount * entryCount; + if (variance < 0 || chainCount == 1) + variance = 0; + else + variance /= chainCount * (chainCount - 1); + sigma = sqrt(variance); + } else { + mean = sigma = 0; + } + + fprintf(fp, "Double hashing statistics:\n"); + fprintf(fp, " table size (in entries): %u\n", tableSize); + fprintf(fp, " number of entries: %u\n", table->entryCount); + fprintf(fp, " number of removed entries: %u\n", table->removedCount); + fprintf(fp, " number of searches: %u\n", table->stats.searches); + fprintf(fp, " number of hits: %u\n", table->stats.hits); + fprintf(fp, " number of misses: %u\n", table->stats.misses); + fprintf(fp, " mean steps per search: %g\n", table->stats.searches ? + (double)table->stats.steps + / table->stats.searches : + 0.); + fprintf(fp, " mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " maximum hash chain length: %u\n", maxChainLen); + fprintf(fp, " number of lookups: %u\n", table->stats.lookups); + fprintf(fp, " adds that made a new entry: %u\n", table->stats.addMisses); + fprintf(fp, "adds that recycled removeds: %u\n", table->stats.addOverRemoved); + fprintf(fp, " adds that found an entry: %u\n", table->stats.addHits); + fprintf(fp, " add failures: %u\n", table->stats.addFailures); + fprintf(fp, " useful removes: %u\n", table->stats.removeHits); + fprintf(fp, " useless removes: %u\n", table->stats.removeMisses); + fprintf(fp, "removes that freed an entry: %u\n", table->stats.removeFrees); + fprintf(fp, " removes while enumerating: %u\n", table->stats.removeEnums); + fprintf(fp, " number of grows: %u\n", table->stats.grows); + fprintf(fp, " number of shrinks: %u\n", table->stats.shrinks); + fprintf(fp, " number of compresses: %u\n", table->stats.compresses); + fprintf(fp, "number of enumerate shrinks: %u\n", table->stats.enumShrinks); + + if (dump && maxChainLen && hash2) { + fputs("Maximum hash chain:\n", fp); + hash1 = maxChainHash1; + hash2 = maxChainHash2; + entry = ADDRESS_ENTRY(table, hash1); + i = 0; + do { + if (dump(table, entry, i++, fp) != PL_DHASH_NEXT) + break; + hash1 -= hash2; + hash1 &= sizeMask; + entry = ADDRESS_ENTRY(table, hash1); + } while (PL_DHASH_ENTRY_IS_BUSY(entry)); + } +} +#endif /* PL_DHASHMETER */ diff --git a/src/libs/xpcom18a4/xpcom/ds/pldhash.h b/src/libs/xpcom18a4/xpcom/ds/pldhash.h new file mode 100644 index 00000000..8c4347c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/pldhash.h @@ -0,0 +1,603 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich <brendan@mozilla.org> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef pldhash_h___ +#define pldhash_h___ +/* + * Double hashing, a la Knuth 6. + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + */ +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_DHashTableInit VBoxNsplPL_DHashTableInit +#define PL_DHashTableFinish VBoxNsplPL_DHashTableFinish +#define PL_DHashTableOperate VBoxNsplPL_DHashTableOperate +#define PL_DHashTableEnumerate VBoxNsplPL_DHashTableEnumerate +#define PL_DHashAllocTable VBoxNsplPL_DHashAllocTable +#define PL_DHashFreeTable VBoxNsplPL_DHashFreeTable +#define PL_DHashMoveEntryStub VBoxNsplPL_DHashMoveEntryStub +#define PL_DHashFinalizeStub VBoxNsplPL_DHashFinalizeStub +#define PL_DHashClearEntryStub VBoxNsplPL_DHashClearEntryStub +#define PL_DHashFreeStringKey VBoxNsplPL_DHashFreeStringKey +#define PL_DHashGetKeyStub VBoxNsplPL_DHashGetKeyStub +#define PL_DHashGetStubOps VBoxNsplPL_DHashGetStubOps +#define PL_DHashMatchEntryStub VBoxNsplPL_DHashMatchEntryStub +#define PL_DHashMatchStringKey VBoxNsplPL_DHashMatchStringKey +#define PL_DHashStringKey VBoxNsplPL_DHashStringKey +#define PL_DHashTableDestroy VBoxNsplPL_DHashTableDestroy +#define PL_DHashTableRawRemove VBoxNsplPL_DHashTableRawRemove +#define PL_DHashTableSetAlphaBounds VBoxNsplPL_DHashTableSetAlphaBounds +#define PL_DHashVoidPtrKeyStub VBoxNsplPL_DHashVoidPtrKeyStub +#define PL_NewDHashTable VBoxNsplPL_NewDHashTable +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +#ifdef DEBUG_XXXbrendan +#define PL_DHASHMETER 1 +#endif + +#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2) +#define PL_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall)) +#else +#define PL_DHASH_FASTCALL +#endif + +/* Table size limit, do not equal or exceed (see min&maxAlphaFrac, below). */ +#undef PL_DHASH_SIZE_LIMIT +#define PL_DHASH_SIZE_LIMIT PR_BIT(24) + +/* Minimum table size, or gross entry count (net is at most .75 loaded). */ +#ifndef PL_DHASH_MIN_SIZE +#define PL_DHASH_MIN_SIZE 16 +#elif (PL_DHASH_MIN_SIZE & (PL_DHASH_MIN_SIZE - 1)) != 0 +#error "PL_DHASH_MIN_SIZE must be a power of two!" +#endif + +/* + * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio, + * expressed as a fixed-point 32-bit fraction. + */ +#define PL_DHASH_BITS 32 +#define PL_DHASH_GOLDEN_RATIO 0x9E3779B9U + +/* Primitive and forward-struct typedefs. */ +typedef PRUint32 PLDHashNumber; +typedef struct PLDHashEntryHdr PLDHashEntryHdr; +typedef struct PLDHashEntryStub PLDHashEntryStub; +typedef struct PLDHashTable PLDHashTable; +typedef struct PLDHashTableOps PLDHashTableOps; + +/* + * Table entry header structure. + * + * In order to allow in-line allocation of key and value, we do not declare + * either here. Instead, the API uses const void *key as a formal parameter, + * and asks each entry for its key when necessary via a getKey callback, used + * when growing or shrinking the table. Other callback types are defined + * below and grouped into the PLDHashTableOps structure, for single static + * initialization per hash table sub-type. + * + * Each hash table sub-type should nest the PLDHashEntryHdr structure at the + * front of its particular entry type. The keyHash member contains the result + * of multiplying the hash code returned from the hashKey callback (see below) + * by PL_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0 + * and 1 values. The stored keyHash value is table size invariant, and it is + * maintained automatically by PL_DHashTableOperate -- users should never set + * it, and its only uses should be via the entry macros below. + * + * The PL_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor + * removed. An entry may be either busy or free; if busy, it may be live or + * removed. Consumers of this API should not access members of entries that + * are not live. + * + * However, use PL_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries + * returned by PL_DHashTableOperate, as PL_DHashTableOperate never returns a + * non-live, busy (i.e., removed) entry pointer to its caller. See below for + * more details on PL_DHashTableOperate's calling rules. + */ +struct PLDHashEntryHdr { + PLDHashNumber keyHash; /* every entry must begin like this */ +}; + +#define PL_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0) +#define PL_DHASH_ENTRY_IS_BUSY(entry) (!PL_DHASH_ENTRY_IS_FREE(entry)) +#define PL_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2) + +/* + * A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead) + * on most architectures, and may be allocated on the stack or within another + * structure or class (see below for the Init and Finish functions to use). + * + * To decide whether to use double hashing vs. chaining, we need to develop a + * trade-off relation, as follows: + * + * Let alpha be the load factor, esize the entry size in words, count the + * entry count, and pow2 the power-of-two table size in entries. + * + * (PLDHashTable overhead) > (PLHashTable overhead) + * (unused table entry space) > (malloc and .next overhead per entry) + + * (buckets overhead) + * (1 - alpha) * esize * pow2 > 2 * count + pow2 + * + * Notice that alpha is by definition (count / pow2): + * + * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2 + * (1 - alpha) * esize > 2 * alpha + 1 + * + * esize > (1 + 2 * alpha) / (1 - alpha) + * + * This assumes both tables must keep keyHash, key, and value for each entry, + * where key and value point to separately allocated strings or structures. + * If key and value can be combined into one pointer, then the trade-off is: + * + * esize > (1 + 3 * alpha) / (1 - alpha) + * + * If the entry value can be a subtype of PLDHashEntryHdr, rather than a type + * that must be allocated separately and referenced by an entry.value pointer + * member, and provided key's allocation can be fused with its entry's, then + * k (the words wasted per entry with chaining) is 4. + * + * To see these curves, feed gnuplot input like so: + * + * gnuplot> f(x,k) = (1 + k * x) / (1 - x) + * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4) + * + * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4 + * words for chaining to be more space-efficient than double hashing. + * + * Solving for alpha helps us decide when to shrink an underloaded table: + * + * esize > (1 + k * alpha) / (1 - alpha) + * esize - alpha * esize > 1 + k * alpha + * esize - 1 > (k + esize) * alpha + * (esize - 1) / (k + esize) > alpha + * + * alpha < (esize - 1) / (esize + k) + * + * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k), + * assuming esize is not too large (in which case, chaining should probably be + * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3 + * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5 + * would still obtain. See the PL_DHASH_MIN_ALPHA macro further below. + * + * The current implementation uses a configurable lower bound on alpha, which + * defaults to .25, when deciding to shrink the table (while still respecting + * PL_DHASH_MIN_SIZE). + * + * Note a qualitative difference between chaining and double hashing: under + * chaining, entry addresses are stable across table shrinks and grows. With + * double hashing, you can't safely hold an entry pointer and use it after an + * ADD or REMOVE operation, unless you sample table->generation before adding + * or removing, and compare the sample after, dereferencing the entry pointer + * only if table->generation has not changed. + * + * The moral of this story: there is no one-size-fits-all hash table scheme, + * but for small table entry size, and assuming entry address stability is not + * required, double hashing wins. + */ +struct PLDHashTable { + const PLDHashTableOps *ops; /* virtual operations, see below */ + void *data; /* ops- and instance-specific data */ + PRInt16 hashShift; /* multiplicative hash shift */ + uint8 maxAlphaFrac; /* 8-bit fixed point max alpha */ + uint8 minAlphaFrac; /* 8-bit fixed point min alpha */ + PRUint32 entrySize; /* number of bytes in an entry */ + PRUint32 entryCount; /* number of entries in table */ + PRUint32 removedCount; /* removed entry sentinels in table */ + PRUint32 generation; /* entry storage generation number */ + char *entryStore; /* entry storage */ +#ifdef PL_DHASHMETER + struct PLDHashStats { + PRUint32 searches; /* total number of table searches */ + PRUint32 steps; /* hash chain links traversed */ + PRUint32 hits; /* searches that found key */ + PRUint32 misses; /* searches that didn't find key */ + PRUint32 lookups; /* number of PL_DHASH_LOOKUPs */ + PRUint32 addMisses; /* adds that miss, and do work */ + PRUint32 addOverRemoved; /* adds that recycled a removed entry */ + PRUint32 addHits; /* adds that hit an existing entry */ + PRUint32 addFailures; /* out-of-memory during add growth */ + PRUint32 removeHits; /* removes that hit, and do work */ + PRUint32 removeMisses; /* useless removes that miss */ + PRUint32 removeFrees; /* removes that freed entry directly */ + PRUint32 removeEnums; /* removes done by Enumerate */ + PRUint32 grows; /* table expansions */ + PRUint32 shrinks; /* table contractions */ + PRUint32 compresses; /* table compressions */ + PRUint32 enumShrinks; /* contractions after Enumerate */ + } stats; +#endif +}; + +/* + * Size in entries (gross, not net of free and removed sentinels) for table. + * We store hashShift rather than sizeLog2 to optimize the collision-free case + * in SearchTable. + */ +#define PL_DHASH_TABLE_SIZE(table) PR_BIT(PL_DHASH_BITS - (table)->hashShift) + +/* + * Table space at entryStore is allocated and freed using these callbacks. + * The allocator should return null on error only (not if called with nbytes + * equal to 0; but note that pldhash.c code will never call with 0 nbytes). + */ +typedef void * +(* PR_CALLBACK PLDHashAllocTable)(PLDHashTable *table, PRUint32 nbytes); + +typedef void +(* PR_CALLBACK PLDHashFreeTable) (PLDHashTable *table, void *ptr); + +/* + * When a table grows or shrinks, each entry is queried for its key using this + * callback. NB: in that event, entry is not in table any longer; it's in the + * old entryStore vector, which is due to be freed once all entries have been + * moved via moveEntry callbacks. + */ +typedef const void * +(* PR_CALLBACK PLDHashGetKey) (PLDHashTable *table, + PLDHashEntryHdr *entry); + +/* + * Compute the hash code for a given key to be looked up, added, or removed + * from table. A hash code may have any PLDHashNumber value. + */ +typedef PLDHashNumber +(* PR_CALLBACK PLDHashHashKey) (PLDHashTable *table, const void *key); + +/* + * Compare the key identifying entry in table with the provided key parameter. + * Return PR_TRUE if keys match, PR_FALSE otherwise. + */ +typedef PRBool +(* PR_CALLBACK PLDHashMatchEntry)(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +/* + * Copy the data starting at from to the new entry storage at to. Do not add + * reference counts for any strong references in the entry, however, as this + * is a "move" operation: the old entry storage at from will be freed without + * any reference-decrementing callback shortly. + */ +typedef void +(* PR_CALLBACK PLDHashMoveEntry)(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + +/* + * Clear the entry and drop any strong references it holds. This callback is + * invoked during a PL_DHASH_REMOVE operation (see below for operation codes), + * but only if the given key is found in the table. + */ +typedef void +(* PR_CALLBACK PLDHashClearEntry)(PLDHashTable *table, + PLDHashEntryHdr *entry); + +/* + * Called when a table (whether allocated dynamically by itself, or nested in + * a larger structure, or allocated on the stack) is finished. This callback + * allows table->ops-specific code to finalize table->data. + */ +typedef void +(* PR_CALLBACK PLDHashFinalize) (PLDHashTable *table); + +/* + * Initialize a new entry, apart from keyHash. This function is called when + * PL_DHashTableOperate's PL_DHASH_ADD case finds no existing entry for the + * given key, and must add a new one. At that point, entry->keyHash is not + * set yet, to avoid claiming the last free entry in a severely overloaded + * table. + */ +typedef PRBool +(* PR_CALLBACK PLDHashInitEntry)(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key); + +/* + * Finally, the "vtable" structure for PLDHashTable. The first eight hooks + * must be provided by implementations; they're called unconditionally by the + * generic pldhash.c code. Hooks after these may be null. + * + * Summary of allocation-related hook usage with C++ placement new emphasis: + * allocTable Allocate raw bytes with malloc, no ctors run. + * freeTable Free raw bytes with free, no dtors run. + * initEntry Call placement new using default key-based ctor. + * Return PR_TRUE on success, PR_FALSE on error. + * moveEntry Call placement new using copy ctor, run dtor on old + * entry storage. + * clearEntry Run dtor on entry. + * finalize Stub unless table->data was initialized and needs to + * be finalized. + * + * Note the reason why initEntry is optional: the default hooks (stubs) clear + * entry storage: On successful PL_DHashTableOperate(tbl, key, PL_DHASH_ADD), + * the returned entry pointer addresses an entry struct whose keyHash member + * has been set non-zero, but all other entry members are still clear (null). + * PL_DHASH_ADD callers can test such members to see whether the entry was + * newly created by the PL_DHASH_ADD call that just succeeded. If placement + * new or similar initialization is required, define an initEntry hook. Of + * course, the clearEntry hook must zero or null appropriately. + * + * XXX assumes 0 is null for pointer types. + */ +struct PLDHashTableOps { + /* Mandatory hooks. All implementations must provide these. */ + PLDHashAllocTable allocTable; + PLDHashFreeTable freeTable; + PLDHashGetKey getKey; + PLDHashHashKey hashKey; + PLDHashMatchEntry matchEntry; + PLDHashMoveEntry moveEntry; + PLDHashClearEntry clearEntry; + PLDHashFinalize finalize; + + /* Optional hooks start here. If null, these are not called. */ + PLDHashInitEntry initEntry; +}; + +/* + * Default implementations for the above ops. + */ +PR_EXTERN(void *) +PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes); + +PR_EXTERN(void) +PL_DHashFreeTable(PLDHashTable *table, void *ptr); + +PR_EXTERN(PLDHashNumber) +PL_DHashStringKey(PLDHashTable *table, const void *key); + +/* A minimal entry contains a keyHash header and a void key pointer. */ +struct PLDHashEntryStub { + PLDHashEntryHdr hdr; + const void *key; +}; + +PR_EXTERN(const void *) +PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(PLDHashNumber) +PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key); + +PR_EXTERN(PRBool) +PL_DHashMatchEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +PR_EXTERN(PRBool) +PL_DHashMatchStringKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +PR_EXTERN(void) +PL_DHashMoveEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + +PR_EXTERN(void) +PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(void) +PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(void) +PL_DHashFinalizeStub(PLDHashTable *table); + +/* + * If you use PLDHashEntryStub or a subclass of it as your entry struct, and + * if your entries move via memcpy and clear via memset(0), you can use these + * stub operations. + */ +PR_EXTERN(const PLDHashTableOps *) +PL_DHashGetStubOps(void); + +/* + * Dynamically allocate a new PLDHashTable using malloc, initialize it using + * PL_DHashTableInit, and return its address. Return null on malloc failure. + * Note that the entry storage at table->entryStore will be allocated using + * the ops->allocTable callback. + */ +PR_EXTERN(PLDHashTable *) +PL_NewDHashTable(const PLDHashTableOps *ops, void *data, PRUint32 entrySize, + PRUint32 capacity); + +/* + * Finalize table's data, free its entry storage (via table->ops->freeTable), + * and return the memory starting at table to the malloc heap. + */ +PR_EXTERN(void) +PL_DHashTableDestroy(PLDHashTable *table); + +/* + * Initialize table with ops, data, entrySize, and capacity. Capacity is a + * guess for the smallest table size at which the table will usually be less + * than 75% loaded (the table will grow or shrink as needed; capacity serves + * only to avoid inevitable early growth from PL_DHASH_MIN_SIZE). + */ +PR_EXTERN(PRBool) +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, + PRUint32 entrySize, PRUint32 capacity); + +/* + * Set maximum and minimum alpha for table. The defaults are 0.75 and .25. + * maxAlpha must be in [0.5, 0.9375] for the default PL_DHASH_MIN_SIZE; or if + * MinSize=PL_DHASH_MIN_SIZE <= 256, in [0.5, (float)(MinSize-1)/MinSize]; or + * else in [0.5, 255.0/256]. minAlpha must be in [0, maxAlpha / 2), so that + * we don't shrink on the very next remove after growing a table upon adding + * an entry that brings entryCount past maxAlpha * tableSize. + */ +PR_IMPLEMENT(void) +PL_DHashTableSetAlphaBounds(PLDHashTable *table, + float maxAlpha, + float minAlpha); + +/* + * Call this macro with k, the number of pointer-sized words wasted per entry + * under chaining, to compute the minimum alpha at which double hashing still + * beats chaining. + */ +#define PL_DHASH_MIN_ALPHA(table, k) \ + ((float)((table)->entrySize / sizeof(void *) - 1) \ + / ((table)->entrySize / sizeof(void *) + (k))) + +/* + * Finalize table's data, free its entry storage using table->ops->freeTable, + * and leave its members unchanged from their last live values (which leaves + * pointers dangling). If you want to burn cycles clearing table, it's up to + * your code to call memset. + */ +PR_EXTERN(void) +PL_DHashTableFinish(PLDHashTable *table); + +/* + * To consolidate keyHash computation and table grow/shrink code, we use a + * single entry point for lookup, add, and remove operations. The operation + * codes are declared here, along with codes returned by PLDHashEnumerator + * functions, which control PL_DHashTableEnumerate's behavior. + */ +typedef enum PLDHashOperator { + PL_DHASH_LOOKUP = 0, /* lookup entry */ + PL_DHASH_ADD = 1, /* add entry */ + PL_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */ + PL_DHASH_NEXT = 0, /* enumerator says continue */ + PL_DHASH_STOP = 1 /* enumerator says stop */ +} PLDHashOperator; + +/* + * To lookup a key in table, call: + * + * entry = PL_DHashTableOperate(table, key, PL_DHASH_LOOKUP); + * + * If PL_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies + * entry. If PL_DHASH_ENTRY_IS_FREE(entry) is true, key was not found. + * + * To add an entry identified by key to table, call: + * + * entry = PL_DHashTableOperate(table, key, PL_DHASH_ADD); + * + * If entry is null upon return, then either the table is severely overloaded, + * and memory can't be allocated for entry storage via table->ops->allocTable; + * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may + * have returned false. + * + * Otherwise, entry->keyHash has been set so that PL_DHASH_ENTRY_IS_BUSY(entry) + * is true, and it is up to the caller to initialize the key and value parts + * of the entry sub-type, if they have not been set already (i.e. if entry was + * not already in the table, and if the optional initEntry hook was not used). + * + * To remove an entry identified by key from table, call: + * + * (void) PL_DHashTableOperate(table, key, PL_DHASH_REMOVE); + * + * If key's entry is found, it is cleared (via table->ops->clearEntry) and + * the entry is marked so that PL_DHASH_ENTRY_IS_FREE(entry). This operation + * returns null unconditionally; you should ignore its return value. + */ +PR_EXTERN(PLDHashEntryHdr *) PL_DHASH_FASTCALL +PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op); + +/* + * Remove an entry already accessed via LOOKUP or ADD. + * + * NB: this is a "raw" or low-level routine, intended to be used only where + * the inefficiency of a full PL_DHashTableOperate (which rehashes in order + * to find the entry given its key) is not tolerable. This function does not + * shrink the table if it is underloaded. It does not update stats #ifdef + * PL_DHASHMETER, either. + */ +PR_EXTERN(void) +PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry); + +/* + * Enumerate entries in table using etor: + * + * count = PL_DHashTableEnumerate(table, etor, arg); + * + * PL_DHashTableEnumerate calls etor like so: + * + * op = etor(table, entry, number, arg); + * + * where number is a zero-based ordinal assigned to live entries according to + * their order in table->entryStore. + * + * The return value, op, is treated as a set of flags. If op is PL_DHASH_NEXT, + * then continue enumerating. If op contains PL_DHASH_REMOVE, then clear (via + * table->ops->clearEntry) and free entry. Then we check whether op contains + * PL_DHASH_STOP; if so, stop enumerating and return the number of live entries + * that were enumerated so far. Return the total number of live entries when + * enumeration completes normally. + * + * If etor calls PL_DHashTableOperate on table with op != PL_DHASH_LOOKUP, it + * must return PL_DHASH_STOP; otherwise undefined behavior results. + * + * If any enumerator returns PL_DHASH_REMOVE, table->entryStore may be shrunk + * or compressed after enumeration, but before PL_DHashTableEnumerate returns. + * Such an enumerator therefore can't safely set aside entry pointers, but an + * enumerator that never returns PL_DHASH_REMOVE can set pointers to entries + * aside, e.g., to avoid copying live entries into an array of the entry type. + * Copying entry pointers is cheaper, and safe so long as the caller of such a + * "stable" Enumerate doesn't use the set-aside pointers after any call either + * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might + * grow or shrink entryStore. + * + * If your enumerator wants to remove certain entries, but set aside pointers + * to other entries that it retains, it can use PL_DHashTableRawRemove on the + * entries to be removed, returning PL_DHASH_NEXT to skip them. Likewise, if + * you want to remove entries, but for some reason you do not want entryStore + * to be shrunk or compressed, you can call PL_DHashTableRawRemove safely on + * the entry being enumerated, rather than returning PL_DHASH_REMOVE. + */ +typedef PLDHashOperator +(* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg); + +PR_EXTERN(PRUint32) +PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg); + +#ifdef PL_DHASHMETER +#include <stdio.h> + +PR_EXTERN(void) +PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp); +#endif + +PR_END_EXTERN_C + +#endif /* pldhash_h___ */ |