<div dir="auto">I don't much like WriteStream on: String empty.<div dir="auto">If String empty is implemented as answering a literal, and WritStream implemented to become the grown contents as it originally did in st80 and could also do in Squeak now that we have a fast become, we take the risk to modify the literal...</div><div dir="auto">String new better express our intention, we want a new substring.</div><div dir="auto">Also, contents does not necessarily answer a copy, it could answer the verbatim contents if full. So i hope that resetContents would perform the copy, but that's far from certain without seing code. We thus risk to have substrings sharing identity, and overwrite previous substring...</div><div dir="auto">Note that we can also efficiently search index of any of a character set, starting at a given index in case of byte string...</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le mar. 4 juin 2019 à 21:34,  <<a href="mailto:commits@source.squeak.org">commits@source.squeak.org</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Chris Muller uploaded a new version of Collections to project The Inbox:<br>
<a href="http://source.squeak.org/inbox/Collections-cmm.836.mcz" rel="noreferrer noreferrer" target="_blank">http://source.squeak.org/inbox/Collections-cmm.836.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Collections-cmm.836<br>
Author: cmm<br>
Time: 4 June 2019, 2:34:30.820747 pm<br>
UUID: 95d228d9-2fda-4e35-9665-d1daf90cbd99<br>
Ancestors: Collections-cmm.835<br>
<br>
- Move utility methods of Collection to 'utilities'.<br>
- #joinSeparatedBy: is useful even for non-SequenceableCollections.<br>
- Speed up String>>#subStrings:.<br>
<br>
=============== Diff against Collections-cmm.835 ===============<br>
<br>
Item was changed:<br>
+ ----- Method: Collection>>asCommaString (in category 'utilities') -----<br>
- ----- Method: Collection>>asCommaString (in category 'printing') -----<br>
  asCommaString<br>
        "Return collection printed as 'a, b, c' "<br>
+       ^ self joinSeparatedBy: ', '!<br>
- <br>
-       ^String streamContents: [:s | self asStringOn: s delimiter: ', ']<br>
-               !<br>
<br>
Item was changed:<br>
+ ----- Method: Collection>>asCommaStringAnd (in category 'utilities') -----<br>
- ----- Method: Collection>>asCommaStringAnd (in category 'printing') -----<br>
  asCommaStringAnd<br>
        "Return collection printed as 'a, b and c' "<br>
<br>
        ^String streamContents: [:s | self asStringOn: s delimiter: ', ' last: ' and ']<br>
                !<br>
<br>
Item was changed:<br>
+ ----- Method: Collection>>asStringOn:delimiter: (in category 'utilities') -----<br>
- ----- Method: Collection>>asStringOn:delimiter: (in category 'printing') -----<br>
  asStringOn: aStream delimiter: delimString<br>
        "Print elements on a stream separated<br>
        with a delimiter String like: 'a, b, c'<br>
        Uses #asString instead of #print:."<br>
<br>
        self do: [:elem | aStream nextPutAll: elem asString]<br>
                separatedBy: [aStream nextPutAll: delimString]!<br>
<br>
Item was changed:<br>
+ ----- Method: Collection>>asStringOn:delimiter:last: (in category 'utilities') -----<br>
- ----- Method: Collection>>asStringOn:delimiter:last: (in category 'printing') -----<br>
  asStringOn: aStream delimiter: delimString last: lastDelimString<br>
        "Print elements on a stream separated<br>
        with a delimiter between all the elements and with<br>
        a special one before the last like: 'a, b and c'.<br>
        Uses #asString instead of #print:<br>
<br>
        Note: Feel free to improve the code to detect the last element."<br>
<br>
        | n sz |<br>
        n := 1.<br>
        sz := self size.<br>
        self do: [:elem |<br>
                n := n + 1.<br>
                aStream nextPutAll: elem asString]<br>
        separatedBy: [<br>
                aStream nextPutAll: (n = sz ifTrue: [lastDelimString] ifFalse: [delimString])]!<br>
<br>
Item was changed:<br>
+ ----- Method: Collection>>histogramOf: (in category 'utilities') -----<br>
- ----- Method: Collection>>histogramOf: (in category 'converting') -----<br>
  histogramOf: aBlock<br>
<br>
        ^ self collect: aBlock as: Bag!<br>
