Snippets

Created by Stefan Glienke
program RangeDemo;

uses
  SysUtils;

type
  // see https://docs.python.org/3/library/stdtypes.html#range
  TRange = record
  private
    fStart, fStop, fStep: Integer;
    type
      TEnumerator = record
      private
        fStop, fStep: Integer;
        fCurrent: Integer;
      public
        function MoveNext: Boolean; inline;
        property Current: Integer read fCurrent;
      end;
  public
    constructor Create(stop: Integer); overload;
    constructor Create(start, stop: Integer; step: Integer = 1); overload;

    function Equals(const other: TRange): Boolean;
    function GetEnumerator: TEnumerator; inline;

    class operator Equal(const left, right: TRange): Boolean; inline;
    class operator NotEqual(const left, right: TRange): Boolean; inline;
  end;

function Range(stop: Integer): TRange; overload; inline;
begin
  Result := TRange.Create(stop);
end;

function Range(start, stop: Integer; step: Integer = 1): TRange; overload; inline;
begin
  Result := TRange.Create(start, stop, step);
end;

{ TRange }

constructor TRange.Create(stop: Integer);
begin
  fStart := 0;
  fStop := stop;
  fStep := 1;
end;

constructor TRange.Create(start, stop, step: Integer);
begin
  fStart := start;
  fStop := stop;
  fStep := step;
end;

class operator TRange.Equal(const left, right: TRange): Boolean;
begin
  Result := left.Equals(right);
end;

function TRange.Equals(const other: TRange): Boolean;
var
  left, right: TEnumerator;
begin
  left := GetEnumerator;
  right := other.GetEnumerator;
  while left.MoveNext do
    if not (right.MoveNext and (left.Current = right.Current)) then
      Exit(False);
  Result := not right.MoveNext;
end;

function TRange.GetEnumerator: TEnumerator;
begin
  Result.fStop := fStop;
  Result.fStep := fStep;
  Result.fCurrent := fStart - fStep;
end;

class operator TRange.NotEqual(const left, right: TRange): Boolean;
begin
  Result := not left.Equals(right);
end;

{ TRange.TEnumerator }

function TRange.TEnumerator.MoveNext: Boolean;
begin
  Inc(fCurrent, fStep);
  if fStep > 0 then
    Result := fCurrent < fStop
  else
    Result := fCurrent > fStop;
end;

procedure List(const r: TRange);
var
  s: string;
  i: Integer;
begin
  for i in r do
  begin
    if s <> '' then
      s := s + ', ';
    s := s + IntToStr(i);
  end;
  s := '[' + s + ']';
  Writeln(s);
end;

begin
  List(Range(10));
  List(Range(1, 11));
  List(Range(0, 30, 5));
  List(Range(0, 10, 3));
  List(range(0, -10, -1));
  List(Range(0));
  List(Range(1, 0));

  Assert(Range(0) = Range(2, 1, 3));
  Assert(Range(0, 3, 2) = Range(0, 4, 2));

  ReadLn;
end.

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.