[fpc-pascal] For ..in GetEnumerator Allocation

Mattias Gaertner nc-gaertnma at netcologne.de
Wed Oct 4 17:26:12 CEST 2017


On Wed, 4 Oct 2017 15:41:27 +0700
Ryan Joseph <ryan at thealchemistguild.com> wrote:

> As I understand the for..in loop GetEnumerator method is expected to create a new object each time it’s called and FPC destroys it later when the loos is finished. Can I retain the enumerator and just reset it in-between calls? I’d like to remove all these alloc/deallocs so I can use for..in more efficiently in tight loops.

Here is an example how to use a global enumerator object:

type
  TMyEnumerator = class
  private
    FOwner: TComponent;
    FCurrent: TComponent;
  public
    procedure Init(Owner: TComponent);
    function MoveNext: boolean;
    property Current: TComponent read FCurrent;
    function GetEnumerator: TMyEnumerator;
  end;

  TForm1 = class(TForm)
  public
    function GetEnumerator: TMyEnumerator;
  end;

var
  Form2: TForm2;
  MyEnumerator: TMyEnumerator;

implementation

procedure TMyEnumerator.Init(Owner: TComponent);
begin
  FOwner:=Owner;
  FCurrent:=nil;
end;

function TMyEnumerator.MoveNext: boolean;
var
  i: Integer;
begin
  if FCurrent=nil then begin
    if FOwner.ComponentCount=0 then exit(false);
    FCurrent:=FOwner.Components[0];
  end else begin
    i:=FCurrent.ComponentIndex+1;
    if i>=FCurrent.Owner.ComponentCount then exit(false);
    FCurrent:=FCurrent.Owner.Components[i];
  end;
  Result:=true;
end;

function TMyEnumerator.GetEnumerator: TMyEnumerator;
begin
  Result:=Self;
end;

function TForm1.GetEnumerator: TMyEnumerator;
begin
  if MyEnumerator=nil then
    MyEnumerator:=TMyEnumerator.Create;
  MyEnumerator.Init(Self);
end;

finalization
  MyEnumerator.Free;
end.



More information about the fpc-pascal mailing list