Closed
Bug 173601
Opened 22 years ago
Closed 22 years ago
nsIStringEnumerator
Categories
(Core :: XPCOM, defect, P1)
Core
XPCOM
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)
17.52 KB,
patch
|
dougt
:
review+
darin.moz
:
superreview+
|
Details | Diff | Splinter Review |
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.
Comment 1•22 years ago
|
||
your suggested interface has apparently no way to append a string to the array
Assignee | ||
Comment 2•22 years ago
|
||
Reporter | ||
Comment 3•22 years ago
|
||
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.
Assignee | ||
Updated•22 years ago
|
Status: NEW → ASSIGNED
Priority: -- → P3
Target Milestone: --- → mozilla1.4alpha
Comment 4•22 years ago
|
||
nsICommandParams needs an enumerator over string values. This an API we want to
freeze soon.
Comment 5•22 years ago
|
||
Nominatig topembed since it blocks bug 191523 which I just nominated as well.
Keywords: topembed
Comment 6•22 years ago
|
||
Discussed in edt bug triage. Plussing because blocks 191523.
Assignee | ||
Comment 7•22 years ago
|
||
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
Assignee | ||
Updated•22 years ago
|
Assignee | ||
Comment 8•22 years ago
|
||
here's the implementation...
Assignee | ||
Comment 9•22 years ago
|
||
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
Assignee | ||
Comment 10•22 years ago
|
||
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.
Assignee | ||
Comment 11•22 years ago
|
||
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 12•22 years ago
|
||
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...
Assignee | ||
Updated•22 years ago
|
Attachment #115068 -
Attachment is obsolete: true
Reporter | ||
Comment 13•22 years ago
|
||
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 :)
Reporter | ||
Comment 14•22 years ago
|
||
>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.
Assignee | ||
Comment 15•22 years ago
|
||
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.
Assignee | ||
Comment 16•22 years ago
|
||
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
Assignee | ||
Comment 17•22 years ago
|
||
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)
Assignee | ||
Updated•22 years ago
|
Attachment #115428 -
Flags: superreview?(darin)
Attachment #115428 -
Flags: review?(dougt)
Assignee | ||
Updated•22 years ago
|
Priority: P3 → P1
Whiteboard: fix in hand
Reporter | ||
Comment 18•22 years ago
|
||
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-
Assignee | ||
Comment 19•22 years ago
|
||
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.
Assignee | ||
Comment 20•22 years ago
|
||
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)
Reporter | ||
Comment 21•22 years ago
|
||
alec: good point. nevermind then ;-)
Assignee | ||
Comment 22•22 years ago
|
||
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
Reporter | ||
Comment 23•22 years ago
|
||
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+
Assignee | ||
Comment 24•22 years ago
|
||
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)
Comment 25•22 years ago
|
||
Attachment #116778 -
Flags: review?(dougt) → review+
Assignee | ||
Comment 26•22 years ago
|
||
thanks guys... the fix is now in.
Status: ASSIGNED → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Assignee | ||
Updated•22 years ago
|
Attachment #116475 -
Flags: review?(dougt)
You need to log in
before you can comment on or make changes to this bug.
Description
•