<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <div class="moz-cite-prefix">Am 31.12.2023 um 04:11 schrieb Amir---
      via fpc-pascal:<br>
    </div>
    <blockquote type="cite"
      cite="mid:01d55559-93a3-449a-b33b-867a95900988@Aavani.net">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <br>
      <div class="moz-cite-prefix">On 12/30/23 00:20, Sven Barth via
        fpc-pascal wrote:<br>
      </div>
      <blockquote type="cite"
cite="mid:CAFMUeB8OJMJ8oBcx_62_pwTBiq8sjJMCFXArA0AEAsQhf7DxAA@mail.gmail.com">
        <meta http-equiv="content-type"
          content="text/html; charset=UTF-8">
        <div dir="auto">
          <div>
            <div class="gmail_quote">
              <div dir="ltr" class="gmail_attr">Amir via fpc-pascal <<a
                  href="mailto:fpc-pascal@lists.freepascal.org"
                  moz-do-not-send="true" class="moz-txt-link-freetext">fpc-pascal@lists.freepascal.org</a>>
                schrieb am Sa., 30. Dez. 2023, 08:11:<br>
              </div>
              <blockquote class="gmail_quote"
style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
                <div dir="auto">
                  <div><br>
                    <div class="gmail_extra"><br>
                      <div class="gmail_quote">On Dec 29, 2023 9:50 PM,
                        Adriaan van Os <<a
                          href="mailto:adriaan@adriaan.biz"
                          target="_blank" rel="noreferrer"
                          moz-do-not-send="true"
                          class="moz-txt-link-freetext">adriaan@adriaan.biz</a>>
                        wrote:<br type="attribution">
                        <blockquote
