unit RSSequential;
//=== File Prolog ============================================================
//    This code was developed by RiverSoftAVG (www.RiverSoftAVG.com)
//
//--- Notes ------------------------------------------------------------------
//
//--- Development History  ---------------------------------------------------
//
//      02/29/2016 T. Grubb
//              Initial version.
//
//      File Contents:
//
//--- Warning ----------------------------------------------------------------
//  This software is property of RiverSoftAVG. Unauthorized use or
//  duplication of this software is strictly prohibited. Authorized users
//  are subject to the following restrictions:
//    * RiverSoftAVG is not responsible for
//      any consequence of the use of this software.
//    * The origin of this software must not be misrepresented either by
//      explicit claim or by omission.
//    * Altered versions of this software must be plainly marked as such.
//    * This notice may not be removed or altered.
//
//      © 2016, Thomas G. Grubb
//
//=== End File Prolog ========================================================

interface

uses
  System.Types, System.SysUtils, System.Classes, System.Generics.Collections,
  System.Generics.Defaults, System.SysConst;

type
  TFunctionEvent<T> = function (Sender: TObject): T of object;
  TSequential = class sealed
  public
  type
    ESequentialAbort = class(EAbort);
    TProcInt = reference to procedure (const Index: Integer);
    TProcInt64 = reference to procedure (const Index: Int64);
    TIteratorEvent = procedure (Sender: TObject; AIndex: Integer) of object;
    TIteratorEvent64 = procedure (Sender: TObject; AIndex: Int64) of object;
  protected
    class function ForWorker(Sender: TObject; AEvent: TIteratorEvent;
      const AProc: TProcInt; ALowInclusive, AHighExclusive: Integer;
      AStride: Integer = 1): Integer; static;
    class function ForWorker64(Sender: TObject; AEvent: TIteratorEvent64;
      const AProc: TProcInt64; ALowInclusive, AHighExclusive: Int64;
      AStride: Int64 = 1): Int64; static;
  public
    class procedure Break;
    class function &For(ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProcInt): Integer; overload; static; inline;
    class function &For(ALowInclusive, AHighInclusive, AStride: Integer; const AIteratorEvent: TProcInt): Integer; overload; static; inline;
    class function &For(ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProcInt64): Int64; overload; static; inline;
    class function &For(ALowInclusive, AHighInclusive, AStride: Int64; const AIteratorEvent: TProcInt64): Int64; overload; static; inline;
  end;

implementation

{ TSequential }

class function TSequential.&For(ALowInclusive, AHighInclusive, AStride: Integer;
  const AIteratorEvent: TProcInt): Integer;
begin
  result := ForWorker(nil, nil, AIteratorEvent, ALowInclusive, AHighInclusive, AStride);
end;

class function TSequential.&For(ALowInclusive, AHighInclusive: Integer;
  const AIteratorEvent: TProcInt): Integer;
begin
  result := ForWorker(nil, nil, AIteratorEvent, ALowInclusive, AHighInclusive);
end;

class procedure TSequential.Break;
begin
  raise ESequentialAbort.CreateRes(@SOperationAborted) at ReturnAddress;
end;

class function TSequential.&For(ALowInclusive, AHighInclusive, AStride: Int64;
  const AIteratorEvent: TProcInt64): Int64;
begin
  result := ForWorker64(nil, nil, AIteratorEvent, ALowInclusive, AHighInclusive, AStride);
end;

class function TSequential.ForWorker(Sender: TObject; AEvent: TIteratorEvent;
  const AProc: TProcInt; ALowInclusive, AHighExclusive,
  AStride: Integer): Integer;
begin
  if AHighExclusive <= ALowInclusive then
  begin
    Result := ALowInclusive;
    Exit;
  end;
  result := ALowInclusive;
  if AStride = 0 then AStride := 1;
  try
    while result <= AHighExclusive do
    begin
      AProc(result);
      result := result + AStride;
    end;
  except
    On ESequentialAbort do;
  end;
end;

class function TSequential.ForWorker64(Sender: TObject;
  AEvent: TIteratorEvent64; const AProc: TProcInt64; ALowInclusive,
  AHighExclusive, AStride: Int64): Int64;
begin
  if AHighExclusive <= ALowInclusive then
  begin
    Result := ALowInclusive;
    Exit;
  end;
  result := ALowInclusive;
  if AStride = 0 then AStride := 1;
  try
    while result <= AHighExclusive do
    begin
      AProc(result);
      result := result + AStride;
    end;
  except
    On ESequentialAbort do;
  end;
end;

class function TSequential.&For(ALowInclusive, AHighInclusive: Int64;
  const AIteratorEvent: TProcInt64): Int64;
begin
  result := ForWorker64(nil, nil, AIteratorEvent, ALowInclusive, AHighInclusive);
end;

end.
