Преглед на файлове

Update Generics.* library to latest version with pointer optimizations and THashSet class.

maciej-izak преди 7 години
родител
ревизия
bf680b0c46

+ 405 - 91
Units/Utils/generics.collections.pas

@@ -136,9 +136,14 @@ type
   private
     FOnNotify: TCollectionNotifyEvent<T>;
     function GetCapacity: SizeInt; inline;
+  private type
+    PItems = ^TItems;
+    TItems = record
+      FLength: SizeInt;
+      FItems: array of T;
+    end;
   protected
-    FItemsLength: SizeInt;
-    FItems: array of T;
+    FItems: TItems;
 
     function PrepareAddingItem: SizeInt; virtual;
     function PrepareAddingRange(ACount: SizeInt): SizeInt; virtual;
@@ -154,7 +159,7 @@ type
     property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
   end;
 
-  TCustomListEnumerator<T> = class abstract(TEnumerator< T >)
+  TCustomListEnumerator<T> = class abstract(TEnumerator<T>)
   private
     FList: TCustomList<T>;
     FIndex: SizeInt;
@@ -166,7 +171,48 @@ type
     constructor Create(AList: TCustomList<T>);
   end;
 
-  TList<T> = class(TCustomList<T>)
+  TCustomListPointersEnumerator<T, PT> = class abstract(TEnumerator<PT>)
+  private type
+    TList = TCustomList<T>; // lazarus bug workaround
+  private var
+    FList: TList.PItems;
+    FIndex: SizeInt;
+  protected
+    function DoMoveNext: boolean; override;
+    function DoGetCurrent: PT; override;
+    function GetCurrent: PT; virtual;
+  public
+    constructor Create(AList: TList.PItems);
+  end;
+
+  TCustomListPointersCollection<TPointersEnumerator, T, PT> = record
+  private type
+    TList = TCustomList<T>; // lazarus bug workaround
+  private
+    function List: TList.PItems; inline;
+    function GetCount: SizeInt; inline;
+    function GetItem(AIndex: SizeInt): PT;
+  public
+    function GetEnumerator: TPointersEnumerator;
+    function ToArray: TArray<PT>;
+    property Count: SizeInt read GetCount;
+    property Items[Index: SizeInt]: PT read GetItem; default;
+  end;
+
+  TCustomListWithPointers<T> = class(TCustomList<T>)
+  public type
+    PT = ^T;
+  private type
+    TPointersEnumerator = class(TCustomListPointersEnumerator<T, PT>);
+    PPointersCollection = ^TPointersCollection;
+    TPointersCollection = TCustomListPointersCollection<TPointersEnumerator, T, PT>;
+  private
+    function GetPointers: PPointersCollection; inline;
+  public
+    property Ptr: PPointersCollection read GetPointers;
+  end;
+
+  TList<T> = class(TCustomListWithPointers<T>)
   private var
     FComparer: IComparer<T>;
   protected
@@ -230,7 +276,7 @@ type
     function BinarySearch(constref AItem: T; out AIndex: SizeInt): Boolean; overload;
     function BinarySearch(constref AItem: T; out AIndex: SizeInt; const AComparer: IComparer<T>): Boolean; overload;
 
-    property Count: SizeInt read FItemsLength write SetCount;
+    property Count: SizeInt read FItems.FLength write SetCount;
     property Items[Index: SizeInt]: T read GetItem write SetItem; default;
   end;
 
@@ -284,7 +330,7 @@ type
     procedure TrimExcess;
   end;
 
-  TStack<T> = class(TCustomList<T>)
+  TStack<T> = class(TCustomListWithPointers<T>)
   protected
   // bug #24287 - workaround for generics type name conflict (Identifier not found)
   // next bug workaround - for another error related to previous workaround
@@ -349,8 +395,52 @@ type
 
 {$I generics.dictionariesh.inc}
 
+  { THashSet }
+
+  THashSet<T> = class(TEnumerable<T>)
+  protected
+    FInternalDictionary : TDictionary<T, TEmptyRecord>;
+    function DoGetEnumerator: TEnumerator<T>; override;
+  public type
+    TSetEnumerator = class(TEnumerator<T>)
+    protected
+      FEnumerator: TDictionary<T, TEmptyRecord>.TKeyEnumerator;
+      function DoMoveNext: boolean; override;
+      function DoGetCurrent: T; override;
+      function GetCurrent: T; virtual;
+    public
+      constructor Create(ASet: THashSet<T>);
+      destructor Destroy; override;
+    end;
+  private
+    function GetCount: SizeInt; inline;
+    function GetPointers: TDictionary<T, TEmptyRecord>.TKeyCollection.PPointersCollection; inline;
+  public type
+    TEnumerator = TSetEnumerator;
+    PT = ^T;
+
+    function GetEnumerator: TEnumerator; reintroduce;
+  public
+    constructor Create; overload;
+    constructor Create(const AComparer: IEqualityComparer<T>); overload;
+    constructor Create(ACollection: TEnumerable<T>); overload;
+    destructor Destroy; override;
+    function Add(constref AValue: T): Boolean;
+    function Remove(constref AValue: T): Boolean;
+    function Contains(constref AValue: T): Boolean; inline;
+    procedure UnionWith(AHashSet: THashSet<T>);
+    procedure IntersectWith(AHashSet: THashSet<T>);
+    procedure ExceptWith(AHashSet: THashSet<T>);
+    procedure SymmetricExceptWith(AHashSet: THashSet<T>);
+    property Count: SizeInt read GetCount;
+    property Ptr: TDictionary<T, TEmptyRecord>.TKeyCollection.PPointersCollection read GetPointers;
+  end;
+
 function InCircularRange(ABottom, AItem, ATop: SizeInt): Boolean;
 