style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Amir---
                          via fpc-pascal wrote: <br>
                          > Hi all, <br>
                          > <br>
                          >  I have a List of record, where the
                          record has a WideString field. <br>
                          >   I have some code like the following: <br>
                          > <br>
                          > function check(constref v: TMyRecord;
                          data: TListOfMyRecord): Boolean; <br>
                          > var <br>
                          >   r: TMyRecord; <br>
                          > <br>
                          > begin <br>
                          >   Result := False; <br>
                          >   for r in data do <br>
                          >     if r.State = v.State then <br>
                          >       Exit(True); <br>
                          > end; <br>
                          > <br>
                          > I call this method a lot and the CPU
                          profiling shows a lot of cpu time <br>
                          > spent on "fpc_copy_proc" (which I assume
                          is doing the deep copy on <br>
                          > records) from
                          "TCustomListEnumerator.GetCurrent". <br>
                          > I considered other alternatives like
                          using enumerators but they all need <br>
                          > a to return a record (and hence copying
                          the widestring field). <br>
                          > I can think of two solutions to get rid
                          of the wasting(!) so much time <br>
                          > on "fpc_copy_proc": <br>
                          > 1) Changing the TMyRecord to TMyClass.
                          But then I need to Create and <br>
                          > Free a "lot" of objects. <br>
                          > 2) Update TListOfMyRecord to
                          TListOfPointerToMyRecord. This requires a <br>
                          > "lot" of memory allocation/fragmentation.
                          <br>
                          > <br>
                          > Is there a better solution? <br>
                          <br>
                          Pass the data parameter by reference.</blockquote>
                      </div>
                    </div>
                  </div>
                  <div dir="auto">This means I need to have a
                    ListOfMyRecord and a ListOfConstRefMyRecord, right? </div>
                </div>
              </blockquote>
            </div>
          </div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">No, that's not a thing.</div>
          <div dir="auto"><br>
          </div>
          <div dir="auto">You simply need to declare your "data"
            parameter as "constref" or "const" as well, just like your
            "v" parameter. </div>
        </div>
      </blockquote>
      Have a look at this piece of code (The complete code is attached):<br>
      <font face="monospace">type</font><br>
      <font face="monospace">  TMyRecord = record</font><br>
      <font face="monospace">    Str: AnsiString;</font><br>
      <font face="monospace">    Index: Integer;</font><br>
      <br>
      <font face="monospace">  end;</font><br>
      <font face="monospace">  PMyRecord = ^TMyRecord;</font><br>
      <br>
      <font face="monospace">  TMyList = specialize
        TList<TMyRecord>;</font><br>
      <font face="monospace">  TMyPtrList = specialize
        TList<PMyRecord>;</font><br>
      <br>
      <font face="monospace">function Check1(const MyList: TMyList):
        Integer;</font><br>
      <font face="monospace">var</font><br>
      <font face="monospace">   data: TMyRecord;</font><br>
      <br>
      <font face="monospace">begin</font><br>
      <font face="monospace">  Result := 0;</font><br>
      <font face="monospace">  for data in MyList do</font><br>
      <font face="monospace">    if data.Index mod 100 = 0 then</font><br>
      <font face="monospace">      Inc(Result);</font><br>
      <br>
      <font face="monospace">end;</font><br>
      <br>
      <font face="monospace">function Check2(MyList: TMyList): Integer;</font><br>
      <font face="monospace">var</font><br>
      <font face="monospace">   data: TMyRecord;</font><br>
      <br>
      <font face="monospace">begin</font><br>
      <font face="monospace">  Result := 0;</font><br>
      <font face="monospace">  for data in MyList do</font><br>
      <font face="monospace">    if data.Index mod 100 = 0 then</font><br>
      <font face="monospace">      Inc(Result);</font><br>
      <br>
      <font face="monospace">end;</font><br>
      <br>
      <font face="monospace">function Check3(MyPtrList: TMyPtrList):
        Integer;</font><br>
      <font face="monospace">var</font><br>
      <font face="monospace">   data: PMyRecord;</font><br>
      <br>
      <font face="monospace">begin</font><br>
      <font face="monospace">  Result := 0;</font><br>
      <font face="monospace">  for data in MyPtrList do</font><br>
      <font face="monospace">    if data^.Index mod 100 = 0 then</font><br>
      <font face="monospace">      Inc(Result);</font><br>
      <br>
      <font face="monospace">end;</font><br>
      <br>
      <br>
      I compiled the code with `fpc -O3 -Sd -gv -g -gl ` and ran
      `valgrind` on it (the output is attached). It does not look like
      there is a big difference between the Check1 and Check2 but Check3
      is about 20 times faster than the other two.<br>
    </blockquote>
    <br>
    For a class type there isn't much difference between being passed as
    "const" or not. It's mainly records and managed types this affects.<br>
    <br>
    <blockquote type="cite"
      cite="mid:01d55559-93a3-449a-b33b-867a95900988@Aavani.net"> I
      believe the issue could be resolved if we make
      "TCustomListWithPointers.GetPtrEnumerator" a public method. Then,
      one can implement the following function:<br>
      <br>
      <font face="monospace">function Check4(MyList: TMyList): Integer;</font><br>
      <font face="monospace">....</font><br>
      <font face="monospace">  it := MyList.GetPreEnumerator;</font><br>
      <font face="monospace">  while it.MoveNext do</font><br>
      <font face="monospace">  begin</font><br>
      <font face="monospace">    if it.Current^.Index mod 100 = 0 then</font><br>
      <font face="monospace">     ....</font><br>
      <font face="monospace">  end;</font><br>
    </blockquote>
    <br>
    You simply need to inherit from the list class so that you can make
    the function public. And with a little trick you can also use it
    inside a for-in-loop:<br>
    <br>
    === code begin ===<br>
    <br>
    program tlistitr;<br>
    <br>
    {$mode objfpc}{$H+}<br>
    {$modeswitch advancedrecords}<br>
    <br>
    uses<br>
      Generics.Collections;<br>
    <br>
    type<br>
      TRec = record<br>
        a, b, c: Int64;<br>
        constructor Create(aArg1, aArg2, aArg3: Int64);<br>
      end;<br>
    <br>
      { this way the GetPtrEnumerator function is available; you could
    also use a class helper }<br>
      TMyList = class(specialize TList<TRec>)<br>
      public<br>
        function GetPtrEnumerator: specialize TEnumerator<PT>;<br>
      end;<br>
    <br>
    constructor TRec.Create(aArg1, aArg2, aArg3: Int64);<br>
    begin<br>
      a := aArg1;<br>
      b := aArg2;<br>
      c := aArg3;<br>
    end;<br>
    <br>
    function TMyList.GetPtrEnumerator: specialize TEnumerator<PT>;<br>
    begin<br>
      Result := inherited GetPtrEnumerator();<br>
    end;<br>
    <br>
    { with this you can simply do "for PtrTypeVar in
    List.GetPtrEnumerator do",<br>
      though this *might* not work in mode Delphi... }<br>
    operator Enumerator(aEnum: specialize
    TEnumerator<TMyList.PT>): specialize
    TEnumerator<TMyList.PT>;<br>
    begin<br>
      Result := aEnum;<br>
    end;<br>
    <br>
    var<br>
      l: TMyList;<br>
      r: TRec;<br>
      p: TMyList.PT;<br>
    begin<br>
      l := TMyList.Create;<br>
      l.Add(TRec.Create(1, 2, 3));<br>
      l.Add(TRec.Create(9, 8, 7));<br>
      for p in l.GetPtrEnumerator do begin<br>
        Writeln(p^.a, ' ', p^.b, ' ', p^.c);<br>
      end;<br>
    end.<br>
    <br>
    === code end ===<br>
    <br>
    Regards,<br>
    Sven<br>
  </body>
</html>