unit IntRanges; // Creating stepped ranges for "for" loops in Delphi // Copyright 2007 Rob Kennedy. Some rights reserved. // For license information, see http://www.cs.wisc.edu/~rkennedy/license interface type TIntegerRangeEnum = class strict private FStarted: Boolean; strict protected FStart, FStop, FStep, FCurrent: Integer; FLimit: Integer; function Check: Boolean; virtual; abstract; function CheckFirst: Boolean; virtual; abstract; public constructor Create(const AStart, AStop, AStep: Integer); function GetCurrent: Integer; function MoveNext: Boolean; property Current: Integer read GetCurrent; end; IIntegerRange = interface function GetEnumerator: TIntegerRangeEnum; end; // for x in RangeTo(0, 100, 3) do ... // Iterates over the values [0,3,6,9,...,96,99]. function RangeTo(const Start, Stop: Integer; const Step: Integer = 1): IIntegerRange; function RangeDownTo(const Start, Stop: Integer; const Step: Integer = -1): IIntegerRange; implementation type TIntegerRangeEnumUp = class(TIntegerRangeEnum) strict protected function Check: Boolean; override; function CheckFirst: Boolean; override; end; TIntegerRangeEnumDown = class(TIntegerRangeEnum) strict protected function Check: Boolean; override; function CheckFirst: Boolean; override; end; TIntegerRange = class(TInterfacedObject, IIntegerRange) private FStart, FStop, FStep: Integer; function GetEnumerator: TIntegerRangeEnum; public constructor Create(const AStart, AStop, AStep: Integer); end; function RangeTo(const Start, Stop: Integer; const Step: Integer = 1): IIntegerRange; begin Assert(Step > 0); Result := TIntegerRange.Create(Start, Stop, Step); end; function RangeDownTo(const Start, Stop: Integer; const Step: Integer = -1): IIntegerRange; begin Assert(Step < 0); Result := TIntegerRange.Create(Start, Stop, Step); end; { TIntegerRange } constructor TIntegerRange.Create(const AStart, AStop, AStep: Integer); begin FStart := AStart; FStop := AStop; FStep := AStep; Assert(AStep <> 0); end; function TIntegerRange.GetEnumerator: TIntegerRangeEnum; begin if FStep > 0 then Result := TIntegerRangeEnumUp.Create(FStart, FStop, FStep) else Result := TIntegerRangeEnumDown.Create(FStart, FStop, FStep); end; { TIntegerRangeEnum } constructor TIntegerRangeEnum.Create(const AStart, AStop, AStep: Integer); begin FStart := AStart; FStop := AStop; FStep := AStep; FStarted := False; FLimit := FStop - FStep; end; function TIntegerRangeEnum.GetCurrent: Integer; begin Result := FCurrent; end; function TIntegerRangeEnum.MoveNext: Boolean; begin if FStarted then begin Result := Check; if Result then Inc(FCurrent, FStep); end else begin Result := CheckFirst; FCurrent := FStart; FStarted := True; end; end; { TIntegerRangeEnumUp } function TIntegerRangeEnumUp.Check: Boolean; begin Result := FCurrent <= FLimit; end; function TIntegerRangeEnumUp.CheckFirst: Boolean; begin Result := FStart <= FStop; end; { TIntegerRangeEnumDown } function TIntegerRangeEnumDown.Check: Boolean; begin Result := FCurrent >= FLimit; end; function TIntegerRangeEnumDown.CheckFirst: Boolean; begin Result := FStart >= FStop; end; end.