+var
+  EmptyRecord: TEmptyRecord;
+
 implementation
 
 function InCircularRange(ABottom, AItem, ATop: SizeInt): Boolean;
@@ -554,17 +644,17 @@ end;
 
 function TCustomList<T>.PrepareAddingItem: SizeInt;
 begin
-  Result := Length(FItems);
+  Result := Length(FItems.FItems);
 
-  if (FItemsLength < 4) and (Result < 4) then
-    SetLength(FItems, 4)
-  else if FItemsLength = High(FItemsLength) then
+  if (FItems.FLength < 4) and (Result < 4) then
+    SetLength(FItems.FItems, 4)
+  else if FItems.FLength = High(FItems.FLength) then
     OutOfMemoryError
-  else if FItemsLength = Result then
-    SetLength(FItems, CUSTOM_LIST_CAPACITY_INC);
+  else if FItems.FLength = Result then
+    SetLength(FItems.FItems, CUSTOM_LIST_CAPACITY_INC);
 
-  Result := FItemsLength;
-  Inc(FItemsLength);
+  Result := FItems.FLength;
+  Inc(FItems.FLength);
 end;
 
 function TCustomList<T>.PrepareAddingRange(ACount: SizeInt): SizeInt;
@@ -572,22 +662,22 @@ begin
   if ACount < 0 then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
   if ACount = 0 then
-    Exit(FItemsLength - 1);
+    Exit(FItems.FLength - 1);
 
-  if (FItemsLength = 0) and (Length(FItems) = 0) then
-    SetLength(FItems, 4)
-  else if FItemsLength = High(FItemsLength) then
+  if (FItems.FLength = 0) and (Length(FItems.FItems) = 0) then
+    SetLength(FItems.FItems, 4)
+  else if FItems.FLength = High(FItems.FLength) then
     OutOfMemoryError;
 
-  Result := Length(FItems);
-  while Pred(FItemsLength + ACount) >= Result do
+  Result := Length(FItems.FItems);
+  while Pred(FItems.FLength + ACount) >= Result do
   begin
-    SetLength(FItems, CUSTOM_LIST_CAPACITY_INC);
-    Result := Length(FItems);
+    SetLength(FItems.FItems, CUSTOM_LIST_CAPACITY_INC);
+    Result := Length(FItems.FItems);
   end;
 
-  Result := FItemsLength;
-  Inc(FItemsLength, ACount);
+  Result := FItems.FLength;
+  Inc(FItems.FLength, ACount);
 end;
 
 function TCustomList<T>.ToArray: TArray<T>;
@@ -597,7 +687,7 @@ end;
 
 function TCustomList<T>.GetCount: SizeInt;
 begin
-  Result := FItemsLength;
+  Result := FItems.FLength;
 end;
 
 procedure TCustomList<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification);
@@ -608,17 +698,17 @@ end;
 
 function TCustomList<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T;
 begin
-  if (AIndex < 0) or (AIndex >= FItemsLength) then
+  if (AIndex < 0) or (AIndex >= FItems.FLength) then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
-  Result := FItems[AIndex];
-  Dec(FItemsLength);
+  Result := FItems.FItems[AIndex];
+  Dec(FItems.FLength);
 
-  FItems[AIndex] := Default(T);
-  if AIndex <> FItemsLength then
+  FItems.FItems[AIndex] := Default(T);
+  if AIndex <> FItems.FLength then
   begin
-    System.Move(FItems[AIndex + 1], FItems[AIndex], (FItemsLength - AIndex) * SizeOf(T));
-    FillChar(FItems[FItemsLength], SizeOf(T), 0);
+    System.Move(FItems.FItems[AIndex + 1], FItems.FItems[AIndex], (FItems.FLength - AIndex) * SizeOf(T));
+    FillChar(FItems.FItems[FItems.FLength], SizeOf(T), 0);
   end;
 
   Notify(Result, ACollectionNotification);
@@ -626,7 +716,7 @@ end;
 
 function TCustomList<T>.GetCapacity: SizeInt;
 begin
-  Result := Length(FItems);
+  Result := Length(FItems.FItems);
 end;
 
 { TCustomListEnumerator<T> }
@@ -634,7 +724,7 @@ end;
 function TCustomListEnumerator<T>.DoMoveNext: boolean;
 begin
   Inc(FIndex);
-  Result := (FList.FItemsLength <> 0) and (FIndex < FList.FItemsLength)
+  Result := (FList.FItems.FLength <> 0) and (FIndex < FList.FItems.FLength)
 end;
 
 function TCustomListEnumerator<T>.DoGetCurrent: T;
@@ -644,7 +734,7 @@ end;
 
 function TCustomListEnumerator<T>.GetCurrent: T;
 begin
-  Result := FList.FItems[FIndex];
+  Result := FList.FItems.FItems[FIndex];
 end;
 
 constructor TCustomListEnumerator<T>.Create(AList: TCustomList<T>);
@@ -654,6 +744,85 @@ begin
   FList := AList;
 end;
 
