From fe6074f0b4caf929c17c12ea3067a7a5dd3b14eb Mon Sep 17 00:00:00 2001 From: "alecf%netscape.com" Date: Mon, 10 Mar 2003 21:09:31 +0000 Subject: [PATCH] fix for bug 173601 - nsIStringEnumerator implementation r=dougt, sr=darin Yes, this will cause a code size increase.. but it is for some upcoming interface freezes... --- xpcom/build/dlldeps.cpp | 7 + xpcom/ds/Makefile.in | 3 + xpcom/ds/nsIStringEnumerator.idl | 58 +++++++ xpcom/ds/nsStringEnumerator.cpp | 262 +++++++++++++++++++++++++++++++ xpcom/ds/nsStringEnumerator.h | 122 ++++++++++++++ 5 files changed, 452 insertions(+) create mode 100644 xpcom/ds/nsIStringEnumerator.idl create mode 100644 xpcom/ds/nsStringEnumerator.cpp create mode 100644 xpcom/ds/nsStringEnumerator.h diff --git a/xpcom/build/dlldeps.cpp b/xpcom/build/dlldeps.cpp index 0d9c7d15db26..f77916999b95 100644 --- a/xpcom/build/dlldeps.cpp +++ b/xpcom/build/dlldeps.cpp @@ -84,6 +84,7 @@ #include "nsStaticNameTable.h" #include "nsProcess.h" #include "nsSlidingString.h" +#include "nsStringEnumerator.h" #include "nsIInputStreamTee.h" #include "nsCheapSets.h" #ifdef DEBUG @@ -181,4 +182,10 @@ void XXXNeverCalled() NS_NewArray(nsnull, dummyArray); NS_NewArrayEnumerator(nsnull, dummyArray); nsVariant(); + nsStringArray array; + NS_NewStringEnumerator(nsnull, &array); + NS_NewAdoptingStringEnumerator(nsnull, &array); + nsCStringArray carray; + NS_NewUTF8StringEnumerator(nsnull, &carray); + NS_NewAdoptingUTF8StringEnumerator(nsnull, &carray); } diff --git a/xpcom/ds/Makefile.in b/xpcom/ds/Makefile.in index 45016dfce185..3b8c35a65964 100644 --- a/xpcom/ds/Makefile.in +++ b/xpcom/ds/Makefile.in @@ -63,6 +63,7 @@ CPPSRCS = \ nsRecyclingAllocator.cpp \ nsStaticNameTable.cpp \ nsStatistics.cpp \ + nsStringEnumerator.cpp \ nsStringService.cpp \ nsSupportsArray.cpp \ nsSupportsArrayEnumerator.cpp \ @@ -113,6 +114,7 @@ EXPORTS = \ nsArray.h \ nsArrayEnumerator.h \ nsCOMArray.h \ + nsStringEnumerator.h \ $(NULL) XPIDLSRCS = \ @@ -125,6 +127,7 @@ XPIDLSRCS = \ nsIRecyclingAllocator.idl \ nsIVariant.idl \ nsISerializable.idl \ + nsIStringEnumerator.idl \ nsIStringService.idl \ nsISupportsArray.idl \ nsISupportsIterators.idl \ diff --git a/xpcom/ds/nsIStringEnumerator.idl b/xpcom/ds/nsIStringEnumerator.idl new file mode 100644 index 000000000000..a7ac9131a74e --- /dev/null +++ b/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 + * + * 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/xpcom/ds/nsStringEnumerator.cpp b/xpcom/ds/nsStringEnumerator.cpp new file mode 100644 index 000000000000..1956e5d7ce64 --- /dev/null +++ b/xpcom/ds/nsStringEnumerator.cpp @@ -0,0 +1,262 @@ +/* -*- 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 + * + * 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 "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) + {} + + virtual ~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); + } + } + + 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: + 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 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 + aResult = NS_ConvertUTF8toUCS2(*mCArray->CStringAt(mIndex++)); + + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsACString& aResult) +{ + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + + // XXX this needs CopyUCS2toUTF8(aResult, + // *mArray->StringAt(mIndex++)); + if (mIsUnicode) + aResult = NS_ConvertUCS2toUTF8(*mArray->StringAt(mIndex++)); + else + aResult = *mCArray->CStringAt(mIndex++); + + return NS_OK; +} + +template +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/xpcom/ds/nsStringEnumerator.h b/xpcom/ds/nsStringEnumerator.h new file mode 100644 index 000000000000..d00800057212 --- /dev/null +++ b/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 + * + * 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);