diff options
author | tobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2009-01-12 23:29:09 +0000 |
---|---|---|
committer | tobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c> | 2009-01-12 23:29:09 +0000 |
commit | dc71ad22a7e3bb2592e360a533843ca7aa88b1f8 (patch) | |
tree | 8c35cf5993cdd1034da7d75d83df4071e57aa3e2 /src/lib/collections/Collections.pas | |
parent | c6b630485c605900405e15fac7ff0f75a780815a (diff) | |
download | usdx-dc71ad22a7e3bb2592e360a533843ca7aa88b1f8.tar.gz usdx-dc71ad22a7e3bb2592e360a533843ca7aa88b1f8.tar.xz usdx-dc71ad22a7e3bb2592e360a533843ca7aa88b1f8.zip |
Delphi Collections by Matthew Greet
for uniform collection (lists, maps, ...) support for both fpc and delphi (delphi misses collections entirely)
git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1570 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to '')
-rw-r--r-- | src/lib/collections/Collections.pas | 5312 |
1 files changed, 5312 insertions, 0 deletions
diff --git a/src/lib/collections/Collections.pas b/src/lib/collections/Collections.pas new file mode 100644 index 00000000..ff7e3aa6 --- /dev/null +++ b/src/lib/collections/Collections.pas @@ -0,0 +1,5312 @@ +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. + * + * $Endlog$ + *****************************************************************************) + +interface + +uses + Classes, SysUtils, Windows; + +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. |