+{ TCustomListPointersEnumerator<T, PT> }
+
+function TCustomListPointersEnumerator<T, PT>.DoMoveNext: boolean;
+begin
+  Inc(FIndex);
+  Result := (FList.FLength <> 0) and (FIndex < FList.FLength)
+end;
+
+function TCustomListPointersEnumerator<T, PT>.DoGetCurrent: PT;
+begin
+  Result := GetCurrent;
+end;
+
+function TCustomListPointersEnumerator<T, PT>.GetCurrent: PT;
+begin
+  Result := @FList.FItems[FIndex];
+end;
+
+constructor TCustomListPointersEnumerator<T, PT>.Create(AList: TCustomList<T>.PItems);
+begin
+  inherited Create;
+  FIndex := -1;
+  FList := AList;
+end;
+
+{ TCustomListPointersCollection<TPointersEnumerator, T, PT> }
+
+function TCustomListPointersCollection<TPointersEnumerator, T, PT>.List: TCustomList<T>.PItems;
+begin
+  Result := @(TCustomList<T>.TItems(Pointer(@Self)^));
+end;
+
+function TCustomListPointersCollection<TPointersEnumerator, T, PT>.GetCount: SizeInt;
+begin
+  Result := List.FLength;
+end;
+
+function TCustomListPointersCollection<TPointersEnumerator, T, PT>.GetItem(AIndex: SizeInt): PT;
+begin
+  Result := @List.FItems[AIndex];
+end;
+
+function TCustomListPointersCollection<TPointersEnumerator, T, PT>.{Do}GetEnumerator: TPointersEnumerator;
+begin
+  Result := TPointersEnumerator(TPointersEnumerator.NewInstance);
+  TCustomListPointersEnumerator<T, PT>(Result).Create(List);
+end;
+
+function TCustomListPointersCollection<TPointersEnumerator, T, PT>.ToArray: TArray<PT>;
+{begin
+  Result := ToArrayImpl(FList.Count);
+end;}
+var
+  i: SizeInt;
+  LEnumerator: TPointersEnumerator;
+begin
+  SetLength(Result, Count);
+
+  try
+    LEnumerator := GetEnumerator;
+
+    i := 0;
+    while LEnumerator.MoveNext do
+    begin
+      Result[i] := LEnumerator.Current;
+      Inc(i);
+    end;
+  finally
+    LEnumerator.Free;
+  end;
+end;
+
+{ TCustomListWithPointers<T> }
+
+function TCustomListWithPointers<T>.GetPointers: PPointersCollection;
+begin
+  Result := PPointersCollection(@FItems);
+end;
+
 { TList<T> }
 
 constructor TList<T>.Create;
@@ -685,7 +854,7 @@ begin
   if AValue < Count then
     Count := AValue;
 
-  SetLength(FItems, AValue);
+  SetLength(FItems.FItems, AValue);
 end;
 
 procedure TList<T>.SetCount(AValue: SizeInt);
@@ -698,7 +867,7 @@ begin
   if AValue < Count then
     DeleteRange(AValue, Count - AValue);
 
-  FItemsLength := AValue;
+  FItems.FLength := AValue;
 end;
 
 function TList<T>.GetItem(AIndex: SizeInt): T;
@@ -706,15 +875,15 @@ begin
   if (AIndex < 0) or (AIndex >= Count) then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
-  Result := FItems[AIndex];
+  Result := FItems.FItems[AIndex];
 end;
 
 procedure TList<T>.SetItem(AIndex: SizeInt; const AValue: T);
 begin
   if (AIndex < 0) or (AIndex >= Count) then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);   
-  Notify(FItems[AIndex], cnRemoved);
-  FItems[AIndex] := AValue;
+  Notify(FItems.FItems[AIndex], cnRemoved);
+  FItems.FItems[AIndex] := AValue;
   Notify(AValue, cnAdded);
 end;
 
@@ -731,7 +900,7 @@ end;
 function TList<T>.Add(constref AValue: T): SizeInt;
 begin
   Result := PrepareAddingItem;
-  FItems[Result] := AValue;
+  FItems.FItems[Result] := AValue;
   Notify(AValue, cnAdded);
 end;
 
@@ -763,11 +932,11 @@ begin
 
   if AIndex <> PrepareAddingItem then
   begin
-    System.Move(FItems[AIndex], FItems[AIndex + 1], ((Count - AIndex) - 1) * SizeOf(T));
-    FillChar(FItems[AIndex], SizeOf(T), 0);
+    System.Move(FItems.FItems[AIndex], FItems.FItems[AIndex + 1], ((Count - AIndex) - 1) * SizeOf(T));
+    FillChar(FItems.FItems[AIndex], SizeOf(T), 0);
   end;
 
-  FItems[AIndex] := AValue;
+  FItems.FItems[AIndex] := AValue;
   Notify(AValue, cnAdded);
 end;
 
@@ -786,14 +955,14 @@ begin
 
   if AIndex <> PrepareAddingRange(LLength) then
   begin
-    System.Move(FItems[AIndex], FItems[AIndex + LLength], ((Count - AIndex) - LLength) * SizeOf(T));
-    FillChar(FItems[AIndex], SizeOf(T) * LLength, 0);
+    System.Move(FItems.FItems[AIndex], FItems.FItems[AIndex + LLength], ((Count - AIndex) - LLength) * SizeOf(T));
+    FillChar(FItems.FItems[AIndex], SizeOf(T) * LLength, 0);
   end;
 
   LValue := @AValues[0];
   for i := AIndex to Pred(AIndex + LLength) do
   begin
-    FItems[i] := LValue^;
+    FItems.FItems[i] := LValue^;
     Notify(LValue^, cnAdded);
     Inc(LValue);
   end;
@@ -856,19 +1025,19 @@ begin
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
   SetLength(LDeleted, Count);
-  System.Move(FItems[AIndex], LDeleted[0], ACount * SizeOf(T));
+  System.Move(FItems.FItems[AIndex], LDeleted[0], ACount * SizeOf(T));
 
   LMoveDelta := Count - (AIndex + ACount);
 
   if LMoveDelta = 0 then
