unit Bcl.Collections;

{$I bcl.inc}

interface

uses
  Rtti, Generics.Defaults, Classes,
  {$IFNDEF NEXTGEN}Contnrs,{$ENDIF}
  Generics.Collections;

type
  THashSet<T> = class
  strict private
    FDictionary: TDictionary<T, Integer>;
  public
    function GetEnumerator: TEnumerator<T>;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add(Item: T);
    procedure Clear;
    function Contains(Item: T): Boolean;
    procedure Remove(Item: T);
  end;

  TObjectSet<T> = class
  strict private
    FDictionary: TObjectDictionary<T, Integer>;
  public
    function GetEnumerator: TEnumerator<T>;
  public
    constructor Create(AOwnsObjects: Boolean = True);
    destructor Destroy; override;
    procedure Add(Item: T);
    procedure Clear;
    function Contains(Item: T): Boolean;
    procedure Remove(Item: T);
  end;

  IDictionary = interface;

  TOrderedDictionary<K, V> = class
  type
    TPairKV = TPair<K, V>;
  private
    FItems: TList<TPairKV>;
    function GetItems(const key: K): V;
    procedure SetItems(const key: K; const value: V);
    function GetKey(const index: integer): K;
    function GetValue(const index: integer): V;
  protected
    FComparer: IEqualityComparer<K>;
    procedure KeyNotify(const Key: K; Action: TCollectionNotification); virtual;
    procedure ValueNotify(const Value: V; Action: TCollectionNotification); virtual;
    procedure Notify(Sender: TObject; const Value: TPairKV; Action: TCollectionNotification); virtual;
  public
    function AsDictionary: IDictionary;
    function GetEnumerator: TList<TPairKV>.TEnumerator;
  public
    procedure Sort; overload;
    procedure Sort(const AComparer: IComparer<TPairKV>); overload;
  public
    constructor Create; overload;
    constructor Create(const AComparer: IEqualityComparer<K>); overload;
    destructor Destroy; override;
    procedure Clear;
    procedure Add(const key: K; const value: V);
    procedure Remove(const key: K);
    function ExtractPair(const key: K): TPairKV;
    function ContainsKey(const key: K): boolean;
    function IndexOfKey(const key: K): integer;
    function TryGetValue(const key: K; out value: V): boolean;
    function Count: integer;
    property Values[const index: integer]: V read GetValue;
    property Keys[const index: integer]: K read GetKey;
    property Items[const key: K]: V read GetItems write SetItems; default;
  end;

  TOrderedObjectDictionary<K; V: class> = class(TOrderedDictionary<K, V>)
  private
    FOwnerships: TDictionaryOwnerships;
  protected
    procedure KeyNotify(const Key: K; Action: TCollectionNotification); override;
    procedure ValueNotify(const Value: V; Action: TCollectionNotification); override;
  public
    constructor Create; overload;
    constructor Create(Ownerships: TDictionaryOwnerships); overload;
    constructor Create(Ownerships: TDictionaryOwnerships;
      const AComparer: IEqualityComparer<K>); overload;
    property Ownerships: TDictionaryOwnerships read FOwnerships;
  end;

  IReadOnlyObjectList = interface
  ['{4B0167B1-7F7A-4FF6-84E3-6C1183536FDC}']
    function Count: Integer;
    function Item(I: Integer): TObject;
    function IndexOf(Obj: TObject): Integer;
  end;

  IObjectList = interface(IReadOnlyObjectList)
  ['{C7B45109-9308-4EDC-95D5-5E8EB63C5682}']
    procedure Delete(I: Integer);
    procedure SetItem(I: Integer; Obj: TObject);
    procedure Clear;
    procedure Add(Obj: TObject);
    procedure Insert(Index: Integer; Obj: TObject);
    function OwnsObjects: Boolean;
  end;

  IValueList = interface
  ['{0F98C4CE-3959-488F-8BC5-EDFBBCF2E520}']
    function Count: Integer;
    function GetItem(I: Integer): TValue;
    procedure Clear;
    procedure Add(const Value: TValue);
    function OwnsValues: Boolean;
  end;

  TValuePair = TPair<TValue, TValue>;

  IDictionary = interface
  ['{0A320447-72D2-4FC8-BB5A-DD177D981704}']
    procedure Add(const Key, Value: TValue);
    procedure AddOrSetValue(const Key, Value: TValue);
    procedure Clear;
    function ContainsKey(const Key: TValue): Boolean;
    function GetItem(const Key: TValue): TValue;
    procedure SetItem(const Key, Value: TValue);
    procedure Remove(const Key: TValue);
    function TryGetValue(const Key: TValue; out Value: TValue): Boolean;
    function GetEnumerator: TEnumerator<TValuePair>;
    function GetOwnerships: TDictionaryOwnerships;
    property Items[const key: TValue]: TValue read GetItem write SetItem; default;
  end;

