unit Collections; (***************************************************************************** * Copyright 2003 by Matthew Greet * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. (http://opensource.org/licenses/lgpl-license.php) * * See http://www.warmachine.u-net.com/delphi_collections for updates and downloads. * * $Version: v1.0 $ * $Revision: 1.1.1.4 $ * $Log: D:\QVCS Repositories\Delphi Collections\Collections.qbt $ * * Main unit containing all interface and abstract class definitions. * * Revision 1.1.1.4 by: Matthew Greet Rev date: 14/03/05 23:26:32 * Fixed RemoveAll for TAbstractList for sorted lists. * * Revision 1.1.1.3 by: Matthew Greet Rev date: 14/10/04 16:31:18 * Fixed memory lean in ContainsKey of TAbstractStringMap and * TAbstractIntegerMap. * * Revision 1.1.1.2 by: Matthew Greet Rev date: 12/06/04 20:03:26 * Capacity property. * Memory leak fixed. * * Revision 1.1.1.1 by: Matthew Greet Rev date: 13/02/04 16:12:10 * v1.0 branch. * * Revision 1.1 by: Matthew Greet Rev date: 06/04/03 10:36:30 * Added integer map and string map collection types with supporting * classes. * Add clone and filter functions with supporting classes. * Added nil not allowed collection error. * Properties appear in collection interfaces as well as abstract * classes. * * Revision 1.0 by: Matthew Greet Rev date: 01/03/03 10:50:02 * Initial revision. * * FPC compatibility fixes by: UltraStar Deluxe Team * * $Endlog$ *****************************************************************************) {$IFDEF FPC} {$MODE Delphi}{$H+} {$ENDIF} interface uses Classes, SysUtils; const EquatableIID: TGUID = '{EAC823A7-0B90-11D7-8120-0002E3165EF8}'; HashableIID: TGUID = '{98998440-4C3E-11D7-8120-0002E3165EF8}'; ComparableIID: TGUID = '{9F4C96C0-0CF0-11D7-8120-0002E3165EF8}'; MappableIID: TGUID = '{DAEC8CA0-0DBB-11D7-8120-0002E3165EF8}'; StringMappableIID: TGUID = '{3CC61F40-5F92-11D7-8120-0002E3165EF8}'; IntegerMappableIID: TGUID = '{774FC760-5F92-11D7-8120-0002E3165EF8}'; type TDefaultComparator = class; TNaturalComparator = class; ICollectable = interface; TCollectableArray = array of ICollectable; TIntegerArray = array of Integer; TStringArray = array of String; TListArray = array of TList; TCollectionError = (ceOK, ceDuplicate, ceDuplicateKey, ceFixedSize, ceNilNotAllowed, ceNotNaturalItem, ceOutOfRange); TCollectionErrors = set of TCollectionError; TSearchResultType = (srNotFound, srFoundAtIndex, srBeforeIndex, srAfterEnd); TCollectionType = (ctBag, ctSet, ctList, ctMap, ctIntegerMap, ctStringMap); TCollectionFilterFunc = function (const Item: ICollectable): Boolean of object; TCollectionCompareFunc = function (const Item1, Item2: ICollectable): Integer of object; TSearchResult = record ResultType: TSearchResultType; Index: Integer; end; ICollectable = interface ['{98998441-4C3E-11D7-8120-0002E3165EF8}'] function GetInstance: TObject; end; IEquatable = interface ['{EAC823A7-0B90-11D7-8120-0002E3165EF8}'] function GetInstance: TObject; function Equals(const Item: ICollectable): Boolean; end; IHashable = interface(IEquatable) ['{98998440-4C3E-11D7-8120-0002E3165EF8}'] function HashCode: Integer; end; IComparable = interface(IEquatable) ['{9F4C96C0-0CF0-11D7-8120-0002E3165EF8}'] function CompareTo(const Item: ICollectable): Integer; end; IMappable = interface(IEquatable) ['{DAEC8CA0-0DBB-11D7-8120-0002E3165EF8}'] function GetKey: ICollectable; end; IStringMappable = interface(IEquatable) ['{3CC61F40-5F92-11D7-8120-0002E3165EF8}'] function GetKey: String; end; IIntegerMappable = interface(IEquatable) ['{774FC760-5F92-11D7-8120-0002E3165EF8}'] function GetKey: Integer; end; IComparator = interface ['{1F20CD60-10FE-11D7-8120-0002E3165EF8}'] function GetInstance: TObject; function Compare(const Item1, Item2: ICollectable): Integer; function Equals(const Item1, Item2: ICollectable): Boolean; overload; function Equals(const Comparator: IComparator): Boolean; overload; end; IFilter = interface ['{27FE44C0-638E-11D7-8120-0002E3165EF8}'] function Accept(const Item: ICollectable): Boolean; end; IIterator = interface ['{F6930500-1113-11D7-8120-0002E3165EF8}'] function GetAllowRemoval: Boolean; function CurrentItem: ICollectable; function EOF: Boolean; function First: ICollectable; function Next: ICollectable; function Remove: Boolean; end; IMapIterator = interface(IIterator) ['{848CC0E0-2A31-11D7-8120-0002E3165EF8}'] function CurrentKey: ICollectable; end; IIntegerMapIterator = interface(IIterator) ['{C7169780-606C-11D7-8120-0002E3165EF8}'] function CurrentKey: Integer; end; IStringMapIterator = interface(IIterator) ['{1345ED20-5F93-11D7-8120-0002E3165EF8}'] function CurrentKey: String; end; IAssociation = interface(ICollectable) ['{556CD700-4DB3-11D7-8120-0002E3165EF8}'] function GetKey: ICollectable; function GetValue: ICollectable; end; IIntegerAssociation = interface(ICollectable) ['{ED954420-5F94-11D7-8120-0002E3165EF8}'] function GetKey: Integer; function GetValue: ICollectable; end; IStringAssociation = interface(ICollectable) ['{FB87D2A0-5F94-11D7-8120-0002E3165EF8}'] function GetKey: String; function GetValue: ICollectable; end; IAssociationComparator = interface(IComparator) ['{EA9BE6E0-A852-11D8-B93A-0002E3165EF8}'] function GetKeyComparator: IComparator; procedure SetKeyComparator(Value: IComparator); property KeyComparator: IComparator read GetKeyComparator write SetKeyComparator; end; IIntegerAssociationComparator = interface(IComparator) ['{EA9BE6E1-A852-11D8-B93A-0002E3165EF8}'] end; IStringAssociationComparator = interface(IComparator) ['{EA9BE6E2-A852-11D8-B93A-0002E3165EF8}'] end; ICollection = interface ['{EAC823AC-0B90-11D7-8120-0002E3165EF8}'] function GetAsArray: TCollectableArray; function GetCapacity: Integer; procedure SetCapacity(Value: Integer); function GetComparator: IComparator; procedure SetComparator(const Value: IComparator); function GetDuplicates: Boolean; function GetFixedSize: Boolean; function GetIgnoreErrors: TCollectionErrors; procedure SetIgnoreErrors(Value: TCollectionErrors); function GetInstance: TObject; function GetIterator: IIterator; overload; function GetIterator(const Filter: IFilter): IIterator; overload; function GetIterator(FilterFunc: TCollectionFilterFunc): IIterator; overload; function GetNaturalItemIID: TGUID; function GetNaturalItemsOnly: Boolean; function GetSize: Integer; function GetType: TCollectionType; function Add(const Item: ICollectable): Boolean; overload; function Add(const ItemArray: array of ICollectable): Integer; overload; function Add(const Collection: ICollection): Integer; overload; function Clear: Integer; function Clone: ICollection; function Contains(const Item: ICollectable): Boolean; overload; function Contains(const ItemArray: array of ICollectable): Boolean; overload; function Contains(const Collection: ICollection): Boolean; overload; function Equals(const Collection: ICollection): Boolean; function Find(const Filter: IFilter): ICollectable; overload; function Find(FilterFunc: TCollectionFilterFunc): ICollectable; overload; function FindAll(const Filter: IFilter = nil): ICollection; overload; function FindAll(FilterFunc: TCollectionFilterFunc): ICollection; overload; function IsEmpty: Boolean; function IsNaturalItem(const Item: ICollectable): Boolean; function IsNilAllowed: Boolean; function ItemAllowed(const Item: ICollectable): TCollectionError; function ItemCount(const Item: ICollectable): Integer; overload; function ItemCount(const ItemArray: array of ICollectable): Integer; overload; function ItemCount(const Collection: ICollection): Integer; overload; function Matching(const ItemArray: array of ICollectable): ICollection; overload; function Matching(const Collection: ICollection): ICollection; overload; function Remove(const Item: ICollectable): ICollectable; overload; function Remove(const ItemArray: array of ICollectable): ICollection; overload; function Remove(const Collection: ICollection): ICollection; overload; function RemoveAll(const Item: ICollectable): ICollection; overload; function RemoveAll(const ItemArray: array of ICollectable): ICollection; overload; function RemoveAll(const Collection: ICollection): ICollection; overload; function Retain(const ItemArray: array of ICollectable): ICollection; overload; function Retain(const Collection: ICollection): ICollection; overload; property AsArray: TCollectableArray read GetAsArray; property Capacity: Integer read GetCapacity write SetCapacity; property Comparator: IComparator read GetComparator write SetComparator; property FixedSize: Boolean read GetFixedSize; property IgnoreErrors: TCollectionErrors read GetIgnoreErrors write SetIgnoreErrors; property NaturalItemIID: TGUID read GetNaturalItemIID; property NaturalItemsOnly: Boolean read GetNaturalItemsOnly; property Size: Integer read GetSize; end; IBag = interface(ICollection) ['{C29C9560-2D59-11D7-8120-0002E3165EF8}'] function CloneAsBag: IBag; end; ISet = interface(ICollection) ['{DD7888E2-0BB1-11D7-8120-0002E3165EF8}'] function CloneAsSet: ISet; function Complement(const Universe: ISet): ISet; function Intersect(const Set2: ISet): ISet; function Union(const Set2: ISet): ISet; end; IList = interface(ICollection) ['{EE81AB60-0B9F-11D7-8120-0002E3165EF8}'] function GetDuplicates: Boolean; procedure SetDuplicates(Value: Boolean); function GetItem(Index: Integer): ICollectable; procedure SetItem(Index: Integer; const Item: ICollectable); function GetSorted: Boolean; procedure SetSorted(Value: Boolean); function CloneAsList: IList; function Delete(Index: Integer): ICollectable; procedure Exchange(Index1, Index2: Integer); function First: ICollectable; function IndexOf(const Item: ICollectable): Integer; function Insert(Index: Integer; const Item: ICollectable): Boolean; overload; function Insert(Index: Integer; const ItemArray: array of ICollectable): Integer; overload; function Insert(Index: Integer; const Collection: ICollection): Integer; overload; function Last: ICollectable; procedure Sort(const Comparator: IComparator); overload; procedure Sort(CompareFunc: TCollectionCompareFunc); overload; property Duplicates: Boolean read GetDuplicates write SetDuplicates; property Items[Index: Integer]: ICollectable read GetItem write SetItem; default; property Sorted: Boolean read GetSorted write SetSorted; end; IMap = interface(ICollection) ['{AD458280-2A6B-11D7-8120-0002E3165EF8}'] function GetItem(const Key: ICollectable): ICollectable; procedure SetItem(const Key, Item: ICollectable); function GetKeyComparator: IComparator; procedure SetKeyComparator(const Value: IComparator); function GetKeyIterator: IIterator; function GetKeys: ISet; function GetMapIterator: IMapIterator; function GetMapIteratorByKey(const Filter: IFilter): IMapIterator; overload; function GetMapIteratorByKey(FilterFunc: TCollectionFilterFunc): IMapIterator; overload; function GetNaturalKeyIID: TGUID; function GetNaturalKeysOnly: Boolean; function GetValues: ICollection; function CloneAsMap: IMap; function ContainsKey(const Key: ICollectable): Boolean; overload; function ContainsKey(const KeyArray: array of ICollectable): Boolean; overload; function ContainsKey(const Collection: ICollection): Boolean; overload; function Get(const Key: ICollectable): ICollectable; function IsNaturalKey(const Key: ICollectable): Boolean; function KeyAllowed(const Key: ICollectable): TCollectionError; function MatchingKey(const KeyArray: array of ICollectable): ICollection; overload; function MatchingKey(const Collection: ICollection): ICollection; overload; function Put(const Item: ICollectable): ICollectable; overload; function Put(const Key, Item: ICollectable): ICollectable; overload; function Put(const ItemArray: array of ICollectable): ICollection; overload; function Put(const Collection: ICollection): ICollection; overload; function Put(const Map: IMap): ICollection; overload; function RemoveKey(const Key: ICollectable): ICollectable; overload; function RemoveKey(const KeyArray: array of ICollectable): ICollection; overload; function RemoveKey(const Collection: ICollection): ICollection; overload; function RetainKey(const KeyArray: array of ICollectable): ICollection; overload; function RetainKey(const Collection: ICollection): ICollection; overload; property KeyComparator: IComparator read GetKeyComparator write SetKeyComparator; property Items[const Key: ICollectable]: ICollectable read GetItem write SetItem; default; property NaturalKeyIID: TGUID read GetNaturalKeyIID; property NaturalKeysOnly: Boolean read GetNaturalKeysOnly; end; IIntegerMap = interface(ICollection) ['{93DBA9A0-606C-11D7-8120-0002E3165EF8}'] function GetItem(const Key: Integer): ICollectable; procedure SetItem(const Key: Integer; const Item: ICollectable); function GetKeys: ISet; function GetMapIterator: IIntegerMapIterator; function GetValues: ICollection; function CloneAsIntegerMap: IIntegerMap; function ContainsKey(const Key: Integer): Boolean; overload; function ContainsKey(const KeyArray: array of Integer): Boolean; overload; function Get(const Key: Integer): ICollectable; function Put(const Item: ICollectable): ICollectable; overload; function Put(const Key: Integer; const Item: ICollectable): ICollectable; overload; function Put(const ItemArray: array of ICollectable): ICollection; overload; function Put(const Collection: ICollection): ICollection; overload; function Put(const Map: IIntegerMap): ICollection; overload; function RemoveKey(const Key: Integer): ICollectable; overload; function RemoveKey(const KeyArray: array of Integer): ICollection; overload; function RetainKey(const KeyArray: array of Integer): ICollection; overload; property Items[const Key: Integer]: ICollectable read GetItem write SetItem; default; end; IStringMap = interface(ICollection) ['{20531A20-5F92-11D7-8120-0002E3165EF8}'] function GetItem(const Key: String): ICollectable; procedure SetItem(const Key: String; const Item: ICollectable); function GetKeys: ISet; function GetMapIterator: IStringMapIterator; function GetValues: ICollection; function CloneAsStringMap: IStringMap; function ContainsKey(const Key: String): Boolean; overload; function ContainsKey(const KeyArray: array of String): Boolean; overload; function Get(const Key: String): ICollectable; function Put(const Item: ICollectable): ICollectable; overload; function Put(const Key: String; const Item: ICollectable): ICollectable; overload; function Put(const ItemArray: array of ICollectable): ICollection; overload; function Put(const Collection: ICollection): ICollection; overload; function Put(const Map: IStringMap): ICollection; overload; function RemoveKey(const Key: String): ICollectable; overload; function RemoveKey(const KeyArray: array of String): ICollection; overload; function RetainKey(const KeyArray: array of String): ICollection; overload; property Items[const Key: String]: ICollectable read GetItem write SetItem; default; end; TCollectionPosition = class private FFound: Boolean; public constructor Create(Found: Boolean); property Found: Boolean read FFound; end; TAbstractComparator = class(TInterfacedObject, IComparator) public class function GetDefaultComparator: IComparator; class function GetNaturalComparator: IComparator; class function GetReverseNaturalComparator: IComparator; function GetInstance: TObject; function Compare(const Item1, Item2: ICollectable): Integer; virtual; abstract; function Equals(const Item1, Item2: ICollectable): Boolean; overload; virtual; abstract; function Equals(const Comparator: IComparator): Boolean; overload; virtual; end; TDefaultComparator = class(TAbstractComparator) protected constructor Create; public function Compare(const Item1, Item2: ICollectable): Integer; override; function Equals(const Item1, Item2: ICollectable): Boolean; override; end; TNaturalComparator = class(TAbstractComparator) protected constructor Create; public function Compare(const Item1, Item2: ICollectable): Integer; override; function Equals(const Item1, Item2: ICollectable): Boolean; override; end; TReverseNaturalComparator = class(TAbstractComparator) protected constructor Create; public function Compare(const Item1, Item2: ICollectable): Integer; override; function Equals(const Item1, Item2: ICollectable): Boolean; override; end; TAssociation = class(TInterfacedObject, ICollectable, IAssociation) private FKey: ICollectable; FValue: ICollectable; public constructor Create(const Key, Value: ICollectable); virtual; destructor Destroy; override; function GetInstance: TObject; virtual; function GetKey: ICollectable; function GetValue: ICollectable; end; TIntegerAssociation = class(TInterfacedObject, ICollectable, IIntegerAssociation) private FKey: Integer; FValue: ICollectable; public constructor Create(const Key: Integer; const Value: ICollectable); virtual; destructor Destroy; override; function GetInstance: TObject; virtual; function GetKey: Integer; function GetValue: ICollectable; end; TStringAssociation = class(TInterfacedObject, ICollectable, IStringAssociation) private FKey: String; FValue: ICollectable; public constructor Create(const Key: String; const Value: ICollectable); virtual; destructor Destroy; override; function GetInstance: TObject; virtual; function GetKey: String; function GetValue: ICollectable; end; TAssociationComparator = class(TAbstractComparator, IAssociationComparator) private FKeyComparator: IComparator; public constructor Create(NaturalKeys: Boolean = false); destructor Destroy; override; function GetKeyComparator: IComparator; procedure SetKeyComparator(Value: IComparator); function Compare(const Item1, Item2: ICollectable): Integer; override; function Equals(const Item1, Item2: ICollectable): Boolean; override; property KeyComparator: IComparator read GetKeyComparator write SetKeyComparator; end; TIntegerAssociationComparator = class(TAbstractComparator, IIntegerAssociationComparator) public constructor Create; destructor Destroy; override; function Compare(const Item1, Item2: ICollectable): Integer; override; function Equals(const Item1, Item2: ICollectable): Boolean; override; end; TStringAssociationComparator = class(TAbstractComparator, IStringAssociationComparator) public constructor Create; destructor Destroy; override; function Compare(const Item1, Item2: ICollectable): Integer; override; function Equals(const Item1, Item2: ICollectable): Boolean; override; end; TAbstractCollection = class(TInterfacedObject, ICollection) private FCreated: Boolean; // Required to avoid passing destroyed object reference to exception FComparator: IComparator; FIgnoreErrors: TCollectionErrors; FNaturalItemsOnly: Boolean; protected procedure CollectionError(ErrorType: TCollectionError); procedure InitFrom(const Collection: ICollection); overload; virtual; function TrueAdd(const Item: ICollectable): Boolean; virtual; abstract; procedure TrueClear; virtual; abstract; function TrueContains(const Item: ICollectable): Boolean; virtual; abstract; function TrueItemCount(const Item: ICollectable): Integer; virtual; function TrueRemove(const Item: ICollectable): ICollectable; virtual; abstract; function TrueRemoveAll(const Item: ICollectable): ICollection; virtual; abstract; public constructor Create; overload; virtual; constructor Create(NaturalItemsOnly: Boolean); overload; virtual; constructor Create(const ItemArray: array of ICollectable); overload; virtual; constructor Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); overload; virtual; constructor Create(const Collection: ICollection); overload; virtual; destructor Destroy; override; class function GetAlwaysNaturalItems: Boolean; virtual; function GetAsArray: TCollectableArray; virtual; function GetCapacity: Integer; virtual; abstract; procedure SetCapacity(Value: Integer); virtual; abstract; function GetComparator: IComparator; virtual; procedure SetComparator(const Value: IComparator); virtual; function GetDuplicates: Boolean; virtual; function GetFixedSize: Boolean; virtual; function GetIgnoreErrors: TCollectionErrors; procedure SetIgnoreErrors(Value: TCollectionErrors); function GetInstance: TObject; function GetIterator: IIterator; overload; virtual; abstract; function GetIterator(const Filter: IFilter): IIterator; overload; virtual; function GetIterator(FilterFunc: TCollectionFilterFunc): IIterator; overload; virtual; function GetNaturalItemIID: TGUID; virtual; abstract; function GetNaturalItemsOnly: Boolean; virtual; function GetSize: Integer; virtual; abstract; function GetType: TCollectionType; virtual; abstract; function Add(const Item: ICollectable): Boolean; overload; virtual; function Add(const ItemArray: array of ICollectable): Integer; overload; virtual; function Add(const Collection: ICollection): Integer; overload; virtual; procedure AfterConstruction; override; procedure BeforeDestruction; override; function Clear: Integer; virtual; function Clone: ICollection; virtual; function Contains(const Item: ICollectable): Boolean; overload; virtual; function Contains(const ItemArray: array of ICollectable): Boolean; overload; virtual; function Contains(const Collection: ICollection): Boolean; overload; virtual; function Equals(const Collection: ICollection): Boolean; virtual; function Find(const Filter: IFilter): ICollectable; overload; virtual; function Find(FilterFunc: TCollectionFilterFunc): ICollectable; overload; virtual; function FindAll(const Filter: IFilter): ICollection; overload; virtual; function FindAll(FilterFunc: TCollectionFilterFunc): ICollection; overload; virtual; function IsEmpty: Boolean; virtual; function IsNaturalItem(const Item: ICollectable): Boolean; virtual; function IsNilAllowed: Boolean; virtual; abstract; function ItemAllowed(const Item: ICollectable): TCollectionError; virtual; function ItemCount(const Item: ICollectable): Integer; overload; virtual; function ItemCount(const ItemArray: array of ICollectable): Integer; overload; virtual; function ItemCount(const Collection: ICollection): Integer; overload; virtual; function Matching(const ItemArray: array of ICollectable): ICollection; overload; virtual; function Matching(const Collection: ICollection): ICollection; overload; virtual; function Remove(const Item: ICollectable): ICollectable; overload; virtual; function Remove(const ItemArray: array of ICollectable): ICollection; overload; virtual; function Remove(const Collection: ICollection): ICollection; overload; virtual; function RemoveAll(const Item: ICollectable): ICollection; overload; virtual; function RemoveAll(const ItemArray: array of ICollectable): ICollection; overload; virtual; function RemoveAll(const Collection: ICollection): ICollection; overload; virtual; function Retain(const ItemArray: array of ICollectable): ICollection; overload; virtual; function Retain(const Collection: ICollection): ICollection; overload; virtual; property AsArray: TCollectableArray read GetAsArray; property Capacity: Integer read GetCapacity write SetCapacity; property Comparator: IComparator read GetComparator write SetComparator; property FixedSize: Boolean read GetFixedSize; property IgnoreErrors: TCollectionErrors read GetIgnoreErrors write SetIgnoreErrors; property NaturalItemIID: TGUID read GetNaturalItemIID; property NaturalItemsOnly: Boolean read GetNaturalItemsOnly; property Size: Integer read GetSize; end; TAbstractBag = class(TAbstractCollection, IBag) public function CloneAsBag: IBag; virtual; function GetNaturalItemIID: TGUID; override; function GetType: TCollectionType; override; function IsNilAllowed: Boolean; override; end; TAbstractSet = class (TAbstractCollection, ISet) protected function GetPosition(const Item: ICollectable): TCollectionPosition; virtual; abstract; function TrueAdd(const Item: ICollectable): Boolean; override; procedure TrueAdd2(Position: TCollectionPosition; const Item: ICollectable); virtual; abstract; function TrueContains(const Item: ICollectable): Boolean; override; function TrueGet(Position: TCollectionPosition): ICollectable; virtual; abstract; function TrueRemove(const Item: ICollectable): ICollectable; override; procedure TrueRemove2(Position: TCollectionPosition); virtual; abstract; function TrueRemoveAll(const Item: ICollectable): ICollection; override; public function GetDuplicates: Boolean; override; function GetNaturalItemIID: TGUID; override; function GetType: TCollectionType; override; function CloneAsSet: ISet; virtual; function Complement(const Universe: ISet): ISet; overload; virtual; function Intersect(const Set2: ISet): ISet; overload; virtual; function IsNilAllowed: Boolean; override; function Union(const Set2: ISet): ISet; overload; virtual; end; TAbstractList = class(TAbstractCollection, IList) private FDuplicates: Boolean; FSorted: Boolean; protected function BinarySearch(const Item: ICollectable): TSearchResult; virtual; procedure InitFrom(const Collection: ICollection); override; procedure QuickSort(Lo, Hi: Integer; const Comparator: IComparator); overload; virtual; procedure QuickSort(Lo, Hi: Integer; CompareFunc: TCollectionCompareFunc); overload; virtual; function SequentialSearch(const Item: ICollectable; const SearchComparator: IComparator = nil): TSearchResult; virtual; function TrueContains(const Item: ICollectable): Boolean; override; function TrueGetItem(Index: Integer): ICollectable; virtual; abstract; procedure TrueSetItem(Index: Integer; const Item: ICollectable); virtual; abstract; function TrueAdd(const Item: ICollectable): Boolean; override; procedure TrueAppend(const Item: ICollectable); virtual; abstract; function TrueDelete(Index: Integer): ICollectable; virtual; abstract; procedure TrueInsert(Index: Integer; const Item: ICollectable); virtual; abstract; function TrueItemCount(const Item: ICollectable): Integer; override; function TrueRemove(const Item: ICollectable): ICollectable; override; function TrueRemoveAll(const Item: ICollectable): ICollection; override; public constructor Create(NaturalItemsOnly: Boolean); override; function GetDuplicates: Boolean; override; procedure SetDuplicates(Value: Boolean); virtual; function GetItem(Index: Integer): ICollectable; virtual; procedure SetItem(Index: Integer; const Item: ICollectable); virtual; function GetIterator: IIterator; override; function GetNaturalItemIID: TGUID; override; function GetSorted: Boolean; virtual; procedure SetSorted(Value: Boolean); virtual; function GetType: TCollectionType; override; function CloneAsList: IList; virtual; function Delete(Index: Integer): ICollectable; virtual; procedure Exchange(Index1, Index2: Integer); virtual; function First: ICollectable; virtual; function IndexOf(const Item: ICollectable): Integer; virtual; function Insert(Index: Integer; const Item: ICollectable): Boolean; overload; virtual; function Insert(Index: Integer; const ItemArray: array of ICollectable): Integer; overload; virtual; function Insert(Index: Integer; const Collection: ICollection): Integer; overload; virtual; function IsNilAllowed: Boolean; override; function Last: ICollectable; virtual; function Search(const Item: ICollectable; const SearchComparator: IComparator = nil): TSearchResult; virtual; procedure Sort(const SortComparator: IComparator = nil); overload; virtual; procedure Sort(CompareFunc: TCollectionCompareFunc); overload; virtual; property Duplicates: Boolean read GetDuplicates write SetDuplicates; property Items[Index: Integer]: ICollectable read GetItem write SetItem; default; property Sorted: Boolean read GetSorted write SetSorted; end; TAbstractMap = class(TAbstractCollection, IMap) private FAssociationComparator: IAssociationComparator; FKeyComparator: IComparator; FNaturalKeysOnly: Boolean; protected function GetAssociationIterator: IMapIterator; virtual; abstract; function GetKeyPosition(const Key: ICollectable): TCollectionPosition; virtual; abstract; procedure InitFrom(const Collection: ICollection); override; function TrueAdd(const Item: ICollectable): Boolean; override; function TrueContains(const Item: ICollectable): Boolean; override; function TrueGet(Position: TCollectionPosition): IAssociation; virtual; abstract; function TruePut(Position: TCollectionPosition; const Association: IAssociation): IAssociation; virtual; abstract; function TrueRemove(const Item: ICollectable): ICollectable; override; function TrueRemove2(Position: TCollectionPosition): IAssociation; virtual; abstract; function TrueRemoveAll(const Item: ICollectable): ICollection; override; property AssociationComparator: IAssociationComparator read FAssociationComparator; public constructor Create; override; constructor Create(NaturalItemsOnly: Boolean); override; constructor Create(NaturalItemsOnly: Boolean; NaturalKeysOnly: Boolean); overload; virtual; constructor Create(const ItemArray: array of ICollectable); overload; override; constructor Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); overload; override; constructor Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean; NaturalKeysOnly: Boolean); overload; virtual; constructor Create(const KeyArray, ItemArray: array of ICollectable); overload; virtual; constructor Create(const KeyArray, ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); overload; virtual; constructor Create(const KeyArray, ItemArray: array of ICollectable; NaturalItemsOnly: Boolean; NaturalKeysOnly: Boolean); overload; virtual; // Don't use this parameter signature as it hits a compiler bug in D5. // constructor Create(const KeyArray, ItemArray: TCollectableArray; NaturalItemsOnly: Boolean = false; NaturalKeysOnly: Boolean = true); overload; virtual; constructor Create(const Map: IMap); overload; virtual; destructor Destroy; override; class function GetAlwaysNaturalKeys: Boolean; virtual; function GetItem(const Key: ICollectable): ICollectable; virtual; procedure SetItem(const Key, Item: ICollectable); virtual; function GetIterator: IIterator; override; function GetKeyComparator: IComparator; virtual; procedure SetKeyComparator(const Value: IComparator); virtual; function GetKeyIterator: IIterator; virtual; function GetKeys: ISet; virtual; function GetMapIterator: IMapIterator; virtual; function GetMapIteratorByKey(const Filter: IFilter): IMapIterator; overload; virtual; function GetMapIteratorByKey(FilterFunc: TCollectionFilterFunc): IMapIterator; overload; virtual; function GetNaturalItemIID: TGUID; override; function GetNaturalKeyIID: TGUID; virtual; function GetNaturalKeysOnly: Boolean; virtual; function GetType: TCollectionType; override; function GetValues: ICollection; virtual; function Clone: ICollection; override; function CloneAsMap: IMap; virtual; function ContainsKey(const Key: ICollectable): Boolean; overload; virtual; function ContainsKey(const KeyArray: array of ICollectable): Boolean; overload; virtual; function ContainsKey(const Collection: ICollection): Boolean; overload; virtual; function Get(const Key: ICollectable): ICollectable; virtual; function KeyAllowed(const Key: ICollectable): TCollectionError; virtual; function IsNaturalKey(const Key: ICollectable): Boolean; virtual; function IsNilAllowed: Boolean; override; function MatchingKey(const KeyArray: array of ICollectable): ICollection; overload; virtual; function MatchingKey(const Collection: ICollection): ICollection; overload; virtual; function Put(const Item: ICollectable): ICollectable; overload; virtual; function Put(const Key, Item: ICollectable): ICollectable; overload; virtual; function Put(const ItemArray: array of ICollectable): ICollection; overload; virtual; function Put(const Collection: ICollection): ICollection; overload; virtual; function Put(const Map: IMap): ICollection; overload; virtual; function RemoveKey(const Key: ICollectable): ICollectable; overload; virtual; function RemoveKey(const KeyArray: array of ICollectable): ICollection; overload; virtual; function RemoveKey(const Collection: ICollection): ICollection; overload; virtual; function RetainKey(const KeyArray: array of ICollectable): ICollection; overload; virtual; function RetainKey(const Collection: ICollection): ICollection; overload; virtual; property KeyComparator: IComparator read GetKeyComparator write SetKeyComparator; property Items[const Key: ICollectable]: ICollectable read GetItem write SetItem; default; property NaturalKeyIID: TGUID read GetNaturalKeyIID; property NaturalKeysOnly: Boolean read GetNaturalKeysOnly; end; TAbstractIntegerMap = class(TAbstractCollection, IIntegerMap) private FAssociationComparator: IIntegerAssociationComparator; protected function GetAssociationIterator: IIntegerMapIterator; virtual; abstract; function GetKeyPosition(const Key: Integer): TCollectionPosition; virtual; abstract; function TrueAdd(const Item: ICollectable): Boolean; override; function TrueContains(const Item: ICollectable): Boolean; override; function TrueGet(Position: TCollectionPosition): IIntegerAssociation; virtual; abstract; function TruePut(Position: TCollectionPosition; const Association: IIntegerAssociation): IIntegerAssociation; virtual; abstract; function TrueRemove(const Item: ICollectable): ICollectable; override; function TrueRemove2(Position: TCollectionPosition): IIntegerAssociation; virtual; abstract; function TrueRemoveAll(const Item: ICollectable): ICollection; override; property AssociationComparator: IIntegerAssociationComparator read FAssociationComparator; public constructor Create(NaturalItemsOnly: Boolean); override; constructor Create(const ItemArray: array of ICollectable); overload; override; constructor Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); overload; override; constructor Create(const KeyArray: array of Integer; const ItemArray: array of ICollectable); overload; virtual; constructor Create(const KeyArray: array of Integer; const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); overload; virtual; constructor Create(const Map: IIntegerMap); overload; virtual; destructor Destroy; override; function GetItem(const Key: Integer): ICollectable; virtual; procedure SetItem(const Key: Integer; const Item: ICollectable); virtual; function GetIterator: IIterator; override; function GetKeys: ISet; virtual; function GetMapIterator: IIntegerMapIterator; virtual; function GetNaturalItemIID: TGUID; override; function GetType: TCollectionType; override; function GetValues: ICollection; virtual; function Clone: ICollection; override; function CloneAsIntegerMap: IIntegerMap; virtual; function ContainsKey(const Key: Integer): Boolean; overload; virtual; function ContainsKey(const KeyArray: array of Integer): Boolean; overload; virtual; function Get(const Key: Integer): ICollectable; virtual; function IsNilAllowed: Boolean; override; function Put(const Item: ICollectable): ICollectable; overload; virtual; function Put(const Key: Integer; const Item: ICollectable): ICollectable; overload; virtual; function Put(const ItemArray: array of ICollectable): ICollection; overload; virtual; function Put(const Collection: ICollection): ICollection; overload; virtual; function Put(const Map: IIntegerMap): ICollection; overload; virtual; function RemoveKey(const Key: Integer): ICollectable; overload; virtual; function RemoveKey(const KeyArray: array of Integer): ICollection; overload; virtual; function RetainKey(const KeyArray: array of Integer): ICollection; overload; virtual; property Items[const Key: Integer]: ICollectable read GetItem write SetItem; default; end; TAbstractStringMap = class(TAbstractCollection, IStringMap) private FAssociationComparator: IStringAssociationComparator; protected function GetAssociationIterator: IStringMapIterator; virtual; abstract; function GetKeyPosition(const Key: String): TCollectionPosition; virtual; abstract; function TrueAdd(const Item: ICollectable): Boolean; override; function TrueContains(const Item: ICollectable): Boolean; override; function TrueGet(Position: TCollectionPosition): IStringAssociation; virtual; abstract; function TruePut(Position: TCollectionPosition; const Association: IStringAssociation): IStringAssociation; virtual; abstract; function TrueRemove(const Item: ICollectable): ICollectable; override; function TrueRemove2(Position: TCollectionPosition): IStringAssociation; virtual; abstract; function TrueRemoveAll(const Item: ICollectable): ICollection; override; property AssociationComparator: IStringAssociationComparator read FAssociationComparator; public constructor Create(NaturalItemsOnly: Boolean); override; constructor Create(const ItemArray: array of ICollectable); overload; override; constructor Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); overload; override; constructor Create(const KeyArray: array of String; const ItemArray: array of ICollectable); overload; virtual; constructor Create(const KeyArray: array of String; const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); overload; virtual; constructor Create(const Map: IStringMap); overload; virtual; destructor Destroy; override; function GetItem(const Key: String): ICollectable; virtual; procedure SetItem(const Key: String; const Item: ICollectable); virtual; function GetIterator: IIterator; override; function GetKeys: ISet; virtual; function GetMapIterator: IStringMapIterator; virtual; function GetNaturalItemIID: TGUID; override; function GetType: TCollectionType; override; function GetValues: ICollection; virtual; function Clone: ICollection; override; function CloneAsStringMap: IStringMap; virtual; function ContainsKey(const Key: String): Boolean; overload; virtual; function ContainsKey(const KeyArray: array of String): Boolean; overload; virtual; function Get(const Key: String): ICollectable; virtual; function IsNilAllowed: Boolean; override; function Put(const Item: ICollectable): ICollectable; overload; virtual; function Put(const Key: String; const Item: ICollectable): ICollectable; overload; virtual; function Put(const ItemArray: array of ICollectable): ICollection; overload; virtual; function Put(const Collection: ICollection): ICollection; overload; virtual; function Put(const Map: IStringMap): ICollection; overload; virtual; function RemoveKey(const Key: String): ICollectable; overload; virtual; function RemoveKey(const KeyArray: array of String): ICollection; overload; virtual; function RetainKey(const KeyArray: array of String): ICollection; overload; virtual; property Items[const Key: String]: ICollectable read GetItem write SetItem; default; end; TAbstractCollectionClass = class of TAbstractCollection; TAbstractBagClass = class of TAbstractBag; TAbstractSetClass = class of TAbstractSet; TAbstractListClass = class of TAbstractList; TAbstractMapClass = class of TAbstractMap; TAbstractIntegerMapClass = class of TAbstractIntegerMap; TAbstractStringMapClass = class of TAbstractStringMap; TAbstractIterator = class(TInterfacedObject, IIterator) private FAllowRemoval: Boolean; FEOF: Boolean; FItem: ICollectable; protected constructor Create(AllowRemoval: Boolean = true); function TrueFirst: ICollectable; virtual; abstract; function TrueNext: ICollectable; virtual; abstract; procedure TrueRemove; virtual; abstract; public procedure AfterConstruction; override; function GetAllowRemoval: Boolean; virtual; function CurrentItem: ICollectable; virtual; function EOF: Boolean; virtual; function First: ICollectable; virtual; function Next: ICollectable; virtual; function Remove: Boolean; virtual; property AllowRemoval: Boolean read GetAllowRemoval; end; TAbstractListIterator = class(TAbstractIterator) private FCollection: TAbstractList; FIndex: Integer; protected constructor Create(Collection: TAbstractList); function TrueFirst: ICollectable; override; function TrueNext: ICollectable; override; procedure TrueRemove; override; end; TAbstractMapIterator = class(TAbstractIterator, IMapIterator) public function CurrentKey: ICollectable; virtual; abstract; end; TAbstractAssociationIterator = class(TInterfacedObject, IIterator, IMapIterator) private FAllowRemoval: Boolean; FEOF: Boolean; FAssociation: IAssociation; protected constructor Create(AllowRemoval: Boolean = true); function TrueFirst: IAssociation; virtual; abstract; function TrueNext: IAssociation; virtual; abstract; procedure TrueRemove; virtual; abstract; public procedure AfterConstruction; override; function GetAllowRemoval: Boolean; virtual; function CurrentKey: ICollectable; virtual; function CurrentItem: ICollectable; virtual; function EOF: Boolean; virtual; function First: ICollectable; virtual; function Next: ICollectable; virtual; function Remove: Boolean; virtual; property AllowRemoval: Boolean read GetAllowRemoval; end; TAbstractIntegerAssociationIterator = class(TInterfacedObject, IIterator, IIntegerMapIterator) private FAllowRemoval: Boolean; FEOF: Boolean; FAssociation: IIntegerAssociation; protected constructor Create(AllowRemoval: Boolean = true); function TrueFirst: IIntegerAssociation; virtual; abstract; function TrueNext: IIntegerAssociation; virtual; abstract; procedure TrueRemove; virtual; abstract; public procedure AfterConstruction; override; function GetAllowRemoval: Boolean; virtual; function CurrentKey: Integer; virtual; function CurrentItem: ICollectable; virtual; function EOF: Boolean; virtual; function First: ICollectable; virtual; function Next: ICollectable; virtual; function Remove: Boolean; virtual; property AllowRemoval: Boolean read GetAllowRemoval; end; TAbstractStringAssociationIterator = class(TInterfacedObject, IIterator, IStringMapIterator) private FAllowRemoval: Boolean; FEOF: Boolean; FAssociation: IStringAssociation; protected constructor Create(AllowRemoval: Boolean = true); function TrueFirst: IStringAssociation; virtual; abstract; function TrueNext: IStringAssociation; virtual; abstract; procedure TrueRemove; virtual; abstract; public procedure AfterConstruction; override; function GetAllowRemoval: Boolean; virtual; function CurrentKey: String; virtual; function CurrentItem: ICollectable; virtual; function EOF: Boolean; virtual; function First: ICollectable; virtual; function Next: ICollectable; virtual; function Remove: Boolean; virtual; property AllowRemoval: Boolean read GetAllowRemoval; end; TAssociationIterator = class(TAbstractIterator, IMapIterator) private FIterator: IIterator; protected function TrueFirst: ICollectable; override; function TrueNext: ICollectable; override; procedure TrueRemove; override; public constructor Create(const Iterator: IIterator); destructor Destroy; override; function CurrentItem: ICollectable; override; function CurrentKey: ICollectable; virtual; end; TAssociationKeyIterator = class(TAbstractIterator) private FIterator: IMapIterator; protected function TrueFirst: ICollectable; override; function TrueNext: ICollectable; override; procedure TrueRemove; override; public constructor Create(const Iterator: IMapIterator); destructor Destroy; override; end; TAbstractFilter = class(TInterfacedObject, IFilter) public function Accept(const Item: ICollectable): Boolean; virtual; abstract; end; TFilterIterator = class(TAbstractIterator) private FIterator: IIterator; FFilter: IFilter; protected function TrueFirst: ICollectable; override; function TrueNext: ICollectable; override; procedure TrueRemove; override; public constructor Create(const Iterator: IIterator; const Filter: IFilter; AllowRemoval: Boolean = true); virtual; destructor Destroy; override; end; TFilterFuncIterator = class(TAbstractIterator) private FIterator: IIterator; FFilterFunc: TCollectionFilterFunc; protected function TrueFirst: ICollectable; override; function TrueNext: ICollectable; override; procedure TrueRemove; override; public constructor Create(const Iterator: IIterator; FilterFunc: TCollectionFilterFunc; AllowRemoval: Boolean = true); virtual; destructor Destroy; override; end; TKeyFilterMapIterator = class(TAbstractMapIterator) private FIterator: IMapIterator; FFilter: IFilter; protected function TrueFirst: ICollectable; override; function TrueNext: ICollectable; override; procedure TrueRemove; override; public constructor Create(const Iterator: IMapIterator; const Filter: IFilter; AllowRemoval: Boolean = true); virtual; destructor Destroy; override; function CurrentKey: ICollectable; override; end; TKeyFilterFuncMapIterator = class(TAbstractMapIterator) private FIterator: IMapIterator; FFilterFunc: TCollectionFilterFunc; protected function TrueFirst: ICollectable; override; function TrueNext: ICollectable; override; procedure TrueRemove; override; public constructor Create(const Iterator: IMapIterator; FilterFunc: TCollectionFilterFunc; AllowRemoval: Boolean = true); virtual; destructor Destroy; override; function CurrentKey: ICollectable; override; end; ECollectionError = class(Exception) private FCollection: ICollection; FErrorType: TCollectionError; public constructor Create(const Msg: String; const Collection: ICollection; ErrorType: TCollectionError); property Collection: ICollection read FCollection; property ErrorType: TCollectionError read FErrorType; end; implementation uses Math, CollArray, CollHash, CollList, CollPArray, CollWrappers; var FDefaultComparator: IComparator; FNaturalComparator: IComparator; FReverseNaturalComparator: IComparator; { TCollectionPosition } constructor TCollectionPosition.Create(Found: Boolean); begin FFound := Found; end; { TAbstractComparator } class function TAbstractComparator.GetDefaultComparator: IComparator; begin if FDefaultComparator = nil then FDefaultComparator := TDefaultComparator.Create; Result := FDefaultComparator; end; class function TAbstractComparator.GetNaturalComparator: IComparator; begin if FNaturalComparator = nil then FNaturalComparator := TNaturalComparator.Create; Result := FNaturalComparator; end; class function TAbstractComparator.GetReverseNaturalComparator: IComparator; begin if FReverseNaturalComparator = nil then FReverseNaturalComparator := TReverseNaturalComparator.Create; Result := FReverseNaturalComparator; end; function TAbstractComparator.GetInstance: TObject; begin Result := Self; end; function TAbstractComparator.Equals(const Comparator: IComparator): Boolean; begin Result := (Self = Comparator.GetInstance); end; { TDefaultComparator } constructor TDefaultComparator.Create; begin // Empty end; function TDefaultComparator.Compare(const Item1, Item2: ICollectable): Integer; var Value1, Value2: Integer; begin if Item1 <> nil then Value1 := Integer(Pointer(Item1)) else Value1 := Low(Integer); if Item2 <> nil then Value2 := Integer(Pointer(Item2)) else Value2 := Low(Integer); if (Value1 < Value2) then Result := -1 else if (Value1 > Value2) then Result := 1 else Result := 0; end; function TDefaultComparator.Equals(const Item1, Item2: ICollectable): Boolean; begin Result := (Item1 = Item2); end; { TNaturalComparator } constructor TNaturalComparator.Create; begin // Empty end; function TNaturalComparator.Compare(const Item1, Item2: ICollectable): Integer; begin if (Item1 = nil) and (Item2 <> nil) then Result := -1 else if (Item1 <> nil) and (Item2 = nil) then Result := 1 else if (Item1 = nil) and (Item2 = nil) then Result := 0 else Result := (Item1 as IComparable).CompareTo(Item2); end; function TNaturalComparator.Equals(const Item1, Item2: ICollectable): Boolean; begin if (Item1 = nil) or (Item2 = nil) then Result := (Item1 = Item2) else begin Result := (Item1 as IEquatable).Equals(Item2); end; end; { TReverseNaturalComparator } constructor TReverseNaturalComparator.Create; begin // Empty end; function TReverseNaturalComparator.Compare(const Item1, Item2: ICollectable): Integer; begin if (Item1 = nil) and (Item2 <> nil) then Result := 1 else if (Item1 <> nil) and (Item2 = nil) then Result := -1 else if (Item1 = nil) and (Item2 = nil) then Result := 0 else Result := -(Item1 as IComparable).CompareTo(Item2); end; function TReverseNaturalComparator.Equals(const Item1, Item2: ICollectable): Boolean; begin if (Item1 = nil) or (Item2 = nil) then Result := (Item1 = Item2) else Result := (Item1 as IEquatable).Equals(Item2); end; { TAssociation } constructor TAssociation.Create(const Key, Value: ICollectable); begin FKey := Key; FValue := Value; end; destructor TAssociation.Destroy; begin FKey := nil; FValue := nil; inherited Destroy; end; function TAssociation.GetInstance: TObject; begin Result := Self; end; function TAssociation.GetKey: ICollectable; begin Result := FKey; end; function TAssociation.GetValue: ICollectable; begin Result := FValue; end; { TIntegerAssociation } constructor TIntegerAssociation.Create(const Key: Integer; const Value: ICollectable); begin FKey := Key; FValue := Value; end; destructor TIntegerAssociation.Destroy; begin FValue := nil; inherited Destroy; end; function TIntegerAssociation.GetInstance: TObject; begin Result := Self; end; function TIntegerAssociation.GetKey: Integer; begin Result := FKey; end; function TIntegerAssociation.GetValue: ICollectable; begin Result := FValue; end; { TStringAssociation } constructor TStringAssociation.Create(const Key: String; const Value: ICollectable); begin FKey := Key; FValue := Value; end; destructor TStringAssociation.Destroy; begin FValue := nil; inherited Destroy; end; function TStringAssociation.GetInstance: TObject; begin Result := Self; end; function TStringAssociation.GetKey: String; begin Result := FKey; end; function TStringAssociation.GetValue: ICollectable; begin Result := FValue; end; { TAbstractIterator } constructor TAbstractIterator.Create(AllowRemoval: Boolean); begin inherited Create; FAllowRemoval := AllowRemoval; FEOF := true; FItem := nil; end; procedure TAbstractIterator.AfterConstruction; begin inherited AfterConstruction; First; end; function TAbstractIterator.GetAllowRemoval: Boolean; begin Result := FAllowRemoval; end; function TAbstractIterator.CurrentItem: ICollectable; begin Result := FItem; end; function TAbstractIterator.EOF: Boolean; begin Result := FEOF; end; function TAbstractIterator.First: ICollectable; begin FEOF := false; FItem := TrueFirst; if FItem = nil then FEOF := true; Result := FItem; end; function TAbstractIterator.Next: ICollectable; begin if not FEOF then begin FItem := TrueNext; if FItem = nil then FEOF := true; end; Result := FItem; end; function TAbstractIterator.Remove: Boolean; begin if (FItem <> nil) and FAllowRemoval then begin TrueRemove; FItem := nil; Result := true; end else Result := false; end; { TAbstractAssociationIterator } constructor TAbstractAssociationIterator.Create(AllowRemoval: Boolean); begin inherited Create; FAllowRemoval := AllowRemoval; FEOF := true; FAssociation := nil; end; procedure TAbstractAssociationIterator.AfterConstruction; begin inherited AfterConstruction; First; end; function TAbstractAssociationIterator.GetAllowRemoval: Boolean; begin Result := FAllowRemoval; end; function TAbstractAssociationIterator.CurrentKey: ICollectable; begin if FAssociation <> nil then Result := FAssociation.GetKey else Result := nil; end; function TAbstractAssociationIterator.CurrentItem: ICollectable; begin if FAssociation <> nil then Result := FAssociation.GetValue else Result := nil; end; function TAbstractAssociationIterator.EOF: Boolean; begin Result := FEOF; end; function TAbstractAssociationIterator.First: ICollectable; begin FAssociation := TrueFirst; if FAssociation <> nil then begin Result := FAssociation.GetValue; FEOF := false; end else begin Result := nil; FEOF := true; end; end; function TAbstractAssociationIterator.Next: ICollectable; begin if not FEOF then begin FAssociation := TrueNext; if FAssociation <> nil then Result := FAssociation.GetValue else begin Result := nil; FEOF := true; end; end; end; function TAbstractAssociationIterator.Remove: Boolean; begin if (FAssociation <> nil) and FAllowRemoval then begin TrueRemove; FAssociation := nil; Result := true; end else Result := false; end; { TAbstractIntegerAssociationIterator } constructor TAbstractIntegerAssociationIterator.Create(AllowRemoval: Boolean); begin inherited Create; FAllowRemoval := AllowRemoval; FEOF := true; FAssociation := nil; end; procedure TAbstractIntegerAssociationIterator.AfterConstruction; begin inherited AfterConstruction; First; end; function TAbstractIntegerAssociationIterator.GetAllowRemoval: Boolean; begin Result := FAllowRemoval; end; function TAbstractIntegerAssociationIterator.CurrentKey: Integer; begin if FAssociation <> nil then Result := FAssociation.GetKey else Result := 0; end; function TAbstractIntegerAssociationIterator.CurrentItem: ICollectable; begin if FAssociation <> nil then Result := FAssociation.GetValue else Result := nil; end; function TAbstractIntegerAssociationIterator.EOF: Boolean; begin Result := FEOF; end; function TAbstractIntegerAssociationIterator.First: ICollectable; begin FAssociation := TrueFirst; if FAssociation <> nil then begin Result := FAssociation.GetValue; FEOF := false; end else begin Result := nil; FEOF := true; end; end; function TAbstractIntegerAssociationIterator.Next: ICollectable; begin if not FEOF then begin FAssociation := TrueNext; if FAssociation <> nil then Result := FAssociation.GetValue else begin Result := nil; FEOF := true; end; end; end; function TAbstractIntegerAssociationIterator.Remove: Boolean; begin if (FAssociation <> nil) and FAllowRemoval then begin TrueRemove; FAssociation := nil; Result := true; end else Result := false; end; { TAbstractStringAssociationIterator } constructor TAbstractStringAssociationIterator.Create(AllowRemoval: Boolean); begin inherited Create; FAllowRemoval := AllowRemoval; FEOF := true; FAssociation := nil; end; procedure TAbstractStringAssociationIterator.AfterConstruction; begin inherited AfterConstruction; First; end; function TAbstractStringAssociationIterator.GetAllowRemoval: Boolean; begin Result := FAllowRemoval; end; function TAbstractStringAssociationIterator.CurrentKey: String; begin if FAssociation <> nil then Result := FAssociation.GetKey else Result := ''; end; function TAbstractStringAssociationIterator.CurrentItem: ICollectable; begin if FAssociation <> nil then Result := FAssociation.GetValue else Result := nil; end; function TAbstractStringAssociationIterator.EOF: Boolean; begin Result := FEOF; end; function TAbstractStringAssociationIterator.First: ICollectable; begin FAssociation := TrueFirst; if FAssociation <> nil then begin Result := FAssociation.GetValue; FEOF := false; end else begin Result := nil; FEOF := true; end; end; function TAbstractStringAssociationIterator.Next: ICollectable; begin if not FEOF then begin FAssociation := TrueNext; if FAssociation <> nil then Result := FAssociation.GetValue else begin Result := nil; FEOF := true; end; end; end; function TAbstractStringAssociationIterator.Remove: Boolean; begin if (FAssociation <> nil) and FAllowRemoval then begin TrueRemove; FAssociation := nil; Result := true; end else Result := false; end; { TAssociationIterator } constructor TAssociationIterator.Create(const Iterator: IIterator); begin inherited Create(Iterator.GetAllowRemoval); FIterator := Iterator; end; destructor TAssociationIterator.Destroy; begin FIterator := nil; inherited Destroy; end; function TAssociationIterator.TrueFirst: ICollectable; var Association: IAssociation; begin Association := FIterator.First as IAssociation; if Association <> nil then Result := Association.GetValue else Result := nil; end; function TAssociationIterator.TrueNext: ICollectable; var Association: IAssociation; begin Association := (FIterator.Next as IAssociation); if Association <> nil then Result := Association.GetValue else Result := nil; end; procedure TAssociationIterator.TrueRemove; begin FIterator.Remove; end; function TAssociationIterator.CurrentItem: ICollectable; var Association: IAssociation; begin Association := FIterator.CurrentItem as IAssociation; if Association <> nil then Result := Association.GetValue else Result := nil; end; function TAssociationIterator.CurrentKey: ICollectable; var Association: IAssociation; begin Association := FIterator.CurrentItem as IAssociation; if Association <> nil then Result := Association.GetKey else Result := nil; end; { TAssociationComparator } constructor TAssociationComparator.Create(NaturalKeys: Boolean); begin inherited Create; if NaturalKeys then FKeyComparator := TAbstractComparator.GetNaturalComparator else FKeyComparator := TAbstractComparator.GetDefaultComparator; end; destructor TAssociationComparator.Destroy; begin FKeyComparator := nil; inherited Destroy; end; function TAssociationComparator.GetKeyComparator: IComparator; begin Result := FKeyComparator; end; procedure TAssociationComparator.SetKeyComparator(Value: IComparator); begin FKeyComparator := Value; end; function TAssociationComparator.Compare(const Item1, Item2: ICollectable): Integer; begin Result := KeyComparator.Compare((Item1 as IAssociation).GetKey, (Item2 as IAssociation).GetKey); end; function TAssociationComparator.Equals(const Item1, Item2: ICollectable): Boolean; begin Result := KeyComparator.Equals((Item1 as IAssociation).GetKey, (Item2 as IAssociation).GetKey); end; { TIntegerAssociationComparator } constructor TIntegerAssociationComparator.Create; begin inherited Create; end; destructor TIntegerAssociationComparator.Destroy; begin inherited Destroy; end; function TIntegerAssociationComparator.Compare(const Item1, Item2: ICollectable): Integer; var Key1, Key2: Integer; begin Key1 := (Item1 as IIntegerAssociation).GetKey; Key2 := (Item2 as IIntegerAssociation).GetKey; if Key1 < Key2 then Result := -1 else if Key1 > Key2 then Result := 1 else Result := 0; end; function TIntegerAssociationComparator.Equals(const Item1, Item2: ICollectable): Boolean; begin Result := ((Item1 as IIntegerAssociation).GetKey = (Item2 as IIntegerAssociation).GetKey); end; { TStringAssociationComparator } constructor TStringAssociationComparator.Create; begin inherited Create; end; destructor TStringAssociationComparator.Destroy; begin inherited Destroy; end; function TStringAssociationComparator.Compare(const Item1, Item2: ICollectable): Integer; var Key1, Key2: String; begin Key1 := (Item1 as IStringAssociation).GetKey; Key2 := (Item2 as IStringAssociation).GetKey; if Key1 < Key2 then Result := -1 else if Key1 > Key2 then Result := 1 else Result := 0; end; function TStringAssociationComparator.Equals(const Item1, Item2: ICollectable): Boolean; begin Result := ((Item1 as IStringAssociation).GetKey = (Item2 as IStringAssociation).GetKey); end; { TAssociationKeyIterator } constructor TAssociationKeyIterator.Create(const Iterator: IMapIterator); begin inherited Create(Iterator.GetAllowRemoval); FIterator := Iterator; end; destructor TAssociationKeyIterator.Destroy; begin FIterator := nil; inherited Destroy; end; function TAssociationKeyIterator.TrueFirst: ICollectable; begin FIterator.First; Result := FIterator.CurrentKey; end; function TAssociationKeyIterator.TrueNext: ICollectable; begin FIterator.Next; Result := FIterator.CurrentKey; end; procedure TAssociationKeyIterator.TrueRemove; begin FIterator.Remove; end; { TFilterIterator } constructor TFilterIterator.Create(const Iterator: IIterator; const Filter: IFilter; AllowRemoval: Boolean = true); begin FIterator := Iterator; FFilter := Filter; end; destructor TFilterIterator.Destroy; begin FIterator := nil; FFilter := nil; end; function TFilterIterator.TrueFirst: ICollectable; var Item: ICollectable; begin Item := FIterator.First; while not FIterator.EOF do begin if FFilter.Accept(Item) then break else Item := FIterator.Next; end; Result := Item; end; function TFilterIterator.TrueNext: ICollectable; var Item: ICollectable; begin Item := FIterator.Next; while not FIterator.EOF do begin if FFilter.Accept(Item) then break else Item := FIterator.Next; end; Result := Item; end; procedure TFilterIterator.TrueRemove; begin FIterator.Remove; end; { TFilterFuncIterator } constructor TFilterFuncIterator.Create(const Iterator: IIterator; FilterFunc: TCollectionFilterFunc; AllowRemoval: Boolean = true); begin FIterator := Iterator; FFilterFunc := FilterFunc; end; destructor TFilterFuncIterator.Destroy; begin FIterator := nil; FFilterFunc := nil; end; function TFilterFuncIterator.TrueFirst: ICollectable; var Item: ICollectable; begin Item := FIterator.First; while not FIterator.EOF do begin if FFilterFunc(Item) then break else Item := FIterator.Next; end; Result := Item; end; function TFilterFuncIterator.TrueNext: ICollectable; var Item: ICollectable; begin Item := FIterator.Next; while not FIterator.EOF do begin if FFilterFunc(Item) then break else Item := FIterator.Next; end; Result := Item; end; procedure TFilterFuncIterator.TrueRemove; begin FIterator.Remove; end; { TKeyFilterMapIterator } constructor TKeyFilterMapIterator.Create(const Iterator: IMapIterator; const Filter: IFilter; AllowRemoval: Boolean = true); begin FIterator := Iterator; FFilter := Filter; end; destructor TKeyFilterMapIterator.Destroy; begin FIterator := nil; FFilter := nil; end; function TKeyFilterMapIterator.TrueFirst: ICollectable; var Key, Item: ICollectable; begin Item := FIterator.First; while not FIterator.EOF do begin Key := FIterator.CurrentKey; if FFilter.Accept(Key) then break else Item := FIterator.Next; end; Result := Item; end; function TKeyFilterMapIterator.TrueNext: ICollectable; var Key, Item: ICollectable; begin Item := FIterator.Next; while not FIterator.EOF do begin Key := FIterator.CurrentKey; if FFilter.Accept(Key) then break else Item := FIterator.Next; end; Result := Item; end; procedure TKeyFilterMapIterator.TrueRemove; begin FIterator.Remove; end; function TKeyFilterMapIterator.CurrentKey: ICollectable; begin Result := FIterator.CurrentKey; end; { TKeyFilterFuncMapIterator } constructor TKeyFilterFuncMapIterator.Create(const Iterator: IMapIterator; FilterFunc: TCollectionFilterFunc; AllowRemoval: Boolean = true); begin FIterator := Iterator; FFilterFunc := FilterFunc; end; destructor TKeyFilterFuncMapIterator.Destroy; begin FIterator := nil; FFilterFunc := nil; end; function TKeyFilterFuncMapIterator.TrueFirst: ICollectable; var Key, Item: ICollectable; begin Item := FIterator.First; while not FIterator.EOF do begin Key := FIterator.CurrentKey; if FFilterFunc(Key) then break else Item := FIterator.Next; end; Result := Item; end; function TKeyFilterFuncMapIterator.TrueNext: ICollectable; var Key, Item: ICollectable; begin Item := FIterator.Next; while not FIterator.EOF do begin Key := FIterator.CurrentKey; if FFilterFunc(Key) then break else Item := FIterator.Next; end; Result := Item; end; procedure TKeyFilterFuncMapIterator.TrueRemove; begin FIterator.Remove; end; function TKeyFilterFuncMapIterator.CurrentKey: ICollectable; begin Result := FIterator.CurrentKey; end; { TAbstractCollection } constructor TAbstractCollection.Create; begin Create(false); end; constructor TAbstractCollection.Create(NaturalItemsOnly: Boolean); begin FCreated := false; inherited Create; FNaturalItemsOnly := NaturalItemsOnly or GetAlwaysNaturalItems; if FNaturalItemsOnly then FComparator := TAbstractComparator.GetNaturalComparator else FComparator := TAbstractComparator.GetDefaultComparator; FIgnoreErrors := [ceDuplicate]; end; constructor TAbstractCollection.Create(const ItemArray: array of ICollectable); begin Create(ItemArray, false); end; // Fixed size collections must override this. constructor TAbstractCollection.Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); var I: Integer; begin Create(NaturalItemsOnly); if not FixedSize then begin Capacity := Length(ItemArray); for I := Low(ItemArray) to High(ItemArray) do begin Add(ItemArray[I]); end; end; end; // Fixed size collections must override this. constructor TAbstractCollection.Create(const Collection: ICollection); var Iterator: IIterator; begin Create(Collection.GetNaturalItemsOnly); InitFrom(Collection); if not FixedSize then begin Capacity := Collection.GetSize; Iterator := Collection.GetIterator; while not Iterator.EOF do begin Add(Iterator.CurrentItem); Iterator.Next; end; end; end; destructor TAbstractCollection.Destroy; begin FCreated := false; FComparator := nil; inherited Destroy; end; procedure TAbstractCollection.CollectionError(ErrorType: TCollectionError); var Msg: String; begin if not (ErrorType in FIgnoreErrors) then begin case ErrorType of ceDuplicate: Msg := 'Collection does not allow duplicates.'; ceDuplicateKey: Msg := 'Collection does not allow duplicate keys.'; ceFixedSize: Msg := 'Collection has fixed size.'; ceNilNotAllowed: Msg := 'Collection does not allow nil.'; ceNotNaturalItem: Msg := 'Collection only accepts natural items.'; ceOutOfRange: Msg := 'Index out of collection range.'; end; // If exception is thrown during construction, collection cannot be // passed to it as destructor is automatically called and this leaves an // interface reference to a destroyed object and crashes. if FCreated then raise ECollectionError.Create(Msg, Self, ErrorType) else raise ECollectionError.Create(Msg, nil, ErrorType); end; end; procedure TAbstractCollection.InitFrom(const Collection: ICollection); begin Comparator := Collection.GetComparator; IgnoreErrors := Collection.GetIgnoreErrors; end; // Implementations should override this if possible function TAbstractCollection.TrueItemCount(const Item: ICollectable): Integer; var Iterator: IIterator; Total: Integer; begin Total := 0; Iterator := GetIterator; while not Iterator.EOF do begin if FComparator.Equals(Item, Iterator.CurrentItem) then Inc(Total); Iterator.Next; end; Result := Total; end; class function TAbstractCollection.GetAlwaysNaturalItems: Boolean; begin Result := false; end; function TAbstractCollection.GetAsArray: TCollectableArray; var Iterator: IIterator; Working: TCollectableArray; I: Integer; begin SetLength(Working, Size); I := 0; Iterator := GetIterator; while not Iterator.EOF do begin Working[I] := Iterator.CurrentItem; Inc(I); Iterator.Next; end; Result := Working; end; function TAbstractCollection.GetComparator: IComparator; begin Result := FComparator; end; function TAbstractCollection.GetDuplicates: Boolean; begin Result := true; // Sets and lists override this. end; procedure TAbstractCollection.SetComparator(const Value: IComparator); begin if Value = nil then begin if NaturalItemsOnly then FComparator := TAbstractComparator.GetNaturalComparator else FComparator := TAbstractComparator.GetDefaultComparator; end else FComparator := Value; end; function TAbstractCollection.GetFixedSize: Boolean; begin Result := false; end; function TAbstractCollection.GetIgnoreErrors: TCollectionErrors; begin Result := FIgnoreErrors; end; procedure TAbstractCollection.SetIgnoreErrors(Value: TCollectionErrors); begin FIgnoreErrors := Value; end; function TAbstractCollection.GetInstance: TObject; begin Result := Self; end; function TAbstractCollection.GetIterator(const Filter: IFilter): IIterator; var Iterator: IIterator; begin Iterator := GetIterator; Result := TFilterIterator.Create(Iterator, Filter, Iterator.GetAllowRemoval); end; function TAbstractCollection.GetIterator(FilterFunc: TCollectionFilterFunc): IIterator; var Iterator: IIterator; begin Iterator := GetIterator; Result := TFilterFuncIterator.Create(Iterator, FilterFunc, Iterator.GetAllowRemoval); end; function TAbstractCollection.GetNaturalItemsOnly: Boolean; begin Result := FNaturalItemsOnly; end; function TAbstractCollection.Add(const Item: ICollectable): Boolean; var ItemError: TCollectionError; Success: Boolean; begin ItemError := ItemAllowed(Item); // Can be natural items only error or nil not allowed error if ItemError <> ceOK then begin CollectionError(ItemError); Success := false; end else if FixedSize then begin CollectionError(ceFixedSize); Success := false; end else begin Success := TrueAdd(Item); end; Result := Success; end; function TAbstractCollection.Add(const ItemArray: array of ICollectable): Integer; var Item: ICollectable; ItemError: TCollectionError; I, Count: Integer; Success: Boolean; begin Count := 0; if FixedSize then begin CollectionError(ceFixedSize); end else begin for I := Low(ItemArray) to High(ItemArray) do begin Item := ItemArray[I]; ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Success := false; end else begin Success := TrueAdd(Item); end; if Success then Inc(Count); end; end; Result := Count; end; function TAbstractCollection.Add(const Collection: ICollection): Integer; var Iterator: IIterator; Item: ICollectable; ItemError: TCollectionError; Count: Integer; Success: Boolean; begin Count := 0; Iterator := Collection.GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem; ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Success := false; end else if FixedSize then begin CollectionError(ceFixedSize); Success := false; end else begin Success := TrueAdd(Item); end; if Success then Inc(Count); Iterator.Next; end; Result := Count; end; procedure TAbstractCollection.AfterConstruction; begin inherited AfterConstruction; FCreated := true; end; procedure TAbstractCollection.BeforeDestruction; begin if not FixedSize then TrueClear; inherited BeforeDestruction; end; function TAbstractCollection.Clear: Integer; begin if not FixedSize then begin Result := Size; TrueClear; end else begin CollectionError(ceFixedSize); Result := 0; end; end; function TAbstractCollection.Clone: ICollection; begin Result := (TAbstractCollectionClass(ClassType)).Create(Self); end; function TAbstractCollection.Contains(const Item: ICollectable): Boolean; var ItemError: TCollectionError; Success: Boolean; begin ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Success := false; end else begin Success := TrueContains(Item); end; Result := Success; end; function TAbstractCollection.Contains(const ItemArray: array of ICollectable): Boolean; var I: Integer; Success: Boolean; begin Success := true; for I := Low(ItemArray) to High(ItemArray) do begin Success := Success and Contains(ItemArray[I]); if not Success then break; end; Result := Success; end; function TAbstractCollection.Contains(const Collection: ICollection): Boolean; var Iterator: IIterator; Success: Boolean; begin Success := true; Iterator := Collection.GetIterator; while not Iterator.EOF do begin Success := Success and Contains(Iterator.CurrentItem); if not Success then break; Iterator.Next; end; Result := Success; end; function TAbstractCollection.Equals(const Collection: ICollection): Boolean; var Iterator: IIterator; Success: Boolean; begin if Collection.GetType <> GetType then Result := false else if Collection.Size <> Size then Result := false else if not Collection.Comparator.Equals(Comparator) then Result := false else if not Collection.GetDuplicates and not GetDuplicates then begin // Not equal if any item not found in parameter collection Success := true; Iterator := GetIterator; while not Iterator.EOF and Success do begin Success := Collection.Contains(Iterator.CurrentItem); Iterator.Next; end; Result := Success; end else begin // Not equal if any item count not equal to item count in parameter collection Success := true; Iterator := GetIterator; while not Iterator.EOF and Success do begin Success := (ItemCount(Iterator.CurrentItem) = Collection.ItemCount(Iterator.CurrentItem)); Iterator.Next; end; Result := Success; end; end; function TAbstractCollection.Find(const Filter: IFilter): ICollectable; begin Result := GetIterator(Filter).First; end; function TAbstractCollection.Find(FilterFunc: TCollectionFilterFunc): ICollectable; begin Result := GetIterator(FilterFunc).First; end; function TAbstractCollection.FindAll(const Filter: IFilter): ICollection; var ResultCollection: ICollection; Iterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Self.GetIterator(Filter); while not Iterator.EOF do begin ResultCollection.Add(Iterator.CurrentItem); Iterator.Next; end; Result := ResultCollection; end; function TAbstractCollection.FindAll(FilterFunc: TCollectionFilterFunc): ICollection; var ResultCollection: ICollection; Iterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Self.GetIterator(FilterFunc); while not Iterator.EOF do begin ResultCollection.Add(Iterator.CurrentItem); Iterator.Next; end; Result := ResultCollection; end; function TAbstractCollection.IsEmpty: Boolean; begin Result := (Size = 0); end; function TAbstractCollection.IsNaturalItem(const Item: ICollectable): Boolean; var Temp: IUnknown; begin if Item <> nil then Result := (Item.QueryInterface(NaturalItemIID, Temp) <> E_NOINTERFACE) else Result := false; end; function TAbstractCollection.ItemAllowed(const Item: ICollectable): TCollectionError; begin if NaturalItemsOnly and not IsNaturalItem(Item) then Result := ceNotNaturalItem else if not IsNilAllowed and (Item = nil) then Result := ceNilNotAllowed else Result := ceOK; end; function TAbstractCollection.ItemCount(const Item: ICollectable): Integer; var ItemError: TCollectionError; begin ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Result := 0; end else if GetDuplicates then begin Result := TrueItemCount(Item); end else begin // Where duplicates are not allowed, TrueContains will be faster than TrueItemCount. if TrueContains(Item) then Result := 1 else Result := 0; end; end; function TAbstractCollection.ItemCount(const ItemArray: array of ICollectable): Integer; var I: Integer; Total: Integer; begin Total := 0; for I := Low(ItemArray) to High(ItemArray) do begin Total := Total + ItemCount(ItemArray[I]); end; Result := Total; end; function TAbstractCollection.ItemCount(const Collection: ICollection): Integer; var Iterator: IIterator; Total: Integer; begin Total := 0; Iterator := Collection.GetIterator; while not Iterator.EOF do begin Total := Total + ItemCount(Iterator.CurrentItem); Iterator.Next; end; Result := Total; end; function TAbstractCollection.Matching(const ItemArray: array of ICollectable): ICollection; var ResultCollection: ICollection; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(ItemArray) to High(ItemArray) do begin if Contains(ItemArray[I]) then ResultCollection.Add(ItemArray[I]); end; Result := ResultCollection; end; function TAbstractCollection.Matching(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Iterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin if Contains(Iterator.CurrentItem) then ResultCollection.Add(Iterator.CurrentItem); Iterator.Next; end; Result := ResultCollection; end; function TAbstractCollection.Remove(const Item: ICollectable): ICollectable; var ItemError: TCollectionError; begin ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Result := nil; end else if FixedSize then begin CollectionError(ceFixedSize); Result := nil; end else begin Result := TrueRemove(Item); end; end; function TAbstractCollection.Remove(const ItemArray: array of ICollectable): ICollection; var ResultCollection: ICollection; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(ItemArray) to High(ItemArray) do begin ResultCollection.Add(Remove(ItemArray[I])); end; Result := ResultCollection; end; function TAbstractCollection.Remove(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Iterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin ResultCollection.Add(Remove(Iterator.CurrentItem)); Iterator.Next; end; Result := ResultCollection; end; function TAbstractCollection.RemoveAll(const Item: ICollectable): ICollection; var ItemError: TCollectionError; begin ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Result := nil; end else if FixedSize then begin CollectionError(ceFixedSize); Result := nil; end else begin Result := TrueRemoveAll(Item); end; end; function TAbstractCollection.RemoveAll(const ItemArray: array of ICollectable): ICollection; var ResultCollection: ICollection; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(ItemArray) to High(ItemArray) do begin ResultCollection.Add(RemoveAll(ItemArray[I])); end; Result := ResultCollection; end; function TAbstractCollection.RemoveAll(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Iterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin ResultCollection.Add(RemoveAll(Iterator.CurrentItem)); Iterator.Next; end; Result := ResultCollection; end; function TAbstractCollection.Retain(const ItemArray: array of ICollectable): ICollection; var ResultCollection: ICollection; Iterator: IIterator; Item: ICollectable; I: Integer; Found, Success: Boolean; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := GetIterator; while not Iterator.EOF do begin // Converting the array to a map would be faster but I don't want to // couple base class code to a complex collection. Found := false; for I := Low(ItemArray) to High(ItemArray) do begin Item := Iterator.CurrentItem; Found := Comparator.Equals(Item, ItemArray[I]); if Found then break; end; if not Found then begin Success := Iterator.Remove; if Success then ResultCollection.Add(Item); end; Iterator.Next; end; Result := ResultCollection; end; function TAbstractCollection.Retain(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Iterator: IIterator; Item: ICollectable; Success: Boolean; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem; if not Collection.Contains(Item) then begin Success := Iterator.Remove; if Success then ResultCollection.Add(Item); end; Iterator.Next; end; Result := ResultCollection; end; { TAbstractBag } function TAbstractBag.CloneAsBag: IBag; begin Result := (TAbstractBagClass(ClassType)).Create(Self); end; function TAbstractBag.GetNaturalItemIID: TGUID; begin Result := EquatableIID; end; function TAbstractBag.GetType: TCollectionType; begin Result := ctBag; end; function TAbstractBag.IsNilAllowed: Boolean; begin Result := true; end; { TAbstractSet } function TAbstractSet.TrueAdd(const Item: ICollectable): Boolean; var Position: TCollectionPosition; begin // Adds if not already present otherwise fails Position := GetPosition(Item); try if Position.Found then begin CollectionError(ceDuplicate); Result := false; end else begin TrueAdd2(Position, Item); Result := true; end; finally Position.Free; end; end; function TAbstractSet.TrueContains(const Item: ICollectable): Boolean; var Position: TCollectionPosition; begin Position := GetPosition(Item); try Result := Position.Found; finally Position.Free; end; end; function TAbstractSet.TrueRemove(const Item: ICollectable): ICollectable; var Position: TCollectionPosition; begin Position := GetPosition(Item); try if Position.Found then begin Result := TrueGet(Position); TrueRemove2(Position); end else Result := nil; finally Position.Free; end; end; function TAbstractSet.TrueRemoveAll(const Item: ICollectable): ICollection; var ResultCollection: ICollection; RemovedItem: ICollectable; begin ResultCollection := TPArrayBag.Create; RemovedItem := TrueRemove(Item); if RemovedItem <> nil then ResultCollection.Add(RemovedItem); Result := ResultCollection; end; function TAbstractSet.GetDuplicates: Boolean; begin Result := false; end; function TAbstractSet.GetNaturalItemIID: TGUID; begin Result := EquatableIID; end; function TAbstractSet.GetType: TCollectionType; begin Result := ctSet; end; function TAbstractSet.CloneAsSet: ISet; begin Result := (TAbstractSetClass(ClassType)).Create(Self); end; function TAbstractSet.Complement(const Universe: ISet): ISet; var ResultSet: ISet; Iterator: IIterator; Item: ICollectable; begin // Return items in universe not found in self. ResultSet := TAbstractSetClass(ClassType).Create(NaturalItemsOnly); Iterator := Universe.GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem; if not Contains(Item) then ResultSet.Add(Item); Iterator.Next; end; Result := ResultSet; end; function TAbstractSet.Intersect(const Set2: ISet): ISet; var ResultSet: ISet; Iterator: IIterator; Item: ICollectable; begin // Return items found in self and parameter. ResultSet := TAbstractSetClass(ClassType).Create(NaturalItemsOnly); Iterator := GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem; if Contains(Item) and Set2.Contains(Item) then ResultSet.Add(Iterator.CurrentItem); Iterator.Next; end; Result := ResultSet; end; function TAbstractSet.IsNilAllowed: Boolean; begin Result := false; end; function TAbstractSet.Union(const Set2: ISet): ISet; var ResultSet: ISet; Iterator: IIterator; Item: ICollectable; begin // Return items found in self or parameter. ResultSet := CloneAsSet; Iterator := Set2.GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem; if not Contains(Item) and Set2.Contains(Item) then ResultSet.Add(Iterator.CurrentItem); Iterator.Next; end; Result := ResultSet; end; { TAbstractList } constructor TAbstractList.Create(NaturalItemsOnly: Boolean); begin inherited Create(NaturalItemsOnly); FDuplicates := true; FSorted := false; end; procedure TAbstractList.InitFrom(const Collection: ICollection); var List: IList; begin inherited InitFrom(Collection); if Collection.QueryInterface(IList, List) = S_OK then begin FDuplicates := List.GetDuplicates; FSorted := List.GetSorted; end; end; function TAbstractList.TrueAdd(const Item: ICollectable): Boolean; var SearchResult: TSearchResult; begin Result := True; if Sorted then begin // Insert in appropriate place to maintain sort order, unless duplicate // not allowed. SearchResult := BinarySearch(Item); case SearchResult.ResultType of srBeforeIndex: TrueInsert(SearchResult.Index, Item); srFoundAtIndex: begin if Duplicates then TrueInsert(SearchResult.Index, Item) else begin CollectionError(ceDuplicate); Result := false; end; end; srAfterEnd: TrueAppend(Item); end; end else begin // Add to end, unless duplicate not allowed. if not Duplicates and (SequentialSearch(Item, Comparator).ResultType = srFoundAtIndex) then begin CollectionError(ceDuplicate); Result := false; end else TrueAppend(Item); end; end; function TAbstractList.TrueContains(const Item: ICollectable): Boolean; begin if Sorted then Result := BinarySearch(Item).ResultType = srFoundAtIndex else Result := SequentialSearch(Item, Comparator).ResultType = srFoundAtIndex end; function TAbstractList.TrueItemCount(const Item: ICollectable): Integer; var SearchResult: TSearchResult; Count: Integer; begin if Sorted then begin // If sorted, use binary search. Count := 0; SearchResult := BinarySearch(Item); if SearchResult.ResultType = srFoundAtIndex then begin repeat Inc(Count); until not Comparator.Equals(Item, Items[SearchResult.Index]); end; Result := Count; end else // Resort to sequential search for unsorted Result := inherited TrueItemCount(Item); end; function TAbstractList.TrueRemove(const Item: ICollectable): ICollectable; var SearchResult: TSearchResult; begin Result := nil; if Sorted then begin SearchResult := BinarySearch(Item); if SearchResult.ResultType = srFoundAtIndex then begin Result := TrueDelete(SearchResult.Index); end; end else begin SearchResult := SequentialSearch(Item); if SearchResult.ResultType = srFoundAtIndex then Result := TrueDelete(SearchResult.Index); end; end; function TAbstractList.TrueRemoveAll(const Item: ICollectable): ICollection; var ResultCollection: ICollection; SearchResult: TSearchResult; I: Integer; begin ResultCollection := TPArrayBag.Create; if Sorted then begin SearchResult := BinarySearch(Item); if SearchResult.ResultType = srFoundAtIndex then begin repeat ResultCollection.Add(TrueDelete(SearchResult.Index)); until not Comparator.Equals(Item, Items[SearchResult.Index]); end; end else begin I := 0; while I < Size do begin if Comparator.Equals(Item, Items[I]) then begin ResultCollection.Add(TrueDelete(I)); end else Inc(I); end; end; Result := ResultCollection; end; procedure TAbstractList.QuickSort(Lo, Hi: Integer; const Comparator: IComparator); var I, J, Mid: Integer; begin repeat I := Lo; J := Hi; Mid := (Lo + Hi) div 2; repeat while Comparator.Compare(Items[I], Items[Mid]) < 0 do Inc(I); while Comparator.Compare(Items[J], Items[Mid]) > 0 do Dec(J); if I <= J then begin Exchange(I, J); if Mid = I then Mid := J else if Mid = J then Mid := I; Inc(I); Dec(J); end; until I > J; if Lo < J then QuickSort(Lo, J, Comparator); Lo := I; until I >= Hi; end; procedure TAbstractList.QuickSort(Lo, Hi: Integer; CompareFunc: TCollectionCompareFunc); var I, J, Mid: Integer; begin repeat I := Lo; J := Hi; Mid := (Lo + Hi) div 2; repeat while CompareFunc(Items[I], Items[Mid]) < 0 do Inc(I); while CompareFunc(Items[J], Items[Mid]) > 0 do Dec(J); if I <= J then begin Exchange(I, J); if Mid = I then Mid := J else if Mid = J then Mid := I; Inc(I); Dec(J); end; until I > J; if Lo < J then QuickSort(Lo, J, CompareFunc); Lo := I; until I >= Hi; end; function TAbstractList.GetDuplicates: Boolean; begin Result := FDuplicates; end; procedure TAbstractList.SetDuplicates(Value: Boolean); var Iterator: IIterator; Failed: Boolean; begin Failed := false; // If trying to set no duplicates, check there are no existing duplicates. if not Value then begin Iterator := GetIterator; while not Iterator.EOF and not Failed do begin Failed := (ItemCount(Iterator.CurrentItem) > 1); Iterator.Next; end; if Failed then CollectionError(ceDuplicate); end; if not Failed then FDuplicates := Value; end; function TAbstractList.GetItem(Index: Integer): ICollectable; begin if (Index < 0) or (Index >= Size) then begin CollectionError(ceOutOfRange); Result := nil; end else Result := TrueGetItem(Index); end; procedure TAbstractList.SetItem(Index: Integer; const Item: ICollectable); var SearchResult: TSearchResult; begin if (Index < 0) or (Index >= Size) then begin CollectionError(ceOutOfRange) end else if not Duplicates then begin // Find any duplicates if Sorted then begin SearchResult := BinarySearch(Item); case SearchResult.ResultType of srBeforeIndex, srAfterEnd: begin // If item is not present FSorted := false; TrueSetItem(Index, Item); end; srFoundAtIndex: begin // If item is already present CollectionError(ceDuplicate); end; end; end else begin // If item is already present if SequentialSearch(Item, Comparator).ResultType = srFoundAtIndex then begin CollectionError(ceDuplicate); end else begin TrueSetItem(Index, Item); end; end; end else begin FSorted := false; TrueSetItem(Index, Item); end; end; function TAbstractList.GetIterator: IIterator; begin Result := TAbstractListIterator.Create(Self); end; function TAbstractList.GetNaturalItemIID: TGUID; begin Result := ComparableIID; end; function TAbstractList.GetSorted: Boolean; begin Result := FSorted; end; procedure TAbstractList.SetSorted(Value: Boolean); begin if Value then Sort; end; function TAbstractList.GetType: TCollectionType; begin Result := ctList; end; function TAbstractList.BinarySearch(const Item: ICollectable): TSearchResult; var Lo, Hi, Mid: Integer; CompareResult: Integer; Success: Boolean; begin if Size = 0 then begin Result.ResultType := srAfterEnd; Exit; end; Lo := 0; Hi := Size - 1; Success := false; repeat Mid := (Lo + Hi) div 2; CompareResult := Comparator.Compare(Item, Items[Mid]); if CompareResult = 0 then Success := true else if CompareResult > 0 then Lo := Mid + 1 else Hi := Mid - 1; until (Lo > Hi) or Success; if Success then begin // Move index back if in cluster of duplicates while (Mid > 0) and Comparator.Equals(Item, Items[Mid - 1]) do Dec(Mid); Result.ResultType := srFoundAtIndex; Result.Index := Mid; end else if CompareResult < 0 then begin Result.ResultType := srBeforeIndex; Result.Index := Mid; end else if Hi < Size - 1 then begin Result.ResultType := srBeforeIndex; Result.Index := Mid + 1; end else Result.ResultType := srAfterEnd; end; function TAbstractList.CloneAsList: IList; begin Result := (TAbstractListClass(ClassType)).Create(Self); end; function TAbstractList.Delete(Index: Integer): ICollectable; begin if FixedSize then begin CollectionError(ceFixedSize); Result := nil; end else if (Index < 0) or (Index >= Size) then begin CollectionError(ceOutOfRange); Result := nil; end else begin Result := TrueDelete(Index); end; end; procedure TAbstractList.Exchange(Index1, Index2: Integer); var Item: ICollectable; begin if (Index1 < 0) or (Index1 >= Size) then CollectionError(ceOutOfRange); if (Index2 < 0) or (Index2 >= Size) then CollectionError(ceOutOfRange); FSorted := false; Item := ICollectable(Items[Index1]); Items[Index1] := Items[Index2]; Items[Index2] := Item; end; function TAbstractList.First: ICollectable; begin if Size > 0 then Result := Items[0] else Result := nil; end; function TAbstractList.IndexOf(const Item: ICollectable): Integer; var SearchResult: TSearchResult; begin if Sorted then SearchResult := BinarySearch(Item) else SearchResult := SequentialSearch(Item, Comparator); if SearchResult.ResultType = srFoundAtIndex then Result := SearchResult.Index else Result := -1; end; function TAbstractList.Insert(Index: Integer; const Item: ICollectable): Boolean; var ItemError: TCollectionError; begin ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Result := false; end else if FixedSize then begin CollectionError(ceFixedSize); Result := false; end else if (Index < 0) or (Index > Size) then begin CollectionError(ceOutOfRange); Result := false; end else begin FSorted := false; if Index = Size then TrueAdd(Item) else TrueInsert(Index, Item); Result := true; end; end; function TAbstractList.Insert(Index: Integer; const ItemArray: array of ICollectable): Integer; var Item: ICollectable; ItemError: TCollectionError; I, NewIndex, Count: Integer; Success: Boolean; begin Count := 0; if FixedSize then begin CollectionError(ceFixedSize); end else if (Index < 0) or (Index > Size) then begin CollectionError(ceOutOfRange); end else begin // Insert entire array in place in correct order NewIndex := Index; for I := Low(ItemArray) to High(ItemArray) do begin Item := ItemArray[I]; ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); end else begin Success := Insert(NewIndex, Item); if Success then begin Inc(NewIndex); Inc(Count); end; end; end; end; Result := Count; end; function TAbstractList.Insert(Index: Integer; const Collection: ICollection): Integer; var Iterator: IIterator; Item: ICollectable; ItemError: TCollectionError; NewIndex, Count: Integer; Success: Boolean; begin Count := 0; if FixedSize then begin CollectionError(ceFixedSize); end else if (Index < 0) or (Index > Size) then begin CollectionError(ceOutOfRange); end else begin // Insert entire collection in place in correct order NewIndex := Index; Iterator := Collection.GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem; ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); end else begin Success := Insert(NewIndex, Item); if Success then begin Inc(NewIndex); Inc(Count); end; end; Iterator.Next; end; end; Result := Count; end; function TAbstractList.IsNilAllowed: Boolean; begin Result := true; end; function TAbstractList.Last: ICollectable; begin if Size > 0 then Result := Items[Size - 1] else Result := nil; end; function TAbstractList.Search(const Item: ICollectable; const SearchComparator: IComparator = nil): TSearchResult; begin if Sorted and (SearchComparator = nil) then Result := BinarySearch(Item) else Result := SequentialSearch(Item, SearchComparator); end; function TAbstractList.SequentialSearch(const Item: ICollectable; const SearchComparator: IComparator): TSearchResult; var WorkingComparator: IComparator; I: Integer; Success: Boolean; begin if SearchComparator = nil then WorkingComparator := Comparator else WorkingComparator := SearchComparator; Result.ResultType := srNotFound; I := 0; Success := false; while (I < Size) and not Success do begin if WorkingComparator.Equals(Item, Items[I]) then begin Result.ResultType := srFoundAtIndex; Result.Index := I; Success := true; end else Inc(I); end; end; procedure TAbstractList.Sort(const SortComparator: IComparator); begin if SortComparator = nil then begin if Size > 0 then QuickSort(0, Size - 1, Comparator); FSorted := true; end else begin if Size > 0 then QuickSort(0, Size - 1, SortComparator); FSorted := false; end; end; procedure TAbstractList.Sort(CompareFunc: TCollectionCompareFunc); begin if Size > 0 then QuickSort(0, Size - 1, CompareFunc); FSorted := false; end; { TAbstractMap } constructor TAbstractMap.Create; begin Create(false, true); end; constructor TAbstractMap.Create(NaturalItemsOnly: Boolean); begin Create(NaturalItemsOnly, true); end; constructor TAbstractMap.Create(NaturalItemsOnly: Boolean; NaturalKeysOnly: Boolean); begin inherited Create(NaturalItemsOnly); FNaturalKeysOnly := NaturalKeysOnly or GetAlwaysNaturalKeys; FAssociationComparator := TAssociationComparator.Create(FNaturalKeysOnly); if FNaturalKeysOnly then FKeyComparator := TAbstractComparator.GetNaturalComparator else FKeyComparator := TAbstractComparator.GetDefaultComparator; end; constructor TAbstractMap.Create(const ItemArray: array of ICollectable); begin Create(ItemArray, true, true); end; constructor TAbstractMap.Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); begin Create(ItemArray, true, true); end; constructor TAbstractMap.Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean; NaturalKeysOnly: Boolean); var I: Integer; begin Create(true, NaturalKeysOnly); if not FixedSize then begin Capacity := Length(ItemArray); for I := Low(ItemArray) to High(ItemArray) do begin Add(ItemArray[I]); end; end; end; constructor TAbstractMap.Create(const KeyArray, ItemArray: array of ICollectable); begin Create(KeyArray, ItemArray, false, true); end; constructor TAbstractMap.Create(const KeyArray, ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); begin Create(KeyArray, ItemArray, NaturalItemsOnly, true); end; constructor TAbstractMap.Create(const KeyArray, ItemArray: array of ICollectable; NaturalItemsOnly: Boolean; NaturalKeysOnly: Boolean); var I, Lo, Hi: Integer; begin Create(NaturalItemsOnly, NaturalKeysOnly); if not FixedSize then begin Capacity := Min(Length(KeyArray), Length(ItemArray)); Lo := Max(Low(KeyArray), Low(ItemArray)); Hi := Min(High(KeyArray), High(ItemArray)); for I := Lo to Hi do begin Put(KeyArray[I], ItemArray[I]); end; end; end; constructor TAbstractMap.Create(const Map: IMap); var MapIterator: IMapIterator; begin Create(Map.GetNaturalItemsOnly, Map.GetNaturalKeysOnly); InitFrom(Map); if not FixedSize then begin Capacity := Map.GetSize; MapIterator := Map.GetMapIterator; while not MapIterator.EOF do begin Put(MapIterator.CurrentKey, MapIterator.CurrentItem); MapIterator.Next; end; end; end; destructor TAbstractMap.Destroy; begin FKeyComparator := nil; FAssociationComparator := nil; inherited Destroy; end; procedure TAbstractMap.InitFrom(const Collection: ICollection); var Map: IMap; begin inherited InitFrom(Collection); if Collection.QueryInterface(IMap, Map) = S_OK then begin FNaturalKeysOnly := Map.GetNaturalKeysOnly or GetAlwaysNaturalKeys; KeyComparator := Map.GetKeyComparator; end; end; function TAbstractMap.TrueAdd(const Item: ICollectable): Boolean; var Position: TCollectionPosition; Mappable: IMappable; begin if IsNaturalItem(Item) then begin Mappable := Item as IMappable; Position := GetKeyPosition(Mappable.GetKey); try if Position.Found then begin CollectionError(ceDuplicateKey); Result := false; end else begin TruePut(Position, TAssociation.Create(Mappable.GetKey, Item)); Result := true; end; finally Position.Free; end; end else begin CollectionError(ceNotNaturalItem); Result := false; end; end; function TAbstractMap.TrueContains(const Item: ICollectable): Boolean; var Item2: ICollectable; Success: Boolean; Iterator: IIterator; begin Iterator := GetIterator; Success := false; while not Iterator.EOF and not Success do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then Success := true; Iterator.Next; end; Result := Success; end; function TAbstractMap.TrueRemove(const Item: ICollectable): ICollectable; var Item2: ICollectable; Iterator: IMapIterator; Found: Boolean; begin // Sequential search Found := false; Result := nil; Iterator := GetAssociationIterator; while not Iterator.EOF and not Found do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then begin Result := Item2; Iterator.Remove; Found := true; end; Iterator.Next; end; end; function TAbstractMap.TrueRemoveAll(const Item: ICollectable): ICollection; var ResultCollection: ICollection; Item2: ICollectable; Iterator: IMapIterator; begin // Sequential search ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := GetAssociationIterator; while not Iterator.EOF do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then begin ResultCollection.Add(Item2); Iterator.Remove; end; Iterator.Next; end; Result := ResultCollection; end; class function TAbstractMap.GetAlwaysNaturalKeys: Boolean; begin Result := false; end; function TAbstractMap.GetItem(const Key: ICollectable): ICollectable; begin Result := Get(Key); end; procedure TAbstractMap.SetItem(const Key, Item: ICollectable); begin Put(Key, Item); end; function TAbstractMap.GetIterator: IIterator; begin Result := GetAssociationIterator; end; function TAbstractMap.GetKeyComparator: IComparator; begin Result := FKeyComparator; end; procedure TAbstractMap.SetKeyComparator(const Value: IComparator); begin FKeyComparator := Value; FAssociationComparator.KeyComparator := Value; end; function TAbstractMap.GetKeyIterator: IIterator; begin Result := TAssociationKeyIterator.Create(GetAssociationIterator); end; function TAbstractMap.GetKeys: ISet; var ResultCollection: TPArraySet; KeyIterator: IIterator; begin ResultCollection := TPArraySet.Create(NaturalKeysOnly); ResultCollection.SetComparator(GetKeyComparator); KeyIterator := GetKeyIterator; while not KeyIterator.EOF do begin ResultCollection.Add(KeyIterator.CurrentItem); KeyIterator.Next; end; Result := ResultCollection; end; function TAbstractMap.GetMapIterator: IMapIterator; begin Result := GetAssociationIterator; end; function TAbstractMap.GetMapIteratorByKey(const Filter: IFilter): IMapIterator; var Iterator: IMapIterator; begin Iterator := GetMapIterator; Result := TKeyFilterMapIterator.Create(Iterator, Filter, Iterator.GetAllowRemoval); end; function TAbstractMap.GetMapIteratorByKey(FilterFunc: TCollectionFilterFunc): IMapIterator; var Iterator: IMapIterator; begin Iterator := GetMapIterator; Result := TKeyFilterFuncMapIterator.Create(Iterator, FilterFunc, Iterator.GetAllowRemoval); end; function TAbstractMap.GetNaturalItemIID: TGUID; begin Result := MappableIID; end; function TAbstractMap.GetNaturalKeyIID: TGUID; begin Result := EquatableIID; end; function TAbstractMap.GetNaturalKeysOnly: Boolean; begin Result := FNaturalKeysOnly; end; function TAbstractMap.GetType: TCollectionType; begin Result := ctMap; end; function TAbstractMap.GetValues: ICollection; var ResultCollection: ICollection; ValueIterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); ValueIterator := GetIterator; while not ValueIterator.EOF do begin ResultCollection.Add(ValueIterator.CurrentItem); ValueIterator.Next; end; Result := ResultCollection; end; // Overrides TAbstractCollection function, otherwise Create(ICollection) is // called, which cannot access keys. function TAbstractMap.Clone: ICollection; begin Result := (TAbstractMapClass(ClassType)).Create(Self); end; function TAbstractMap.CloneAsMap: IMap; begin Result := (TAbstractMapClass(ClassType)).Create(Self); end; function TAbstractMap.ContainsKey(const Key: ICollectable): Boolean; var Position: TCollectionPosition; begin Position := GetKeyPosition(Key); try Result := Position.Found; finally Position.Free; end; end; function TAbstractMap.ContainsKey(const KeyArray: array of ICollectable): Boolean; var I: Integer; Success: Boolean; begin Success := true; for I := Low(KeyArray) to High(KeyArray) do begin Success := Success and ContainsKey(KeyArray[I]); if not Success then break; end; Result := Success; end; function TAbstractMap.ContainsKey(const Collection: ICollection): Boolean; var Iterator: IIterator; Success: Boolean; begin Success := true; Iterator := Collection.GetIterator; while not Iterator.EOF do begin Success := Success and ContainsKey(Iterator.CurrentItem); if not Success then break; Iterator.Next; end; Result := Success; end; function TAbstractMap.Get(const Key: ICollectable): ICollectable; var KeyError: TCollectionError; Position: TCollectionPosition; begin KeyError := KeyAllowed(Key); if KeyError <> ceOK then begin CollectionError(KeyError); Result := nil; end else begin Position := GetKeyPosition(Key); try if Position.Found then Result := TrueGet(Position).GetValue else Result := nil; finally Position.Free; end; end; end; function TAbstractMap.KeyAllowed(const Key: ICollectable): TCollectionError; begin if NaturalKeysOnly and not IsNaturalKey(Key) then Result := ceNotNaturalItem else if Key = nil then Result := ceNilNotAllowed else Result := ceOK; end; function TAbstractMap.IsNaturalKey(const Key: ICollectable): Boolean; var Temp: IUnknown; begin if Key.QueryInterface(NaturalKeyIID, Temp) <> E_NOINTERFACE then Result := true else Result := false; end; function TAbstractMap.IsNilAllowed: Boolean; begin Result := true; end; function TAbstractMap.MatchingKey(const KeyArray: array of ICollectable): ICollection; var ResultCollection: ICollection; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(KeyArray) to High(KeyArray) do begin if ContainsKey(KeyArray[I]) then ResultCollection.Add(KeyArray[I]); end; Result := ResultCollection; end; function TAbstractMap.MatchingKey(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Iterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin if ContainsKey(Iterator.CurrentItem) then ResultCollection.Add(Iterator.CurrentItem); Iterator.Next; end; Result := ResultCollection; end; function TAbstractMap.Put(const Item: ICollectable): ICollectable; var Mappable: IMappable; OldAssociation, NewAssociation: IAssociation; Position: TCollectionPosition; begin if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); Result := nil; end else begin Item.QueryInterface(IMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then Result := OldAssociation.GetValue else Result := nil; finally Position.Free; end; end; end; function TAbstractMap.Put(const Key, Item: ICollectable): ICollectable; var OldAssociation, NewAssociation: IAssociation; ItemError, KeyError: TCollectionError; Position: TCollectionPosition; begin ItemError := ItemAllowed(Item); KeyError := KeyAllowed(Key); if ItemError <> ceOK then begin CollectionError(ItemError); Result := nil; end else if KeyError <> ceOK then begin CollectionError(KeyError); Result := nil; end else begin // Find appropriate place, then place key-item association there Position := GetKeyPosition(Key); try NewAssociation := TAssociation.Create(Key, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then Result := OldAssociation.GetValue else Result := nil; finally Position.Free; end; end; end; function TAbstractMap.Put(const ItemArray: array of ICollectable): ICollection; var ResultCollection: ICollection; Mappable: IMappable; OldAssociation, NewAssociation: IAssociation; Position: TCollectionPosition; Item: ICollectable; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(ItemArray) to High(ItemArray) do begin Item := ItemArray[I]; if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); end else begin // Find appropriate place, then place key-item association there Item.QueryInterface(IMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; end; Result := ResultCollection; end; function TAbstractMap.Put(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Mappable: IMappable; OldAssociation, NewAssociation: IAssociation; Position: TCollectionPosition; Iterator: IIterator; Item: ICollectable; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem;; if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); end else begin // Find appropriate place, then place key-item association there Item.QueryInterface(IMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; Iterator.Next; end; Result := ResultCollection; end; function TAbstractMap.Put(const Map: IMap): ICollection; var ResultCollection: ICollection; OldAssociation, NewAssociation: IAssociation; ItemError, KeyError: TCollectionError; Position: TCollectionPosition; MapIterator: IMapIterator; Key, Item: ICollectable; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); MapIterator := Map.GetMapIterator; while not MapIterator.EOF do begin Key := MapIterator.CurrentKey; Item := MapIterator.CurrentItem; ItemError := ItemAllowed(Item); KeyError := KeyAllowed(Key); if ItemError <> ceOK then begin CollectionError(ItemError); end else if KeyError <> ceOK then begin CollectionError(KeyError); end else begin // Find appropriate place, then place key-item association there Position := GetKeyPosition(Key); try NewAssociation := TAssociation.Create(Key, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; MapIterator.Next; end; Result := ResultCollection; end; function TAbstractMap.RemoveKey(const Key: ICollectable): ICollectable; var KeyError: TCollectionError; Position: TCollectionPosition; OldAssociation: IAssociation; begin KeyError := KeyAllowed(Key); if KeyError <> ceOK then begin CollectionError(KeyError); Result := nil; end else begin Position := GetKeyPosition(Key); try if Position.Found then begin OldAssociation := TrueRemove2(Position); Result := OldAssociation.GetValue end else Result := nil; finally Position.Free; end; end; end; function TAbstractMap.RemoveKey(const KeyArray: array of ICollectable): ICollection; var ResultCollection: ICollection; OldAssociation: IAssociation; KeyError: TCollectionError; Position: TCollectionPosition; Key: ICollectable; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(KeyArray) to High(KeyArray) do begin Key := KeyArray[I]; KeyError := KeyAllowed(Key); if KeyError <> ceOK then begin CollectionError(KeyError); end else begin Position := GetKeyPosition(Key); try if Position.Found then begin OldAssociation := TrueRemove2(Position); ResultCollection.Add(OldAssociation.GetValue); end; finally Position.Free; end; end; end; Result := ResultCollection; end; function TAbstractMap.RemoveKey(const Collection: ICollection): ICollection; var ResultCollection: ICollection; OldAssociation: IAssociation; KeyError: TCollectionError; Position: TCollectionPosition; Key: ICollectable; Iterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin Key := Iterator.CurrentItem; KeyError := KeyAllowed(Key); if KeyError <> ceOK then begin CollectionError(KeyError); end else begin Position := GetKeyPosition(Key); try if Position.Found then begin OldAssociation := TrueRemove2(Position); ResultCollection.Add(OldAssociation.GetValue); end; finally Position.Free; end; end; Iterator.Next; end; Result := ResultCollection; end; function TAbstractMap.RetainKey(const KeyArray: array of ICollectable): ICollection; var ResultCollection: ICollection; MapIterator: IMapIterator; I: Integer; Found: Boolean; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); if FixedSize then begin CollectionError(ceFixedSize); end else begin MapIterator := GetMapIterator; while not MapIterator.EOF do begin // Converting the array to a map would be faster but I don't want to // couple base class code to a complex collection. Found := false; for I := Low(KeyArray) to High(KeyArray) do begin Found := KeyComparator.Equals(MapIterator.CurrentKey, KeyArray[I]); if Found then break; end; if not Found then begin ResultCollection.Add(MapIterator.CurrentItem); MapIterator.Remove; end; MapIterator.Next; end; Result := ResultCollection; end; end; function TAbstractMap.RetainKey(const Collection: ICollection): ICollection; var ResultCollection: ICollection; MapIterator: IMapIterator; Key: ICollectable; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); if FixedSize then begin CollectionError(ceFixedSize); end else begin MapIterator := GetMapIterator; while not MapIterator.EOF do begin Key := MapIterator.CurrentKey; if not Collection.Contains(Key) then begin ResultCollection.Add(MapIterator.CurrentItem); MapIterator.Remove; end; MapIterator.Next; end; end; Result := ResultCollection; end; { TAbstractIntegerMap } constructor TAbstractIntegerMap.Create(NaturalItemsOnly: Boolean); begin inherited Create(NaturalItemsOnly); FAssociationComparator := TIntegerAssociationComparator.Create; end; constructor TAbstractIntegerMap.Create(const ItemArray: array of ICollectable); begin Create(ItemArray, true); end; constructor TAbstractIntegerMap.Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); begin inherited Create(ItemArray, true); end; constructor TAbstractIntegerMap.Create(const KeyArray: array of Integer; const ItemArray: array of ICollectable); begin Create(KeyArray, ItemArray, false); end; constructor TAbstractIntegerMap.Create(const KeyArray: array of Integer; const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); var I, Lo, Hi: Integer; begin Create(NaturalItemsOnly); Capacity := Min(Length(KeyArray), Length(ItemArray)); if not FixedSize then begin Lo := Max(Low(KeyArray), Low(ItemArray)); Hi := Min(High(KeyArray), High(ItemArray)); for I := Lo to Hi do begin Put(KeyArray[I], ItemArray[I]); end; end; end; constructor TAbstractIntegerMap.Create(const Map: IIntegerMap); var MapIterator: IIntegerMapIterator; begin Create(Map.GetNaturalItemsOnly); InitFrom(Map); Capacity := Map.GetSize; if not FixedSize then begin MapIterator := Map.GetMapIterator; while not MapIterator.EOF do begin Put(MapIterator.CurrentKey, MapIterator.CurrentItem); MapIterator.Next; end; end; end; destructor TAbstractIntegerMap.Destroy; begin FAssociationComparator := nil; inherited Destroy; end; function TAbstractIntegerMap.TrueAdd(const Item: ICollectable): Boolean; var Position: TCollectionPosition; Mappable: IIntegerMappable; begin if IsNaturalItem(Item) then begin Mappable := Item as IIntegerMappable; Position := GetKeyPosition(Mappable.GetKey); try if Position.Found then begin CollectionError(ceDuplicateKey); Result := false; end else begin TruePut(Position, TIntegerAssociation.Create(Mappable.GetKey, Item)); Result := true; end; finally Position.Free; end; end else begin CollectionError(ceNotNaturalItem); Result := false; end; end; function TAbstractIntegerMap.TrueContains(const Item: ICollectable): Boolean; var Item2: ICollectable; Success: Boolean; Iterator: IIterator; begin Iterator := GetIterator; Success := false; while not Iterator.EOF and not Success do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then Success := true; Iterator.Next; end; Result := Success; end; function TAbstractIntegerMap.TrueRemove(const Item: ICollectable): ICollectable; var Item2: ICollectable; Iterator: IIntegerMapIterator; Found: Boolean; begin // Sequential search Found := false; Result := nil; Iterator := GetAssociationIterator; while not Iterator.EOF and not Found do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then begin Result := Item2; Iterator.Remove; Found := true; end; Iterator.Next; end; end; function TAbstractIntegerMap.TrueRemoveAll(const Item: ICollectable): ICollection; var ResultCollection: ICollection; Item2: ICollectable; Iterator: IIntegerMapIterator; begin // Sequential search ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := GetAssociationIterator; while not Iterator.EOF do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then begin ResultCollection.Add(Item2); Iterator.Remove; end; Iterator.Next; end; Result := ResultCollection; end; function TAbstractIntegerMap.GetItem(const Key: Integer): ICollectable; begin Result := Get(Key); end; procedure TAbstractIntegerMap.SetItem(const Key: Integer; const Item: ICollectable); begin Put(Key, Item); end; function TAbstractIntegerMap.GetIterator: IIterator; begin Result := GetAssociationIterator; end; function TAbstractIntegerMap.GetKeys: ISet; var ResultCollection: TPArraySet; MapIterator: IIntegerMapIterator; begin ResultCollection := TPArraySet.Create(true); MapIterator := GetMapIterator; while not MapIterator.EOF do begin ResultCollection.Add(TIntegerWrapper.Create(MapIterator.CurrentKey) as ICollectable); MapIterator.Next; end; Result := ResultCollection; end; function TAbstractIntegerMap.GetMapIterator: IIntegerMapIterator; begin Result := GetAssociationIterator; end; function TAbstractIntegerMap.GetNaturalItemIID: TGUID; begin Result := IntegerMappableIID; end; function TAbstractIntegerMap.GetType: TCollectionType; begin Result := ctIntegerMap; end; function TAbstractIntegerMap.GetValues: ICollection; var ResultCollection: ICollection; ValueIterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); ValueIterator := GetIterator; while not ValueIterator.EOF do begin ResultCollection.Add(ValueIterator.CurrentItem); ValueIterator.Next; end; Result := ResultCollection; end; // Overrides TAbstractCollection function, otherwise Create(ICollection) is // called, which cannot access keys. function TAbstractIntegerMap.Clone: ICollection; begin Result := (TAbstractIntegerMapClass(ClassType)).Create(Self); end; function TAbstractIntegerMap.CloneAsIntegerMap: IIntegerMap; begin Result := (TAbstractIntegerMapClass(ClassType)).Create(Self); end; function TAbstractIntegerMap.ContainsKey(const Key: Integer): Boolean; var Position: TCollectionPosition; begin Position := GetKeyPosition(Key); try Result := Position.Found; finally Position.Free; end; end; function TAbstractIntegerMap.ContainsKey(const KeyArray: array of Integer): Boolean; var I: Integer; Success: Boolean; begin Success := true; for I := Low(KeyArray) to High(KeyArray) do begin Success := Success and ContainsKey(KeyArray[I]); if not Success then break; end; Result := Success; end; function TAbstractIntegerMap.Get(const Key: Integer): ICollectable; var Position: TCollectionPosition; begin Position := GetKeyPosition(Key); try if Position.Found then Result := TrueGet(Position).GetValue else Result := nil; finally Position.Free; end; end; function TAbstractIntegerMap.IsNilAllowed: Boolean; begin Result := true; end; function TAbstractIntegerMap.Put(const Item: ICollectable): ICollectable; var Mappable: IIntegerMappable; OldAssociation, NewAssociation: IIntegerAssociation; Position: TCollectionPosition; begin if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); Result := nil; end else begin Item.QueryInterface(IIntegerMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TIntegerAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then Result := OldAssociation.GetValue else Result := nil; finally Position.Free; end; end; end; function TAbstractIntegerMap.Put(const Key: Integer; const Item: ICollectable): ICollectable; var OldAssociation, NewAssociation: IIntegerAssociation; ItemError: TCollectionError; Position: TCollectionPosition; begin ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Result := nil; end else begin Position := GetKeyPosition(Key); try NewAssociation := TIntegerAssociation.Create(Key, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then Result := OldAssociation.GetValue else Result := nil; finally Position.Free; end; end; end; function TAbstractIntegerMap.Put(const ItemArray: array of ICollectable): ICollection; var ResultCollection: ICollection; Mappable: IIntegerMappable; OldAssociation, NewAssociation: IIntegerAssociation; Position: TCollectionPosition; Item: ICollectable; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(ItemArray) to High(ItemArray) do begin Item := ItemArray[I]; if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); end else begin Item.QueryInterface(IIntegerMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TIntegerAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; end; Result := ResultCollection; end; function TAbstractIntegerMap.Put(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Mappable: IIntegerMappable; OldAssociation, NewAssociation: IIntegerAssociation; Position: TCollectionPosition; Iterator: IIterator; Item: ICollectable; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem;; if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); end else begin Item.QueryInterface(IIntegerMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TIntegerAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; Iterator.Next; end; Result := ResultCollection; end; function TAbstractIntegerMap.Put(const Map: IIntegerMap): ICollection; var ResultCollection: ICollection; OldAssociation, NewAssociation: IIntegerAssociation; ItemError: TCollectionError; Position: TCollectionPosition; MapIterator: IIntegerMapIterator; Item: ICollectable; Key: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); MapIterator := Map.GetMapIterator; while not MapIterator.EOF do begin Key := MapIterator.CurrentKey; Item := MapIterator.CurrentItem; ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); end else begin Position := GetKeyPosition(Key); try NewAssociation := TIntegerAssociation.Create(Key, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; MapIterator.Next; end; Result := ResultCollection; end; function TAbstractIntegerMap.RemoveKey(const Key: Integer): ICollectable; var Position: TCollectionPosition; OldAssociation: IIntegerAssociation; begin Position := GetKeyPosition(Key); try if Position.Found then begin OldAssociation := TrueRemove2(Position); Result := OldAssociation.GetValue end else Result := nil; finally Position.Free; end; end; function TAbstractIntegerMap.RemoveKey(const KeyArray: array of Integer): ICollection; var ResultCollection: ICollection; OldAssociation: IIntegerAssociation; Position: TCollectionPosition; Key: Integer; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(KeyArray) to High(KeyArray) do begin Key := KeyArray[I]; Position := GetKeyPosition(Key); try if Position.Found then begin OldAssociation := TrueRemove2(Position); ResultCollection.Add(OldAssociation.GetValue); end; finally Position.Free; end; end; Result := ResultCollection; end; function TAbstractIntegerMap.RetainKey(const KeyArray: array of Integer): ICollection; var ResultCollection: ICollection; MapIterator: IIntegerMapIterator; I: Integer; Found: Boolean; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); if FixedSize then begin CollectionError(ceFixedSize); end else begin MapIterator := GetMapIterator; while not MapIterator.EOF do begin // Converting the array to a map would be faster but I don't want to // couple base class code to a complex collection. Found := false; for I := Low(KeyArray) to High(KeyArray) do begin Found := (MapIterator.CurrentKey = KeyArray[I]); if Found then break; end; if not Found then begin ResultCollection.Add(MapIterator.CurrentItem); MapIterator.Remove; end; MapIterator.Next; end; Result := ResultCollection; end; end; { TAbstractStringMap } constructor TAbstractStringMap.Create(NaturalItemsOnly: Boolean); begin inherited Create(NaturalItemsOnly); FAssociationComparator := TStringAssociationComparator.Create; end; constructor TAbstractStringMap.Create(const ItemArray: array of ICollectable); begin Create(ItemArray, true); end; constructor TAbstractStringMap.Create(const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); begin inherited Create(ItemArray, true); end; constructor TAbstractStringMap.Create(const KeyArray: array of String; const ItemArray: array of ICollectable); begin Create(KeyArray, ItemArray, false); end; constructor TAbstractStringMap.Create(const KeyArray: array of String; const ItemArray: array of ICollectable; NaturalItemsOnly: Boolean); var I, Lo, Hi: Integer; begin Create(NaturalItemsOnly); Capacity := Min(Length(KeyArray), Length(ItemArray)); if not FixedSize then begin Lo := Max(Low(KeyArray), Low(ItemArray)); Hi := Min(High(KeyArray), High(ItemArray)); for I := Lo to Hi do begin Put(KeyArray[I], ItemArray[I]); end; end; end; constructor TAbstractStringMap.Create(const Map: IStringMap); var MapIterator: IStringMapIterator; begin Create(Map.GetNaturalItemsOnly); InitFrom(Map); Capacity := Map.GetSize; if not FixedSize then begin MapIterator := Map.GetMapIterator; while not MapIterator.EOF do begin Put(MapIterator.CurrentKey, MapIterator.CurrentItem); MapIterator.Next; end; end; end; destructor TAbstractStringMap.Destroy; begin FAssociationComparator := nil; inherited Destroy; end; function TAbstractStringMap.TrueAdd(const Item: ICollectable): Boolean; var Position: TCollectionPosition; Mappable: IStringMappable; begin if IsNaturalItem(Item) then begin Mappable := Item as IStringMappable; Position := GetKeyPosition(Mappable.GetKey); try if Position.Found then begin CollectionError(ceDuplicateKey); Result := false; end else begin TruePut(Position, TStringAssociation.Create(Mappable.GetKey, Item)); Result := true; end; finally Position.Free; end; end else begin CollectionError(ceNotNaturalItem); Result := false; end; end; function TAbstractStringMap.TrueContains(const Item: ICollectable): Boolean; var Item2: ICollectable; Success: Boolean; Iterator: IIterator; begin Iterator := GetIterator; Success := false; while not Iterator.EOF and not Success do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then Success := true; Iterator.Next; end; Result := Success; end; function TAbstractStringMap.TrueRemove(const Item: ICollectable): ICollectable; var Item2: ICollectable; Iterator: IStringMapIterator; Found: Boolean; begin // Sequential search Found := false; Result := nil; Iterator := GetAssociationIterator; while not Iterator.EOF and not Found do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then begin Result := Item2; Iterator.Remove; Found := true; end; Iterator.Next; end; end; function TAbstractStringMap.TrueRemoveAll(const Item: ICollectable): ICollection; var ResultCollection: ICollection; Item2: ICollectable; Iterator: IIterator; begin // Sequential search ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := GetAssociationIterator; while not Iterator.EOF do begin Item2 := Iterator.CurrentItem; if Comparator.Equals(Item, Item2) then begin ResultCollection.Add(Item2); Iterator.Remove; end; Iterator.Next; end; Result := ResultCollection; end; function TAbstractStringMap.GetItem(const Key: String): ICollectable; begin Result := Get(Key); end; procedure TAbstractStringMap.SetItem(const Key: String; const Item: ICollectable); begin Put(Key, Item); end; function TAbstractStringMap.GetIterator: IIterator; begin Result := GetAssociationIterator; end; function TAbstractStringMap.GetKeys: ISet; var ResultCollection: TPArraySet; MapIterator: IStringMapIterator; begin ResultCollection := TPArraySet.Create(true); MapIterator := GetMapIterator; while not MapIterator.EOF do begin ResultCollection.Add(TStringWrapper.Create(MapIterator.CurrentKey) as ICollectable); MapIterator.Next; end; Result := ResultCollection; end; function TAbstractStringMap.GetMapIterator: IStringMapIterator; begin Result := GetAssociationIterator; end; function TAbstractStringMap.GetNaturalItemIID: TGUID; begin Result := StringMappableIID; end; function TAbstractStringMap.GetType: TCollectionType; begin Result := ctStringMap; end; function TAbstractStringMap.GetValues: ICollection; var ResultCollection: ICollection; ValueIterator: IIterator; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); ValueIterator := GetIterator; while not ValueIterator.EOF do begin ResultCollection.Add(ValueIterator.CurrentItem); ValueIterator.Next; end; Result := ResultCollection; end; // Overrides TAbstractCollection function, otherwise Create(ICollection) is // called, which cannot access keys. function TAbstractStringMap.Clone: ICollection; begin Result := (TAbstractStringMapClass(ClassType)).Create(Self); end; function TAbstractStringMap.CloneAsStringMap: IStringMap; begin Result := (TAbstractStringMapClass(ClassType)).Create(Self); end; function TAbstractStringMap.ContainsKey(const Key: String): Boolean; var Position: TCollectionPosition; begin Position := GetKeyPosition(Key); try Result := Position.Found; finally Position.Free; end; end; function TAbstractStringMap.ContainsKey(const KeyArray: array of String): Boolean; var I: Integer; Success: Boolean; begin Success := true; for I := Low(KeyArray) to High(KeyArray) do begin Success := Success and ContainsKey(KeyArray[I]); if not Success then break; end; Result := Success; end; function TAbstractStringMap.Get(const Key: String): ICollectable; var Position: TCollectionPosition; begin Position := GetKeyPosition(Key); try if Position.Found then Result := TrueGet(Position).GetValue else Result := nil; finally Position.Free; end; end; function TAbstractStringMap.IsNilAllowed: Boolean; begin Result := true; end; function TAbstractStringMap.Put(const Item: ICollectable): ICollectable; var Mappable: IStringMappable; OldAssociation, NewAssociation: IStringAssociation; Position: TCollectionPosition; begin if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); Result := nil; end else begin Item.QueryInterface(IStringMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TStringAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then Result := OldAssociation.GetValue else Result := nil; finally Position.Free; end; end; end; function TAbstractStringMap.Put(const Key: String; const Item: ICollectable): ICollectable; var OldAssociation, NewAssociation: IStringAssociation; ItemError: TCollectionError; Position: TCollectionPosition; begin ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); Result := nil; end else begin Position := GetKeyPosition(Key); try NewAssociation := TStringAssociation.Create(Key, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then Result := OldAssociation.GetValue else Result := nil; finally Position.Free; end; end; end; function TAbstractStringMap.Put(const ItemArray: array of ICollectable): ICollection; var ResultCollection: ICollection; Mappable: IStringMappable; OldAssociation, NewAssociation: IStringAssociation; Position: TCollectionPosition; Item: ICollectable; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(ItemArray) to High(ItemArray) do begin Item := ItemArray[I]; if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); end else begin Item.QueryInterface(IStringMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TStringAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; end; Result := ResultCollection; end; function TAbstractStringMap.Put(const Collection: ICollection): ICollection; var ResultCollection: ICollection; Mappable: IStringMappable; OldAssociation, NewAssociation: IStringAssociation; Position: TCollectionPosition; Iterator: IIterator; Item: ICollectable; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); Iterator := Collection.GetIterator; while not Iterator.EOF do begin Item := Iterator.CurrentItem;; if not IsNaturalItem(Item) then begin CollectionError(ceNotNaturalItem); end else begin Item.QueryInterface(IStringMappable, Mappable); Position := GetKeyPosition(Mappable.GetKey); try NewAssociation := TStringAssociation.Create(Mappable.GetKey, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; Iterator.Next; end; Result := ResultCollection; end; function TAbstractStringMap.Put(const Map: IStringMap): ICollection; var ResultCollection: ICollection; OldAssociation, NewAssociation: IStringAssociation; ItemError: TCollectionError; Position: TCollectionPosition; MapIterator: IStringMapIterator; Item: ICollectable; Key: String; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); MapIterator := Map.GetMapIterator; while not MapIterator.EOF do begin Key := MapIterator.CurrentKey; Item := MapIterator.CurrentItem; ItemError := ItemAllowed(Item); if ItemError <> ceOK then begin CollectionError(ItemError); end else begin Position := GetKeyPosition(Key); try NewAssociation := TStringAssociation.Create(Key, Item); OldAssociation := TruePut(Position, NewAssociation); if OldAssociation <> nil then ResultCollection.Add(OldAssociation.GetValue); finally Position.Free; end; end; MapIterator.Next; end; Result := ResultCollection; end; function TAbstractStringMap.RemoveKey(const Key: String): ICollectable; var Position: TCollectionPosition; OldAssociation: IStringAssociation; begin Position := GetKeyPosition(Key); try if Position.Found then begin OldAssociation := TrueRemove2(Position); Result := OldAssociation.GetValue end else Result := nil; finally Position.Free; end; end; function TAbstractStringMap.RemoveKey(const KeyArray: array of String): ICollection; var ResultCollection: ICollection; OldAssociation: IStringAssociation; Position: TCollectionPosition; Key: String; I: Integer; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); for I := Low(KeyArray) to High(KeyArray) do begin Key := KeyArray[I]; Position := GetKeyPosition(Key); try if Position.Found then begin OldAssociation := TrueRemove2(Position); ResultCollection.Add(OldAssociation.GetValue); end; finally Position.Free; end; end; Result := ResultCollection; end; function TAbstractStringMap.RetainKey(const KeyArray: array of String): ICollection; var ResultCollection: ICollection; MapIterator: IStringMapIterator; I: Integer; Found: Boolean; begin ResultCollection := TPArrayBag.Create(NaturalItemsOnly); if FixedSize then begin CollectionError(ceFixedSize); end else begin MapIterator := GetMapIterator; while not MapIterator.EOF do begin // Converting the array to a map would be faster but I don't want to // couple base class code to a complex collection. Found := false; for I := Low(KeyArray) to High(KeyArray) do begin Found := (MapIterator.CurrentKey = KeyArray[I]); if Found then break; end; if not Found then begin ResultCollection.Add(MapIterator.CurrentItem); MapIterator.Remove; end; MapIterator.Next; end; Result := ResultCollection; end; end; { ECollectionError } constructor ECollectionError.Create(const Msg: String; const Collection: ICollection; ErrorType: TCollectionError); begin inherited Create(Msg); FCollection := Collection; FErrorType := ErrorType; end; { TAbstractListIterator } constructor TAbstractListIterator.Create(Collection: TAbstractList); begin inherited Create(true); FCollection := Collection; First; end; function TAbstractListIterator.TrueFirst: ICollectable; begin FIndex := 0; if FIndex < FCollection.GetSize then Result := FCollection.GetItem(FIndex) else Result := nil; end; function TAbstractListIterator.TrueNext: ICollectable; begin Inc(FIndex); if FIndex < FCollection.GetSize then Result := FCollection.GetItem(FIndex) else Result := nil; end; procedure TAbstractListIterator.TrueRemove; begin FCollection.Delete(FIndex); Dec(FIndex); end; end.