-    FillChar(FItems[AIndex], ACount * SizeOf(T), #0)
+    FillChar(FItems.FItems[AIndex], ACount * SizeOf(T), #0)
   else
   begin
-    System.Move(FItems[AIndex + ACount], FItems[AIndex], LMoveDelta * SizeOf(T));
-    FillChar(FItems[Count - ACount], ACount * SizeOf(T), #0);
+    System.Move(FItems.FItems[AIndex + ACount], FItems.FItems[AIndex], LMoveDelta * SizeOf(T));
+    FillChar(FItems.FItems[Count - ACount], ACount * SizeOf(T), #0);
   end;
 
-  FItemsLength -= ACount;
+  FItems.FLength -= ACount;
 
   for i := 0 to High(LDeleted) do
     Notify(LDeleted[i], cnRemoved);
@@ -894,9 +1063,9 @@ procedure TList<T>.Exchange(AIndex1, AIndex2: SizeInt);
 var
   LTemp: T;
 begin
-  LTemp := FItems[AIndex1];
-  FItems[AIndex1] := FItems[AIndex2];
-  FItems[AIndex2] := LTemp;
+  LTemp := FItems.FItems[AIndex1];
+  FItems.FItems[AIndex1] := FItems.FItems[AIndex2];
+  FItems.FItems[AIndex2] := LTemp;
 end;
 
 procedure TList<T>.Move(AIndex, ANewIndex: SizeInt);
@@ -909,16 +1078,16 @@ begin
   if (ANewIndex < 0) or (ANewIndex >= Count) then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
-  LTemp := FItems[AIndex];
-  FItems[AIndex] := Default(T);
+  LTemp := FItems.FItems[AIndex];
+  FItems.FItems[AIndex] := Default(T);
 
   if AIndex < ANewIndex then
-    System.Move(FItems[Succ(AIndex)], FItems[AIndex], (ANewIndex - AIndex) * SizeOf(T))
+    System.Move(FItems.FItems[Succ(AIndex)], FItems.FItems[AIndex], (ANewIndex - AIndex) * SizeOf(T))
   else
-    System.Move(FItems[ANewIndex], FItems[Succ(ANewIndex)], (AIndex - ANewIndex) * SizeOf(T));
+    System.Move(FItems.FItems[ANewIndex], FItems.FItems[Succ(ANewIndex)], (AIndex - ANewIndex) * SizeOf(T));
 
-  FillChar(FItems[ANewIndex], SizeOf(T), #0);
-  FItems[ANewIndex] := LTemp;
+  FillChar(FItems.FItems[ANewIndex], SizeOf(T), #0);
+  FItems.FItems[ANewIndex] := LTemp;
 end;
 
 function TList<T>.First: T;
@@ -952,7 +1121,7 @@ var
   i: SizeInt;
 begin
   for i := 0 to Count - 1 do
-    if FComparer.Compare(AValue, FItems[i]) = 0 then
+    if FComparer.Compare(AValue, FItems.FItems[i]) = 0 then
       Exit(i);
   Result := -1;
 end;
@@ -962,7 +1131,7 @@ var
   i: SizeInt;
 begin
   for i := Count - 1 downto 0 do
-    if FComparer.Compare(AValue, FItems[i]) = 0 then
+    if FComparer.Compare(AValue, FItems.FItems[i]) = 0 then
       Exit(i);
   Result := -1;
 end;
@@ -976,9 +1145,9 @@ begin
   b := Count - 1;
   while a < b do
   begin
-    LTemp := FItems[a];
-    FItems[a] := FItems[b];
-    FItems[b] := LTemp;
+    LTemp := FItems.FItems[a];
+    FItems.FItems[a] := FItems.FItems[b];
+    FItems.FItems[b] := LTemp;
     Inc(a);
     Dec(b);
   end;
@@ -986,22 +1155,22 @@ end;
 
 procedure TList<T>.Sort;
 begin
-  TArrayHelperBugHack.Sort(FItems, FComparer, 0, Count);
+  TArrayHelperBugHack.Sort(FItems.FItems, FComparer, 0, Count);
 end;
 
 procedure TList<T>.Sort(const AComparer: IComparer<T>);
 begin
-  TArrayHelperBugHack.Sort(FItems, AComparer, 0, Count);
+  TArrayHelperBugHack.Sort(FItems.FItems, AComparer, 0, Count);
 end;
 
 function TList<T>.BinarySearch(constref AItem: T; out AIndex: SizeInt): Boolean;
 begin
-  Result := TArrayHelperBugHack.BinarySearch(FItems, AItem, AIndex);
+  Result := TArrayHelperBugHack.BinarySearch(FItems.FItems, AItem, AIndex);
 end;
 
 function TList<T>.BinarySearch(constref AItem: T; out AIndex: SizeInt; const AComparer: IComparer<T>): Boolean;
 begin
-  Result := TArrayHelperBugHack.BinarySearch(FItems, AItem, AIndex, AComparer);
+  Result := TArrayHelperBugHack.BinarySearch(FItems.FItems, AItem, AIndex, AComparer);
 end;
 
 { TThreadList<T> }
@@ -1101,14 +1270,14 @@ end;
 
 function TQueue<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T;
 begin
-  Result := FItems[AIndex];
-  FItems[AIndex] := Default(T);
+  Result := FItems.FItems[AIndex];
+  FItems.FItems[AIndex] := Default(T);
   Notify(Result, ACollectionNotification);
   FLow += 1;
-  if FLow = FItemsLength then
+  if FLow = FItems.FLength then
   begin
     FLow := 0;
-    FItemsLength := 0;
+    FItems.FLength := 0;
   end;
 end;
 
@@ -1117,23 +1286,23 @@ begin
   if AValue < Count then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
-  if AValue = FItemsLength then
+  if AValue = FItems.FLength then
     Exit;
 
   if (Count > 0) and (FLow > 0) then
   begin
-    Move(FItems[FLow], FItems[0], Count * SizeOf(T));
-    FillChar(FItems[Count], (FItemsLength - Count) * SizeOf(T), #0);
+    Move(FItems.FItems[FLow], FItems.FItems[0], Count * SizeOf(T));
+    FillChar(FItems.FItems[Count], (FItems.FLength - Count) * SizeOf(T), #0);
   end;
 
-  SetLength(FItems, AValue);
-  FItemsLength := Count;
+  SetLength(FItems.FItems, AValue);
+  FItems.FLength := Count;
   FLow := 0;
 end;
 
 function TQueue<T>.GetCount: SizeInt;
 begin
-  Result := FItemsLength - FLow;
+  Result := FItems.FLength - FLow;
 end;
 
 constructor TQueue<T>.Create(ACollection: TEnumerable<T>);
@@ -1154,7 +1323,7 @@ var
   LIndex: SizeInt;
 begin
   LIndex := PrepareAddingItem;
-  FItems[LIndex] := AValue;
+  FItems.FItems[LIndex] := AValue;
   Notify(AValue, cnAdded);
 end;
 
@@ -1173,7 +1342,7 @@ begin
   if (Count = 0) then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
-  Result := FItems[FLow];
+  Result := FItems.FItems[FLow];
 end;
 
 procedure TQueue<T>.Clear;
@@ -1181,7 +1350,7 @@ begin
   while Count <> 0 do
     Dequeue;
   FLow := 0;
-  FItemsLength := 0;
+  FItems.FLength := 0;
 end;
 
 procedure TQueue<T>.TrimExcess;
@@ -1214,9 +1383,9 @@ begin
   if AIndex < 0 then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
-  Result := FItems[AIndex];
-  FItems[AIndex] := Default(T);
-  FItemsLength -= 1;
+  Result := FItems.FItems[AIndex];
+  FItems.FItems[AIndex] := Default(T);
+  FItems.FLength -= 1;
   Notify(Result, ACollectionNotification);
 end;
 
@@ -1236,7 +1405,7 @@ begin
   if AValue < Count then
     AValue := Count;
 
-  SetLength(FItems, AValue);
+  SetLength(FItems.FItems, AValue);
 end;
 
 procedure TStack<T>.Push(constref AValue: T);
@@ -1244,13 +1413,13 @@ var
   LIndex: SizeInt;
 begin
   LIndex := PrepareAddingItem;
-  FItems[LIndex] := AValue;
+  FItems.FItems[LIndex] := AValue;
   Notify(AValue, cnAdded);
 end;
 
 function TStack<T>.Pop: T;
 begin
-  Result := DoRemove(FItemsLength - 1, cnRemoved);
+  Result := DoRemove(FItems.FLength - 1, cnRemoved);
 end;
 
 function TStack<T>.Peek: T;
@@ -1258,12 +1427,12 @@ begin
   if (Count = 0) then
     raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
 
-  Result := FItems[FItemsLength - 1];
+  Result := FItems.FItems[FItems.FLength - 1];
 end;
 
 function TStack<T>.Extract: T;
 begin
-  Result := DoRemove(FItemsLength - 1, cnExtracted);
+  Result := DoRemove(FItems.FLength - 1, cnExtracted);
 end;
 
 procedure TStack<T>.TrimExcess;
@@ -1360,4 +1529,149 @@ end;
 
 {$I generics.dictionaries.inc}
 
+{ THashSet<T> }
+
+function THashSet<T>.TEnumerator.DoMoveNext: boolean;
+begin
+  Result := FEnumerator.DoMoveNext;
+end;
+
+function THashSet<T>.TEnumerator.DoGetCurrent: T;
+begin
+  Result := FEnumerator.DoGetCurrent;
+end;
+
+function THashSet<T>.TEnumerator.GetCurrent: T;
+begin
+  Result := FEnumerator.GetCurrent;
+end;
+
+constructor THashSet<T>.TEnumerator.Create(ASet: THashSet<T>);
+begin
+  FEnumerator := ASet.FInternalDictionary.Keys.DoGetEnumerator;
+end;
+
+destructor THashSet<T>.TEnumerator.Destroy;
+begin
+  FEnumerator.Free;
+end;
+
+function THashSet<T>.DoGetEnumerator: Generics.Collections.TEnumerator<T>;
+begin
+  Result := GetEnumerator;
+end;
+
+function THashSet<T>.GetCount: SizeInt;
+begin
+  Result := FInternalDictionary.Count;
+end;
+
+function THashSet<T>.GetPointers: TDictionary<T, TEmptyRecord>.TKeyCollection.PPointersCollection;
+begin
+  Result := FInternalDictionary.Keys.Ptr;
+end;
+
+function THashSet<T>.GetEnumerator: TEnumerator;
+begin
+  Result := TEnumerator.Create(Self);
+end;
+
+constructor THashSet<T>.Create;
+begin
+  FInternalDictionary := TDictionary<T, TEmptyRecord>.Create;
+end;
+
+constructor THashSet<T>.Create(const AComparer: IEqualityComparer<T>);
+begin
+  FInternalDictionary := TDictionary<T, TEmptyRecord>.Create(AComparer);
+end;
+
+constructor THashSet<T>.Create(ACollection: TEnumerable<T>);
+var
+  i: T;
+begin
+  Create;
+  for i in ACollection do
+    Add(i);
+end;
+
+destructor THashSet<T>.Destroy;
+begin
+  FInternalDictionary.Free;
+end;
+
+function THashSet<T>.Add(constref AValue: T): Boolean;
+begin
+  Result := not FInternalDictionary.ContainsKey(AValue);
+  if Result then
+    FInternalDictionary.Add(AValue, EmptyRecord);
+end;
+
+function THashSet<T>.Remove(constref AValue: T): Boolean;
+var
+  LIndex: SizeInt;
+begin
+  LIndex := FInternalDictionary.FindBucketIndex(AValue);
+  Result := LIndex >= 0;
+  if Result then
+    FInternalDictionary.DoRemove(LIndex, cnRemoved);
+end;
+
+function THashSet<T>.Contains(constref AValue: T): Boolean;
+begin
+  Result := FInternalDictionary.ContainsKey(AValue);
+end;
+
+procedure THashSet<T>.UnionWith(AHashSet: THashSet<T>);
+var
+  i: PT;
+begin
+  for i in AHashSet.Ptr^ do
+    Add(i^);
+end;
+
+procedure THashSet<T>.IntersectWith(AHashSet: THashSet<T>);
+var
+  LList: TList<PT>;
+  i: PT;
+begin
+  LList := TList<PT>.Create;
+
+  for i in Ptr^ do
+    if not AHashSet.Contains(i^) then
+      LList.Add(i);
+
+  for i in LList do
+    Remove(i^);
+
+  LList.Free;
+end;
+
+procedure THashSet<T>.ExceptWith(AHashSet: THashSet<T>);
+var
+  i: PT;
+begin
+  for i in AHashSet.Ptr^ do
+    FInternalDictionary.Remove(i^);
+end;
+
+procedure THashSet<T>.SymmetricExceptWith(AHashSet: THashSet<T>);
+var
+  LList: TList<PT>;
+  i: PT;
+begin
+  LList := TList<PT>.Create;
+
+  for i in AHashSet.Ptr^ do
+    if Contains(i^) then
+      LList.Add(i)
+    else
+      Add(i^);
+
+  for i in LList do
+    Remove(i^);
+
+  LList.Free;
+end;
+
 end.

+ 97 - 23
Units/Utils/generics.dictionaries.inc

@@ -143,27 +143,73 @@ begin
   Result := GetCurrent;
 end;
 
-{ TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS> }
+{ TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS> }
 
-constructor TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.Create(
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.
+  TPointersCollection.Dictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>;
+begin
+  Result := TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>(Pointer(@Self)^);
+end;
+
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.
+  TPointersCollection.{Do}GetEnumerator: TDictionaryPointersEnumerator;
+begin
+  Result := TDictionaryPointersEnumerator(TDictionaryPointersEnumerator.NewInstance);
+  TCustomDictionaryEnumerator<PT, CUSTOM_DICTIONARY_CONSTRAINTS>(Result).Create(Dictionary);
+end;
+
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.
+  TPointersCollection.GetCount: SizeInt;
+begin
+  Result := Dictionary.Count;
+end;
+
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.
+  TPointersCollection.ToArray: TArray<PT>;
+var
+  i: SizeInt;
+  LEnumerator: TDictionaryPointersEnumerator;
+begin
+  SetLength(Result, Count);
+
+  try
+    LEnumerator := GetEnumerator;
+
+    i := 0;
+    while LEnumerator.MoveNext do
+    begin
+      Result[i] := LEnumerator.Current;
+      Inc(i);
+    end;
+  finally
+    LEnumerator.Free;
+  end;
+end;
+
+constructor TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.Create(
   ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
 begin
   FDictionary := ADictionary;
 end;
 
-function TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.
   DoGetEnumerator: TDictionaryEnumerator;
 begin
   Result := TDictionaryEnumerator(TDictionaryEnumerator.NewInstance);
   TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>(Result).Create(FDictionary);
 end;
 
-function TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.GetCount: SizeInt;
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.GetCount: SizeInt;
 begin
   Result := TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>(FDictionary).Count;
 end;
 
-function TDictionaryEnumerable<TDictionaryEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray: TArray<T>;
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.GetPointers: PPointersCollection;
+begin
+  Result := @FPointers;
+end;
+
+function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, PT, CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray: TArray<T>;
 begin
   Result := ToArrayImpl(FDictionary.Count);
 end;
@@ -224,7 +270,7 @@ begin
   Result := FindBucketIndex(FItems, AKey, LHash);
 end;
 
-function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.PrepareAddingItem: SizeInt;
+procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.PrepareAddingItem;
 begin
   if RealItemsLength > FItemsThreshold then
     Rehash(Length(FItems) shl 1)
@@ -235,9 +281,6 @@ begin
   end
   else if FItemsLength = $40000001 then // High(TIndex) ... Error: Type mismatch
     OutOfMemoryError;
-
-  Result := FItemsLength;
-  Inc(FItemsLength);
 end;
 
 procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt);
@@ -255,6 +298,9 @@ begin
   AItem.Pair.Key := AKey;
   AItem.Pair.Value := AValue;
 
+  // ! very important. FItemsLength must be increased after above code (because constref has meaning)
+  Inc(FItemsLength);
+
   PairNotify(AItem.Pair, cnAdded);
 end;
 
@@ -302,7 +348,7 @@ var
   LIndex: SizeInt;
 begin
   LIndex := FindBucketIndex(AKey);
-  if LIndex  < 0 then
+  if LIndex < 0 then
     Exit;
 
   DoRemove(LIndex, cnRemoved);
@@ -313,7 +359,7 @@ var
   LIndex: SizeInt;
 begin
   LIndex := FindBucketIndex(AKey);
-  if LIndex  < 0 then
+  if LIndex < 0 then
     Exit(Default(TPair<TKey, TValue>));
 
   Result.Key := AKey;
@@ -555,6 +601,13 @@ begin
   Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Value;
 end;
 
+{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPValueEnumerator }
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPValueEnumerator.GetCurrent: PValue;
+begin
+  Result := @(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Value);
+end;
+
 { TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TKeyEnumerator }
 
 function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TKeyEnumerator.GetCurrent: TKey;
@@ -562,6 +615,13 @@ begin
   Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Key;
 end;
 
+{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPKeyEnumerator }
+
+function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPKeyEnumerator.GetCurrent: PKey;
+begin
+  Result := @(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Key);
+end;
+
 { TOpenAddressingLP<DICTIONARY_CONSTRAINTS> }
 
 procedure TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.NotifyIndexChange(AFrom, ATo: SizeInt);
@@ -1133,7 +1193,7 @@ end;
 
 function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Pop: Pointer;
 var
-  AIndex, LGap: SizeInt;
+  AIndex: SizeInt;
   //LResult: TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TItem; !!!bug #25917
 begin
   AIndex := FIdx.DoRemove(FIdx.Count - 1, cnExtracted);
@@ -1310,7 +1370,7 @@ begin
   Result := LR_NIL;
 end;
 
-function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PrepareAddingItem: SizeInt;
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PrepareAddingItem;
 var
   i: SizeInt;
 begin
@@ -1324,9 +1384,6 @@ begin
   end
   else if FItemsLength = $40000001 then // High(TIndex) ... Error: Type mismatch
     OutOfMemoryError;
-
-  Result := FItemsLength;
-  Inc(FItemsLength);
 end;
 
 procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt);
@@ -1348,7 +1405,7 @@ var
   y: boolean = false;
   b: UInt32;
   LIndex: UInt32;
-  i, j, LLengthMask: SizeInt;
+  i, LLengthMask: SizeInt;
   LTempItem: TItem;
   LHashList: array[0..1] of UInt32;
   LHashListParams: array[0..3] of UInt16 absolute LHashList;
@@ -1411,10 +1468,11 @@ begin
     FQueue.InsertIntoHead(@LNewItem);
 end;
 
-procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoAdd(constref AKey: TKey; constref AValue: TValue;
+procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoAdd(const AKey: TKey; const AValue: TValue;
   const AHashList: PUInt32);
 begin
   AddItem(FItems, AKey, AValue, AHashList);
+  Inc(FItemsLength);
   KeyNotify(AKey, cnAdded);
   ValueNotify(AValue, cnAdded);
 end;
@@ -1545,10 +1603,8 @@ end;
 procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Rehash(ASizePow2: SizeInt);
 var
   LNewItems: TItemsDArray;
-  LHash: UInt32;
-  LIndex: SizeInt;
   i, j: SizeInt;
-  LItem, LNewItem: PItem;
+  LItem: PItem;
   LOldQueue: TQueueDictionary;
 var
   LHashList: array[0..1] of UInt32;
@@ -1711,7 +1767,6 @@ var
   LHashList: array[0..TCuckooCfg.D] of UInt32;
   LHashListOrIndex: PUint32;
   LLookupResult: SizeInt;
-  LIndex: UInt32;
 begin
   LHashListOrIndex := @LHashList[0];
   LLookupResult := Lookup(AKey, LHashListOrIndex);
@@ -1747,7 +1802,6 @@ var
   LHashList: array[0..TCuckooCfg.D] of UInt32;
   LHashListOrIndex: PUint32;
   LLookupResult: SizeInt;
-  LIndex: UInt32;
 begin
   LHashListOrIndex := @LHashList[0];
   LLookupResult := Lookup(AKey, LHashListOrIndex);
@@ -1832,6 +1886,16 @@ begin
     Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Value;
 end;
 
+{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPValueEnumerator }
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPValueEnumerator.GetCurrent: PValue;
+begin
+  if FMainIndex = TCuckooCfg.D then
+    Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Value)
+  else
+    Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Value);
+end;
+
 { TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TKeyEnumerator }
 
 function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TKeyEnumerator.GetCurrent: TKey;
@@ -1842,6 +1906,16 @@ begin
     Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Key;
 end;
 
+{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPKeyEnumerator }
+
+function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPKeyEnumerator.GetCurrent: TKey;
+begin
+  if FMainIndex = TCuckooCfg.D then
+    Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Key)
+  else
+    Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Key);
+end;
+
 { TObjectDictionary<DICTIONARY_CONSTRAINTS> }
 
 procedure TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.KeyNotify(

+ 43 - 12
Units/Utils/generics.dictionariesh.inc

@@ -110,16 +110,30 @@ type
 
   { TDictionaryEnumerable }
 
-  TDictionaryEnumerable<TDictionaryEnumerator: TObject; // ... inherits from TCustomDictionaryEnumerator. workaround...
-    T, CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract(TEnumerable<T>)
+  TDictionaryEnumerable<TDictionaryEnumerator: TObject; TDictionaryPointersEnumerator, // ... inherits from TCustomDictionaryEnumerator. workaround...
+    T, PT, CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract(TEnumerable<T>)
+  private type
+    PPointersCollection = ^TPointersCollection;
+    TPointersCollection = record
+    private
+      function Dictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>; inline;
+      function GetCount: SizeInt; inline;
+    public
+      function GetEnumerator: TDictionaryPointersEnumerator;
+      function ToArray: TArray<PT>;
+      property Count: SizeInt read GetCount;
+    end;
   private
+    FPointers: TPointersCollection;
     FDictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>;
     function GetCount: SizeInt;
+    function GetPointers: PPointersCollection; inline;
   public
     constructor Create(ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>);
     function DoGetEnumerator: TDictionaryEnumerator; override;
     function ToArray: TArray<T>; override; final;
     property Count: SizeInt read GetCount;
+    property Ptr: PPointersCollection read GetPointers;
   end;
 
   // more info : http://en.wikipedia.org/wiki/Open_addressing
@@ -147,7 +161,7 @@ type
     FItems: TItemsArray;
 
     procedure Resize(ANewSize: SizeInt);
-    function PrepareAddingItem: SizeInt;
+    procedure PrepareAddingItem;
   protected
     function RealItemsLength: SizeInt; virtual;
     function Rehash(ASizePow2: SizeInt; AForce: Boolean = False): boolean; virtual;
@@ -166,15 +180,25 @@ type
         function GetCurrent: TValue; override;
       end;
 
+      TPValueEnumerator = class(TOpenAddressingEnumerator<PValue, OPEN_ADDRESSING_CONSTRAINTS>)
+      protected
+        function GetCurrent: PValue; override;
+      end;
+
       TKeyEnumerator = class(TOpenAddressingEnumerator<TKey, OPEN_ADDRESSING_CONSTRAINTS>)
       protected
         function GetCurrent: TKey; override;
       end;
 
+      TPKeyEnumerator = class(TOpenAddressingEnumerator<PKey, OPEN_ADDRESSING_CONSTRAINTS>)
+      protected
+        function GetCurrent: PKey; override;
+      end;
+
       // Collections
-      TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TValue, CUSTOM_DICTIONARY_CONSTRAINTS>);
+      TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TPValueEnumerator, TValue, PValue, CUSTOM_DICTIONARY_CONSTRAINTS>);
 
-      TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TKey, CUSTOM_DICTIONARY_CONSTRAINTS>);
+      TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TPKeyEnumerator, TKey, PKey, CUSTOM_DICTIONARY_CONSTRAINTS>);
 
     // bug #24283 - workaround related to lack of DoGetEnumerator
     function GetEnumerator: TPairEnumerator; reintroduce;
@@ -373,7 +397,7 @@ type
 
     procedure Resize(ANewSize: SizeInt);
     procedure Rehash(ASizePow2: SizeInt);
-    function PrepareAddingItem: SizeInt;
+    procedure PrepareAddingItem;
   protected
     procedure UpdateItemsThreshold(ASize: SizeInt); override;
     function Lookup(constref AKey: TKey; var AHashListOrIndex: PUInt32): SizeInt; inline; overload;
@@ -391,15 +415,25 @@ type
         function GetCurrent: TValue; override;
       end;
 
+      TPValueEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<PValue, CUCKOO_CONSTRAINTS>)
+      protected
+        function GetCurrent: PValue; override;
+      end;
+
       TKeyEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<TKey, CUCKOO_CONSTRAINTS>)
       protected
         function GetCurrent: TKey; override;
       end;
 