type
  {$IFNDEF NEXTGEN}
  TListWrapper = class(TInterfacedObject, IObjectList)
  private
    FList: TList;
  public
    constructor Create(AList: TList);
    function Count: Integer;
    procedure Delete(I: Integer);
    function Item(I: Integer): TObject;
    procedure SetItem(I: Integer; Obj: TObject);
    procedure Clear;
    procedure Add(Obj: TObject);
    function IndexOf(Obj: TObject): Integer;
    procedure Insert(Index: Integer; Obj: TObject);
    function OwnsObjects: Boolean;
  end;
  {$ENDIF}

  TObjectListWrapper = class(TInterfacedObject, IObjectList)
  private
    FList: TList<TObject>;
  public
    function Count: Integer;
    procedure Delete(I: Integer);
    constructor Create(AList: TObject);
    function Item(I: Integer): TObject;
    procedure SetItem(I: Integer; Obj: TObject);
    procedure Clear;
    procedure Add(Obj: TObject);
    function IndexOf(Obj: TObject): Integer;
    procedure Insert(Index: Integer; Obj: TObject);
    function OwnsObjects: Boolean;
  end;

  TValueListWrapper = class(TInterfacedObject, IValueList)
  private
    FContext: TRttiContext;
    FList: TObject;
    FAddMethod: TRttiMethod;
    FClearMethod: TRttiMethod;
    FCountProperty: TRttiProperty;
    FGetItemMethod: TRttiMethod;
    FOwnsObjectsProperty: TRttiProperty;
  public
    constructor Create(AList: TObject);
    destructor Destroy; override;
    function Count: Integer;
    function GetItem(I: Integer): TValue;
    procedure Clear;
    procedure Add(const Value: TValue);
    function OwnsValues: Boolean;
  end;

  {$IFNDEF DELPHIXE3_LVL}
  TOrdinalIStringComparer = class(TEqualityComparer<string>)
  public
    function Equals(const Left, Right: string): Boolean;
      reintroduce; overload; override;
    function GetHashCode(const Value: string): Integer;
      reintroduce; overload; override;
  end;
  {$ENDIF}

  TOrderedDictionaryAdapter<K, V> = class(TInterfacedObject, IDictionary)
  public
    type
      TEnumeratorAdapter = class(TEnumerator<TValuePair>)
      strict private
        FEnumerator: TList<TPair<K, V>>.TEnumerator;
      protected
        function DoGetCurrent: TValuePair; override;
        function DoMoveNext: Boolean; override;
      public
        constructor Create(AEnumerator: TList<TPair<K, V>>.TEnumerator);
        destructor Destroy; override;
      end;
  strict private
    FDictionary: TOrderedDictionary<K, V>;
    FOwnershipsProperty: TRttiProperty;
    FContext: TRttiContext;
  public
    { IDictionary implementation }
    procedure Add(const Key, Value: TValue);
    procedure AddOrSetValue(const Key, Value: TValue);
    procedure Clear;
    function ContainsKey(const Key: TValue): Boolean;
    function GetItem(const Key: TValue): TValue;
    procedure SetItem(const Key, Value: TValue);
    function TryGetValue(const Key: TValue; out Value: TValue): Boolean;
    function GetEnumerator: TEnumerator<TValuePair>;
    procedure Remove(const Key: TValue);
    function GetOwnerships: TDictionaryOwnerships;
  public
    constructor Create(ADictionary: TOrderedDictionary<K, V>);
    destructor Destroy; override;
  end;

function IsValueList(Clazz: TClass): Boolean;
function ValueListType(Clazz: TClass): TRttiType;
function AsValueList(Obj: TObject): IValueList;

function IsObjectList(Clazz: TClass): Boolean;
function AsObjectList(Obj: TObject): IObjectList;

implementation

uses
  SysUtils, StrUtils,
  Bcl.Utils,
  Bcl.Rtti.Utils;

{$IFNDEF DELPHIXE3_LVL}

{ TOrdinalIStringComparer }

