fpc/tests/tbs/tb0664.pp

916 lines
21 KiB
ObjectPascal

unit tb0664;
{$mode delphi}
interface
uses Generics.Defaults, Generics.Collections, SysUtils;
type
TuList<T> = class
{$IFDEF FPC}
type
TArrayT = Array of T;
{$ENDIF}
private
function GetCapacity: integer;
procedure SetCapacity(const Value: integer);
protected
{$IFDEF FPC}
FData: TArrayT;
{$ELSE}
FData: TArray<T>;
{$ENDIF}
FCount : integer;
function GetItem(Index: Integer): T;
procedure SetItem(Index: Integer; const Value: T);
public
constructor Create; overload;
constructor Create(const aCapacity: integer); overload;
function Add(const item: T): integer;
property Count: integer read FCount;
property Items[Index: Integer]: T read GetItem write SetItem; default;
procedure Clear; virtual;
{$IFDEF FPC}
function ToArray: TArrayT;
{$ELSE}
function ToArray: TArray<T>;
{$ENDIF}
procedure TrimExcess;
property Capacity: integer read GetCapacity write SetCapacity;
end;
ListHelper = record
public
class procedure Reverse<T>(const List: TuList<T>); static;
class function ToArray<T>(const List: TuList<T>): TArray<T>; static;
class procedure Sort<T>(const List: TuList<T>); overload; static;
class procedure Sort<T>(const List: TuList<T>; AComparer: IComparer<T>); overload; static;
class procedure StableSort<T>(const List: TuList<T>; AComparer: IComparer<T>); overload; static;
class function BinarySearch<T>(const List: TuList<T>; const Item: T): Integer; overload; static;
class function BinarySearch<T>(const List: TuList<T>; const Item: T; AComparer: IComparer<T>): SizeInt; overload; static;
class procedure Insert<T>(const List: TuList<T>; const index: integer; const Item: T); static;
class procedure Delete<T>(const List: TuList<T>; const index: integer); static;
class procedure InsertRange<T>(const List: TuList<T>; const index: integer; const Items: TArray<T>); static;
class procedure DeleteRange<T>(const List: TuList<T>; const index: integer; const dCount: integer); static;
class procedure Remove<T>(const List: TuList<T>; const obj: T; AComparer: IComparer<T>); static;
class procedure AddManyInts(const List: TuList<UInt32>; const obj: UInt32; const aCount: Int32); static;
class procedure AddArrayByte(const List: TuList<UInt32>; const Source: TArray<Byte>; const aCount: Int32); static;
end;
TuObjectList = class(TuList<TObject>)
private
FDontFree: Boolean;
public
constructor Create(const aCapacity: integer; const OwnsObjects: boolean);
destructor Destroy; override;
procedure Clear; override;
procedure Insert(Index: Integer; const Value: TObject);
procedure Delete(Index: Integer);
procedure DeleteAndNotFree(Index: Integer);
procedure RemoveRange(Index, Count: Integer);
procedure SetCount(const a: integer);
function IndexOfPointer(const Value: TObject): Integer;
procedure RemovePointer(const obj: TObject);
procedure SetButDontDestroy(const i: integer; const r: TObject);
property DontFree: Boolean read FDontFree write FDontFree;
end;
{TuVListEnumerator<T> = class(TEnumerator<T>)
private
FList: TObject; //silly generics don't allow forward decl
Position: integer;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const aList: TObject);
end;}
TuVList<T: class> = class(TuObjectList)
protected
function GetItemTyped(Index: Integer): T;
procedure SetItemTyped(Index: Integer; const Value: T);
protected
FComparer: IComparer<T>;
public
constructor Create(const aCapacity: integer; const OwnsObjects: boolean); overload;
constructor Create(const aComparer: IComparer<T>); overload;
property ItemTyped[Index: Integer]: T read GetItemTyped write SetItemTyped; default;
//function GetEnumerator: TEnumerator<T>;
function ToArray: TArray<T>;
procedure Sort; overload;
procedure Sort(aComparer: IComparer<T>); overload;
procedure StableSort(aComparer: IComparer<T>);
function BinarySearch(const Item: T): Integer; overload;
function BinarySearch(const Item: T; aComparer: IComparer<T>): Integer; overload;
end;
{$ifdef blubb}
TuStack<T> = class
private
FData: TArray<T>;
FCount: integer;
public
procedure Push(const v: T);
function Pop: T;
function Peek: T;
function Count: integer;
procedure Clear;
end;
TuOStack<T: class> = class
private
FData: TArray<T>;
FCount: integer;
public
procedure Push(const v: T);
procedure Pop;
function Peek: T;
function Count: integer;
procedure Clear;
end;
{ //can't create an instance in XE6 android
TKeyComparer<K, V> = class(TInterfacedObject, IComparer<TPair<K, V>>)
function Compare(const Left, Right: TPair<K, V>): Integer;
end; }
TuSortedList<K, V> = class
type
TPairKV = TPair<K, V>;
private
List: TuList<TPairKV>;
function GetItems(const key: K): V;
procedure SetItems(const key: K; const value: V);
protected
FComparer: IComparer<K>;
public
constructor Create; overload;
constructor Create(const aComparer: IComparer<K>); overload;
destructor Destroy; override;
procedure Add(const key: K; const value: V);
procedure Remove(const key: K);
function ContainsKey(const key: K): boolean;
function IndexOfKey(const key: K): integer;
function TryGetValue(const key: K; out value: V): boolean;
property Items[const key: K]: V read GetItems write SetItems; default;
function Count: integer;
function Values(const index: integer): V;
function Keys(const index: integer): K;
end;
{$endif}
procedure TrueFree(const obj: TObject); inline;
procedure FreeObj(var obj); inline;
procedure RaiseArgEx;
function GetNextCapacity(const c: integer): integer;
implementation
//uses b;
procedure TrueFree(const obj: TObject);
begin
{$ifdef AUTOREFCOUNT}
begin
obj.DisposeOf;
end;
{$else}
begin
obj.Free;
end;
{$endif}
end;
procedure FreeObj(var obj);
{$ifdef AUTOREFCOUNT}
begin
if (Pointer(obj) <> nil) then TObject(obj).DisposeOf;
TObject(obj) := nil;
end;
{$else}
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;
{$endif}
procedure RaiseArgEx;
begin
raise EArgumentOutOfRangeException.Create('Index out of bounds');
end;
function GetNextCapacity(const c: integer): integer;
begin
if (c = 0) then exit(4);
if c < 1000 then exit (c * 2);
exit(c + 1000);
end;
{$RANGECHECKS OFF}
procedure FillDWord(var Dest; Count, Value: UInt32);
{$IFDEF CPUX86}
asm
XCHG EDX, ECX
PUSH EDI
MOV EDI, EAX
MOV EAX, EDX
REP STOSD
POP EDI
end;
{$ELSE}
type
IntArray = array[0..0] of integer;
PIntArray = ^IntArray;
var
i: integer;
Arr: PIntArray;
begin
Arr := PIntArray(@Dest);
for i := 0 to Count - 1 do Arr[i] := Value;
end;
{$ENDIF CPUX86}
{ TuList<T> }
constructor TuList<T>.Create;
begin
inherited Create;
end;
constructor TuList<T>.Create(const aCapacity: integer);
begin
inherited Create;
Capacity := aCapacity;
end;
{$RANGECHECKS OFF}
function TuList<T>.Add(const item: T): integer;
begin
if FCount >= Length(FData) then
begin
SetLength(FData, GetNextCapacity(FCount));
end;
FData[FCount] := item;
Result := FCount;
inc(FCount);
end;
procedure TuList<T>.Clear;
begin
FData := nil;
FCount := 0;
end;
function TuList<T>.GetItem(Index: Integer): T;
begin
{$R-}
if (Index >= Count) or (Index < 0)then RaiseArgEx;
Result := FData[Index];
{$R+}
end;
procedure TuList<T>.SetItem(Index: Integer; const Value: T);
begin
{$R-}
if (Index >= Count) or (Index < 0)then RaiseArgEx;
FData[Index] := Value;
{$R+}
end;
{$IFDEF FPC}
function TuList<T>.ToArray: TArrayT;
{$ELSE}
function TuList<T>.ToArray: TArray<T>;
{$ENDIF}
begin
SetLength(FData, FCount);
Result := FData; //we won't return a deep copy.
end;
procedure TuList<T>.TrimExcess;
begin
SetLength(FData, FCount);
end;
function TuList<T>.GetCapacity: integer;
begin
Result := Length(FData);
end;
procedure TuList<T>.SetCapacity(const Value: integer);
begin
if Value > FCount then SetLength(FData, value) else SetLength(FData, FCount);
end;
{ TuVList<T> }
function TuVList<T>.BinarySearch(const Item: T): Integer;
begin
Result := ListHelper.BinarySearch<T>(TuList<T>(self), Item, FComparer);
end;
function TuVList<T>.BinarySearch(const Item: T;
aComparer: IComparer<T>): Integer;
begin
Result := ListHelper.BinarySearch<T>(TuList<T>(self), Item, aComparer);
end;
constructor TuVList<T>.Create(const aCapacity: integer;
const OwnsObjects: boolean);
var
Tmp: T;
begin
inherited Create(aCapacity, OwnsObjects);
// Tmp := Default(T);
// if Supports(TObject(Tmp), IComparable<T>) then FComparer := TComparableComparer<T>.Create();
end;
constructor TuVList<T>.Create(const aComparer: IComparer<T>);
begin
inherited Create(4, true);
FComparer := aComparer;
end;
{function TuVList<T>.GetEnumerator: TEnumerator<T>;
begin
Result := TuVListEnumerator<T>.Create(self);
end;}
function TuVList<T>.GetItemTyped(Index: Integer): T;
begin
{$R-}
if (Index >= Count) or (Index < 0)then RaiseArgEx;
Result := T(FData[Index]);
{$R+}
end;
procedure TuVList<T>.SetItemTyped(Index: Integer; const Value: T);
begin
{$R-}
if (Index >= Count) or (Index < 0)then RaiseArgEx;
if not DontFree then TrueFree(FData[Index]);
FData[Index] := Value;
{$R+}
end;
procedure TuVList<T>.Sort(aComparer: IComparer<T>);
begin
ListHelper.Sort<T>(TuList<T>(self), aComparer);
end;
procedure TuVList<T>.StableSort(aComparer: IComparer<T>);
var
CastData: TArray<T>;
begin
TrimExcess;
CastData := TArray<T>(FData);
// MergeSort.Sort<T>(CastData, aComparer);
end;
procedure TuVList<T>.Sort;
begin
ListHelper.Sort<T>(TuList<T>(self), FComparer);
end;
function TuVList<T>.ToArray: TArray<T>;
var
i: integer;
begin
Result := nil;
SetLength(Result, FCount);
for i := 0 to FCount - 1 do Result[i] := T(FData[i]);
end;
{ ListHelper }
class function ListHelper.BinarySearch<T>(const List: TuList<T>; const Item: T): Integer;
begin
Result := BinarySearch<T>(List, Item, TComparer<T>.Default);
end;
class function ListHelper.BinarySearch<T>(const List: TuList<T>; const Item: T;
AComparer: IComparer<T>): SizeInt;
var
b: boolean;
begin
if AComparer = nil then AComparer := TComparer<T>.Default;
b := {$IFDEF FPC}TArrayHelper<T>.BinarySearch{$ELSE}TArray.BinarySearch<T>{$ENDIF}(List.FData, Item, Result, AComparer, 0, List.Count);
if not b then Result := not Result;
end;
class procedure ListHelper.Delete<T>(const List: TuList<T>;
const index: integer);
begin
if (index > List.Count) or (index < 0) then RaiseArgEx;
{$IFDEF FPC}
List[index] := Default(T); //clear strings or interfaces.
{$ELSE}
{$if (CompilerVersion = 33.0) and (Defined(MACOS32) or Defined(IOS))} //see https://quality.embarcadero.com/browse/RSB-2792 We don't do it for the future since it should be fixed after RIO (and likely in a RIO ServicePack.)
Finalize(List.FData[Index]);
{$else}
List[index] := Default(T); //clear strings or interfaces.
{$ifend}
{$ENDIF}
if index + 1 < List.Count then
begin
Move(List.FData[index + 1], List.FData[index], SizeOf(T) * (List.Count - (index + 1)));
FillChar(List.FData[List.FCount - 1], SizeOf(T), 0); //avoid having those records finalized
end;
dec(List.FCount);
end;
class procedure ListHelper.DeleteRange<T>(const List: TuList<T>; const index,
dCount: integer);
var
i: integer;
remaining, ToClean: integer;
begin
if dCount = 0 then exit;
if (index > List.Count) or (index < 0) or (dCount < 0) or (dCount + index > List.Count) then RaiseArgEx;
for i := 0 to dCount - 1 do List[index + i] := Default(T); //clear strings or interfaces.
if index + dCount < List.Count then
begin
remaining := List.Count - (index + dcount);
Move(List.FData[index + dCount], List.FData[index], SizeOf(T) * remaining);
ToClean := remaining; if ToClean > dCount then ToClean := dCount;
FillChar(List.FData[List.FCount - ToClean], ToClean * SizeOf(T), 0); //avoid having those records finalized
end;
dec(List.FCount, dCount);
end;
class procedure ListHelper.Insert<T>(const List: TuList<T>;
const index: integer; const Item: T);
begin
if (index > List.Count) or (index < 0) then RaiseArgEx;
if List.Count >= Length(List.FData) then
begin
SetLength(List.FData, GetNextCapacity(List.FCount));
end;
if index < List.Count then
begin
Move(List.FData[index], List.FData[index + 1], SizeOf(T) * (List.Count - index));
FillChar(List.FData[index], SizeOf(T), 0); //avoid having those records finalized
end;
List.FData[index] := item;
inc(List.FCount);
end;
class procedure ListHelper.InsertRange<T>(const List: TuList<T>;
const index: integer; const Items: TArray<T>);
var
i: integer;
begin
if Length(Items) = 0 then exit;
if (index > List.Count) or (index < 0) then RaiseArgEx;
if List.Count + Length(Items) > Length(List.FData) then
begin
SetLength(List.FData, GetNextCapacity(List.FCount + Length(Items)));
end;
if index < List.Count then
begin
Move(List.FData[index], List.FData[index + Length(Items)], SizeOf(T) * (List.Count - index));
FillChar(List.FData[index], Length(Items) * SizeOf(T), 0); //avoid having those records finalized
end;
for i := 0 to Length(Items) - 1 do List.FData[index + i] := Items[i];
inc(List.FCount, Length(Items));
end;
class procedure ListHelper.AddManyInts(const List: TuList<UInt32>; const obj: UInt32; const aCount: Int32);
begin
if (aCount <= 0) then exit;
if List.Count + aCount > Length(List.FData) then
begin
SetLength(List.FData, GetNextCapacity(List.FCount + aCount));
end;
FillDWord(List.FData[List.Count], aCount, Obj);
inc(List.FCount, aCount);
end;
class procedure ListHelper.AddArrayByte(const List: TuList<UInt32>; const Source: TArray<Byte>; const aCount: Int32);
begin
if (aCount <= 0) then exit;
if List.Count + aCount > Length(List.FData) then
begin
SetLength(List.FData, GetNextCapacity(List.FCount + aCount));
end;
System.Move(Source[0], List.FData[List.Count], aCount * SizeOf(UInt32));
inc(List.FCount, aCount);
end;
class procedure ListHelper.Remove<T>(const List: TuList<T>; const obj: T; AComparer: IComparer<T>);
var
i: Integer;
begin
if (AComparer = nil) then AComparer := TComparer<T>.Default;
for i := 0 to List.Count - 1 do
begin
if AComparer.Compare(List[i], obj) = 0 then
begin
Delete<T>(List, i);
exit;
end;
end;
end;
class procedure ListHelper.Reverse<T>(const List: TuList<T>);
var
i, k: integer;
Tmp: T;
begin
k := List.Count - 1;
for i := 0 to (List.Count div 2) - 1 do
begin
Tmp := List[i];
List[i] := List[k];
List[k] := Tmp;
dec(k);
end;
end;
class procedure ListHelper.Sort<T>(const List: TuList<T>;
AComparer: IComparer<T>);
begin
if AComparer = nil then AComparer := TComparer<T>.Default;
{$IFDEF FPC}TArrayHelper<T>.Sort{$ELSE}TArray.Sort<T>{$ENDIF}(List.FData, AComparer, 0, List.Count);
end;
class procedure ListHelper.Sort<T>(const List: TuList<T>);
begin
{$IFDEF FPC}TArrayHelper<T>.Sort{$ELSE}TArray.Sort<T>{$ENDIF}(List.FData, TComparer<T>.Default, 0, List.Count);
end;
class procedure ListHelper.StableSort<T>(const List: TuList<T>;
AComparer: IComparer<T>);
begin
if AComparer = nil then AComparer := TComparer<T>.Default;
List.TrimExcess;
// MergeSort.Sort<T>(List.FData, AComparer);
end;
class function ListHelper.ToArray<T>(const List: TuList<T>): TArray<T>;
var
i: Integer;
begin
SetLength(Result, List.Count);
for i := 0 to Length(Result) - 1 do
begin
Result[i] := List[i];
end;
end;
{ TuObjectList }
procedure TuObjectList.Clear;
var
i: integer;
begin
if not DontFree then for i := 0 to FCount - 1 do TrueFree(FData[i]);
inherited;
end;
constructor TuObjectList.Create(const aCapacity: integer;
const OwnsObjects: boolean);
begin
inherited Create;
SetLength(FData, aCapacity);
DontFree := not OwnsObjects;
end;
procedure TuObjectList.Delete(Index: Integer);
begin
if not DontFree then TrueFree(Self[Index]);
ListHelper.Delete<TObject>(self, Index);
end;
procedure TuObjectList.DeleteAndNotFree(Index: Integer);
begin
ListHelper.Delete<TObject>(self, Index);
end;
procedure TuObjectList.RemoveRange(Index, Count: Integer);
var
i: integer;
begin
if not DontFree then for i := Index to Index + Count - 1 do TrueFree(Self[i]);
ListHelper.DeleteRange<TObject>(self, Index, Count);
end;
destructor TuObjectList.Destroy;
begin
if not DontFree then Clear;
inherited;
end;
function TuObjectList.IndexOfPointer(const Value: TObject): Integer;
var
i: Integer;
begin
for i := 0 to Count - 1 do
if Items[i] = Value then
Exit(i);
Result := -1;
end;
procedure TuObjectList.Insert(Index: Integer; const Value: TObject);
begin
ListHelper.Insert<TObject>(self, Index, Value);
end;
procedure TuObjectList.RemovePointer(const obj: TObject);
var
i: integer;
begin
i := IndexOfPointer(obj);
if i >= 0 then Delete(i);
end;
procedure TuObjectList.SetButDontDestroy(const i: integer; const r: TObject);
begin
SetItem(i, r);
end;
procedure TuObjectList.SetCount(const a: integer);
begin
FCount := a;
Capacity := a;
end;
{ TuVListEnumerator<T> }
{$ifdef blubb}
constructor TuVListEnumerator<T>.Create(const aList: TObject);
begin
inherited Create;
FList := aList;
Position := -1;
end;
function TuVListEnumerator<T>.DoGetCurrent: T;
begin
Result := TuList<T>(FList)[Position];
end;
function TuVListEnumerator<T>.DoMoveNext: Boolean;
begin
if Position >= (TuList<T>(FList)).Count then exit(false);
inc(Position);
Result := Position < (TuList<T>(FList)).Count;
end;
{ TuStack<T> }
procedure TuStack<T>.Clear;
begin
FData := nil;
FCount := 0;
end;
function TuStack<T>.Count: integer;
begin
Result := FCount;
end;
function TuStack<T>.Peek: T;
begin
if (FCount <= 0) then RaiseArgEx;
Result := FData[FCount - 1];
end;
function TuStack<T>.Pop: T;
begin
if (FCount <= 0) then RaiseArgEx;
dec(FCount);
Result := FData[FCount];
FData[FCount] := Default(T);
end;
procedure TuStack<T>.Push(const v: T);
begin
if FCount >= Length(FData) then
begin
SetLength(FData, GetNextCapacity(FCount));
end;
FData[FCount] := v;
inc(FCount);
end;
{ TuStack<T> }
procedure TuOStack<T>.Clear;
begin
FData := nil;
FCount := 0;
end;
function TuOStack<T>.Count: integer;
begin
Result := FCount;
end;
function TuOStack<T>.Peek: T;
begin
if (FCount <= 0) then RaiseArgEx;
Result := FData[FCount - 1];
end;
procedure TuOStack<T>.Pop;
begin
if (FCount <= 0) then RaiseArgEx;
dec(FCount);
TrueFree(FData[Count]);
FData[FCount] := Default(T);
end;
procedure TuOStack<T>.Push(const v: T);
begin
if FCount >= Length(FData) then
begin
SetLength(FData, GetNextCapacity(FCount));
end;
FData[FCount] := v;
inc(FCount);
end;
{ TuSortedList<K, V> }
constructor TuSortedList<K, V>.Create;
begin
Create(TComparer<K>.Default);
end;
constructor TuSortedList<K, V>.Create(const aComparer: IComparer<K>);
begin
List := TuList<TPairKV>.Create;
FComparer := aComparer;
end;
destructor TuSortedList<K, V>.Destroy;
begin
FreeObj(List);
inherited;
end;
procedure TuSortedList<K, V>.Add(const key: K; const value: V);
var
index: integer;
begin
index := IndexOfKey(key);
if index >= 0 then RaiseArgEx;
index := not index;
ListHelper.Insert<TPairKV>(List, index, TPairKV.Create(key, value));
end;
procedure TuSortedList<K, V>.Remove(const key: K);
var
index: integer;
begin
index := IndexOfKey(key);
if index < 0 then RaiseArgEx;
ListHelper.Delete<TPairKV>(List, index);
end;
function TuSortedList<K, V>.IndexOfKey(const key: K): integer;
//begin
// fails in android /iosdevice XE6 Result := ListHelper.BinarySearch<TPairKV>(List, TPairKV.Create(key, Default(V)), TKeyComparer<K, V>.Create);
var
L, H: Integer;
mid, cmp: Integer;
found: boolean;
begin
found := false;
if Count = 0 then exit(not 0);
L := 0;
H := Count - 1;
while L <= H do
begin
mid := L + (H - L) shr 1;
cmp := FComparer.Compare(List[mid].Key, key);
if cmp < 0 then
L := mid + 1
else
begin
H := mid - 1;
if cmp = 0 then
begin
found := true;
end;
end;
end;
Result := L;
if (not found) then Result := not Result;
end;
function TuSortedList<K, V>.GetItems(const key: K): V;
begin
Result := List[IndexOfKey(key)].Value;
end;
function TuSortedList<K, V>.Keys(const index: integer): K;
begin
Result := List[index].Key;
end;
procedure TuSortedList<K, V>.SetItems(const key: K; const value: V);
var
index: integer;
begin
index := IndexOfKey(key);
if (index >= 0) then List[index] := TPairKV.Create(key, value)
else Add(key, value);
end;
function TuSortedList<K, V>.TryGetValue(const key: K; out value: V): boolean;
var
i: integer;
begin
i := IndexOfKey(key);
if (i < 0) then
begin
value := Default(V);
exit(false);
end;
value := List[i].Value;
Result := true;
end;
function TuSortedList<K, V>.Values(const index: integer): V;
begin
Result := List[index].Value;
end;
function TuSortedList<K, V>.ContainsKey(const key: K): boolean;
begin
Result := IndexOfKey(key) >= 0;
end;
function TuSortedList<K, V>.Count: integer;
begin
Result := List.Count;
end;
{$endif}
(*
{ TKeyComparer<K, V> }
function TKeyComparer<K, V>.Compare(const Left, Right: TPairKV): Integer;
begin
Result := TComparer<K>.Default.Compare(Left.Key, Right.Key);
end;*)
end.