+{***************************************************************************}
+{ 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. }
+{***************************************************************************}
+ function GetCurrent: T; inline;
+ function MoveNext: Boolean; inline;
+ property Current: T read GetCurrent;
+ function GetIsEmpty: Boolean; inline;
+ function GetItem(index: Integer): T; inline;
+ 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; 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;
+ ReadOnlySpan<T> = record
+ fSpan: ^ReadOnlySpan<T>;
+ function GetCurrent: T; inline;
+ function MoveNext: Boolean; inline;
+ property Current: T read GetCurrent;
+ function GetIsEmpty: Boolean; inline;
+ function GetItem(index: Integer): T; inline;
+ 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;
+function AsReadOnlySpan(const s: string): ReadOnlySpan<Char>; inline;
+function AsReadOnlySpan(const s: string): ReadOnlySpan<Char>;
+ Result.fLength := Length(s);
+ if Result.fLength > 0 then
+ Result.fData := Pointer(s)
+class function Span<T>.Create(const arr: TArray<T>): Span<T>;
+ Result.fData := @arr[0];
+ Result.fLength := System.Length(arr);
+class function Span<T>.Create(const arr: TArray<T>;
+ startIndex: Integer): Span<T>;
+ Guard.CheckRange(System.Length(arr), startIndex, length);
+ Result.fData := @arr[startIndex];
+ Result.fLength := System.Length(arr) - startIndex;
+class function Span<T>.Create(const arr: TArray<T>; startIndex,
+ length: Integer): Span<T>;
+ Guard.CheckRange(System.Length(arr), startIndex, length);
+ Result.fData := @arr[startIndex];
+ Result.fLength := length;
+class function Span<T>.Create(const p: Pointer; length: Integer): Span<T>;
+ Pointer(Result.fData) := p;
+ Result.fLength := length;
+function Span<T>.GetEnumerator: TEnumerator;
+function Span<T>.GetIsEmpty: Boolean;
+function Span<T>.GetItem(index: Integer): T;
+ Guard.CheckIndex(fLength, index);
+ Result := fData[index];
+function Span<T>.Slice(startIndex: Integer): Span<T>;
+ Guard.CheckIndex(fLength, startIndex);
+ Result.fData := @fData[startIndex];
+ Result.fLength := fLength - startIndex;
+function Span<T>.Slice(startIndex, length: Integer): Span<T>;
+ Guard.CheckRange(fLength, startIndex, length);
+ Result.fData := @fData[startIndex];
+ Result.fLength := length;
+function Span<T>.ToArray: TArray<T>;
+ SetLength(Result, fLength);
+ if TType.IsManaged<T> then
+ CopyArray(@Result[0], fData, TypeInfo(T), fLength)
+ Move(fData^, Result[0], fLength * SizeOf(T));
+class operator Span<T>.Implicit(const arr: TArray<T>): Span<T>;
+ Result.fData := @arr[0];
+ Result.fLength := System.Length(arr);
+class operator Span<T>.Equal(const left, right: Span<T>): Boolean;
+ Result := (left.fLength = right.fLength) and (left.fData = right.fData);
+class operator Span<T>.NotEqual(const left, right: Span<T>): Boolean;
+ Result := (left.fLength <> right.fLength) or (left.fData <> right.fData);
+{$REGION 'Span<T>.TEnumerator'}
+function Span<T>.TEnumerator.GetCurrent: T;
+ Result := fSpan.fData[fIndex];
+function Span<T>.TEnumerator.MoveNext: Boolean;
+ Result := fIndex < fSpan.fLength;
+{$REGION 'ReadOnlySpan<T>'}
+class function ReadOnlySpan<T>.Create(const arr: TArray<T>): ReadOnlySpan<T>;
+ Result.fData := @arr[0];
+ Result.fLength := System.Length(arr);
+class function ReadOnlySpan<T>.Create(const arr: TArray<T>;
+ startIndex: Integer): ReadOnlySpan<T>;
+ Guard.CheckRange(System.Length(arr), startIndex, length);
+ Result.fData := @arr[startIndex];
+ Result.fLength := System.Length(arr) - startIndex;
+class function ReadOnlySpan<T>.Create(const arr: TArray<T>; startIndex,
+ length: Integer): ReadOnlySpan<T>;
+ Guard.CheckRange(System.Length(arr), startIndex, length);
+ Result.fData := @arr[startIndex];
+ Result.fLength := length;
+class function ReadOnlySpan<T>.Create(const p: Pointer;
+ length: Integer): ReadOnlySpan<T>;
+ Pointer(Result.fData) := @p;
+ Result.fLength := length;
+function ReadOnlySpan<T>.GetEnumerator: TEnumerator;
+function ReadOnlySpan<T>.GetIsEmpty: Boolean;
+function ReadOnlySpan<T>.GetItem(index: Integer): T;
+ Guard.CheckIndex(fLength, index);
+ Result := fData[index];
+function ReadOnlySpan<T>.Slice(startIndex: Integer): ReadOnlySpan<T>;
+ Guard.CheckIndex(fLength, startIndex);
+ Result.fData := @fData[startIndex];
+ Result.fLength := fLength - startIndex;
+function ReadOnlySpan<T>.Slice(startIndex, length: Integer): ReadOnlySpan<T>;
+ Guard.CheckRange(fLength, startIndex, length);
+ Result.fData := @fData[startIndex];
+ Result.fLength := length;
+function ReadOnlySpan<T>.ToArray: TArray<T>;
+ SetLength(Result, fLength);
+ if TType.IsManaged<T> then
+ CopyArray(@Result[0], fData, TypeInfo(T), fLength)
+ Move(fData^, Result[0], fLength * SizeOf(T));
+class operator ReadOnlySpan<T>.Implicit(const arr: TArray<T>): ReadOnlySpan<T>;
+ Result.fData := @arr[0];
+ Result.fLength := System.Length(arr);
+class operator ReadOnlySpan<T>.Implicit(const span: Span<T>): ReadOnlySpan<T>;
+ Result.fData := span.fData;
+ Result.fLength := span.fLength;
+class operator ReadOnlySpan<T>.Equal(const left,
+ right: ReadOnlySpan<T>): Boolean;
+ Result := (left.fLength = right.fLength) and (left.fData = right.fData);
+class operator ReadOnlySpan<T>.NotEqual(const left,
+ right: ReadOnlySpan<T>): Boolean;
+ Result := (left.fLength <> right.fLength) or (left.fData <> right.fData);
+{$REGION 'ReadOnlySpan<T>.TEnumerator'}
+function ReadOnlySpan<T>.TEnumerator.GetCurrent: T;
+ Result := fSpan.fData[fIndex];
+function ReadOnlySpan<T>.TEnumerator.MoveNext: Boolean;
+ Result := fIndex < fSpan.fLength;