function TOrdinalIStringComparer.Equals(const Left, Right: string): Boolean;
var
  len: Integer;
  L, R: string;
begin
  L := AnsiLowerCase(Left);
  R := AnsiLowerCase(Right);
  len := Length(L);
  Result := (len - Length(R) = 0) and CompareMem(PChar(L), PChar(R), len * SizeOf(Char));
end;

function TOrdinalIStringComparer.GetHashCode(const Value: string): Integer;
var
  S: string;
begin
  S := AnsiLowerCase(Value);
  Result := BobJenkinsHash(PChar(S)^, SizeOf(Char) * Length(S), 0);
end;

{$ENDIF}

function IsValueList(Clazz: TClass): Boolean;
begin
  if Clazz = nil then Exit(False);
  Result := TRttiUtils.GetInstance.IsGenericOf(Clazz, TList<TObject>);
end;

function ValueListType(Clazz: TClass): TRttiType;
var
  Params: TArray<TRttiType>;
begin
  Params := TRttiUtils.GetInstance.ExtractGenericTypes(Clazz);
  if Length(Params) = 1 then
    Result := Params[0]
  else
    Result := nil;
end;

function AsValueList(Obj: TObject): IValueList;
begin
  if IsValueList(Obj.ClassType) then
    Result := TValueListWrapper.Create(Obj)
  else
    Result := nil;
end;

function IsObjectList(Clazz: TClass): Boolean;
var
  Types: TArray<TRttiType>;
begin
  if Clazz = nil then Exit(False);

  {$IFNDEF NEXTGEN}
  if Clazz.InheritsFrom(TList) then
    Exit(True);
  {$ENDIF}

  if TRttiUtils.GetInstance.IsGenericOf(Clazz, TList<TObject>) then
  begin
    Types := TRttiUtils.GetInstance.ExtractGenericTypes(Clazz);
    Result := (Length(Types) = 1) and Types[0].IsInstance;
  end
  else
    Result := False;
end;

function AsObjectList(Obj: TObject): IObjectList;
begin
  {$IFNDEF NEXTGEN}
  if Obj is TList then
    Exit(TListWrapper.Create(Obj as TList));
  {$ENDIF}

  // If Obj is not a TList, it MUST be a TList<T> !
  Result := TObjectListWrapper.Create(TList<TObject>(Obj));
end;

{ TListWrapper }

{$IFNDEF NEXTGEN}
procedure TListWrapper.Add(Obj: TObject);
begin
  FList.Add(Obj);
end;

procedure TListWrapper.Clear;
begin
  FList.Clear;
end;

function TListWrapper.Count: Integer;
begin
  result := FList.Count;
end;

constructor TListWrapper.Create(AList: TList);
begin
  FList := AList;
end;

procedure TListWrapper.Delete(I: Integer);
begin
  FList.Delete(I);
end;

function TListWrapper.IndexOf(Obj: TObject): Integer;
begin
  Result := FList.IndexOf(Obj);
end;

procedure TListWrapper.Insert(Index: Integer; Obj: TObject);
begin
  FList.Insert(Index, Obj);
end;

function TListWrapper.Item(I: Integer): TObject;
begin
  result := TObject(FList[I]);
end;

function TListWrapper.OwnsObjects: Boolean;
begin
  if FList is TObjectList then
    Result := TObjectList(FList).OwnsObjects
  else
    Result := False;
end;

procedure TListWrapper.SetItem(I: Integer; Obj: TObject);
begin
  FList[I] := Obj;
end;
{$ENDIF}

{ TObjectListWrapper }

procedure TObjectListWrapper.Add(Obj: TObject);
begin
  FList.Add(Obj);
end;

procedure TObjectListWrapper.Clear;
begin
  FList.Clear;
end;

function TObjectListWrapper.Count: Integer;
begin
  result := FList.Count;
end;

constructor TObjectListWrapper.Create(AList: TObject);
begin
  FList := TList<TObject>(AList);
end;

procedure TObjectListWrapper.Delete(I: Integer);
begin
  FList.Delete(I);
end;

function TObjectListWrapper.IndexOf(Obj: TObject): Integer;
begin
  Result := FList.IndexOf(Obj);
end;

procedure TObjectListWrapper.Insert(Index: Integer; Obj: TObject);
begin
  FList.Insert(Index, Obj);
end;

function TObjectListWrapper.Item(I: Integer): TObject;
begin
  result := FList[I];