+      TPKeyEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<PKey, CUCKOO_CONSTRAINTS>)
+      protected
+        function GetCurrent: PKey; override;
+      end;
+
       // Collections
-      TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TValue, CUSTOM_DICTIONARY_CONSTRAINTS>);
+      TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TPValueEnumerator, TValue, PValue, CUSTOM_DICTIONARY_CONSTRAINTS>);
 
-      TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TKey, CUSTOM_DICTIONARY_CONSTRAINTS>);
+      TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TPKeyEnumerator, TKey, PKey, CUSTOM_DICTIONARY_CONSTRAINTS>);
 
     // bug #24283 - workaround related to lack of DoGetEnumerator
     function GetEnumerator: TPairEnumerator; reintroduce;
@@ -412,7 +446,7 @@ type
     procedure SetItem(constref AValue: TValue; const AHashListOrIndex: PUInt32; ALookupResult: SizeInt); overload;
 
     procedure AddItem(constref AItems: TItemsDArray; constref AKey: TKey; constref AValue: TValue; const AHashList: PUInt32); overload;
-    procedure DoAdd(constref AKey: TKey; constref AValue: TValue; const AHashList: PUInt32); overload; inline;
+    procedure DoAdd(const AKey: TKey; const AValue: TValue; const AHashList: PUInt32); overload; inline;
     function DoRemove(const AHashListOrIndex: PUInt32; ALookupResult: SizeInt;
       ACollectionNotification: TCollectionNotification): TValue;
 
@@ -539,6 +573,3 @@ type
 
   THashMap<TKey, TValue> = class(TCuckooD4<TKey, TValue>);
   TObjectHashMap<TKey, TValue> = class(TObjectCuckooD4<TKey, TValue>);
-
-var
-  EmptyRecord: TEmptyRecord;

+ 2 - 0
Units/Utils/generics.helpers.pas

@@ -20,6 +20,8 @@ unit Generics.Helpers;
 
 {$MODE DELPHI}{$H+}
 {$MODESWITCH TYPEHELPERS}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
 
 interface
 

+ 2 - 0
Units/Utils/generics.memoryexpanders.pas

@@ -21,6 +21,8 @@ unit Generics.MemoryExpanders;
 
 {$mode delphi}
 {$MACRO ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
 {.$WARN 5024 OFF}
 {.$WARN 4079 OFF}