mirror of
https://gitlab.com/freepascal.org/fpc/pas2js.git
synced 2025-08-20 08:29:09 +02:00
* Add comparer version of dictionary
This commit is contained in:
parent
b892a8a8bf
commit
0f656ddf5f
@ -362,6 +362,8 @@ type
|
|||||||
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
|
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
|
||||||
private
|
private
|
||||||
FMap: TJSMap;
|
FMap: TJSMap;
|
||||||
|
FComparer: IComparer<TKey>;
|
||||||
|
function GetEffectiveKey(Key : TKey) : TKey;
|
||||||
function GetItem(const Key: TKey): TValue;
|
function GetItem(const Key: TKey): TValue;
|
||||||
procedure SetItem(const Key: TKey; const Value: TValue);
|
procedure SetItem(const Key: TKey; const Value: TValue);
|
||||||
procedure DoAdd(const Key: TKey; const Value: TValue);
|
procedure DoAdd(const Key: TKey; const Value: TValue);
|
||||||
@ -380,6 +382,7 @@ type
|
|||||||
|
|
||||||
constructor Create(ACapacity: Integer=0); overload;
|
constructor Create(ACapacity: Integer=0); overload;
|
||||||
constructor Create(const Collection: TEnumerable<TMyPair>); overload;
|
constructor Create(const Collection: TEnumerable<TMyPair>); overload;
|
||||||
|
constructor Create(const AComparer: IComparer<TKey>); overload;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
|
||||||
procedure Add(const Key: TKey; const Value: TValue);
|
procedure Add(const Key: TKey; const Value: TValue);
|
||||||
@ -1191,13 +1194,35 @@ ResourceString
|
|||||||
SErrDictKeyNotFound = 'Key value not found';
|
SErrDictKeyNotFound = 'Key value not found';
|
||||||
SErrDictDuplicateKey = 'Duplicate key value';
|
SErrDictDuplicateKey = 'Duplicate key value';
|
||||||
|
|
||||||
|
function TDictionary<TKey, TValue>.GetEffectiveKey(Key: TKey): TKey;
|
||||||
|
|
||||||
|
Var
|
||||||
|
it : TJSIterator;
|
||||||
|
v : TJSIteratorValue;
|
||||||
|
vv : JSValue;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if Not assigned(FComparer) then
|
||||||
|
Exit(key);
|
||||||
|
it:=FMap.Keys;
|
||||||
|
v:=it.next;
|
||||||
|
While not v.Done do
|
||||||
|
begin
|
||||||
|
Result:=TKey(v.Value);
|
||||||
|
if FComparer.Compare(Result,Key)=0 then
|
||||||
|
exit;
|
||||||
|
v:=it.Next;
|
||||||
|
end;
|
||||||
|
Result:=Key;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDictionary<TKey, TValue>.GetItem(const Key: TKey): TValue;
|
function TDictionary<TKey, TValue>.GetItem(const Key: TKey): TValue;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
V : JSValue;
|
V : JSValue;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
V:=FMap.Get(Key);
|
v:=FMap.Get(GetEffectiveKey(Key));
|
||||||
if isUndefined(v) then
|
if isUndefined(v) then
|
||||||
Raise EDictionary.Create(SErrDictKeyNotFound);
|
Raise EDictionary.Create(SErrDictKeyNotFound);
|
||||||
Result:=TValue(V);
|
Result:=TValue(V);
|
||||||
@ -1209,7 +1234,7 @@ Var
|
|||||||
V : JSValue;
|
V : JSValue;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
V:=FMap.Get(Key);
|
v:=FMap.Get(GetEffectiveKey(Key));
|
||||||
if Not isUndefined(v) then
|
if Not isUndefined(v) then
|
||||||
ValueNotify(TValue(V),cnRemoved);
|
ValueNotify(TValue(V),cnRemoved);
|
||||||
FMap.&Set(Key,Value);
|
FMap.&Set(Key,Value);
|
||||||
@ -1217,8 +1242,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDictionary<TKey, TValue>.DoAdd(const Key: TKey; const Value: TValue);
|
procedure TDictionary<TKey, TValue>.DoAdd(const Key: TKey; const Value: TValue);
|
||||||
|
Var
|
||||||
|
k : Tkey;
|
||||||
begin
|
begin
|
||||||
FMap.&Set(Key,Value);
|
FMap.&Set(GetEffectiveKey(Key),Value);
|
||||||
KeyNotify(Key,cnAdded);
|
KeyNotify(Key,cnAdded);
|
||||||
ValueNotify(Value,cnAdded);
|
ValueNotify(Value,cnAdded);
|
||||||
end;
|
end;
|
||||||
@ -1227,12 +1254,14 @@ end;
|
|||||||
function TDictionary<TKey, TValue>.DoRemove(const Key: TKey; Notification: TCollectionNotification): TValue;
|
function TDictionary<TKey, TValue>.DoRemove(const Key: TKey; Notification: TCollectionNotification): TValue;
|
||||||
Var
|
Var
|
||||||
V : JSValue;
|
V : JSValue;
|
||||||
|
K : TKey;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
V:=FMap.Get(Key);
|
K:=GetEffectiveKey(Key);
|
||||||
|
V:=FMap.Get(k);
|
||||||
if Not isUndefined(v) then
|
if Not isUndefined(v) then
|
||||||
begin
|
begin
|
||||||
FMap.Delete(Key);
|
FMap.Delete(k);
|
||||||
Result:=TValue(v);
|
Result:=TValue(v);
|
||||||
KeyNotify(Key,Notification);
|
KeyNotify(Key,Notification);
|
||||||
ValueNotify(Result,Notification);
|
ValueNotify(Result,Notification);
|
||||||
@ -1244,7 +1273,8 @@ begin
|
|||||||
Result:=FMap.Size;
|
Result:=FMap.Size;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDictionary<TKey, TValue>.DoGetEnumerator: TEnumerator<TMyPair>;
|
function TDictionary<TKey, TValue>.DoGetEnumerator: TEnumerator<TPair<TKey,
|
||||||
|
TValue>>;
|
||||||
begin
|
begin
|
||||||
Result:=TPairEnumerator.Create(Self);
|
Result:=TPairEnumerator.Create(Self);
|
||||||
end;
|
end;
|
||||||
@ -1285,6 +1315,12 @@ begin
|
|||||||
Add(aPair.Key,aPair.Value);
|
Add(aPair.Key,aPair.Value);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor TDictionary<TKey, TValue>.Create(const AComparer: IComparer<TKey>);
|
||||||
|
begin
|
||||||
|
Create(0);
|
||||||
|
FComparer:=aComparer;
|
||||||
|
end;
|
||||||
|
|
||||||
destructor TDictionary<TKey, TValue>.Destroy;
|
destructor TDictionary<TKey, TValue>.Destroy;
|
||||||
begin
|
begin
|
||||||
FreeAndNil(FKeyCollection);
|
FreeAndNil(FKeyCollection);
|
||||||
@ -1296,7 +1332,7 @@ end;
|
|||||||
|
|
||||||
procedure TDictionary<TKey, TValue>.Add(const Key: TKey; const Value: TValue);
|
procedure TDictionary<TKey, TValue>.Add(const Key: TKey; const Value: TValue);
|
||||||
begin
|
begin
|
||||||
if FMap.Has(Key) then
|
if FMap.Has(GetEffectiveKey(Key)) then
|
||||||
Raise EDictionary.Create(SErrDictDuplicateKey);
|
Raise EDictionary.Create(SErrDictDuplicateKey);
|
||||||
DoAdd(Key,Value);
|
DoAdd(Key,Value);
|
||||||
end;
|
end;
|
||||||
@ -1308,18 +1344,22 @@ end;
|
|||||||
|
|
||||||
function TDictionary<TKey, TValue>.ExtractPair(const Key: TKey): TMyPair;
|
function TDictionary<TKey, TValue>.ExtractPair(const Key: TKey): TMyPair;
|
||||||
|
|
||||||
|
Var
|
||||||
|
K : TKey;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=Default(TMyPair);
|
Result:=Default(TMyPair);
|
||||||
if FMap.Has(Key) then
|
K:=GetEffectiveKey(Key);
|
||||||
|
if FMap.Has(K) then
|
||||||
begin
|
begin
|
||||||
Result.Create(Key,TValue(FMap.get(key)));
|
Result.Create(Key,TValue(FMap.get(K)));
|
||||||
FMap.Delete(Key);
|
FMap.Delete(k);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Result.Create(Key,Default(TValue));
|
Result.Create(Key,Default(TValue));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TDictionary<TKey, TValue>.CanClearMap : Boolean;
|
function TDictionary<TKey, TValue>.CanClearMap: Boolean;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=(FOnKeyNotify=Nil) and (FOnValueNotify=Nil);
|
Result:=(FOnKeyNotify=Nil) and (FOnValueNotify=Nil);
|
||||||
@ -1356,23 +1396,33 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
function TDictionary<TKey, TValue>.TryGetValue(const Key: TKey; out Value: TValue): Boolean;
|
function TDictionary<TKey, TValue>.TryGetValue(const Key: TKey; out Value: TValue): Boolean;
|
||||||
|
|
||||||
|
Var
|
||||||
|
K : TKey;
|
||||||
begin
|
begin
|
||||||
Result:=FMap.Has(Key);
|
K:=GetEffectiveKey(Key);
|
||||||
|
Result:=FMap.Has(K);
|
||||||
If Result then
|
If Result then
|
||||||
Value:=TValue(FMap.get(Key));
|
Value:=TValue(FMap.get(K));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TDictionary<TKey, TValue>.AddOrSetValue(const Key: TKey; const Value: TValue);
|
procedure TDictionary<TKey, TValue>.AddOrSetValue(const Key: TKey; const Value: TValue);
|
||||||
|
|
||||||
|
Var
|
||||||
|
k : TKey;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if Not FMap.Has(Key) then
|
K:=GetEffectiveKey(Key);
|
||||||
|
if Not FMap.Has(k) then
|
||||||
DoAdd(Key,Value)
|
DoAdd(Key,Value)
|
||||||
else
|
else
|
||||||
SetItem(Key,Value);
|
SetItem(K,Value);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDictionary<TKey, TValue>.ContainsKey(const Key: TKey): Boolean;
|
function TDictionary<TKey, TValue>.ContainsKey(const Key: TKey): Boolean;
|
||||||
begin
|
begin
|
||||||
Result:=FMap.Has(Key);
|
Result:=FMap.Has(GetEffectiveKey(Key));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDictionary<TKey, TValue>.ContainsValue(const Value: TValue): Boolean;
|
function TDictionary<TKey, TValue>.ContainsValue(const Value: TValue): Boolean;
|
||||||
|
@ -110,8 +110,102 @@ Type
|
|||||||
Procedure TestNoFreeOnRemove;
|
Procedure TestNoFreeOnRemove;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TMyStringDict = Class(Specialize TDictionary<string,string>);
|
||||||
|
TMyStringComparer = Specialize TComparer<string>;
|
||||||
|
|
||||||
|
{ TTestComparerDictionary }
|
||||||
|
|
||||||
|
TTestComparerDictionary = Class(TTestCase)
|
||||||
|
private
|
||||||
|
FDict: TMyStringDict;
|
||||||
|
public
|
||||||
|
Procedure Setup; override;
|
||||||
|
Procedure TearDown; override;
|
||||||
|
Procedure FillDict;
|
||||||
|
Property Dict : TMyStringDict Read FDict;
|
||||||
|
Published
|
||||||
|
Procedure TestHasKey;
|
||||||
|
Procedure TestTryGetValue;
|
||||||
|
Procedure TestAddOrSet;
|
||||||
|
Procedure TestRemove;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
{ TTestComparerDictionary }
|
||||||
|
|
||||||
|
procedure TTestComparerDictionary.Setup;
|
||||||
|
begin
|
||||||
|
inherited Setup;
|
||||||
|
FDict:=TMyStringDict.Create(TMyStringComparer.Construct(function (Const a,b : String) : integer
|
||||||
|
begin
|
||||||
|
Result:=CompareText(a,b);
|
||||||
|
// writeln('Comparing ',a,' and ',b,' result: ',Result);
|
||||||
|
end
|
||||||
|
));
|
||||||
|
FillDict;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestComparerDictionary.TearDown;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FDict);
|
||||||
|
inherited TearDown;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestComparerDictionary.FillDict;
|
||||||
|
begin
|
||||||
|
With Dict do
|
||||||
|
begin
|
||||||
|
add('a','A');
|
||||||
|
add('B','b');
|
||||||
|
add('c','C');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestComparerDictionary.TestHasKey;
|
||||||
|
begin
|
||||||
|
AssertTrue('ContainsKey A',Dict.ContainsKey('A'));
|
||||||
|
AssertTrue('ContainsKey b',Dict.ContainsKey('b'));
|
||||||
|
AssertTrue('ContainsKey c',Dict.ContainsKey('c'));
|
||||||
|
AssertFalse('ContainsKey D',Dict.ContainsKey('D'));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestComparerDictionary.TestTryGetValue;
|
||||||
|
|
||||||
|
Var
|
||||||
|
S : String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
AssertTrue('A',Dict.TryGetValue('A',S));
|
||||||
|
AssertEquals('Value A','A',S);
|
||||||
|
AssertTrue('b',Dict.TryGetValue('b',S));
|
||||||
|
AssertEquals('Value b','b',S);
|
||||||
|
AssertTrue('c',Dict.TryGetValue('c',S));
|
||||||
|
AssertEquals('Value C','C',S);
|
||||||
|
AssertFalse('d',Dict.TryGetValue('D',S));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestComparerDictionary.TestAddOrSet;
|
||||||
|
|
||||||
|
Var
|
||||||
|
S : String;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Dict.AddOrSetValue('d','E');
|
||||||
|
AssertTrue('d',Dict.TryGetValue('d',S));
|
||||||
|
AssertEquals('Value d','E',S);
|
||||||
|
Dict.AddOrSetValue('D','D');
|
||||||
|
AssertTrue('D',Dict.TryGetValue('D',S));
|
||||||
|
AssertEquals('Value D','D',S);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestComparerDictionary.TestRemove;
|
||||||
|
begin
|
||||||
|
Dict.Remove('C');
|
||||||
|
AssertFalse('ContainsKey C',Dict.ContainsKey('C'));
|
||||||
|
AssertFalse('ContainsKey c',Dict.ContainsKey('c'));
|
||||||
|
end;
|
||||||
|
|
||||||
{ TTestSingleObjectDict }
|
{ TTestSingleObjectDict }
|
||||||
|
|
||||||
procedure TTestSingleObjectDict.SetUp;
|
procedure TTestSingleObjectDict.SetUp;
|
||||||
@ -668,8 +762,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
RegisterTests([TTestSimpleDictionary,
|
RegisterTests([{TTestSimpleDictionary,
|
||||||
TTestSingleObjectDict,
|
TTestSingleObjectDict,
|
||||||
TTestDualObjectDict]);
|
TTestDualObjectDict,}
|
||||||
|
TTestComparerDictionary]);
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user