end;

function TObjectListWrapper.OwnsObjects: Boolean;
begin
  if StartsStr('TObjectList<', FList.ClassName) then
    Result := TObjectList<TObject>(FList).OwnsObjects
  else
    Result := False;
end;

procedure TObjectListWrapper.SetItem(I: Integer; Obj: TObject);
begin
  FList[I] := Obj;
end;

{ THashSet<T> }

procedure THashSet<T>.Add(Item: T);
begin
  FDictionary.AddOrSetValue(Item, 0);
end;

procedure THashSet<T>.Clear;
begin
  FDictionary.Clear;
end;

function THashSet<T>.Contains(Item: T): Boolean;
begin
  Result := FDictionary.ContainsKey(Item);
end;

constructor THashSet<T>.Create;
begin
  FDictionary := TDictionary<T, Integer>.Create;
end;

destructor THashSet<T>.Destroy;
begin
  FDictionary.Free;
  inherited;
end;

function THashSet<T>.GetEnumerator: TEnumerator<T>;
begin
  Result := FDictionary.Keys.GetEnumerator;
end;

procedure THashSet<T>.Remove(Item: T);
begin
  FDictionary.Remove(Item);
end;

{ TObjectSet<T> }

procedure TObjectSet<T>.Add(Item: T);
begin
  FDictionary.AddOrSetValue(Item, 0);
end;

procedure TObjectSet<T>.Clear;
begin
  FDictionary.Clear;
end;

function TObjectSet<T>.Contains(Item: T): Boolean;
begin
  Result := FDictionary.ContainsKey(Item);
end;

constructor TObjectSet<T>.Create(AOwnsObjects: Boolean);
var
  Ownerships: TDictionaryOwnerships;
begin
  if AOwnsObjects then
    Ownerships := [doOwnsKeys]
  else
    Ownerships := [];

  FDictionary := TObjectDictionary<T, Integer>.Create(Ownerships);
end;

destructor TObjectSet<T>.Destroy;
begin
  FDictionary.Free;
  inherited;
end;

function TObjectSet<T>.GetEnumerator: TEnumerator<T>;
begin
  Result := FDictionary.Keys.GetEnumerator;
end;

procedure TObjectSet<T>.Remove(Item: T);
begin
  FDictionary.Remove(Item);
end;

{ TValueListWrapper }

procedure TValueListWrapper.Add(const Value: TValue);
begin
  FAddMethod.Invoke(FList, [Value]);
end;

procedure TValueListWrapper.Clear;
begin
  FClearMethod.Invoke(FList, []);
end;

function TValueListWrapper.Count: Integer;
begin
  Result := FCountProperty.GetValue(FList).AsInteger;
end;

constructor TValueListWrapper.Create(AList: TObject);
var
  RttiType: TRttiType;
begin
  FList := AList;
  FContext := TRttiContext.Create;
  RttiType := FContext.GetType(AList.ClassType);
  FAddMethod := RttiType.GetMethod('Add');
  Assert(FAddMethod <> nil, 'Add method not found');

  FClearMethod := RttiType.GetMethod('Clear');
  Assert(FClearMethod <> nil, 'Clear method not found');

  {$IFDEF DELPHIXE2_LVL}
  FGetItemMethod := RttiType.GetIndexedProperty('Items').ReadMethod;
  {$ENDIF}
  if FGetItemMethod = nil then
    FGetItemMethod := RttiType.GetMethod('GetItem');
  Assert(FGetItemMethod <> nil, 'GetItem method not found');

  FCountProperty := RttiType.GetProperty('Count');
  Assert(FCountProperty <> nil, 'Count property not found');

  FOwnsObjectsProperty := RttiType.GetProperty('OwnsObjects');
end;

destructor TValueListWrapper.Destroy;
begin
  FContext.Free;
  inherited;
end;

function TValueListWrapper.GetItem(I: Integer): TValue;
begin
  Result := FGetItemMethod.Invoke(FList, [I]);
end;

function TValueListWrapper.OwnsValues: Boolean;
begin
  if FOwnsObjectsProperty <> nil then
    Result := FOwnsObjectsProperty.GetValue(FList).AsBoolean
  else
    Result := False;
end;

{ TOrderedDictionary<K, V> }

procedure TOrderedDictionary<K, V>.Add(const key: K; const value: V);
var
  Index: integer;
