program tenumerator;
{$mode objfpc}
{$modeswitch advancedrecords}
{$modeswitch implicitfunctionspecialization}
uses
Classes;
{$Region type with enumerator}
type
TInverseStringsEnumerator = class
private
FStrings: TStrings;
FPosition: Integer;
public
constructor Create(AStrings: TStrings);
function GetCurrent: String;
function MoveNext: Boolean;
property Current: String read GetCurrent;
end;
TMyStrings = class(TStringList)
function GetInverseEnumerator: TInverseStringsEnumerator;
end;
constructor TInverseStringsEnumerator.Create(AStrings: TStrings);
begin
inherited Create;
FStrings := AStrings;
FPosition := AStrings.Count;
end;
function TInverseStringsEnumerator.GetCurrent: String;
begin
Result := FStrings[FPosition];
end;
function TInverseStringsEnumerator.MoveNext: Boolean;
begin
Dec(FPosition);
Result := FPosition >= 0;
end;
function TMyStrings.GetInverseEnumerator: TInverseStringsEnumerator;
begin
Result := TInverseStringsEnumerator.Create(Self);
end;
{$EndRegion}
{$Region enumerator utility}
type
generic TEnumeratorClassWrapper<T> = class
private
fEnum: T;
public
constructor Create(aEnum: T);
destructor Destroy; override;
function GetEnumerator: T;
end;
constructor TEnumeratorClassWrapper.Create(aEnum: T);
begin
fEnum := aEnum;
end;
destructor TEnumeratorClassWrapper.Destroy;
begin
fEnum.Free;
inherited;
end;
function TEnumeratorClassWrapper.GetEnumerator: T;
begin
Result := fEnum;
end;
generic function WrapClass<T>(aEnum: T): specialize TEnumeratorClassWrapper<T>;
begin
Result := specialize TEnumeratorClassWrapper<T>.Create(aEnum);
end;
type
generic TEnumeratorRecordWrapper<T> = record
private
fEnum: T;
public
constructor Create(aEnum: T);
function GetEnumerator: T;
end;
constructor TEnumeratorRecordWrapper.Create(aEnum: T);
begin
fEnum := aEnum;
end;
function TEnumeratorRecordWrapper.GetEnumerator: T;
begin
Result := fEnum;
end;
generic function WrapRecord<T>(aEnum: T): specialize TEnumeratorRecordWrapper<T>;
begin
Result := specialize TEnumeratorRecordWrapper<T>.Create(aEnum);
end;
{$EndRegion}
var
slist: TMyStrings;
s: String;
begin
slist := TMyStrings.Create;
try
slist.Add('One');
slist.Add('Two');
slist.Add('Three');
Writeln('In order:');
for s in slist do
Writeln(s);
Writeln;
Writeln('Reverse:');
for s in WrapClass(slist.GetInverseEnumerator) do
Writeln(s);
finally
slist.Free;
end;
end.