<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body smarttemplateinserted="true">
<div id="smartTemplate4-template">Hi,<br>
<br>
<blockquote type="cite"
cite="mid:CAL4d7FjqeUuHLRLni3wtMid3dzbmpbaBHCeqE=rC91jho0AvyQ@mail.gmail.com">
<div>The trick with enumerators is to never make them classes,
and use advanced records instead, I've found. This way you
avoid the heap allocation and the implicit try/finally. Also
make sure you inline the MoveNext and GetCurrent! </div>
</blockquote>
</div>
<div><br>
</div>
<div>that's what I do.</div>
<div><br>
</div>
<div><br>
</div>
<div>But the generated assembly is still worse than an old for loop,
because it keeps all the fields of the record in memory.</div>
<div><br>
</div>
<div>for example<br>
</div>
<div><br>
</div>
<div>> for I in TSlice<SizeUInt>.TakeWhile(Arr, Test) do
J := I;</div>
<div><br>
</div>
<div>generates something like this<br>
</div>
<div><br>
</div>
<div>0000000000401290 488b45f0 mov
-0x10(%rbp),%rax<br>
0000000000401294 488b00 mov (%rax),%rax<br>
0000000000401297 488905b22a0300 mov
%rax,0x32ab2(%rip) # 0x433d50 <U_$P$PROJECT1_$$_I><br>
project1.lpr:75 J := I;<br>
000000000040129E 488905bb2a0300 mov
%rax,0x32abb(%rip) # 0x433d60 <U_$P$PROJECT1_$$_J><br>
project1.lpr:74 for I in
TSlice<SizeUInt>.TakeWhile(Arr, Test) do<br>
00000000004012A5 488345f008 addq $0x8,-0x10(%rbp)<br>
project1.lpr:69 begin<br>
00000000004012AA 488b45e8 mov -0x18(%rbp),%rax<br>
project1.lpr:74 for I in
TSlice<SizeUInt>.TakeWhile(Arr, Test) do<br>
00000000004012AE 483b45f0 cmp -0x10(%rbp),%rax<br>
00000000004012B2 720a jb 0x4012be
<main+334><br>
00000000004012B4 483b45e0 cmp -0x20(%rbp),%rax<br>
00000000004012B8 7404 je 0x4012be
<main+334><br>
00000000004012BA b001 mov $0x1,%al<br>
00000000004012BC eb02 jmp 0x4012c0
<main+336><br>
00000000004012BE 30c0 xor %al,%al<br>
00000000004012C0 84c0 test %al,%al<br>
00000000004012C2 75cc jne 0x401290
<main+288><br>
</div>
<div><br>
</div>
<div>Nearly every line is accessing some memory, when it could keep
everything in a few registers. amd64 has 16 registers, but fpc
seems to only know three when records are involved<br>
</div>
<div><br>
</div>
<br>
<div><br>
Cheers,<br>
Benito </div>
<br>
<div class="moz-cite-prefix">Am 22.02.19 um 16:51 schrieb Ben
Grasset:<br>
</div>
<blockquote type="cite"
cite="mid:CAL4d7Fjw5J4L5rM_U_ecEUoqainFDHoNfc9oxWUSs4YjUP-kFA@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">On Fri, Feb 22, 2019 at 1:07 AM Paul van Helden
<<a href="mailto:paul@planetgis.co.za"
moz-do-not-send="true">paul@planetgis.co.za</a>> wrote:<br>
</div>
<div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left:1px solid
rgb(204,204,204);padding-left:1ex">
<div dir="ltr">
<div class="gmail_quote">
<div> How do you make a (for in) enumerator with a
record? I don't use them for exactly this reason,
and they did seem to be another useful language
feature that turned out to be poorly implemented by
Embarcadero. (Haven't checked with FPC).</div>
</div>
</div>
</blockquote>
<div><br>
</div>
<div>Here's an example (for FPC) that demonstrates it by
implementing the "take-while" pattern:</div>
<div><br>
</div>
<div>program TakeWhileExample;</div>
<div><br>
</div>
<div>{$mode Delphi}{$H+}{$J-}</div>
<div>{$modeswitch NestedProcVars}</div>
<div>{$ImplicitExceptions Off}</div>
<div>{$PointerMath On}</div>
<div><br>
</div>
<div>type</div>
<div> TSlice<T> = record</div>
<div> public type</div>
<div> PT = ^T;</div>
<div> ArrayType = array of T;</div>
<div> private</div>
<div> FFirst, FLast, FCurrent: PT;</div>
<div> function GetCurrent: T; inline;</div>
<div> public</div>
<div> function GetEnumerator: TSlice<T>; inline;</div>
<div> function MoveNext: Boolean; inline;</div>
<div> class function TakeWhile(const A: ArrayType;
function F(const Val: T): Boolean): TSlice<T>;
static; inline;</div>
<div> property Current: T read GetCurrent;</div>
<div> end;</div>
<div><br>
</div>
<div> TTestFunc<T> = function(const Val: T): Boolean;</div>
<div><br>
</div>
<div> function TSlice<T>.GetCurrent: T;</div>
<div> begin</div>
<div> Result := FCurrent^;</div>
<div> end;</div>
<div><br>
</div>
<div> function TSlice<T>.GetEnumerator:
TSlice<T>;</div>
<div> begin</div>
<div> Result := Self;</div>
<div> with Result do FCurrent := FFirst - 1;</div>
<div> end;</div>
<div><br>
</div>
<div> function TSlice<T>.MoveNext: Boolean;</div>
<div> begin</div>
<div> Inc(FCurrent);</div>
<div> Exit((FCurrent <= FLast) and (FFirst <>
FLast));</div>
<div> end;</div>
<div><br>
</div>
<div> function Test(const Val: SizeUInt): Boolean; inline;</div>
<div> begin</div>
<div> Exit((Val < 50000000));</div>
<div> end;</div>
<div><br>
</div>
<div> class function TSlice<T>.TakeWhile(const A:
ArrayType; function F(const Val: T): Boolean):
TSlice<T>;</div>
<div> var</div>
<div> I: SizeUInt;</div>
<div> X: TTestFunc<T> absolute F;</div>
<div> //FPC generates slightly better code for the
"absolute" way, not sure why...</div>
<div> begin</div>
<div> with Result do begin</div>
<div> FFirst := @A[0];</div>
<div> FLast := @A[0];</div>
<div> for I := 0 to High(A) do</div>
<div> case X(A[I]) of</div>
<div> True: Inc(FLast);</div>
<div> False: Exit();</div>
<div> end;</div>
<div> end;</div>
<div> end;</div>
<div><br>
</div>
<div>var</div>
<div> I, J: SizeUInt;</div>
<div> Arr: TSlice<SizeUInt>.ArrayType;</div>
<div><br>
</div>
<div>begin</div>
<div> SetLength(Arr, 100000000);</div>
<div> for I := 0 to 99999999 do Arr[I] := I;</div>
<div> I := 0;</div>
<div> J := 0;</div>
<div> for I in TSlice<SizeUInt>.TakeWhile(Arr, Test)
do J := I;</div>
<div> WriteLn(J);</div>
<div>end. </div>
</div>
</div>
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<pre class="moz-quote-pre" wrap="">_______________________________________________
fpc-devel maillist - <a class="moz-txt-link-abbreviated" href="mailto:fpc-devel@lists.freepascal.org">fpc-devel@lists.freepascal.org</a>
<a class="moz-txt-link-freetext" href="http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel">http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel</a>
</pre>
</blockquote>
</body>
</html>