mirror of
https://gitlab.com/freepascal.org/fpc/pas2js.git
synced 2025-04-05 00:47:47 +02:00
* Dictionary start
This commit is contained in:
parent
25cd4a3287
commit
8bf4930531
@ -6,7 +6,7 @@ unit Generics.Collections;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,
|
||||
Classes, SysUtils, rtlconsts, Types,
|
||||
{$IFDEF Pas2js}JS,{$ENDIF}
|
||||
Generics.Strings, Generics.Defaults;
|
||||
|
||||
@ -198,6 +198,151 @@ type
|
||||
property Items[Index: SizeInt]: T read GetItem write SetItem; default;
|
||||
end;
|
||||
|
||||
{ TPair }
|
||||
|
||||
TPair<TKey,TValue> = record
|
||||
Key: TKey;
|
||||
Value: TValue;
|
||||
constructor Create(const AKey: TKey; const AValue: TValue);
|
||||
end;
|
||||
|
||||
// Hash table using linear probing
|
||||
|
||||
{ TDictionary }
|
||||
EDictionary = Class(Exception);
|
||||
|
||||
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
|
||||
private
|
||||
FMap: TJSMap;
|
||||
function GetItem(const Key: TKey): TValue;
|
||||
procedure SetItem(const Key: TKey; const Value: TValue);
|
||||
procedure DoAdd(const Key: TKey; const Value: TValue);
|
||||
function DoRemove(const Key: TKey; Notification: TCollectionNotification): TValue;
|
||||
Function GetCount : Integer;
|
||||
protected
|
||||
function DoGetEnumerator: TEnumerator<TPair<TKey,TValue>>; override;
|
||||
procedure PairNotify(const Key: TKey; Value : TValue; Action: TCollectionNotification); virtual;
|
||||
procedure KeyNotify(const Key: TKey; Action: TCollectionNotification); virtual;
|
||||
procedure ValueNotify(const Value: TValue; Action: TCollectionNotification); virtual;
|
||||
public
|
||||
Type
|
||||
TMyType = TDictionary<TKey,TValue>;
|
||||
TMyPair = TPair<TKey,TValue>;
|
||||
|
||||
constructor Create(ACapacity: Integer); overload;
|
||||
constructor Create2(const Collection: TEnumerable<TMyPair>); overload;
|
||||
destructor Destroy; override;
|
||||
|
||||
procedure Add(const Key: TKey; const Value: TValue);
|
||||
procedure Remove(const Key: TKey);
|
||||
function ExtractPair(const Key: TKey): TMyPair;
|
||||
procedure Clear;
|
||||
function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
|
||||
procedure AddOrSetValue(const Key: TKey; const Value: TValue);
|
||||
function ContainsKey(const Key: TKey): Boolean;
|
||||
function ContainsValue(const Value: TValue): Boolean;
|
||||
function ToArray: TArray<TMyPair>; override;
|
||||
|
||||
property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
|
||||
property Count: Integer read GetCount;
|
||||
|
||||
type
|
||||
{ TPairEnumerator }
|
||||
|
||||
TPairEnumerator = class(TEnumerator<TMyPair>)
|
||||
private
|
||||
FIter: TJSIterator;
|
||||
FVal : TJSIteratorValue;
|
||||
function GetCurrent: TMyPair;
|
||||
protected
|
||||
function DoGetCurrent: TMyPair; override;
|
||||
function DoMoveNext: Boolean; override;
|
||||
public
|
||||
constructor Create(const ADictionary: TMyType);
|
||||
function MoveNext: Boolean; reintroduce;
|
||||
property Current: TMyPair read GetCurrent;
|
||||
end;
|
||||
|
||||
{ TKeyEnumerator }
|
||||
|
||||
TKeyEnumerator = class(TEnumerator<TKey>)
|
||||
private
|
||||
FIter: TJSIterator;
|
||||
FVal : TJSIteratorValue;
|
||||
function GetCurrent: TKey;
|
||||
protected
|
||||
function DoGetCurrent: TKey; override;
|
||||
function DoMoveNext: Boolean; override;
|
||||
public
|
||||
constructor Create(const AIter: TJSIterator); overload;
|
||||
constructor Create(const ADictionary: TMyType); overload;
|
||||
function MoveNext: Boolean; reintroduce;
|
||||
property Current: TKey read GetCurrent;
|
||||
end;
|
||||
|
||||
{ TValueEnumerator }
|
||||
|
||||
TValueEnumerator = class(TEnumerator<TValue>)
|
||||
private
|
||||
FIter: TJSIterator;
|
||||
FVal : TJSIteratorValue;
|
||||
function GetCurrent: TValue;
|
||||
protected
|
||||
function DoGetCurrent: TValue; override;
|
||||
function DoMoveNext: Boolean; override;
|
||||
public
|
||||
constructor Create(const AIter: TJSIterator); overload;
|
||||
constructor Create(const ADictionary: TMyType); overload;
|
||||
function MoveNext: Boolean; reintroduce;
|
||||
property Current: TValue read GetCurrent;
|
||||
end;
|
||||
|
||||
{ TValueCollection }
|
||||
|
||||
TValueCollection = class(TEnumerable<TValue>)
|
||||
private
|
||||
FMap: TJSMap;
|
||||
function GetCount: Integer;
|
||||
protected
|
||||
function DoGetEnumerator: TEnumerator<TValue>; override;
|
||||
public
|
||||
constructor Create(const ADictionary: TMyType);
|
||||
function GetEnumerator: TValueEnumerator; reintroduce;
|
||||
function ToArray: TArray<TValue>; override;
|
||||
property Count: Integer read GetCount;
|
||||
end;
|
||||
|
||||
{ TKeyCollection }
|
||||
|
||||
TKeyCollection = class(TEnumerable<TKey>)
|
||||
private
|
||||
FMap: TJSMap;
|
||||
function GetCount: Integer;
|
||||
protected
|
||||
function DoGetEnumerator: TEnumerator<TKey>; override;
|
||||
public
|
||||
constructor Create(const ADictionary: TMyType);
|
||||
function GetEnumerator: TKeyEnumerator; reintroduce;
|
||||
function ToArray: TArray<TKey>; override;
|
||||
property Count: Integer read GetCount;
|
||||
end;
|
||||
|
||||
private
|
||||
FOnKeyNotify: TCollectionNotifyEvent<TKey>;
|
||||
FOnValueNotify: TCollectionNotifyEvent<TValue>;
|
||||
FKeyCollection: TKeyCollection;
|
||||
FValueCollection: TValueCollection;
|
||||
function GetKeys: TKeyCollection;
|
||||
function GetValues: TValueCollection;
|
||||
public
|
||||
function GetEnumerator: TPairEnumerator; reintroduce;
|
||||
property Keys: TKeyCollection read GetKeys;
|
||||
property Values: TValueCollection read GetValues;
|
||||
property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify;
|
||||
property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{ TCustomArrayHelper }
|
||||
@ -864,4 +1009,384 @@ begin
|
||||
Result := TMyArrayHelper.BinarySearch(FItems, AItem, AIndex, AComparer, 0, Count);
|
||||
end;
|
||||
|
||||
{ TPair }
|
||||
|
||||
constructor TPair<TKey,TValue>.Create(const AKey: TKey; const AValue: TValue);
|
||||
begin
|
||||
Key:=aKey;
|
||||
Value:=aValue;
|
||||
end;
|
||||
|
||||
{ TDictionary }
|
||||
|
||||
ResourceString
|
||||
SErrDictKeyNotFound = 'Key value not found';
|
||||
SErrDictDuplicateKey = 'Duplicate key value';
|
||||
|
||||
function TDictionary<TKey, TValue>.GetItem(const Key: TKey): TValue;
|
||||
|
||||
Var
|
||||
V : JSValue;
|
||||
|
||||
begin
|
||||
V:=FMap.Get(Key);
|
||||
if isUndefined(v) then
|
||||
Raise EDictionary.Create(SErrDictKeyNotFound);
|
||||
Result:=TValue(V);
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.SetItem(const Key: TKey; const Value: TValue);
|
||||
|
||||
Var
|
||||
V : JSValue;
|
||||
|
||||
begin
|
||||
V:=FMap.Get(Key);
|
||||
if isUndefined(v) then
|
||||
ValueNotify(TValue(V),cnRemoved);
|
||||
FMap.&Set(Key,Value);
|
||||
ValueNotify(Value, cnAdded);
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.DoAdd(const Key: TKey; const Value: TValue);
|
||||
begin
|
||||
FMap.&Set(Key,Value);
|
||||
KeyNotify(Key,cnAdded);
|
||||
ValueNotify(Value,cnAdded);
|
||||
end;
|
||||
|
||||
|
||||
function TDictionary<TKey, TValue>.DoRemove(const Key: TKey; Notification: TCollectionNotification): TValue;
|
||||
Var
|
||||
V : JSValue;
|
||||
|
||||
begin
|
||||
V:=FMap.Get(Key);
|
||||
if Not isUndefined(v) then
|
||||
begin
|
||||
FMap.Delete(Key);
|
||||
Result:=TValue(v);
|
||||
KeyNotify(Key,Notification);
|
||||
ValueNotify(Result,Notification);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.GetCount: Integer;
|
||||
begin
|
||||
Result:=FMap.Size;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.DoGetEnumerator: TEnumerator<TMyPair>;
|
||||
begin
|
||||
Result:=TPairEnumerator.Create(Self);
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.PairNotify(const Key: TKey; Value : TValue; Action: TCollectionNotification);
|
||||
|
||||
begin
|
||||
KeyNotify(Key,action);
|
||||
ValueNotify(Value,action);
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.KeyNotify(const Key: TKey; Action: TCollectionNotification);
|
||||
begin
|
||||
if Assigned(FOnKeyNotify) then
|
||||
FOnKeyNotify(Self,Key,Action);
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.ValueNotify(const Value: TValue; Action: TCollectionNotification);
|
||||
begin
|
||||
if Assigned(FOnValueNotify) then
|
||||
FOnValueNotify(Self,Value,Action);
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.Create(ACapacity: Integer = 0);
|
||||
begin
|
||||
|
||||
FMap:=TJSMap.New;
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.Create2(const Collection: TEnumerable<TMyPair>);
|
||||
|
||||
Var
|
||||
aPair : TMyPair;
|
||||
|
||||
begin
|
||||
Create(0);
|
||||
For aPair in Collection do
|
||||
Add(aPair.Key,aPair.Value);
|
||||
end;
|
||||
|
||||
destructor TDictionary<TKey, TValue>.Destroy;
|
||||
begin
|
||||
FreeAndNil(FKeyCollection);
|
||||
FreeAndNil(FValueCollection);
|
||||
Clear;
|
||||
FMap:=Nil;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.Add(const Key: TKey; const Value: TValue);
|
||||
begin
|
||||
if FMap.Has(Key) then
|
||||
Raise EDictionary.Create(SErrDictDuplicateKey);
|
||||
DoAdd(Key,Value);
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.Remove(const Key: TKey);
|
||||
begin
|
||||
doRemove(Key,cnRemoved);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.ExtractPair(const Key: TKey): TMyPair;
|
||||
|
||||
begin
|
||||
if FMap.Has(Key) then
|
||||
begin
|
||||
Result.Create(Key,TValue(FMap.get(key)));
|
||||
FMap.Delete(Key);
|
||||
end
|
||||
else
|
||||
Result.Create(Key,Default(TValue));
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.Clear;
|
||||
begin
|
||||
FMap.Clear;
|
||||
end;
|
||||
|
||||
|
||||
function TDictionary<TKey, TValue>.TryGetValue(const Key: TKey; out Value: TValue): Boolean;
|
||||
begin
|
||||
Result:=FMap.Has(Key);
|
||||
If Result then
|
||||
Value:=TValue(FMap.get(Key));
|
||||
end;
|
||||
|
||||
procedure TDictionary<TKey, TValue>.AddOrSetValue(const Key: TKey; const Value: TValue);
|
||||
begin
|
||||
if Not FMap.Has(Key) then
|
||||
DoAdd(Key,Value)
|
||||
else
|
||||
SetItem(Key,Value);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.ContainsKey(const Key: TKey): Boolean;
|
||||
begin
|
||||
Result:=FMap.Has(Key);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.ContainsValue(const Value: TValue): Boolean;
|
||||
|
||||
Var
|
||||
It : TJSIterator;
|
||||
Res : TJSIteratorValue;
|
||||
|
||||
begin
|
||||
Result:=False;
|
||||
It:=FMap.Values;
|
||||
Repeat
|
||||
Res:=It.next;
|
||||
if not Res.done then
|
||||
Result:=(Value=TValue(Res.value));
|
||||
Until (Result or Res.done);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.ToArray: TArray<TMyPair>;
|
||||
begin
|
||||
Result:=inherited ToArray;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.GetKeys: TKeyCollection;
|
||||
begin
|
||||
if FKeyCollection=Nil then
|
||||
FKeyCollection:=TKeyCollection.Create(Self);
|
||||
Result:=FKeyCollection;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.GetValues: TValueCollection;
|
||||
begin
|
||||
if FValueCollection=Nil then
|
||||
FValueCollection:=TValueCollection.Create(Self);
|
||||
Result:=FValueCollection;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.GetEnumerator: TPairEnumerator;
|
||||
begin
|
||||
Result:=TPairEnumerator.Create(Self);
|
||||
end;
|
||||
|
||||
{ TDictionary.TPairEnumerator }
|
||||
|
||||
function TDictionary<TKey, TValue>.TPairEnumerator.GetCurrent: TMyPair;
|
||||
begin
|
||||
Result:=DoGetCurrent;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TPairEnumerator.DoGetCurrent: TMyPair;
|
||||
|
||||
Var
|
||||
A : TJSValueDynArray;
|
||||
|
||||
begin
|
||||
A:=TJSValueDynArray(FVal.Value);
|
||||
Result.Create(TKey(A[0]),TValue(A[1]));
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TPairEnumerator.DoMoveNext: Boolean;
|
||||
begin
|
||||
FIter.Next;
|
||||
Result:=Not FVal.Done;
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.TPairEnumerator.Create(const ADictionary: TMyType);
|
||||
begin
|
||||
FIter:=ADictionary.FMap.Entries;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TPairEnumerator.MoveNext: Boolean;
|
||||
begin
|
||||
Result:=DoMoveNext;
|
||||
end;
|
||||
|
||||
{ TDictionary.TKeyEnumerator }
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyEnumerator.GetCurrent: TKey;
|
||||
begin
|
||||
Result:=DoGetCurrent;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyEnumerator.DoGetCurrent: TKey;
|
||||
begin
|
||||
Result:=TKey(FVal.Value);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyEnumerator.DoMoveNext: Boolean;
|
||||
begin
|
||||
FIter.Next;
|
||||
Result:=Not FVal.Done;
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.TKeyEnumerator.Create(const ADictionary: TMyType);
|
||||
begin
|
||||
Create(ADictionary.FMap.Keys);
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.TKeyEnumerator.Create(const AIter : TJSIterator);
|
||||
begin
|
||||
FIter:=aIter;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyEnumerator.MoveNext: Boolean;
|
||||
begin
|
||||
Result:=DoMoveNext;
|
||||
end;
|
||||
|
||||
{ TDictionary.TValueEnumerator }
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueEnumerator.GetCurrent: TValue;
|
||||
begin
|
||||
Result:=DoGetCurrent;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueEnumerator.DoGetCurrent: TValue;
|
||||
begin
|
||||
Result:=TValue(FVal.Value);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueEnumerator.DoMoveNext: Boolean;
|
||||
begin
|
||||
FIter.Next;
|
||||
Result:=Not FVal.Done;
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.TValueEnumerator.Create(const ADictionary: TMyType);
|
||||
begin
|
||||
Create(aDictionary.FMap.Values);
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.TValueEnumerator.Create(const AIter: TJSIterator);
|
||||
begin
|
||||
FIter:=AIter;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueEnumerator.MoveNext: Boolean;
|
||||
begin
|
||||
Result:=DoMoveNext;
|
||||
end;
|
||||
|
||||
{ TDictionary.TValueCollection }
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueCollection.GetCount: Integer;
|
||||
begin
|
||||
Result:=FMap.Size;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueCollection.DoGetEnumerator: TEnumerator<TValue>;
|
||||
begin
|
||||
Result:=TValueEnumerator.Create(FMap.Values);
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.TValueCollection.Create(const ADictionary: TMyType);
|
||||
begin
|
||||
FMap:=ADictionary.FMap;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueCollection.GetEnumerator: TValueEnumerator;
|
||||
begin
|
||||
Result:=TValueEnumerator(DoGetEnumerator);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TValueCollection.ToArray: TArray<TValue>;
|
||||
|
||||
Var
|
||||
I : Integer;
|
||||
P : TValue;
|
||||
|
||||
begin
|
||||
SetLength(Result,FMap.Size);
|
||||
For P in Self do
|
||||
begin
|
||||
Result[i]:=P;
|
||||
Inc(I);
|
||||
End;
|
||||
end;
|
||||
|
||||
{ TDictionary.TKeyCollection }
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyCollection.GetCount: Integer;
|
||||
begin
|
||||
Result:=FMap.Size;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyCollection.DoGetEnumerator: TEnumerator<TKey>;
|
||||
begin
|
||||
Result:=GetEnumerator;
|
||||
end;
|
||||
|
||||
constructor TDictionary<TKey, TValue>.TKeyCollection.Create(const ADictionary: TMyType);
|
||||
begin
|
||||
FMap:=aDictionary.FMap;
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyCollection.GetEnumerator: TKeyEnumerator;
|
||||
begin
|
||||
Result:=TKeyEnumerator.Create(FMap.Keys);
|
||||
end;
|
||||
|
||||
function TDictionary<TKey, TValue>.TKeyCollection.ToArray: TArray<TKey>;
|
||||
begin
|
||||
Result:=inherited ToArray;
|
||||
end;
|
||||
|
||||
Type
|
||||
TMyDict = TDictionary<integer,string>;
|
||||
|
||||
Var
|
||||
MyDict : TMyDict;
|
||||
|
||||
begin
|
||||
MyDict:=TMyDict.Create;
|
||||
MyDict.Add(1,'aloga');
|
||||
MyDict.Free;
|
||||
end.
|
||||
|
@ -58,7 +58,7 @@ procedure TTestArrayHelper.CheckBinarySearch(constref AArray: TArray<Integer>;
|
||||
|
||||
begin
|
||||
CheckEquals(AExpectedResult,
|
||||
TArrayHelper<Integer>.BinarySearch(AArray,AValue,ASearchResult,aComparer),
|
||||
TArrayHelper<Integer>.BinarySearch(AArray,AValue,ASearchResult,aComparer,0,Length(AArray)),
|
||||
'Wrong BinarySearch result for ' + AValue.ToString);
|
||||
end;
|
||||
|
||||
|
202
test/tcgenericdictionary.pp
Normal file
202
test/tcgenericdictionary.pp
Normal file
@ -0,0 +1,202 @@
|
||||
unit tcgenericdictionary;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
fpcunit, testregistry, Classes, SysUtils, Generics.Defaults, Generics.Collections;
|
||||
|
||||
Type
|
||||
TMySimpleDict = Class(Specialize TDictionary<Integer,String>);
|
||||
|
||||
{ TTestSimpleDictionary }
|
||||
|
||||
TTestSimpleDictionary = Class(TTestCase)
|
||||
Private
|
||||
FDict : TMySimpleDict;
|
||||
procedure DoAdd(aCount: Integer; aOffset: Integer=0);
|
||||
procedure DoAdd2;
|
||||
procedure DoGetValue(aKey: Integer; Match: String; ExceptionClass: TClass=nil);
|
||||
Public
|
||||
Procedure SetUp; override;
|
||||
Procedure TearDown; override;
|
||||
Property Dict : TMySimpleDict Read FDict;
|
||||
Published
|
||||
Procedure TestEmpty;
|
||||
Procedure TestAdd;
|
||||
Procedure TestClear;
|
||||
Procedure TestTryGetValue;
|
||||
Procedure TestGetValue;
|
||||
Procedure TestSetValue;
|
||||
Procedure TestAddDuplicate;
|
||||
Procedure TestAddOrSet;
|
||||
Procedure TestContainsKey;
|
||||
Procedure TestDelete;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TTestSimpleDictionary }
|
||||
|
||||
procedure TTestSimpleDictionary.SetUp;
|
||||
begin
|
||||
inherited SetUp;
|
||||
FDict:=TMySimpleDict.Create;
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TearDown;
|
||||
begin
|
||||
FreeAndNil(FDict);
|
||||
inherited TearDown;
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestEmpty;
|
||||
begin
|
||||
AssertNotNull('Have dictionary',Dict);
|
||||
AssertEquals('empty dictionary',0,Dict.Count);
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.DoAdd(aCount : Integer; aOffset : Integer=0);
|
||||
|
||||
Var
|
||||
I : Integer;
|
||||
|
||||
begin
|
||||
if aOffset=-1 then
|
||||
aOffset:=Dict.Count;
|
||||
For I:=aOffset+1 to aOffset+aCount do
|
||||
Dict.Add(I,IntToStr(i));
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestAdd;
|
||||
|
||||
begin
|
||||
DoAdd(1);
|
||||
AssertEquals('Count OK',1,Dict.Count);
|
||||
AssertTrue('Has added value',Dict.ContainsKey(1));
|
||||
DoAdd(1,1);
|
||||
AssertEquals('Count OK',2,Dict.Count);
|
||||
AssertTrue('Has added value',Dict.ContainsKey(2));
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestClear;
|
||||
begin
|
||||
DoAdd(3);
|
||||
AssertEquals('Count OK',3,Dict.Count);
|
||||
Dict.Clear;
|
||||
AssertEquals('Count after clear OK',0,Dict.Count);
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestTryGetValue;
|
||||
|
||||
Var
|
||||
I : integer;
|
||||
SI,A : string;
|
||||
|
||||
begin
|
||||
DoAdd(3);
|
||||
For I:=1 to 3 do
|
||||
begin
|
||||
SI:=IntToStr(I);
|
||||
AssertTrue('Have value '+SI,Dict.TryGetValue(I,A));
|
||||
AssertEquals('Value is correct '+SI,SI,A);
|
||||
end;
|
||||
AssertFalse('Have no value 4',Dict.TryGetValue(4,A));
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.DoGetValue(aKey: Integer; Match: String; ExceptionClass: TClass);
|
||||
|
||||
Var
|
||||
EC : TClass;
|
||||
A,EM : String;
|
||||
|
||||
begin
|
||||
EC:=Nil;
|
||||
try
|
||||
A:=Dict.Items[aKey];
|
||||
except
|
||||
On E : Exception do
|
||||
begin
|
||||
EC:=E.ClassType;
|
||||
EM:=E.Message;
|
||||
end
|
||||
end;
|
||||
if ExceptionClass=Nil then
|
||||
begin
|
||||
if EC<>Nil then
|
||||
Fail('Got exception '+EC.ClassName+' with message: '+EM);
|
||||
AssertEquals('Value is correct for '+IntToStr(aKey),Match,A)
|
||||
end
|
||||
else
|
||||
begin
|
||||
if EC=Nil then
|
||||
Fail('Expected exception '+ExceptionClass.ClassName+' but got none');
|
||||
if EC<>ExceptionClass then
|
||||
Fail('Expected exception class '+ExceptionClass.ClassName+' but got '+EC.ClassName+' with message '+EM);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestGetValue;
|
||||
|
||||
Var
|
||||
I : integer;
|
||||
|
||||
begin
|
||||
DoAdd(3);
|
||||
For I:=1 to 3 do
|
||||
DoGetValue(I,IntToStr(I));
|
||||
DoGetValue(4,'4',EDictionary);
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestSetValue;
|
||||
begin
|
||||
TestGetValue;
|
||||
Dict.Items[3]:='Six';
|
||||
DoGetValue(3,'Six');
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.DoAdd2;
|
||||
|
||||
begin
|
||||
Dict.Add(2,'A new 2');
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestAddDuplicate;
|
||||
begin
|
||||
DoAdd(3);
|
||||
AssertException('Cannot add duplicate',EDictionary,@DoAdd2);
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestAddOrSet;
|
||||
|
||||
begin
|
||||
DoAdd(3);
|
||||
Dict.AddOrSetValue(2,'a new 2');
|
||||
DoGetValue(2,'a new 2');
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestContainsKey;
|
||||
|
||||
Var
|
||||
I : Integer;
|
||||
|
||||
begin
|
||||
DoAdd(3);
|
||||
For I:=1 to 3 do
|
||||
AssertTrue('Has '+IntToStr(i),Dict.ContainsKey(I));
|
||||
AssertFalse('Has not 4',Dict.ContainsKey(4));
|
||||
end;
|
||||
|
||||
procedure TTestSimpleDictionary.TestDelete;
|
||||
begin
|
||||
DoAdd(3);
|
||||
Dict.Remove(2);
|
||||
AssertEquals('Count',2,Dict.Count);
|
||||
AssertFalse('Has not 2',Dict.ContainsKey(2));
|
||||
end;
|
||||
|
||||
begin
|
||||
RegisterTest(TTestSimpleDictionary);
|
||||
end.
|
||||
|
@ -76,6 +76,10 @@
|
||||
<Filename Value="tcgenarrayhelper.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="tcgenericdictionary.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
@ -95,6 +99,9 @@
|
||||
</Parsing>
|
||||
<CodeGeneration>
|
||||
<TargetOS Value="browser"/>
|
||||
<Optimizations>
|
||||
<OptimizationLevel Value="0"/>
|
||||
</Optimizations>
|
||||
</CodeGeneration>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
@ -103,7 +110,7 @@
|
||||
</Debugging>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc"/>
|
||||
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -O-"/>
|
||||
<CompilerPath Value="$(pas2js)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
|
@ -27,14 +27,16 @@ program testrtl;
|
||||
uses
|
||||
browserconsole, consoletestrunner, frmrtlrun,
|
||||
// tcstream, tccompstreaming, simplelinkedlist, tcsyshelpers
|
||||
tcgenarrayhelper,
|
||||
// tcgenarrayhelper,
|
||||
// tcstringhelp
|
||||
strutils;
|
||||
tcgenericdictionary,
|
||||
strutils, sysutils;
|
||||
|
||||
var
|
||||
Application : TTestRunner;
|
||||
|
||||
begin
|
||||
SysUtils.HookUncaughtExceptions;
|
||||
Application:=TTestRunner.Create(nil);
|
||||
Application.RunFormClass:=TConsoleRunner;
|
||||
Application.Initialize;
|
||||
|
Loading…
Reference in New Issue
Block a user