Closed Bug 173601 Opened 22 years ago Closed 22 years ago

nsIStringEnumerator

Categories

(Core :: XPCOM, defect, P1)

defect

Tracking

()

RESOLVED FIXED
mozilla1.4alpha

People

(Reporter: darin.moz, Assigned: alecf)

References

Details

(Keywords: topembed+, Whiteboard: fix in hand)

Attachments

(1 file, 4 obsolete files)

it would be really great if we had specialized interfaces for arrays of AString and ACString to avoid nsISupportsAString and nsISupportsACString. something like this: interface nsIStringArray : nsISupports { readonly attribute unsigned long length; AString getElementAt(in unsigned long index); unsigned long indexOf(in unsigned long startIndex, in ACString element); nsIStringEnumerator enumerate(); }; interface nsIStringEnumerator : nsISupports { boolean hasMore(); AString getNext(); }; ditto for ACString. i think it is worthwhile to special case strings since string arrays are so common. i'm not sure that nsIStringEnumerator is the correct name... wouldn't want to confuse it with iterating over a string, but nsIStringArrayEnumerator seems wrong since the enumeration need not be of an array.
your suggested interface has apparently no way to append a string to the array
yes, that's the point. i should have clarified that this is meant to parallel nsIArray. hence, there would be a nsIMutableStringArray, which would mimic the functionality of nsIMutableArray.
Status: NEW → ASSIGNED
Priority: -- → P3
Target Milestone: --- → mozilla1.4alpha
nsICommandParams needs an enumerator over string values. This an API we want to freeze soon.
Blocks: 191523
Nominatig topembed since it blocks bug 191523 which I just nominated as well.
Keywords: topembed
Discussed in edt bug triage. Plussing because blocks 191523.
Keywords: topembedtopembed+
Blocks: 194289
I've got a working version of this. I had to make both a copying and a non-copying version of the enumerator... The non-copying version was darin's suggestion, and the copying one is for bug 194289 I'm attaching a straw man patch in a bit. I still need to merge the unicode/non-unicode versions of the copying enumerator together.. they share enough code that it might be worth it.
Blocks: 113164
Summary: nsIStringArray? → nsIStringEnumerator
Blocks: 50823
No longer blocks: 113164
Attached patch straw man implementation (obsolete) — Splinter Review
here's the implementation...
Attached patch straw man implementation (obsolete) — Splinter Review
ack, lets try that again.. this one actually includes the interface... note that I provided a base interface and then two subinterfaces that deal with each kind of string... also note that I also internally implement nsISimpleEnumerator and give back the appropriate primitive type. This will allow us to reuse this in classes like nsICategoryManager, which is frozen and gives back an nsISimpleEnumerator class. Consumers of nsICategoryManager can QI() to nsIStringEnumerator or nsIUTF8StringEnumerator if they are so inclined. http://lxr.mozilla.org/seamonkey/source/xpcom/components/nsICategoryManager.idl#85 (and jeez, we need to update the docs to nsICategoryManager to explain what crazyness is going on there)
Attachment #115067 - Attachment is obsolete: true
No longer blocks: 191523
Attached patch first candidate (obsolete) — Splinter Review
ok, I think this is ready to go. a few updates since the last patch: - used some template methods to simplify the constructors tremendously - combined the 2 CopyingEnumerators into a single enumerator that handles both unicode and utf8 strings. - implemented nsISimpleEnumerator on the copying enumerator too.
Comment on attachment 115428 [details] [diff] [review] first candidate doug/darin, yet another set of patches for you to review.. hopefully the patch should speak for itself. Its implementation of a scriptable enumerator for strings. I commented pretty heavily throughout the code, so it should be pretty straight forward.
Attachment #115428 - Flags: superreview?(darin)
Attachment #115428 - Flags: review?(dougt)
Comment on attachment 115428 [details] [diff] [review] first candidate fix the license date. add some javadocs to the interfaces so that when we go to freeze them, it is less painful. Do we really have to provide NS_New functions? OMG - a union. someone is thinking about footprint. :-) + // XXX this needs CopyUCS2toUTF8(aResult, + // *mArray->StringAt(mIndex++)); what about a threadsafe version of this impl. Do we care? we should talk to wtc and the intl folks about adding support for a strlen(PRUnichar) +// so that the template routine will work for strlen() +static PRUint32 strlen(const PRUnichar* aSrc) +{ + return nsCRT::strlen(aSrc); +} all for now...
Attachment #115068 - Attachment is obsolete: true
Comment on attachment 115428 [details] [diff] [review] first candidate >Index: nsIStringEnumerator.idl >+ * Portions created by the Initial Developer are Copyright (C) 2___ probably safe to fill in the blank now ;-) >+interface nsIStringEnumeratorBase : nsISupports >+{ >+ boolean hasMore(); >+}; >+interface nsIStringEnumerator : nsIStringEnumeratorBase >+{ >+ AString getNext(); >+}; >+interface nsIUTF8StringEnumerator : nsIStringEnumeratorBase >+{ >+ AUTF8String getNext(); >+}; i'd prefer to have just two interfaces because from a users point of view there doesn't seem to be much value to the nsIStringEnumeratorBase interface by itself. supporting this interface means an additional QI, etc. i imagine you are doing this so you can have one class impl both interfaces. we have a similar situation with classes that wish to support both nsIInputStream and nsIOutputStream (both have a Close method). you can see how this is handled in nsPipe3.cpp for example. you might consider something similar so the interfaces can be cleaner. or maybe it's not worth it :-/ >Index: nsStringEnumerator.h >+#include "nsVoidArray.h" can you do without this #include? (maybe i missed where it is needed) are you sure you don't want to call this NS_NewUTF8StringEnumerator instead? sure C++ lets you call them the same thing, but it might help make code more self documenting (and help folks keep on top of what charset they have) if you add UTF8 to the name. >+>+NS_COM nsresult >+NS_NewStringEnumerator(nsIUTF8StringEnumerator** aResult, >+ const nsCStringArray* aArray, >+ PRBool aOwnsArray = PR_FALSE); >+ >+NS_COM nsresult >+NS_NewStringEnumerator(nsIStringEnumerator** aResult, >+ const nsStringArray* aArray, >+ PRBool aOwnsArray = PR_FALSE); hmm.. what if nsStringArray supported shallow copy? then users could allocate nsStringArray on the stack, avoiding a heap allocation for the array container. it's also a bit icky to talk about calling delete on a pointer declared const. (i know you're declaring it const to make this interface work with both const and non-const, but it's shame to have to abuse constructs like this.) >+// Copying enumerators make a copy of all the strings in question, >+// essentially a snapshot of the current state of the array. The >+// implementation is memory efficient, making a single allocation to >+// hold the enumerator and all of its strings. this feels like something a string array should be able to do. then you would only need a dependent enumerator. also, do you know of any instances in the tree where someone actually wants to modify an array as they are enumerating it? copying the array is usually not the best solution to such a problem. e.g., sometimes you can enumerate backwards if all you might do is remove the current element or append to the end of the list or just after the iterator. i worry that folks will use a copying enumerator when they could of just used a smarter form of a non-copying enumerator. >Index: nsStringEnumerator.cpp let's agree on the interfaces first :)
>hmm.. what if nsStringArray supported shallow copy? then >users could allocate nsStringArray on the stack, avoiding >a heap allocation for the array container. i think this is actually a non-issue. this works great: { nsStringArray array; // build up array NS_NewStringEnumerator(getter_AddRefs(enumerator), &array, PR_FALSE); } but i'm still bothered by saying that this thing is going to delete a |const| pointer when aOwnsArray == TRUE.
darin - the issue with making a full fledged copy of the array is that there's nowguarantee of ownership since nsStringArrays aren't refcounted. (i.e. it isn't so much about the array getting modified) so the internal nsStringArray could get deleted before the enumerator goes away - but they still need to own the nsStringArray for their purposes. some of the consumers are going to require this, such as the nsIParam object in bug 194289 (blocked on this bug) But as for the names of the NS_* methods, I'm flexible. In fact I'm debating adding the "Copying" to some of them to indicate exactly what they're doing... And finally as for deleting "const" nsStringArrays - I know its ugly. I could split it into two methods: >+NS_COM nsresult >+NS_NewStringEnumerator(nsIStringEnumerator** aResult, >+ nsStringArray* aArray, >+ PRBool aOwnsArray = PR_FALSE); >+ >+NS_COM nsresult >+NS_NewStringEnumerator(nsIStringEnumerator** aResult, >+ const nsStringArray* aArray) ..where the 2nd method internally sets mOwnsArray to PR_FALSE. This syntactically hides the possibility of deleting a const nsStringArray.
Attached patch string enumerator implementation (obsolete) — Splinter Review
darin convinced me to ditch the copying string enumerator... we discussed that the real issue is that nsStringArray is not refcounted. We talked about how if there were special ownership models that had to be adhered to, that the clients/providers of such an enumerator should provide a custom enumerator. After poking at the code a little more, I realized it is really easy to just add an optional "owner" parameter to the constructors which allow the enumerator to hold a reference to an XPCOM object which IS refcounted, which will be responsible for destroying the array. Here's the updated patch. Anyone want to review?
Attachment #115428 - Attachment is obsolete: true
Comment on attachment 116475 [details] [diff] [review] string enumerator implementation ok, here's the updated enumerator. Can I get some reviews? Thanks. this is more or less the same as the last patch without the copying enumerator and with the ownership object.
Attachment #116475 - Flags: superreview?(darin)
Attachment #116475 - Flags: review?(dougt)
Attachment #115428 - Flags: superreview?(darin)
Attachment #115428 - Flags: review?(dougt)
Priority: P3 → P1
Whiteboard: fix in hand
Comment on attachment 116475 [details] [diff] [review] string enumerator implementation >Index: ds/nsIStringEnumerator.idl >+ * Portions created by the Initial Developer are Copyright (C) 2___ 2003 :-) >Index: ds/nsStringEnumerator.h >+// Non-copying 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. reference to "non-copying" implies existance of "copying" version :( >+NS_NewStringEnumerator(nsIStringEnumerator** aResult, >+ nsStringArray* aArray, >+ PRBool aOwnsArray = PR_FALSE); if i don't want the enumerator to "own" the array, then why wouldn't i just call the |const| versions of these methods? seems like the boolean parameter is redundant. of course, without it you have C++ name conflicts :-/ maybe NS_NewAdoptingStringEnumerator??? >+NS_COM nsresult >+NS_NewStringEnumerator(nsIStringEnumerator** aResult, >+ nsStringArray* aArray, nsISupports* aOwner); shouldn't the array be |const| here as well? also, should we define a nsICStringEnumerator? it might be useful when dealing strictly with ASCII data. i'm a bit iffy myself about whether or not this should be added. >Index: ds/nsStringEnumerator.cpp all the mIsUnicode branches make me think you should be defining separate classes for each interface. you could allocate them all as one object and bind their AddRef, Release, and QueryInterface much as is done with nsPipe, nsPipeInputStream, nsPipeOutputStream. but, i'm not going to hold you to it ;-) >+template<class T> >+static nsresult >+StringEnumeratorTail(T** aResult) decl inline? >+NS_NewStringEnumerator(nsIStringEnumerator** aResult, >+ nsStringArray* aArray, nsISupports* aOwner) >+{ >+ NS_ENSURE_ARG_POINTER(aResult); >+ NS_ENSURE_ARG_POINTER(aArray); are runtime checks really required here? why not just use debug assertions?
Attachment #116475 - Flags: superreview?(darin) → superreview-
I know there are a lot of branches, but it really didn't seem worth the effort to make all these seperate classes. I had them as seperate classes at one point, and there was just a lot of redundant code. I'll clean up the other stuff and reattach a patch.
oh, by "worth the effort" I meant "worth the code bloat" - as I previously had them seperated, I had clearly made the effort before :) There is just one branch per each GetNext() (which is the method that will be called the most often) and its pretty cheap (just checking a boolean member variable) - the only other branches are the one in the destructor and in Count() - but I feel like if we're using nsIStringEnumerators, we can't be THAT concerned about performance on a branch-counting level. (i.e. if performance is a concern somewhere that uses nsIStringEnumerator, then they should come up with some specialized non-COM mechanism or use IDL arrays)
alec: good point. nevermind then ;-)
ok, here's what I think is the final version. I didn't add an nsICStringEnumerator because the nsIUTF8StringEnumerator will behave exactly like a cstring-version as long as you give it an nsCStringArray - no conversion will be performed. When crossing language boundaries also shouldn't cause problems as long as we're dealing with 7-bit ASCII. For now I'd like to stick to what we have and see if there is really a need down the road. (i.e. where crossing language boundaries causes bad conversions)
Attachment #116475 - Attachment is obsolete: true
Comment on attachment 116778 [details] [diff] [review] string enumerator v1.2 >+template<class T> >+inline nsresult >+StringEnumeratorTail(T** aResult) i would have said "static inline" just for good measure... don't want some compiler/linker thinking it should do extra work to possibly support an extern decl / separate instance of this method in some other translation unit :-/ sr=darin
Attachment #116778 - Flags: superreview+
Comment on attachment 116778 [details] [diff] [review] string enumerator v1.2 thanks I'll make it static inline.. over to dougt.
Attachment #116778 - Flags: review?(dougt)
Attachment #116778 - Flags: review?(dougt) → review+
thanks guys... the fix is now in.
Status: ASSIGNED → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Attachment #116475 - Flags: review?(dougt)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: