TextMorph&gt;&gt;releaseParagraph is called a lot.<div>Getting that faster would speed up the feel of the GUI<br><div><br></div><div>Karl<br><br><div class="gmail_quote">On Tue, Aug 2, 2011 at 9:22 PM, Nicolas Cellier <span dir="ltr">&lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Normal text editing (inserting) follows that path and main RunArray<br>
operation is #copyReplaceFrom:to:with:<br>
It seems it could be marginally optimized, but I don&#39;t think this<br>
would be noticed at all.<br>
Anyway, the operation never appear on a MessageTally (maybe I should<br>
try again with a huge Text).<br>
<br>
TextMorph handleKeyStroke:<br>
  TextMorphForEditView keyStroke:<br>
    TextMorph keyStroke:<br>
      TextMorphForEditView handleInteraction:fromEvent:<br>
        TextMorph handleInteraction:fromEvent:<br>
          TextEditor readKeyboard<br>
            TextEditor dispatchOnCharacter:with:<br>
              TextEditor normalCharacter:<br>
            TextEditor zapSelectionWith:<br>
              NewParagraph replaceFrom:to:with:<br>
                Text replaceFrom:to:with:<br>
                  RunArray copyReplaceFrom:to:with:<br>
<div class="im"><br>
Nicolas<br>
<br>
2011/8/2 Nicolas Cellier &lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt;:<br>
</div><div><div></div><div class="h5">&gt; No, I wanted to reuse RunArray for other purposes, that&#39;s why the<br>
&gt; methods weren&#39;t optimized.<br>
&gt; For Text, the major operation is ... Hmm wait, this is really hard to<br>
&gt; track by just reading code, and debugging it is not that easy !<br>
&gt;<br>
&gt; Nicolas<br>
&gt;<br>
&gt; 2011/8/2 Bert Freudenberg &lt;<a href="mailto:bert@freudenbergs.de">bert@freudenbergs.de</a>&gt;:<br>
&gt;&gt; On 02.08.2011, at 10:17, Nicolas Cellier wrote:<br>
&gt;&gt;<br>
&gt;&gt;&gt; I played a bit with RunArray, and found some un-optimized features.<br>
&gt;&gt;&gt; First, I don&#39;t know why RunArray is an ArrayedCollection. It cannot<br>
&gt;&gt;&gt; #add: but it can #addFirst: and #addLast:.<br>
&gt;&gt;&gt; It cannot #add:withOccurrences: but it can #addLast:times:. Why<br>
&gt;&gt;&gt; inventing new selectors for old behaviours ?<br>
&gt;&gt;<br>
&gt;&gt; The RunArray selectors may in fact precede the more common ones. RunArray&#39;s purpose was to make Text operations efficient. I think that&#39;s still the only actual use of RunArrays. In any case, speeding up Text is a good idea, though you might want to check what methods it actually uses.<br>