begin
  Index := IndexOfKey(key);
  if Index >= 0 then
    FItems[Index] := TPairKV.Create(key, value)
  else
    FItems.Add(TPairKV.Create(key, value));
end;

function TOrderedDictionary<K, V>.AsDictionary: IDictionary;
begin
  Result := TOrderedDictionaryAdapter<K, V>.Create(Self);
end;

procedure TOrderedDictionary<K, V>.Clear;
begin
  FItems.Clear;
end;

function TOrderedDictionary<K, V>.ContainsKey(const key: K): boolean;
begin
  Result := IndexOfKey(key) >= 0;
end;

function TOrderedDictionary<K, V>.Count: integer;
begin
  Result := FItems.Count;
end;

constructor TOrderedDictionary<K, V>.Create(const AComparer: IEqualityComparer<K>);
begin
  FComparer := AComparer;
  FItems := TList<TPairKV>.Create;
  FItems.OnNotify := Notify;
end;

constructor TOrderedDictionary<K, V>.Create;
begin
  Create(TEqualityComparer<K>.Default);
end;

destructor TOrderedDictionary<K, V>.Destroy;
begin
  Clear;
  FreeObj(FItems);
  inherited;
end;

function TOrderedDictionary<K, V>.ExtractPair(const key: K): TPairKV;
var
  index: integer;
begin
  index := IndexOfKey(key);
  if index < 0 then
    Exit(TPair<K,V>.Create(Key, Default(V)));

  Result := FItems.Extract(FItems[index]);
end;

function TOrderedDictionary<K, V>.GetEnumerator: TList<TPairKV>.TEnumerator;
begin
  Result := FItems.GetEnumerator;
end;

function TOrderedDictionary<K, V>.GetItems(const key: K): V;
begin
  Result := FItems[IndexOfKey(key)].Value;
end;

function TOrderedDictionary<K, V>.GetKey(const index: integer): K;
begin
  Result := FItems[index].Key;
end;

function TOrderedDictionary<K, V>.GetValue(const index: integer): V;
begin
  Result := FItems[index].Value;
end;

function TOrderedDictionary<K, V>.IndexOfKey(const key: K): integer;
var
  I: Integer;
begin
  for I := 0 to FItems.Count - 1 do
    if FComparer.Equals(FItems[I].Key, key) then
      Exit(I);
  Result := -1;
end;

procedure TOrderedDictionary<K, V>.KeyNotify(const Key: K;
  Action: TCollectionNotification);
begin
end;

procedure TOrderedDictionary<K, V>.Notify(Sender: TObject; const Value: TPairKV;
  Action: TCollectionNotification);
begin
  KeyNotify(Value.Key, Action);
  ValueNotify(Value.Value, Action);
end;

procedure TOrderedDictionary<K, V>.Remove(const key: K);
var
  index: integer;
begin
  index := IndexOfKey(key);
  if index >= 0 then;
    FItems.Delete(index);
end;

procedure TOrderedDictionary<K, V>.SetItems(const key: K; const value: V);
begin
  Add(key, value);
end;

procedure TOrderedDictionary<K, V>.Sort;
var
  Comparer: IComparer<K>;
begin
  Comparer := TComparer<K>.Default;
  FItems.Sort(TComparer<TPairKV>.Construct(
    function(const Left, Right: TPairKV): Integer
    begin
      Result := Comparer.Compare(Left.Key, Right.Key);
    end
  ));
end;

procedure TOrderedDictionary<K, V>.Sort(const AComparer: IComparer<TPairKV>);
begin
  FItems.Sort(AComparer);
end;

function TOrderedDictionary<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 := FItems[I].Value;
  Result := True;
end;

procedure TOrderedDictionary<K, V>.ValueNotify(const Value: V;
  Action: TCollectionNotification);
begin
end;

{ TObjectOrderedDictionary<K, V> }

constructor TOrderedObjectDictionary<K, V>.Create;
begin
  Create([doOwnsValues]);
end;

constructor TOrderedObjectDictionary<K, V>.Create(
  Ownerships: TDictionaryOwnerships);
begin
  Create(Ownerships, TEqualityComparer<K>.Default);
end;

constructor TOrderedObjectDictionary<K, V>.Create(
  Ownerships: TDictionaryOwnerships; const AComparer: IEqualityComparer<K>);
begin
  inherited Create(AComparer);
  FOwnerships := Ownerships;
end;

procedure TOrderedObjectDictionary<K, V>.KeyNotify(const Key: K;
  Action: TCollectionNotification);
