test

progging - To wander about and beg; to seek food or other supplies by low arts; to seek for advantage by mean shift or tricks.
progging - Programmer slang for writing computer code.
Viser innlegg med etiketten Enumerators. Vis alle innlegg
Viser innlegg med etiketten Enumerators. Vis alle innlegg

tirsdag 30. august 2011

Delphi Enumerable List - example

Just an example of a list of a specific type in delphi.
unit MyUtility;

interface

uses
  Classes,  {TList}
  Chart;    {TChart}

type
  TChartList = class;
  TChartListEnumerator = record
  private
    FIndex: Integer;
    FList: TChartList;
  public
    constructor Create(AList: TChartList);
    function MoveNext: Boolean; inline;
    function GetCurrent: TChart; inline;
    property Current: TChart read GetCurrent;
  end;
  TChartList = class(TList)
  public
    procedure Add(AChart: TChart);
    function GetItem(i:Integer): TChart;
    function GetEnumerator: TChartListEnumerator;
    property Items[i:Integer]: TChart read GetItem; default;
  end;

implementation

{TChartList}

procedure TChartList.Add(AChart: TChart);
begin
  inherited Add(AChart);
end;

function TChartList.GetItem(i:Integer): TChart;
begin
  Result := List[i];
end;

function TChartList.GetEnumerator: TChartListEnumerator;
begin
  Result := TChartListEnumerator.Create(Self);
end;

{ TChartListEnumerator }

constructor TChartListEnumerator.Create(AList: TChartList);
begin
  FIndex := -1;
  FList := AList;
end;

function TChartListEnumerator.GetCurrent: TChart;
begin
  Result := FList.List[FIndex];
end;

function TChartListEnumerator.MoveNext: Boolean;
begin
  Result := FIndex < FList.Count - 1;
  if Result then
    Inc(FIndex);
end;

end.
And it's use:
var
  Chart: TChart;
begin
  for Chart in ChartList do begin
    Chart.DoSomeThing();
  end;

fredag 19. august 2011

Implementing enumerators on delphi records

Implementing enumerators are pretty easy in Delphi and many articles exist on the topic:

http://hallvards.blogspot.com/2007/10/more-fun-with-enumerators.html
http://www.thedelphigeek.com/2007/03/fun-with-enumerators.html

For some reason, I had a simple record to hold a small array of another type where the use was to loop round and do some action on every type. I used a record instead of a class to avoid the Create/Destroy and since it was just used to hold some simple data.
The first thing I noticed was that the Enumerator had to be a class (and not a record as recommended here) because I could not have a forward declaration to a record. Since my "list type" was a record I had to "forward declare" the enumerator before the record type.

  TLongTrendFieldsEnumerator = class;

  TLongTrendFields = record
  private
    { Private declarations }
    PlotList: array[0..MAX_LONG_TREND_FIELDS] of TPlot;
    function GetItem(index : Integer) : TPlot;
  public
    { Public declarations }
    property Items[i:Integer] : TPlot read GetItem; default;
    function GetEnumerator: TLongTrendFieldsEnumerator;
  end;

The next thing to think of is that the list type is a record, so we don't want to copy the instance when we pass it to the enumerator. So we use pointer instead, beginning with declaring a pointer type

  TLongTrendFieldsEnumerator = class;

  TLongTrendFieldsPointer = ^TLongTrendFields;
  TLongTrendFields = record
  private
  ...
So then the enumerator class will look like this:


  TLongTrendFieldsEnumerator = class
  private
    index: Integer;
    fields: TLongTrendFieldsPointer;
  public
    constructor Create(aFields: TLongTrendFieldsPointer);
    function MoveNext: Boolean;
    function GetCurrent: TPlot;
    property Current: TPlot read GetCurrent;
  end;  
The only difference in the implementation is that when the list type creates the enumerator it has to send a reference/pointer to the enumerator's constructor.
function TLongTrendFields.GetEnumerator: TLongTrendFieldsEnumerator;
begin
  Result := TLongTrendFieldsEnumerator.Create(@Self);
end;
The rest of the implementation is identical to the other examples (without pointers) thanks to Delphi's nice pointer syntax handling!