&gt;&gt;<br>
&gt;&gt; - Bert -<br>
&gt;&gt;<br>
&gt;&gt;&gt; These operations will cost a realloc it the last value is different,<br>
&gt;&gt;&gt; so the underlying runs/values could better be an OrderedCollection if<br>
&gt;&gt;&gt; these operations are used often.<br>
&gt;&gt;&gt; A RunArray cannot remove at all.<br>
&gt;&gt;&gt; Very weird collection species, I don&#39;t like the implementation too much.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Then, #do: loops could be far faster. They rely on ArrayedCollection<br>
&gt;&gt;&gt; which inlines do: loops with #to:do: and #at:<br>
&gt;&gt;&gt; But #at: is not that fast. Scanning the runs and counting elements<br>
&gt;&gt;&gt; would result in a n^2 cost.<br>
&gt;&gt;&gt; Fortunately there is a cache lastIndex,lastRun,lastOffset to keep a cost n.<br>
&gt;&gt;&gt; Nonetheless, all the tests cost, and the loop is suboptimal.<br>
&gt;&gt;&gt; Let use see:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; version 1:<br>
&gt;&gt;&gt; RunArray&gt;&gt;fastDo: aBlock<br>
&gt;&gt;&gt;       runs with: values do: [:r :v |<br>
&gt;&gt;&gt;               r timesRepeat: [aBlock value: v]].<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; | tmp |<br>
&gt;&gt;&gt; tmp := ((Array new: 1000) collect: [:e | 4 atRandom]) as: RunArray.<br>
&gt;&gt;&gt; {<br>
&gt;&gt;&gt; [ tmp do: [:e |]] bench.<br>
&gt;&gt;&gt; [ tmp fastDo: [:e |]] bench.<br>
&gt;&gt;&gt; }<br>
&gt;&gt;&gt; #(&#39;3,220 per second.&#39; &#39;6,290 per second.&#39;)<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; But timesRepeat: is slow, it is unoptimized by the compiler and costs<br>
&gt;&gt;&gt; a message send.<br>
&gt;&gt;&gt; I think we should implement BlockClosure&gt;&gt;repeat: and optimize that<br>
&gt;&gt;&gt; call in Compiler.<br>
&gt;&gt;&gt; But let&#39;s not do it, and rather inline by ourself:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; version 2:<br>
&gt;&gt;&gt;       runs with: values do: [:r :v |<br>
&gt;&gt;&gt;               1 to: r do: [:i | aBlock value: v]].<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; | tmp |<br>
&gt;&gt;&gt; tmp := ((Array new: 1000) collect: [:e | 4 atRandom]) as: RunArray.<br>
&gt;&gt;&gt; {<br>
&gt;&gt;&gt; [ tmp do: [:e |]] bench.<br>
&gt;&gt;&gt; [ tmp do2: [:e |]] bench.<br>
&gt;&gt;&gt; }<br>
&gt;&gt;&gt; #(&#39;3,070 per second.&#39; &#39;25,500 per second.&#39;)<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; We can even inline the with:do: loop itself:<br>
&gt;&gt;&gt; version 3:<br>
&gt;&gt;&gt;       1 to: runs size do: [:i |<br>
&gt;&gt;&gt;               | r v |<br>
&gt;&gt;&gt;               v := values at: i.<br>
&gt;&gt;&gt;               r := runs at: i.<br>
&gt;&gt;&gt;               [( r := r - 1) &gt;= 0]<br>
&gt;&gt;&gt;                       whileTrue: [aBlock value: v]].<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; | tmp |<br>
&gt;&gt;&gt; tmp := ((Array new: 1000) collect: [:e | 4 atRandom]) as: RunArray.<br>
&gt;&gt;&gt; {<br>
&gt;&gt;&gt; [ tmp do: [:e |]] bench.<br>
&gt;&gt;&gt; [ tmp do2: [:e |]] bench.<br>
&gt;&gt;&gt; }<br>
&gt;&gt;&gt; #(&#39;3,370 per second.&#39; &#39;32,200 per second.&#39;)<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Now the operation I wanted to use was reverseDo: so I implemented:<br>
&gt;&gt;&gt; RunArray&gt;&gt;fastReverseDo: aBlock<br>
&gt;&gt;&gt;       | i |<br>
&gt;&gt;&gt;       i := runs size.<br>
&gt;&gt;&gt;       [i &gt; 0]<br>
&gt;&gt;&gt;               whileTrue:<br>
&gt;&gt;&gt;                       [ | r v |<br>
&gt;&gt;&gt;                       v := values at: i.<br>
&gt;&gt;&gt;                       r := runs at: i.<br>
&gt;&gt;&gt;                       i := i - 1.<br>
&gt;&gt;&gt;                       [( r := r - 1) &gt;= 0]<br>
&gt;&gt;&gt;                               whileTrue: [aBlock value: v]].<br>
&gt;&gt;&gt; | tmp |<br>
&gt;&gt;&gt; tmp := ((Array new: 1000) collect: [:e | 4 atRandom]) as: RunArray.<br>
&gt;&gt;&gt; {<br>
&gt;&gt;&gt; [ tmp reverseDo: [:e |]] bench.<br>
&gt;&gt;&gt; [ tmp reverseDo2: [:e |]] bench.<br>
&gt;&gt;&gt; }<br>
&gt;&gt;&gt; #(&#39;83.9 per second.&#39; &#39;32,600 per second.&#39;)<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Ouch! The cache is missing a lot of indices, and our loop turns into a n^2 cost.<br>
&gt;&gt;&gt; I know, premature optimization bla bla bla, but a factor x400 is worth<br>
&gt;&gt;&gt; some inlining no?<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; I guess these features are never used.<br>
&gt;&gt;&gt; By now RunArray is kind of private utility for Text implementation.<br>
&gt;&gt;&gt; But it could / should be generic.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; I also have proposals for count: / select: / collect:. etc...<br>
&gt;&gt;&gt; It would be to evaluate the block only once per group of values.<br>
&gt;&gt;&gt; For example<br>
&gt;&gt;&gt; RunArray&gt;&gt;collect: aBlock<br>
&gt;&gt;&gt;       &quot;Beware, the block will be evaluated only once per group of values.&quot;<br>
&gt;&gt;&gt;       ^(self class runs: (runs collect: aBlock) contents values: values<br>
&gt;&gt;&gt; copy) coalesce<br>
&gt;&gt;&gt; But that&#39;s controversial, it would make the RunArray behave<br>
&gt;&gt;&gt; differently if the block has side effects...<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; | i tmp tmp2 tmp3 |<br>
&gt;&gt;&gt; tmp := ((Array new: 1000) collect: [:e | 4 atRandom]).<br>
&gt;&gt;&gt; i := 0.<br>
&gt;&gt;&gt; tmp2 := tmp collect: [:e | i := i + 1].<br>
&gt;&gt;&gt; i := 0.<br>
&gt;&gt;&gt; tmp3 := (tmp as: RunArray) collect: [:e | i := i + 1].<br>
&gt;&gt;&gt; tmp2 = tmp3 asArray<br>
&gt;&gt;&gt; ==&gt; false<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Nicolas<br>
&gt;&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;<br>
<br>
</div></div></blockquote></div><br></div></div>