Snippets

You are viewing an old version of this snippet. View the current version.
Revised by Stefan Glienke 91e653a
{***************************************************************************}
{                                                                           }
{           Spring Framework for Delphi                                     }
{                                                                           }
{           Copyright (c) 2009-2018 Spring4D Team                           }
{                                                                           }
{           http://www.spring4d.org                                         }
{                                                                           }
{***************************************************************************}
{                                                                           }
{  Licensed under the Apache License, Version 2.0 (the "License");          }
{  you may not use this file except in compliance with the License.         }
{  You may obtain a copy of the License at                                  }
{                                                                           }
{      http://www.apache.org/licenses/LICENSE-2.0                           }
{                                                                           }
{  Unless required by applicable law or agreed to in writing, software      }
{  distributed under the License is distributed on an "AS IS" BASIS,        }
{  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
{  See the License for the specific language governing permissions and      }
{  limitations under the License.                                           }
{                                                                           }
{***************************************************************************}

{$I Spring.inc}
{$O+,W-}

unit Spring.Span;

interface

uses
  Spring;

type
  Span<T> = record
  private type
  {$POINTERMATH ON}
    PT = ^T;
  {$POINTERMATH OFF}
    TEnumerator = record
    private
      fSpan: ^Span<T>;
      fIndex: Integer;
      function GetCurrent: T; inline;
    public
      function MoveNext: Boolean; inline;
      property Current: T read GetCurrent;
    end;
  private
    fData: PT;
    fLength: Integer;
    function GetIsEmpty: Boolean; inline;
    function GetItem(index: Integer): T; inline;
    procedure SetItem(index: Integer; const value: T); inline;
  public
    class function Create(const arr: TArray<T>): Span<T>; overload; static; inline;
    class function Create(const arr: TArray<T>; startIndex: Integer): Span<T>; overload; static; inline;
    class function Create(const arr: TArray<T>; startIndex, length: Integer): Span<T>; overload; static; inline;
    class function Create(const p: Pointer; length: Integer): Span<T>; overload; static; inline;

    function GetEnumerator: TEnumerator; inline;

    function Slice(startIndex: Integer): Span<T>; overload; inline;
    function Slice(startIndex, length: Integer): Span<T>; overload; inline;

    function ToArray: TArray<T>;

    property IsEmpty: Boolean read GetIsEmpty;
    property Items[index: Integer]: T read GetItem write SetItem; default;
    property Length: Integer read fLength;

    class operator Implicit(const arr: TArray<T>): Span<T>; inline;
    class operator Equal(const left, right: Span<T>): Boolean; inline;
    class operator NotEqual(const left, right: Span<T>): Boolean; inline;
  end;

  ReadOnlySpan<T> = record
  private type
  {$POINTERMATH ON}
    PT = ^T;
  {$POINTERMATH OFF}
    TEnumerator = record
    private
      fSpan: ^ReadOnlySpan<T>;
      fIndex: Integer;
      function GetCurrent: T; inline;
    public
      function MoveNext: Boolean; inline;
      property Current: T read GetCurrent;
    end;
  private
    fData: PT;
    fLength: Integer;
    function GetIsEmpty: Boolean; inline;
    function GetItem(index: Integer): T; inline;
  public
    class function Create(const arr: TArray<T>): ReadOnlySpan<T>; overload; static; inline;
    class function Create(const arr: TArray<T>; startIndex: Integer): ReadOnlySpan<T>; overload; static; inline;
    class function Create(const arr: TArray<T>; startIndex, length: Integer): ReadOnlySpan<T>; overload; static; inline;
    class function Create(const p: Pointer; length: Integer): ReadOnlySpan<T>; overload; static; inline;

    function GetEnumerator: TEnumerator; inline;

    function Slice(startIndex: Integer): ReadOnlySpan<T>; overload; inline;
    function Slice(startIndex, length: Integer): ReadOnlySpan<T>; overload; inline;

    function ToArray: TArray<T>;

    property IsEmpty: Boolean read GetIsEmpty;
    property Items[index: Integer]: T read GetItem; default;
    property Length: Integer read fLength;

    class operator Implicit(const arr: TArray<T>): ReadOnlySpan<T>; inline;
    class operator Implicit(const span: Span<T>): ReadOnlySpan<T>; inline;
    class operator Equal(const left, right: ReadOnlySpan<T>): Boolean; inline;
    class operator NotEqual(const left, right: ReadOnlySpan<T>): Boolean; inline;
  end;

function AsReadOnlySpan(const s: string): ReadOnlySpan<Char>; inline;

implementation

function AsReadOnlySpan(const s: string): ReadOnlySpan<Char>;
begin
  Result.fLength := Length(s);
  if Result.fLength > 0 then
    Result.fData := Pointer(s)
  else
    Result.fData := nil;
end;


{$REGION 'Span<T>'}

class function Span<T>.Create(const arr: TArray<T>): Span<T>;
begin
  Result.fData := @arr[0];
  Result.fLength := System.Length(arr);
end;

class function Span<T>.Create(const arr: TArray<T>;
  startIndex: Integer): Span<T>;
begin
{$IFOPT R+}
  Guard.CheckIndex(System.Length(arr), startIndex);
{$ENDIF}
  Result.fData := @arr[startIndex];
  Result.fLength := System.Length(arr) - startIndex;
end;

class function Span<T>.Create(const arr: TArray<T>; startIndex,
  length: Integer): Span<T>;
begin
{$IFOPT R+}
  Guard.CheckRange(System.Length(arr), startIndex, length);
{$ENDIF}
  Result.fData := @arr[startIndex];
  Result.fLength := length;
end;

class function Span<T>.Create(const p: Pointer; length: Integer): Span<T>;
begin
  Pointer(Result.fData) := p;
  Result.fLength := length;
end;

function Span<T>.GetEnumerator: TEnumerator;
begin
  Result.fSpan := @Self;
  Result.fIndex := -1;
end;

function Span<T>.GetIsEmpty: Boolean;
begin
  Result := fLength = 0;
end;

function Span<T>.GetItem(index: Integer): T;
begin
{$IFOPT R+}
  Guard.CheckIndex(fLength, index);
{$ENDIF}
  Result := fData[index];
end;

function Span<T>.Slice(startIndex: Integer): Span<T>;
begin
{$IFOPT R+}
  Guard.CheckIndex(fLength, startIndex);
{$ENDIF}
  Result.fData := @fData[startIndex];
  Result.fLength := fLength - startIndex;
end;

procedure Span<T>.SetItem(index: Integer; const value: T);
begin
{$IFOPT R+}
  Guard.CheckIndex(fLength, index);
{$ENDIF}
  fData[index] := value;
end;

function Span<T>.Slice(startIndex, length: Integer): Span<T>;
begin
{$IFOPT R+}
  Guard.CheckRange(fLength, startIndex, length);
{$ENDIF}
  Result.fData := @fData[startIndex];
  Result.fLength := length;
end;

function Span<T>.ToArray: TArray<T>;
begin
  SetLength(Result, fLength);
  if TType.IsManaged<T> then
    CopyArray(@Result[0], fData, TypeInfo(T), fLength)
  else
    Move(fData^, Result[0], fLength * SizeOf(T));
end;

class operator Span<T>.Implicit(const arr: TArray<T>): Span<T>;
begin
  Result.fData := @arr[0];
  Result.fLength := System.Length(arr);
end;

class operator Span<T>.Equal(const left, right: Span<T>): Boolean;
begin
  Result := (left.fLength = right.fLength) and (left.fData = right.fData);
end;

class operator Span<T>.NotEqual(const left, right: Span<T>): Boolean;
begin
  Result := (left.fLength <> right.fLength) or (left.fData <> right.fData);
end;

{$ENDREGION}


{$REGION 'Span<T>.TEnumerator'}

function Span<T>.TEnumerator.GetCurrent: T;
begin
  Result := fSpan.fData[fIndex];
end;

function Span<T>.TEnumerator.MoveNext: Boolean;
begin
  Inc(fIndex);
  Result := fIndex < fSpan.fLength;
end;

{$ENDREGION}


{$REGION 'ReadOnlySpan<T>'}

class function ReadOnlySpan<T>.Create(const arr: TArray<T>): ReadOnlySpan<T>;
begin
  Result.fData := @arr[0];
  Result.fLength := System.Length(arr);
end;

class function ReadOnlySpan<T>.Create(const arr: TArray<T>;
  startIndex: Integer): ReadOnlySpan<T>;
begin
{$IFOPT R+}
  Guard.CheckIndex(System.Length(arr), startIndex);
{$ENDIF}
  Result.fData := @arr[startIndex];
  Result.fLength := System.Length(arr) - startIndex;
end;

class function ReadOnlySpan<T>.Create(const arr: TArray<T>; startIndex,
  length: Integer): ReadOnlySpan<T>;
begin
{$IFOPT R+}
  Guard.CheckRange(System.Length(arr), startIndex, length);
{$ENDIF}
  Result.fData := @arr[startIndex];
  Result.fLength := length;
end;

class function ReadOnlySpan<T>.Create(const p: Pointer;
  length: Integer): ReadOnlySpan<T>;
begin
  Pointer(Result.fData) := @p;
  Result.fLength := length;
end;

function ReadOnlySpan<T>.GetEnumerator: TEnumerator;
begin
  Result.fSpan := @Self;
  Result.fIndex := -1;
end;

function ReadOnlySpan<T>.GetIsEmpty: Boolean;
begin
  Result := fLength = 0;
end;

function ReadOnlySpan<T>.GetItem(index: Integer): T;
begin
{$IFOPT R+}
  Guard.CheckIndex(fLength, index);
{$ENDIF}
  Result := fData[index];
end;

function ReadOnlySpan<T>.Slice(startIndex: Integer): ReadOnlySpan<T>;
begin
{$IFOPT R+}
  Guard.CheckIndex(fLength, startIndex);
{$ENDIF}
  Result.fData := @fData[startIndex];
  Result.fLength := fLength - startIndex;
end;

function ReadOnlySpan<T>.Slice(startIndex, length: Integer): ReadOnlySpan<T>;
begin
{$IFOPT R+}
  Guard.CheckRange(fLength, startIndex, length);
{$ENDIF}
  Result.fData := @fData[startIndex];
  Result.fLength := length;
end;

function ReadOnlySpan<T>.ToArray: TArray<T>;
begin
  SetLength(Result, fLength);
  if TType.IsManaged<T> then
    CopyArray(@Result[0], fData, TypeInfo(T), fLength)
  else
    Move(fData^, Result[0], fLength * SizeOf(T));
end;

class operator ReadOnlySpan<T>.Implicit(const arr: TArray<T>): ReadOnlySpan<T>;
begin
  Result.fData := @arr[0];
  Result.fLength := System.Length(arr);
end;

class operator ReadOnlySpan<T>.Implicit(const span: Span<T>): ReadOnlySpan<T>;
begin
  Result.fData := PT(span.fData);
  Result.fLength := span.fLength;
end;

class operator ReadOnlySpan<T>.Equal(const left,
  right: ReadOnlySpan<T>): Boolean;
begin
  Result := (left.fLength = right.fLength) and (left.fData = right.fData);
end;

class operator ReadOnlySpan<T>.NotEqual(const left,
  right: ReadOnlySpan<T>): Boolean;
begin
  Result := (left.fLength <> right.fLength) or (left.fData <> right.fData);
end;

{$ENDREGION}


{$REGION 'ReadOnlySpan<T>.TEnumerator'}

function ReadOnlySpan<T>.TEnumerator.GetCurrent: T;
begin
  Result := fSpan.fData[fIndex];
end;

function ReadOnlySpan<T>.TEnumerator.MoveNext: Boolean;
begin
  Inc(fIndex);
  Result := fIndex < fSpan.fLength;
end;

{$ENDREGION}


end.
HTTPS SSH

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