(*
* Copyright (c) 2011, Ciobanu Alexandru
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)
unit Collections.BidiDictionaries;
interface
uses SysUtils,
Generics.Defaults,
Generics.Collections,
Collections.Base,
Collections.Dictionaries;
type
/// <summary>The base abstract class for all <c>bidi-dictionaries</c> in this package.</summary>
TAbstractBidiDictionary<TKey, TValue> = class abstract(TEnexAssociativeCollection<TKey, TValue>,
IMap<TKey, TValue>, IDictionary<TKey, TValue>, IBidiDictionary<TKey, TValue>)
private
FByKeyDictionary: IDictionary<TKey, TValue>;
FByValueDictionary: IDictionary<TValue, TKey>;
{ Got from the underlying collections }
FValueCollection: IEnexCollection<TValue>;
FKeyCollection: IEnexCollection<TKey>;
protected
procedure IDictionary<TKey, TValue>.SetItem = SetValue;
function IDictionary<TKey, TValue>.GetItem = GetValue;
/// <summary>Specifies the internal dictionary used as back-end to store key relations.</summary>
/// <returns>A map used as back-end.</summary>
property ByKeyDictionary: IDictionary<TKey, TValue> read FByKeyDictionary;
/// <summary>Specifies the internal dictionary used as back-end to store value relations.</summary>
/// <returns>A map used as back-end.</summary>
property ByValueDictionary: IDictionary<TValue, TKey> read FByValueDictionary;
/// <summary>Called when this bidirectional dictionary needs to initialize its internal key dictionary.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
function CreateKeyDictionary(const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>): IDictionary<TKey, TValue>; virtual; abstract;
/// <summary>Called when this bidirectional dictionary needs to initialize its internal value dictionary.</summary>
/// <param name="AValueRules">The rule set describing the values.</param>
function CreateValueDictionary(const AValueRules: TRules<TValue>;
const AKeyRules: TRules<TKey>): IDictionary<TValue, TKey>; virtual; abstract;
/// <summary>Returns the number of pairs in the bidi-dictionary.</summary>
/// <returns>A positive value specifying the total number of pairs in the bidi-dictionary.</returns>
function GetCount(): NativeInt; override;
/// <summary>Returns the value associated with a key.</summary>
/// <param name="AKey">The key for which to obtain the associated value.</param>
/// <returns>The associated value.</returns>
/// <exception cref="Collections.Base|EKeyNotFoundException">The key is not found in the collection.</exception>
function GetValue(const AKey: TKey): TValue;
/// <summary>Sets the value for a given key.</summary>
/// <param name="AKey">The key for which to set the value.</param>
/// <param name="AValue">The value to set.</param>
/// <remarks>If the dictionary does not contain the key, this method acts like <c>Add</c>; otherwise the
/// value of the specified key is modified.</remarks>
/// <exception cref="Collections.Base|EDuplicateKeyException">The new value is already used by another key.</exception>
procedure SetValue(const AKey: TKey; const AValue: TValue);
/// <summary>Returns the key associated with a value.</summary>
/// <param name="AValue">The value for which to obtain the associated key.</param>
/// <returns>The associated key.</returns>
/// <exception cref="Collections.Base|EKeyNotFoundException">The value is not found in the collection.</exception>
function GetKey(const AValue: TValue): TKey;
/// <summary>Sets the key for a given value.</summary>
/// <param name="AValue">The value for which to set the key.</param>
/// <param name="AKey">The key to set.</param>
/// <remarks>If the dictionary does not contain the value, this method acts like <c>Add</c>; otherwise the
/// key of the specified value is modified.</remarks>
/// <exception cref="Collections.Base|EDuplicateKeyException">The new key is already used by another value.</exception>
procedure SetKey(const AValue: TValue; const AKey: TKey);
public
/// <summary>Creates a new instance of this class.</summary>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="ACollection">A collection to copy pairs from.</param>
/// <exception cref="SysUtils|EArgumentNilException"><paramref name="ACollection"/> is <c>nil</c>.</exception>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(const ACollection: IEnumerable<TPair<TKey,TValue>>); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AArray">An array to copy pairs from.</param>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(const AArray: array of TPair<TKey,TValue>); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">A rule set describing the keys in the bidi-map.</param>
/// <param name="AValueRules">A rule set describing the values in the bidi-map.</param>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">A rule set describing the keys in the bidi-map.</param>
/// <param name="AValueRules">A rule set describing the values in the bidi-map.</param>
/// <param name="ACollection">A collection to copy pairs from.</param>
/// <exception cref="SysUtils|EArgumentNilException"><paramref name="ACollection"/> is <c>nil</c>.</exception>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const ACollection: IEnumerable<TPair<TKey,TValue>>); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">A rule set describing the keys in the bidi-map.</param>
/// <param name="AValueRules">A rule set describing the values in the bidi-map.</param>
/// <param name="AArray">An array to copy pairs from.</param>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AArray: array of TPair<TKey,TValue>); overload;
/// <summary>Destroys this instance.</summary>
/// <remarks>Do not call this method directly; call <c>Free</c> instead.</remarks>
destructor Destroy(); override;
/// <summary>Clears the contents of the bidi-dictionary.</summary>
procedure Clear();
/// <summary>Adds a key-value pair to the bidi-dictionary.</summary>
/// <param name="APair">The key-value pair to add.</param>
/// <exception cref="Collections.Base|EDuplicateKeyException">The dictionary already contains a pair with the given key or value.</exception>
procedure Add(const APair: TPair<TKey, TValue>); overload;
/// <summary>Adds a key-value pair to the bidi-dictionary.</summary>
/// <param name="AKey">The key of the pair.</param>
/// <param name="AValue">The value associated with the key.</param>
/// <exception cref="Collections.Base|EDuplicateKeyException">The dictionary already contains a pair with the given key or value.</exception>
procedure Add(const AKey: TKey; const AValue: TValue); overload;
/// <summary>Removes a key-value pair using a given key.</summary>
/// <param name="AKey">The key (and its associated value) to remove.</param>
procedure RemoveKey(const AKey: TKey);
/// <summary>Removes a key-value pair using a given key.</summary>
/// <param name="AKey">The key of the pair.</param>
procedure Remove(const AKey: TKey); overload;
/// <summary>Removes a key-value pair using a given value.</summary>
/// <param name="AValue">The value (and its associated key) to remove.</param>
procedure RemoveValue(const AValue: TValue);
/// <summary>Removes a specific key-value combination.</summary>
/// <param name="AKey">The key to remove.</param>
/// <param name="AValue">The value to remove.</param>
/// <remarks>This method only removes a key-value combination if that combination actually exists in the bidi-dictionary.
/// If the key is associated with another value, nothing happens.</remarks>
procedure Remove(const AKey: TKey; const AValue: TValue); overload;
/// <summary>Removes a specific key-value combination.</summary>
/// <param name="AKey">The key to remove.</param>
/// <param name="AValue">The value to remove.</param>
/// <remarks>This method only removes a key-value combination if that combination actually exists in the bidi-dictionary.
/// If the key is associated with another value, nothing happens.</remarks>
procedure Remove(const APair: TPair<TKey, TValue>); overload;
/// <summary>Checks whether the dictionary contains a key-value pair identified by the given key.</summary>
/// <param name="AKey">The key to check for.</param>
/// <returns><c>True</c> if the dictionary contains a pair identified by the given key; <c>False</c> otherwise.</returns>
function ContainsKey(const AKey: TKey): Boolean;
/// <summary>Checks whether the dictionary contains a key-value pair that contains a given value.</summary>
/// <param name="AValue">The value to check for.</param>
/// <returns><c>True</c> if the dictionary contains a pair holding the given value; <c>False</c> otherwise.</returns>
function ContainsValue(const AValue: TValue): Boolean;
/// <summary>Checks whether the dictionary contains the given key-value combination.</summary>
/// <param name="AKey">The key associated with the value.</param>
/// <param name="AValue">The value associated with the key.</param>
/// <returns><c>True</c> if the dictionary contains the given association; <c>False</c> otherwise.</returns>
function ContainsPair(const AKey: TKey; const AValue: TValue): Boolean; overload;
/// <summary>Checks whether the dictionary contains a given key-value combination.</summary>
/// <param name="APair">The key-value pair combination.</param>
/// <returns><c>True</c> if the dictionary contains the given association; <c>False</c> otherwise.</returns>
function ContainsPair(const APair: TPair<TKey, TValue>): Boolean; overload;
/// <summary>Tries to obtain the value associated with a given key.</summary>
/// <param name="AKey">The key for which to try to retrieve the value.</param>
/// <param name="AFoundValue">The found value (if the result is <c>True</c>).</param>
/// <returns><c>True</c> if the dictionary contains a value for the given key; <c>False</c> otherwise.</returns>
function TryGetValue(const AKey: TKey; out AFoundValue: TValue): Boolean;
/// <summary>Tries to obtain the key associated with a given value.</summary>
/// <param name="AValue">The value for which to try to retrieve the key.</param>
/// <param name="AFoundKey">The found key (if the result is <c>True</c>).</param>
/// <returns><c>True</c> if the dictionary contains a key for the given value; <c>False</c> otherwise.</returns>
function TryGetKey(const AValue: TValue; out AFoundKey: TKey): Boolean;
/// <summary>Returns the value associated with a key.</summary>
/// <param name="AKey">The key for which to obtain the associated value.</param>
/// <returns>The associated value.</returns>
/// <exception cref="Collections.Base|EKeyNotFoundException">The key is not found in the bidi-dictionary.</exception>
property ByKey[const AKey: TKey]: TValue read GetValue write SetValue;
/// <summary>Returns the key associated with a value.</summary>
/// <param name="AValue">The value for which to obtain the associated key.</param>
/// <returns>The associated value.</returns>
/// <exception cref="Collections.Base|EKeyNotFoundException">The key is not found in the bidi-dictionary.</exception>
property ByValue[const AValue: TValue]: TKey read GetKey write SetKey;
/// <summary>Specifies the collection that contains only the keys.</summary>
/// <returns>An Enex collection that contains all the keys stored in the bidi-dictionary.</returns>
property Keys: IEnexCollection<TKey> read FKeyCollection;
/// <summary>Specifies the collection that contains only the values.</summary>
/// <returns>An Enex collection that contains all the values stored in the bidi-dictionary.</returns>
property Values: IEnexCollection<TValue> read FValueCollection;
/// <summary>Returns the number of pairs in the bidi-map.</summary>
/// <returns>A positive value specifying the total number of pairs in the bidi-dictionary.</returns>
property Count: NativeInt read GetCount;
/// <summary>Returns a new enumerator object used to enumerate this bidi-dictionary.</summary>
/// <remarks>This method is usually called by compiler-generated code. Its purpose is to create an enumerator
/// object that is used to actually traverse the bidi-map.</remarks>
/// <returns>An enumerator object.</returns>
function GetEnumerator(): IEnumerator<TPair<TKey, TValue>>; override;
/// <summary>Copies the values stored in the bidi-dictionary to a given array.</summary>
/// <param name="AArray">An array where to copy the contents of the bidi-dictionary.</param>
/// <param name="AStartIndex">The index into the array at which the copying begins.</param>
/// <remarks>This method assumes that <paramref name="AArray"/> has enough space to hold the contents of the bidi-dictionary.</remarks>
/// <exception cref="SysUtils|EArgumentOutOfRangeException"><paramref name="AStartIndex"/> is out of bounds.</exception>
/// <exception cref="Collections.Base|EArgumentOutOfSpaceException">The array is not long enough.</exception>
procedure CopyTo(var AArray: array of TPair<TKey,TValue>; const AStartIndex: NativeInt); overload; override;
/// <summary>Returns the value associated with the given key.</summary>
/// <param name="AKey">The key for which to return the associated value.</param>
/// <returns>The value associated with the given key.</returns>
/// <exception cref="Collections.Base|EKeyNotFoundException">No such key in the bidi-dictionary.</exception>
function ValueForKey(const AKey: TKey): TValue; override;
/// <summary>Checks whether the bidi-map contains a given key-value pair.</summary>
/// <param name="AKey">The key part of the pair.</param>
/// <param name="AValue">The value part of the pair.</param>
/// <returns><c>True</c> if the given key-value pair exists; <c>False</c> otherwise.</returns>
function KeyHasValue(const AKey: TKey; const AValue: TValue): Boolean; override;
/// <summary>Returns an Enex collection that contains only the keys.</summary>
/// <returns>An Enex collection that contains all the keys stored in the bidi-map.</returns>
function SelectKeys(): IEnexCollection<TKey>; override;
/// <summary>Returns an Enex collection that contains only the values.</summary>
/// <returns>An Enex collection that contains all the values stored in the bidi-map.</returns>
function SelectValues(): IEnexCollection<TValue>; override;
/// <summary>Checks whether the dictionary is empty.</summary>
/// <returns><c>True</c> if the dictionary is empty; <c>False</c> otherwise.</returns>
/// <remarks>This method is the recommended way of detecting if the collection is empty. It is optimized
/// in most collections to offer a fast response.</remarks>
function Empty(): Boolean; override;
/// <summary>Returns the biggest key.</summary>
/// <returns>The biggest key stored in this bidirectional dictionary.</returns>
/// <exception cref="Collections.Base|ECollectionEmptyException">The dictionary is empty.</exception>
function MaxKey(): TKey; override;
/// <summary>Returns the smallest key.</summary>
/// <returns>The smallest key stored in this bidirectional dictionary.</returns>
/// <exception cref="Collections.Base|ECollectionEmptyException">The dictionary is empty.</exception>
function MinKey(): TKey; override;
/// <summary>Returns the biggest value.</summary>
/// <returns>The biggest value stored in this bidirectional dictionary.</returns>
/// <exception cref="Collections.Base|ECollectionEmptyException">The dictionary is empty.</exception>
function MaxValue(): TValue; override;
/// <summary>Returns the smallest value.</summary>
/// <returns>The smallest value stored in this bidirectional dictionary.</returns>
/// <exception cref="Collections.Base|ECollectionEmptyException">The dictionary is empty.</exception>
function MinValue(): TValue; override;
end;
type
/// <summary>The generic <c>bidirectional dictionary</c> collection.</summary>
/// <remarks>This type uses two <c>hash-based dictionaries</c> to store its keys and values.</remarks>
TBidiDictionary<TKey, TValue> = class(TAbstractBidiDictionary<TKey, TValue>)
private
FInitialCapacity: NativeInt;
protected
/// <summary>Called when the dictionary needs to initialize the key sub-dictionary.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <remarks>This method creates a hash-based dictionary used as the underlying back-end for the keys.</remarks>
function CreateKeyDictionary(const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>): IDictionary<TKey, TValue>; override;
/// <summary>Called when the dictionary needs to initialize the value sub-dictionary.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <remarks>This method creates a hash-based dictionary used as the underlying back-end for the values.</remarks>
function CreateValueDictionary(const AValueRules: TRules<TValue>;
const AKeyRules: TRules<TKey>): IDictionary<TValue, TKey>; override;
public
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AInitialCapacity">The map's initial capacity.</param>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(const AInitialCapacity: NativeInt); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <param name="AInitialCapacity">The map's initial capacity.</param>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>; const AInitialCapacity: NativeInt); overload;
end;
/// <summary>The generic <c>bidirectional dictionary</c> collection designed to store objects.</summary>
/// <remarks>This type uses two <c>hash-based dictionaries</c> to store its keys and values.</remarks>
TObjectBidiDictionary<TKey, TValue> = class(TBidiDictionary<TKey, TValue>)
private
FOwnsKeys, FOwnsValues: Boolean;
protected
/// <summary>Frees the key (object) that was removed from the collection.</summary>
/// <param name="AKey">The key that was removed from the collection.</param>
procedure HandleKeyRemoved(const AKey: TKey); override;
/// <summary>Frees the value (object) that was removed from the collection.</summary>
/// <param name="AKey">The value that was removed from the collection.</param>
procedure HandleValueRemoved(const AValue: TValue); override;
public
/// <summary>Specifies whether this dictionary owns the keys.</summary>
/// <returns><c>True</c> if the dictionary owns the keys; <c>False</c> otherwise.</returns>
/// <remarks>This property specifies the way the dictionary controls the life-time of the stored keys. The value of this property has effect only
/// if the keys are objects, otherwise it is ignored.</remarks>
property OwnsKeys: Boolean read FOwnsKeys write FOwnsKeys;
/// <summary>Specifies whether this dictionary owns the values.</summary>
/// <returns><c>True</c> if the dictionary owns the values; <c>False</c> otherwise.</returns>
/// <remarks>This property specifies the way the dictionary controls the life-time of the stored values.
/// The value of this property has effect only if the values are objects, otherwise it is ignored.</remarks>
property OwnsValues: Boolean read FOwnsValues write FOwnsValues;
end;
type
/// <summary>The generic <c>bidirectional dictionary</c> collection.</summary>
/// <remarks>This type uses a <c>sorted dictionary</c> to store its keys and a <c>hash-based dictionary</c> for its values.</remarks>
TSortedBidiDictionary<TKey, TValue> = class(TAbstractBidiDictionary<TKey, TValue>)
private
FAscSort: Boolean;
protected
/// <summary>Called when the dictionary needs to initialize the key sub-dictionary.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <remarks>This method creates a sorted dictionary used as the underlying back-end for the keys.</remarks>
function CreateKeyDictionary(const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>): IDictionary<TKey, TValue>; override;
/// <summary>Called when the dictionary needs to initialize the value sub-dictionary.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <remarks>This method creates a hash-based dictionary used as the underlying back-end for the values.</remarks>
function CreateValueDictionary(const AValueRules: TRules<TValue>;
const AKeyRules: TRules<TKey>): IDictionary<TValue, TKey>; override;
public
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AAscending">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(const AAscending: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="ACollection">A collection to copy the key-value pairs from.</param>
/// <param name="AAscending">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <remarks>The default rule set is requested.</remarks>
/// <exception cref="SysUtils|EArgumentNilException"><paramref name="ACollection"/> is <c>nil</c>.</exception>
constructor Create(const ACollection: IEnumerable<TPair<TKey,TValue>>; const AAscending: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AArray">An array to copy the key-value pairs from.</param>
/// <param name="AAscending">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(const AArray: array of TPair<TKey,TValue>; const AAscending: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <param name="AAscending">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AAscending: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <param name="ACollection">A collection to copy the key-value pairs from.</param>
/// <param name="AAscending">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <exception cref="SysUtils|EArgumentNilException"><paramref name="ACollection"/> is <c>nil</c>.</exception>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const ACollection: IEnumerable<TPair<TKey,TValue>>; const AAscending: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <param name="AArray">An array to copy the key-value pairs from.</param>
/// <param name="AAscending">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AArray: array of TPair<TKey,TValue>; const AAscending: Boolean = true); overload;
end;
/// <summary>The generic <c>bidirectional dictionary</c> collection designed to store objects.</summary>
/// <remarks>This type uses a <c>sorted dictionary</c> to store its keys and a <c>hash-based dictionary</c> for its values.</remarks>
TObjectSortedBidiDictionary<TKey, TValue> = class(TSortedBidiDictionary<TKey, TValue>)
private
FOwnsKeys, FOwnsValues: Boolean;
protected
/// <summary>Frees the key (object) that was removed from the collection.</summary>
/// <param name="AKey">The key that was removed from the collection.</param>
procedure HandleKeyRemoved(const AKey: TKey); override;
/// <summary>Frees the value (object) that was removed from the collection.</summary>
/// <param name="AKey">The value that was removed from the collection.</param>
procedure HandleValueRemoved(const AValue: TValue); override;
public
/// <summary>Specifies whether this dictionary owns the keys.</summary>
/// <returns><c>True</c> if the dictionary owns the keys; <c>False</c> otherwise.</returns>
/// <remarks>This property specifies the way the dictionary controls the life-time of the stored keys. The value of this property has effect only
/// if the keys are objects, otherwise it is ignored.</remarks>
property OwnsKeys: Boolean read FOwnsKeys write FOwnsKeys;
/// <summary>Specifies whether this dictionary owns the values.</summary>
/// <returns><c>True</c> if the dictionary owns the values; <c>False</c> otherwise.</returns>
/// <remarks>This property specifies the way the dictionary controls the life-time of the stored values.
/// The value of this property has effect only if the values are objects, otherwise it is ignored.</remarks>
property OwnsValues: Boolean read FOwnsValues write FOwnsValues;
end;
type
/// <summary>The generic <c>bidirectional dictionary</c> collection.</summary>
/// <remarks>This type uses two <c>sorted dictionaries</c> to store its keys and values.</remarks>
TDoubleSortedBidiDictionary<TKey, TValue> = class(TAbstractBidiDictionary<TKey, TValue>)
private
FAscKeys, FAscValues: Boolean;
protected
/// <summary>Called when the dictionary needs to initialize the key sub-dictionary.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <remarks>This method creates a sorted dictionary used as the underlying back-end for the keys.</remarks>
function CreateKeyDictionary(const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>): IDictionary<TKey, TValue>; override;
/// <summary>Called when the dictionary needs to initialize the value sub-dictionary.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <remarks>This method creates a sorted dictionary used as the underlying back-end for the values.</remarks>
function CreateValueDictionary(const AValueRules: TRules<TValue>;
const AKeyRules: TRules<TKey>): IDictionary<TValue, TKey>; override;
public
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AAscendingKeys">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <param name="AAscendingValues">A value specifying whether the values are sorted in ascending order. The default is <c>True</c>.</param>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(const AAscendingKeys: Boolean = true; const AAscendingValues: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="ACollection">A collection to copy the key-value pairs from.</param>
/// <param name="AAscendingKeys">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <param name="AAscendingValues">A value specifying whether the values are sorted in ascending order. The default is <c>True</c>.</param>
/// <remarks>The default rule set is requested.</remarks>
/// <exception cref="SysUtils|EArgumentNilException"><paramref name="ACollection"/> is <c>nil</c>.</exception>
constructor Create(const ACollection: IEnumerable<TPair<TKey,TValue>>;
const AAscendingKeys: Boolean = true; const AAscendingValues: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AArray">An array to copy the key-value pairs from.</param>
/// <param name="AAscendingKeys">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <param name="AAscendingValues">A value specifying whether the values are sorted in ascending order. The default is <c>True</c>.</param>
/// <remarks>The default rule set is requested.</remarks>
constructor Create(const AArray: array of TPair<TKey,TValue>;
const AAscendingKeys: Boolean = true; const AAscendingValues: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <param name="AAscendingKeys">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <param name="AAscendingValues">A value specifying whether the values are sorted in ascending order. The default is <c>True</c>.</param>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AAscendingKeys: Boolean = true; const AAscendingValues: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <param name="ACollection">A collection to copy the key-value pairs from.</param>
/// <param name="AAscendingKeys">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <param name="AAscendingValues">A value specifying whether the values are sorted in ascending order. The default is <c>True</c>.</param>
/// <exception cref="SysUtils|EArgumentNilException"><paramref name="ACollection"/> is <c>nil</c>.</exception>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const ACollection: IEnumerable<TPair<TKey,TValue>>; const AAscendingKeys: Boolean = true;
const AAscendingValues: Boolean = true); overload;
/// <summary>Creates a new instance of this class.</summary>
/// <param name="AKeyRules">The rule set describing the keys.</param>
/// <param name="AValueRules">The rule set describing the values.</param>
/// <param name="AArray">An array to copy the key-value pairs from.</param>
/// <param name="AAscendingKeys">A value specifying whether the keys are sorted in ascending order. The default is <c>True</c>.</param>
/// <param name="AAscendingValues">A value specifying whether the values are sorted in ascending order. The default is <c>True</c>.</param>
constructor Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AArray: array of TPair<TKey,TValue>; const AAscendingKeys: Boolean = true;
const AAscendingValues: Boolean = true); overload;
end;
/// <summary>The generic <c>bidirectional dictionary</c> collection designed to store objects.</summary>
/// <remarks>This type uses two <c>hsorted dictionaries</c> to store its keys and values.</remarks>
TObjectDoubleSortedBidiDictionary<TKey, TValue> = class(TDoubleSortedBidiDictionary<TKey, TValue>)
private
FOwnsKeys, FOwnsValues: Boolean;
protected
/// <summary>Frees the key (object) that was removed from the collection.</summary>
/// <param name="AKey">The key that was removed from the collection.</param>
procedure HandleKeyRemoved(const AKey: TKey); override;
/// <summary>Frees the value (object) that was removed from the collection.</summary>
/// <param name="AKey">The value that was removed from the collection.</param>
procedure HandleValueRemoved(const AValue: TValue); override;
public
/// <summary>Specifies whether this dictionary owns the keys.</summary>
/// <returns><c>True</c> if the dictionary owns the keys; <c>False</c> otherwise.</returns>
/// <remarks>This property specifies the way the dictionary controls the life-time of the stored keys. The value of this property has effect only
/// if the keys are objects, otherwise it is ignored.</remarks>
property OwnsKeys: Boolean read FOwnsKeys write FOwnsKeys;
/// <summary>Specifies whether this dictionary owns the values.</summary>
/// <returns><c>True</c> if the dictionary owns the values; <c>False</c> otherwise.</returns>
/// <remarks>This property specifies the way the dictionary controls the life-time of the stored values. The value of this property has effect only
/// if the values are objects, otherwise it is ignored.</remarks>
property OwnsValues: Boolean read FOwnsValues write FOwnsValues;
end;
implementation
{ TAbstractBidiDictionary<TKey, TValue> }
procedure TAbstractBidiDictionary<TKey, TValue>.Add(const AKey: TKey; const AValue: TValue);
begin
if FByKeyDictionary.ContainsKey(AKey) then
ExceptionHelper.Throw_DuplicateKeyError('AKey');
if FByValueDictionary.ContainsKey(AValue) then
ExceptionHelper.Throw_DuplicateKeyError('AValue');
FByKeyDictionary.Add(AKey, AValue);
FByValueDictionary.Add(AValue, AKey);
end;
procedure TAbstractBidiDictionary<TKey, TValue>.Add(const APair: TPair<TKey, TValue>);
begin
{ Redirect ... }
Add(APair.Key, APair.Value);
end;
procedure TAbstractBidiDictionary<TKey, TValue>.Clear;
begin
if Assigned(FByKeyDictionary) then
FByKeyDictionary.Clear();
if Assigned(FByValueDictionary) then
FByValueDictionary.Clear();
end;
function TAbstractBidiDictionary<TKey, TValue>.ContainsKey(const AKey: TKey): Boolean;
begin
{ Use the value dictionary }
Result := FByKeyDictionary.ContainsKey(AKey);
end;
function TAbstractBidiDictionary<TKey, TValue>.ContainsPair(const APair: TPair<TKey, TValue>): Boolean;
begin
{ Call the best method eva! }
Result := ContainsPair(APair.Key, APair.Value);
end;
function TAbstractBidiDictionary<TKey, TValue>.ContainsPair(const AKey: TKey; const AValue: TValue): Boolean;
var
LRealValue: TValue;
begin
{ Check that the key exists and that the associated value is the same one. }
Result := FByKeyDictionary.TryGetValue(AKey, LRealValue) and ValuesAreEqual(AValue, LRealValue);
end;
function TAbstractBidiDictionary<TKey, TValue>.ContainsValue(const AValue: TValue): Boolean;
begin
{ Use the value dictionary }
Result := FByValueDictionary.ContainsKey(AValue);
end;
procedure TAbstractBidiDictionary<TKey, TValue>.CopyTo(var AArray: array of TPair<TKey, TValue>; const AStartIndex: NativeInt);
begin
{ Copy from the key dictionary }
FByKeyDictionary.CopyTo(AArray, AStartIndex);
end;
constructor TAbstractBidiDictionary<TKey, TValue>.Create(const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>);
begin
{ Install the types }
inherited Create(AKeyRules, AValueRules);
{ Create the maps }
FByKeyDictionary := CreateKeyDictionary(AKeyRules, ValueRules);
FByValueDictionary := CreateValueDictionary(AValueRules, KeyRules);
{ The collections }
FValueCollection := FByValueDictionary.Keys;
FKeyCollection := FByKeyDictionary.Keys;
end;
constructor TAbstractBidiDictionary<TKey, TValue>.Create(const AArray: array of TPair<TKey, TValue>);
begin
{ Call the correct constructor }
Create(TRules<TKey>.Default, TRules<TValue>.Default, AArray);
end;
constructor TAbstractBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AArray: array of TPair<TKey, TValue>);
var
I: NativeInt;
begin
{ Call the correct constructor }
Create(AKeyRules, AValueRules);
{ Copy all items in }
for I := 0 to Length(AArray) - 1 do
Add(AArray[I]);
end;
constructor TAbstractBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const ACollection: IEnumerable<TPair<TKey, TValue>>);
var
LValue: TPair<TKey, TValue>;
begin
{ Call the correct constructor }
Create(AKeyRules, AValueRules);
for LValue in ACollection do
begin
{$IF CompilerVersion < 22}
Add(LValue);
{$ELSE}
Add(LValue.Key, LValue.Value);
{$IFEND}
end;
end;
constructor TAbstractBidiDictionary<TKey, TValue>.Create;
begin
{ Call the correct constructor }
Create(TRules<TKey>.Default, TRules<TValue>.Default);
end;
constructor TAbstractBidiDictionary<TKey, TValue>.Create(const ACollection: IEnumerable<TPair<TKey, TValue>>);
begin
{ Call the correct constructor }
Create(TRules<TKey>.Default, TRules<TValue>.Default, ACollection);
end;
destructor TAbstractBidiDictionary<TKey, TValue>.Destroy;
begin
Clear();
inherited;
end;
function TAbstractBidiDictionary<TKey, TValue>.Empty: Boolean;
begin
{ Redirect }
Result := FByKeyDictionary.Empty();
end;
function TAbstractBidiDictionary<TKey, TValue>.GetCount: NativeInt;
begin
{ Redirect }
Result := FByKeyDictionary.Count;
end;
function TAbstractBidiDictionary<TKey, TValue>.GetEnumerator: IEnumerator<TPair<TKey, TValue>>;
begin
Result := FByKeyDictionary.GetEnumerator();
end;
function TAbstractBidiDictionary<TKey, TValue>.GetKey(const AValue: TValue): TKey;
begin
{ Use indexed property. }
Result := FByValueDictionary[AValue];
end;
function TAbstractBidiDictionary<TKey, TValue>.GetValue(const AKey: TKey): TValue;
begin
{ Use indexed property. }
Result := FByKeyDictionary[AKey];
end;
function TAbstractBidiDictionary<TKey, TValue>.KeyHasValue(const AKey: TKey; const AValue: TValue): Boolean;
begin
{ Call into the key dictionary }
Result := FByKeyDictionary.KeyHasValue(AKey, AValue);
end;
function TAbstractBidiDictionary<TKey, TValue>.MaxKey: TKey;
begin
Result := FByKeyDictionary.MaxKey;
end;
function TAbstractBidiDictionary<TKey, TValue>.MaxValue: TValue;
begin
{ Use the value dictionary for lookup by keys -- much faster }
Result := FByValueDictionary.MaxKey;
end;
function TAbstractBidiDictionary<TKey, TValue>.MinKey: TKey;
begin
Result := FByKeyDictionary.MinKey;
end;
function TAbstractBidiDictionary<TKey, TValue>.MinValue: TValue;
begin
{ Use the value dictionary for lookup by keys -- much faster }
Result := FByValueDictionary.MinKey;
end;
procedure TAbstractBidiDictionary<TKey, TValue>.Remove(const AKey: TKey; const AValue: TValue);
var
LAssociatedValue: TValue;
begin
{ Check if key -> value relationship actually exists }
if FByKeyDictionary.TryGetValue(AKey, LAssociatedValue) and
ValuesAreEqual(LAssociatedValue, AValue) then
begin
{ Remove the key/value from their dictionaries }
FByKeyDictionary.Remove(AKey);
FByValueDictionary.Remove(AValue);
end;
end;
procedure TAbstractBidiDictionary<TKey, TValue>.Remove(const AKey: TKey);
begin
{ Redirect ... }
RemoveKey(AKey);
end;
procedure TAbstractBidiDictionary<TKey, TValue>.Remove(const APair: TPair<TKey, TValue>);
begin
{ Redirect ... }
Remove(APair.Key, APair.Value);
end;
procedure TAbstractBidiDictionary<TKey, TValue>.RemoveKey(const AKey: TKey);
var
LAssociatedValue: TValue;
begin
if FByKeyDictionary.TryGetValue(AKey, LAssociatedValue) then
begin
{ Remove the key/value from their dictionaries }
FByKeyDictionary.Remove(AKey);
FByValueDictionary.Remove(LAssociatedValue);
end;
end;
procedure TAbstractBidiDictionary<TKey, TValue>.RemoveValue(const AValue: TValue);
var
LAssociatedKey: TKey;
begin
if FByValueDictionary.TryGetValue(AValue, LAssociatedKey) then
begin
{ Remove the key/value from their dictionaries }
FByKeyDictionary.Remove(LAssociatedKey);
FByValueDictionary.Remove(AValue);
end;
end;
function TAbstractBidiDictionary<TKey, TValue>.SelectKeys: IEnexCollection<TKey>;
begin
Result := FKeyCollection;
end;
function TAbstractBidiDictionary<TKey, TValue>.SelectValues: IEnexCollection<TValue>;
begin
Result := FValueCollection;
end;
procedure TAbstractBidiDictionary<TKey, TValue>.SetKey(const AValue: TValue; const AKey: TKey);
var
LOldKey: TKey;
begin
{ AKey cannot be in the dictionary! }
if FByKeyDictionary.ContainsKey(AKey) then
ExceptionHelper.Throw_DuplicateKeyError('AKey');
{ Replace or add }
if FByValueDictionary.TryGetValue(AValue, LOldKey) then
FByKeyDictionary.Remove(LOldKey);
{ Register the new Key --> Value relation }
FByKeyDictionary.Add(AKey, AValue);
{ Update the old Value --> Key relation }
FByValueDictionary[AValue] := AKey;
end;
procedure TAbstractBidiDictionary<TKey, TValue>.SetValue(const AKey: TKey; const AValue: TValue);
var
LOldValue: TValue;
begin
{ AKey cannot be in the dictionary! }
if FByValueDictionary.ContainsKey(AValue) then
ExceptionHelper.Throw_DuplicateKeyError('AValue');
{ Replace or add }
if FByKeyDictionary.TryGetValue(AKey, LOldValue) then
FByValueDictionary.Remove(LOldValue);
{ Register the new Value --> Key relation }
FByValueDictionary.Add(AValue, AKey);
{ Update the old Key --> Value relation }
FByKeyDictionary[AKey] := AValue;
end;
function TAbstractBidiDictionary<TKey, TValue>.TryGetKey(const AValue: TValue; out AFoundKey: TKey): Boolean;
begin
{ Act as a bridge }
Result := FByValueDictionary.TryGetValue(AValue, AFoundKey);
end;
function TAbstractBidiDictionary<TKey, TValue>.TryGetValue(const AKey: TKey; out AFoundValue: TValue): Boolean;
begin
{ Act as a bridge }
Result := FByKeyDictionary.TryGetValue(AKey, AFoundValue);
end;
function TAbstractBidiDictionary<TKey, TValue>.ValueForKey(const AKey: TKey): TValue;
begin
{ Act as a bridge }
Result := FByKeyDictionary.ValueForKey(AKey);
end;
{ TBidiDictionary<TKey, TValue> }
constructor TBidiDictionary<TKey, TValue>.Create(const AInitialCapacity: NativeInt);
begin
FInitialCapacity := AInitialCapacity;
inherited Create();
end;
constructor TBidiDictionary<TKey, TValue>.Create(const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>; const AInitialCapacity: NativeInt);
begin
FInitialCapacity := AInitialCapacity;
inherited Create(AKeyRules, AValueRules);
end;
function TBidiDictionary<TKey, TValue>.CreateKeyDictionary(
const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>): IDictionary<TKey, TValue>;
var
LDictionary: TDictionary<TKey, TValue>;
begin
{ Use a double sorted map }
LDictionary := TDictionary<TKey, TValue>.Create(AKeyRules, AValueRules, FInitialCapacity);
LDictionary.KeyRemoveNotification := NotifyKeyRemoved;
Result := LDictionary;
end;
function TBidiDictionary<TKey, TValue>.CreateValueDictionary(
const AValueRules: TRules<TValue>;
const AKeyRules: TRules<TKey>): IDictionary<TValue, TKey>;
var
LDictionary: TDictionary<TValue, TKey>;
begin
{ Use a double sorted map }
LDictionary := TDictionary<TValue, TKey>.Create(AValueRules, AKeyRules, FInitialCapacity);
LDictionary.KeyRemoveNotification := NotifyValueRemoved;
Result := LDictionary;
end;
{ TObjectBidiDictionary<TKey, TValue> }
procedure TObjectBidiDictionary<TKey, TValue>.HandleKeyRemoved(const AKey: TKey);
begin
if FOwnsKeys then
TObject(AKey).Free;
end;
procedure TObjectBidiDictionary<TKey, TValue>.HandleValueRemoved(const AValue: TValue);
begin
if FOwnsValues then
TObject(AValue).Free;
end;
{ TSortedBidiDictionary<TKey, TValue> }
constructor TSortedBidiDictionary<TKey, TValue>.Create(
const AArray: array of TPair<TKey, TValue>; const AAscending: Boolean);
begin
{ Do the dew and continue }
FAscSort := AAscending;
inherited Create(AArray);
end;
constructor TSortedBidiDictionary<TKey, TValue>.Create(
const ACollection: IEnumerable<TPair<TKey, TValue>>;
const AAscending: Boolean);
begin
{ Do the dew and continue }
FAscSort := AAscending;
inherited Create(ACollection);
end;
constructor TSortedBidiDictionary<TKey, TValue>.Create(const AAscending: Boolean);
begin
{ Do the dew and continue }
FAscSort := AAscending;
inherited Create();
end;
constructor TSortedBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AArray: array of TPair<TKey, TValue>; const AAscending: Boolean);
begin
{ Do the dew and continue }
FAscSort := AAscending;
inherited Create(AKeyRules, AValueRules, AArray);
end;
function TSortedBidiDictionary<TKey, TValue>.CreateKeyDictionary(
const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>): IDictionary<TKey, TValue>;
var
LDictionary: TSortedDictionary<TKey, TValue>;
begin
{ Use a double sorted map }
LDictionary := TSortedDictionary<TKey, TValue>.Create(AKeyRules, AValueRules, FAscSort);
LDictionary.KeyRemoveNotification := NotifyKeyRemoved;
Result := LDictionary;
end;
function TSortedBidiDictionary<TKey, TValue>.CreateValueDictionary(
const AValueRules: TRules<TValue>;
const AKeyRules: TRules<TKey>): IDictionary<TValue, TKey>;
var
LDictionary: TDictionary<TValue, TKey>;
begin
{ Use a double sorted map }
LDictionary := TDictionary<TValue, TKey>.Create(AValueRules, AKeyRules);
LDictionary.KeyRemoveNotification := NotifyValueRemoved;
Result := LDictionary;
end;
constructor TSortedBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const ACollection: IEnumerable<TPair<TKey, TValue>>;
const AAscending: Boolean);
begin
{ Do the dew and continue }
FAscSort := AAscending;
inherited Create(AKeyRules, AValueRules, ACollection);
end;
constructor TSortedBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AAscending: Boolean);
begin
{ Do the dew and continue }
FAscSort := AAscending;
inherited Create(AKeyRules, AValueRules);
end;
{ TObjectSortedBidiDictionary<TKey, TValue> }
procedure TObjectSortedBidiDictionary<TKey, TValue>.HandleKeyRemoved(const AKey: TKey);
begin
if FOwnsKeys then
TObject(AKey).Free;
end;
procedure TObjectSortedBidiDictionary<TKey, TValue>.HandleValueRemoved(const AValue: TValue);
begin
if FOwnsValues then
TObject(AValue).Free;
end;
{ TDoubleSortedBidiDictionary<TKey, TValue> }
constructor TDoubleSortedBidiDictionary<TKey, TValue>.Create(
const AArray: array of TPair<TKey, TValue>; const AAscendingKeys,
AAscendingValues: Boolean);
begin
{ Do the dew and continue }
FAscKeys := AAscendingKeys;
FAscValues := AAscendingValues;
inherited Create(AArray);
end;
constructor TDoubleSortedBidiDictionary<TKey, TValue>.Create(
const ACollection: IEnumerable<TPair<TKey, TValue>>; const AAscendingKeys,
AAscendingValues: Boolean);
begin
{ Do the dew and continue }
FAscKeys := AAscendingKeys;
FAscValues := AAscendingValues;
inherited Create(ACollection);
end;
constructor TDoubleSortedBidiDictionary<TKey, TValue>.Create(
const AAscendingKeys, AAscendingValues: Boolean);
begin
{ Do the dew and continue }
FAscKeys := AAscendingKeys;
FAscValues := AAscendingValues;
inherited Create();
end;
constructor TDoubleSortedBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AArray: array of TPair<TKey, TValue>; const AAscendingKeys,
AAscendingValues: Boolean);
begin
{ Do the dew and continue }
FAscKeys := AAscendingKeys;
FAscValues := AAscendingValues;
inherited Create(AKeyRules, AValueRules, AArray);
end;
function TDoubleSortedBidiDictionary<TKey, TValue>.CreateKeyDictionary(
const AKeyRules: TRules<TKey>;
const AValueRules: TRules<TValue>): IDictionary<TKey, TValue>;
var
LDictionary: TSortedDictionary<TKey, TValue>;
begin
{ Use a double sorted map }
LDictionary := TSortedDictionary<TKey, TValue>.Create(AKeyRules, AValueRules, FAscKeys);
LDictionary.KeyRemoveNotification := NotifyKeyRemoved;
Result := LDictionary;
end;
function TDoubleSortedBidiDictionary<TKey, TValue>.CreateValueDictionary(
const AValueRules: TRules<TValue>;
const AKeyRules: TRules<TKey>): IDictionary<TValue, TKey>;
var
LDictionary: TSortedDictionary<TValue, TKey>;
begin
{ Use a double sorted map }
LDictionary := TSortedDictionary<TValue, TKey>.Create(AValueRules, AKeyRules, FAscValues);
LDictionary.KeyRemoveNotification := NotifyValueRemoved;
Result := LDictionary;
end;
constructor TDoubleSortedBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const ACollection: IEnumerable<TPair<TKey, TValue>>; const AAscendingKeys,
AAscendingValues: Boolean);
begin
{ Do the dew and continue }
FAscKeys := AAscendingKeys;
FAscValues := AAscendingValues;
inherited Create(AKeyRules, AValueRules, ACollection);
end;
constructor TDoubleSortedBidiDictionary<TKey, TValue>.Create(
const AKeyRules: TRules<TKey>; const AValueRules: TRules<TValue>;
const AAscendingKeys, AAscendingValues: Boolean);
begin
{ Do the dew and continue }
FAscKeys := AAscendingKeys;
FAscValues := AAscendingValues;
inherited Create(AKeyRules, AValueRules);
end;
{ TObjectDoubleSortedBidiDictionary<TKey, TValue> }
procedure TObjectDoubleSortedBidiDictionary<TKey, TValue>.HandleKeyRemoved(const AKey: TKey);
begin
if FOwnsKeys then
TObject(AKey).Free;
end;
procedure TObjectDoubleSortedBidiDictionary<TKey, TValue>.HandleValueRemoved(const AValue: TValue);
begin
if FOwnsValues then
TObject(AValue).Free;
end;
end.