begin
  inherited;
  if (Action = cnRemoved) and (doOwnsKeys in FOwnerships) then
    {$IFDEF DELPHIXE4_LVL}
    (PObject(@Key)^).DisposeOf;
	{$ELSE}
    (PObject(@Key)^).Free;
	{$ENDIF}
end;

procedure TOrderedObjectDictionary<K, V>.ValueNotify(const Value: V;
  Action: TCollectionNotification);
begin
  inherited;
  if (Action = cnRemoved) and (doOwnsValues in FOwnerships) then
    {$IFDEF DELPHIXE4_LVL}
    (PObject(@Value)^).DisposeOf;
	{$ELSE}
    (PObject(@Value)^).Free;
	{$ENDIF}
end;

{ TOrderedDictionaryAdapter<K, V> }

procedure TOrderedDictionaryAdapter<K, V>.Add(const Key, Value: TValue);
begin
  FDictionary.Add(Key.AsType<K>, Value.AsType<V>);
end;

procedure TOrderedDictionaryAdapter<K, V>.AddOrSetValue(const Key,
  Value: TValue);
begin
  FDictionary.Add(Key.AsType<K>, Value.AsType<V>);
end;

procedure TOrderedDictionaryAdapter<K, V>.Clear;
begin
  FDictionary.Clear;
end;

function TOrderedDictionaryAdapter<K, V>.ContainsKey(
  const Key: TValue): Boolean;
begin
  Result := FDictionary.ContainsKey(Key.AsType<K>);
end;

constructor TOrderedDictionaryAdapter<K, V>.Create(
  ADictionary: TOrderedDictionary<K, V>);
var
  RttiType: TRttiType;
begin
  FDictionary := ADictionary;
  FContext := TRttiContext.Create;
  RttiType := FContext.GetType(ADictionary.ClassType);
  FOwnershipsProperty := RttiType.GetProperty('Ownerships');
end;

destructor TOrderedDictionaryAdapter<K, V>.Destroy;
begin
  FContext.Free;
  inherited;
end;

function TOrderedDictionaryAdapter<K, V>.GetEnumerator: TEnumerator<TValuePair>;
begin
  Result := TEnumeratorAdapter.Create(FDictionary.GetEnumerator);
end;

function TOrderedDictionaryAdapter<K, V>.GetItem(const Key: TValue): TValue;
begin
  Result := TValue.From<V>(FDictionary.Items[Key.AsType<K>]);
end;

function TOrderedDictionaryAdapter<K, V>.GetOwnerships: TDictionaryOwnerships;
begin
  if FOwnershipsProperty <> nil then
    Result := FOwnershipsProperty.GetValue(FDictionary).AsType<TDictionaryOwnerships>
  else
    Result := [];
end;

procedure TOrderedDictionaryAdapter<K, V>.Remove(const Key: TValue);
begin
  FDictionary.Remove(Key.AsType<K>);
end;

procedure TOrderedDictionaryAdapter<K, V>.SetItem(const Key, Value: TValue);
begin
  FDictionary[Key.AsType<K>] := Value.AsType<V>;
end;

function TOrderedDictionaryAdapter<K, V>.TryGetValue(const Key: TValue;
  out Value: TValue): Boolean;
var
  TempValue: V;
begin
  Result := FDictionary.TryGetValue(Key.AsType<K>, TempValue);
  Value := TValue.From<V>(TempValue);
end;

{ TOrderedDictionaryAdapter<K, V>.TEnumeratorAdapter }

constructor TOrderedDictionaryAdapter<K, V>.TEnumeratorAdapter.Create(
  AEnumerator: TList<TPair<K, V>>.TEnumerator);
begin
  FEnumerator := AEnumerator;
end;

destructor TOrderedDictionaryAdapter<K, V>.TEnumeratorAdapter.Destroy;
begin
  FEnumerator.Free;
  inherited;
end;

function TOrderedDictionaryAdapter<K, V>.TEnumeratorAdapter.DoGetCurrent: TValuePair;
var
  TempCurrent: TPair<K, V>;
begin
  TempCurrent := FEnumerator.Current;
  Result := TValuePair.Create(TValue.From<K>(TempCurrent.Key), TValue.From<V>(TempCurrent.Value));
end;

function TOrderedDictionaryAdapter<K, V>.TEnumeratorAdapter.DoMoveNext: Boolean;
begin
  Result := FEnumerator.MoveNext;
end;

end.
