Delphi. HashMap

Из проекта

uses
  System.SysUtils, System.Classes, System.Generics.Collections, Rtti, xsuperjson, xsuperobject, System.TypInfo, System.Generics.Defaults;
{hash map for objects on TDictionary and TList<>}
  THashMap<K, V> = class
  private
    FDictionary: TDictionary<K, TList<TPair<K, V>>>;
    FKeyComparer: IComparer<K>;
    FOwnsObjects: Boolean;
    function GetItems(aKey: K): V;
    procedure SetItems(aKey: K; const aValue: V);
  public
    constructor Create(aKeyComparer: IComparer<K>; aOwnsObjects: Boolean = true);
    destructor Destroy; override;
    procedure Clear();
    procedure Add(aKey: K; aValue: V);
    procedure Remove(aKey: K);
    function ContainsKey(aKey: K): Boolean;
    property Items[aKey: K]: V read GetItems write SetItems; default;
  end;
{ THashMap }

procedure THashMap<K, V>.Add(aKey: K; aValue: V);
begin
  if not FDictionary.ContainsKey(aKey) then
    FDictionary.Add(aKey, TList<TPair<K, V>>.Create());

  FDictionary[aKey].Add(TPair<K, V>.Create(aKey, aValue));
end;

procedure THashMap<K, V>.Clear;
var
  key: K;
begin
  for key in FDictionary.Keys do
    Remove(key);
end;

function THashMap<K, V>.ContainsKey(aKey: K): Boolean;
begin
  Result := FDictionary.ContainsKey(aKey)
end;

constructor THashMap<K, V>.Create(aKeyComparer: IComparer<K>; aOwnsObjects: Boolean = true);
begin
  FDictionary := TDictionary<K, TList<TPair<K, V>>>.Create();
  EnsureNotNull(aKeyComparer, 'aKeyComparer');
  FKeyComparer := aKeyComparer;
  FOwnsObjects := aOwnsObjects;
end;

destructor THashMap<K, V>.Destroy;
begin
  Clear();
  FDictionary.Free();
  inherited;
end;

function THashMap<K, V>.GetItems(aKey: K): V;
var
  p: TPair<K, V>;
  i: integer;
begin
  if FDictionary[aKey].Count = 1 then
  begin
    p := FDictionary[aKey].Items[0];
    Result := p.Value;
    Exit;
  end
  else if FDictionary[aKey].Count > 1 then
  begin
    // compare keys in list
    for i := 0 to FDictionary[aKey].Count - 1 do
    begin
      p := FDictionary[aKey][i];
      if FKeyComparer.Compare(p.Key, aKey) = 0 then
      begin
        Result := p.Value;
        Exit;
      end;
    end;
  end;
end;

procedure THashMap<K, V>.Remove(aKey: K);
var
  i: integer;
  list: TList<TPair<K, V>>;
begin
  if not FDictionary.ContainsKey(aKey) then
    raise Exception.Create('cannnot remove, item not found');

  list := FDictionary[aKey];
  for i := list.Count - 1 downto 0 do
  begin
    if (FOwnsObjects) and (TValueTypeChecker<V>.IsValueAnObject(list[i].Value)) then
      PObject(@list[i].Value)^.Free();
  end;

  FreeAndNil(list);

  FDictionary.Remove(aKey);
end;

procedure THashMap<K, V>.SetItems(aKey: K; const aValue: V);
var
  p: TPair<K, V>;
  i: integer;
begin
  if FDictionary[aKey].Count = 1 then
  begin
    p := FDictionary[aKey].Items[0];
    FDictionary[aKey].Remove(p);
    FDictionary[aKey].Add(TPair<K, V>.Create(aKey, aValue));
    Exit;
  end
  else if FDictionary[aKey].Count > 1 then
  begin
    // compare keys in list
    for i := 0 to FDictionary[aKey].Count - 1 do
    begin
      p := FDictionary[aKey][i];
      if FKeyComparer.Compare(p.Key, aKey) = 0 then
      begin
        FDictionary[aKey].Remove(p);
        FDictionary[aKey].Add(TPair<K, V>.Create(aKey, aValue));
        Exit;
      end;
    end;
  end;
end;
This entry was posted in Без рубрики. Bookmark the permalink.