<br>
Item was added:<br>
+ ----- Method: Collection>>join (in category 'utilities') -----<br>
+ join<br>
+       "Example: #(H e l l o W o r l d) join = 'HelloWorld'."<br>
+       ^ self joinSeparatedBy: String empty!<br>
<br>
Item was added:<br>
+ ----- Method: Collection>>joinSeparatedBy: (in category 'utilities') -----<br>
+ joinSeparatedBy: aString<br>
+       "Returns a string, which is a concatenation of each element's string representation separated by another string."<br>
+       ^ String streamContents:<br>
+               [ : stream | self asStringOn: stream delimiter: aString ]!<br>
<br>
Item was changed:<br>
+ ----- Method: Collection>>topologicallySortedUsing: (in category 'utilities') -----<br>
- ----- Method: Collection>>topologicallySortedUsing: (in category 'converting') -----<br>
  topologicallySortedUsing: aSortBlock <br>
        "Answer a SortedCollection whose elements are the elements of the <br>
        receiver, but topologically sorted. The topological order is defined <br>
        by the argument, aSortBlock."<br>
<br>
        | aSortedCollection |<br>
        aSortedCollection := SortedCollection new: self size.<br>
        aSortedCollection sortBlock: aSortBlock.<br>
        self do: [:each | aSortedCollection addLast: each].     "avoids sorting"<br>
        ^ aSortedCollection sortTopologically<br>
  !<br>
<br>
Item was removed:<br>
- ----- Method: SequenceableCollection>>join (in category 'converting') -----<br>
- join<br>
-       "Example: #(H e l l o W o r l d) join = 'HelloWorld'.  "<br>
- <br>
-       ^ self joinSeparatedBy: ''!<br>
<br>
Item was removed:<br>
- ----- Method: SequenceableCollection>>joinSeparatedBy: (in category 'converting') -----<br>
- joinSeparatedBy: aSeparator<br>
-       "Returns a string, which is a concatenation of each element's string representation separated by another string."<br>
- <br>
-       ^ String streamContents: [:stream |<br>
-               self<br>
-                       do: [:ea | stream nextPutAll: ea asString]<br>
-                       separatedBy: [stream nextPutAll: aSeparator asString]]!<br>
<br>
Item was changed:<br>
  ----- Method: String>>subStrings: (in category 'converting') -----<br>
  subStrings: separators <br>
+       "Answer an array containing the substrings in the receiver separated by the elements of separators."<br>
-       "Answer an array containing the substrings in the receiver separated <br>
-       by the elements of separators."<br>
        | char result sourceStream subString |<br>
+       (separators isString or:<br>
+               [ separators allSatisfy:<br>
+                       [ : element | element isCharacter ] ]) ifFalse: [ ^ self error: 'separators must be Characters.' ].<br>
-       #Collectn.<br>
-       "Changed 2000/04/08 For ANSI <readableString> protocol."<br>
-       (separators isString or:[separators allSatisfy: [:element | element isCharacter]]) ifFalse:<br>
-               [^ self error: 'separators must be Characters.'].<br>
        sourceStream := ReadStream on: self.<br>
        result := OrderedCollection new.<br>
+       subString := WriteStream on: String empty.<br>
+       [ sourceStream atEnd ] whileFalse:<br>
+               [ char := sourceStream next.<br>
+               (separators includes: char)<br>
+                       ifTrue:<br>
+                               [ subString isEmpty ifFalse:<br>
+                                       [ result add: subString contents.<br>
+                                       subString resetContents ] ]<br>
+                       ifFalse: [ subString nextPut: char ] ].<br>
+       subString isEmpty ifFalse: [ result add: subString contents ].<br>
-       subString := String new.<br>
-       [sourceStream atEnd]<br>
-               whileFalse: <br>
-                       [char := sourceStream next.<br>
-                       (separators includes: char)<br>
-                               ifTrue: [subString notEmpty<br>
-                                               ifTrue: <br>
-                                                       [result add: subString copy.<br>
-                                                       subString := String new]]<br>
-                               ifFalse: [subString := subString , (String with: char)]].<br>
-       subString notEmpty ifTrue: [result add: subString copy].<br>
        ^ result asArray!<br>
<br>
<br>
</blockquote></div>