diff --git a/uutlEventManager.pas b/uutlEventManager.pas index 2d8edde..d3d4d3a 100644 --- a/uutlEventManager.pas +++ b/uutlEventManager.pas @@ -71,7 +71,7 @@ type public class function MakeMask (const aTypes: array of TutlEventType): TutlEventTypeMask; class function CombineMasks(const aMasks: array of TutlEventTypeMask): TutlEventTypeMask; - class function MaskHasType (const aMask: TutlEventTypeMask; const aType: TutlEventType): Boolean; + class function MaskHasType (const aMask: TutlEventTypeMask; const aType: TutlEventType): Boolean; inline; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/uutlGenerics.pas b/uutlGenerics.pas index b7ac0d9..844c5a9 100644 --- a/uutlGenerics.pas +++ b/uutlGenerics.pas @@ -110,10 +110,10 @@ type function CreateItem: PListItem; virtual; procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); virtual; procedure InsertIntern(const aIndex: Integer; const aItem: T); virtual; - procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true); + procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true); virtual; public - property OwnsObjects: Boolean read fOwnsObjects write fOwnsObjects; + property OwnsObjects: Boolean read fOwnsObjects write fOwnsObjects; function GetEnumerator: TEnumerator; function GetReverseEnumerator: TEnumerator; @@ -178,12 +178,20 @@ type end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - generic TutlCustomHashSet = class(specialize TutlListBase) + generic TutlHashSetBase = class(specialize TutlListBase) public type IComparer = specialize IutlComparer; private fComparer: IComparer; + protected function SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer; + public + constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlCustomHashSet = class(specialize TutlHashSetBase) public property Items[const aIndex: Integer]: T read GetItem; default; property Count: Integer read GetCount; @@ -193,9 +201,6 @@ type function IndexOf(const aItem: T): Integer; function Remove(const aItem: T): Boolean; procedure Delete(const aIndex: Integer); - - constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true); - destructor Destroy; override; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -216,23 +221,23 @@ type public constructor Create; end; - generic TutlCustomMap = class(TObject) + + generic TutlMapBase = class(TObject) public type IComparer = specialize IutlComparer; TKeyValuePair = packed record Key: TKey; Value: TValue; end; - private type - THashSetBase = specialize TutlCustomHashSet; - THashSet = class(THashSetBase) + + THashSet = class(specialize TutlCustomHashSet) protected procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); override; public property Items[const aIndex: Integer]: TKeyValuePair read GetItem write SetItem; default; end; - TKVPComparer = class(TInterfacedObject, THashSet.IComparer) + TKeyValuePairComparer = class(TInterfacedObject, THashSet.IComparer) private fComparer: IComparer; public @@ -299,8 +304,7 @@ type end; private - fComparer: IComparer; - fHashSet: THashSet; + fHashSetRef: THashSet; fKeyWrapper: TKeyWrapper; fKeyValuePairWrapper: TKeyValuePairWrapper; @@ -326,7 +330,16 @@ type function GetEnumerator: TValueEnumerator; - constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true); + constructor Create(const aHashSet: THashSet); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlCustomMap = class(specialize TutlMapBase) + private + fHashSetImpl: THashSet; + public + constructor Create(const aComparer: IComparer; const aOwnsObjects: Boolean = true); destructor Destroy; override; end; @@ -629,6 +642,20 @@ begin end; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlCustomMap.Create(const aComparer: IComparer; const aOwnsObjects: Boolean); +begin + fHashSetImpl := THashSet.Create(TKeyValuePairComparer.Create(aComparer), aOwnsObjects); + inherited Create(fHashSetImpl); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TutlCustomMap.Destroy; +begin + inherited Destroy; + FreeAndNil(fHashSetImpl); +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //EutlEnumConvert/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1094,9 +1121,9 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlHashSetBase/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomHashSet.SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer; +function TutlHashSetBase.SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer; var i, cmp: Integer; begin @@ -1115,6 +1142,22 @@ begin end; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlHashSetBase.Create(aComparer: IComparer; const aOwnsObjects: Boolean); +begin + inherited Create(aOwnsObjects); + fComparer := aComparer; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TutlHashSetBase.Destroy; +begin + fComparer := nil; + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlCustomHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlCustomHashSet.Add(const aItem: T): Boolean; var @@ -1158,20 +1201,6 @@ begin DeleteIntern(aIndex); end; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsObjects: Boolean); -begin - inherited Create(aOwnsObjects); - fComparer := aComparer; -end; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -destructor TutlCustomHashSet.Destroy; -begin - fComparer := nil; - inherited Destroy; -end; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1181,9 +1210,9 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap.THashSet//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TutlCustomMap.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean); +procedure TutlMapBase.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean); begin // never free objects used as keys, but do finalize strings, interfaces etc. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), false); @@ -1192,44 +1221,44 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap.TKVPComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase.TKeyValuePairComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKVPComparer.Compare(const i1, i2: TKeyValuePair): Integer; +function TutlMapBase.TKeyValuePairComparer.Compare(const i1, i2: TKeyValuePair): Integer; begin result := fComparer.Compare(i1.Key, i2.Key); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomMap.TKVPComparer.Create(aComparer: IComparer); +constructor TutlMapBase.TKeyValuePairComparer.Create(aComparer: IComparer); begin inherited Create; fComparer := aComparer; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -destructor TutlCustomMap.TKVPComparer.Destroy; +destructor TutlMapBase.TKeyValuePairComparer.Destroy; begin fComparer := nil; inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap.TValueEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TValueEnumerator.GetCurrent: TValue; +function TutlMapBase.TValueEnumerator.GetCurrent: TValue; begin result := fHashSet[fPos].Value; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TValueEnumerator.MoveNext: Boolean; +function TutlMapBase.TValueEnumerator.MoveNext: Boolean; begin inc(fPos); result := (fPos < fHashSet.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomMap.TValueEnumerator.Create(const aHashSet: THashSet); +constructor TutlMapBase.TValueEnumerator.Create(const aHashSet: THashSet); begin inherited Create; fHashSet := aHashSet; @@ -1237,22 +1266,22 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap.TKeyEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey; +function TutlMapBase.TKeyEnumerator.GetCurrent: TKey; begin result := fHashSet[fPos].Key; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyEnumerator.MoveNext: Boolean; +function TutlMapBase.TKeyEnumerator.MoveNext: Boolean; begin inc(fPos); result := (fPos < fHashSet.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomMap.TKeyEnumerator.Create(const aHashSet: THashSet); +constructor TutlMapBase.TKeyEnumerator.Create(const aHashSet: THashSet); begin inherited Create; fHashSet := aHashSet; @@ -1260,22 +1289,22 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap.TKeyValuePairEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase.TKeyValuePairEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair; +function TutlMapBase.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair; begin result := fHashSet[fPos]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyValuePairEnumerator.MoveNext: Boolean; +function TutlMapBase.TKeyValuePairEnumerator.MoveNext: Boolean; begin inc(fPos); result := (fPos < fHashSet.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomMap.TKeyValuePairEnumerator.Create(const aHashSet: THashSet); +constructor TutlMapBase.TKeyValuePairEnumerator.Create(const aHashSet: THashSet); begin inherited Create; fHashSet := aHashSet; @@ -1283,185 +1312,183 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap.TKeyWrapper///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase.TKeyWrapper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyWrapper.GetItem(const aIndex: Integer): TKey; +function TutlMapBase.TKeyWrapper.GetItem(const aIndex: Integer): TKey; begin result := fHashSet[aIndex].Key; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyWrapper.GetCount: Integer; +function TutlMapBase.TKeyWrapper.GetCount: Integer; begin result := fHashSet.Count; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyWrapper.GetEnumerator: TKeyEnumerator; +function TutlMapBase.TKeyWrapper.GetEnumerator: TKeyEnumerator; begin result := TKeyEnumerator.Create(fHashSet); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomMap.TKeyWrapper.Create(const aHashSet: THashSet); +constructor TutlMapBase.TKeyWrapper.Create(const aHashSet: THashSet); begin inherited Create; fHashSet := aHashSet; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap.TKeyValuePairWrapper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase.TKeyValuePairWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair; +function TutlMapBase.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair; begin result := fHashSet[aIndex]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyValuePairWrapper.GetCount: Integer; +function TutlMapBase.TKeyValuePairWrapper.GetCount: Integer; begin result := fHashSet.Count; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator; +function TutlMapBase.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator; begin result := TKeyValuePairEnumerator.Create(fHashSet); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomMap.TKeyValuePairWrapper.Create(const aHashSet: THashSet); +constructor TutlMapBase.TKeyValuePairWrapper.Create(const aHashSet: THashSet); begin inherited Create; fHashSet := aHashSet; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//TutlCustomMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlMapBase/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.GetValues(const aKey: TKey): TValue; +function TutlMapBase.GetValues(const aKey: TKey): TValue; var i: Integer; kvp: TKeyValuePair; begin kvp.Key := aKey; - i := fHashSet.IndexOf(kvp); + i := fHashSetRef.IndexOf(kvp); if (i < 0) then FillByte(result{%H-}, SizeOf(result), 0) else - result := fHashSet[i].Value; + result := fHashSetRef[i].Value; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue; +function TutlMapBase.GetValueAt(const aIndex: Integer): TValue; begin - result := fHashSet[aIndex].Value; + result := fHashSetRef[aIndex].Value; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.GetCount: Integer; +function TutlMapBase.GetCount: Integer; begin - result := fHashSet.Count; + result := fHashSetRef.Count; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TutlCustomMap.SetValues(const aKey: TKey; aValue: TValue); +procedure TutlMapBase.SetValues(const aKey: TKey; aValue: TValue); var i: Integer; kvp: TKeyValuePair; begin kvp.Key := aKey; kvp.Value := aValue; - i := fHashSet.IndexOf(kvp); + i := fHashSetRef.IndexOf(kvp); if (i < 0) then raise EutlMap.Create('key not found'); - fHashSet[i] := kvp; + fHashSetRef[i] := kvp; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TutlCustomMap.SetValueAt(const aIndex: Integer; aValue: TValue); +procedure TutlMapBase.SetValueAt(const aIndex: Integer; aValue: TValue); var kvp: TKeyValuePair; begin - kvp := fHashSet[aIndex]; + kvp := fHashSetRef[aIndex]; kvp.Value := aValue; - fHashSet[aIndex] := kvp; + fHashSetRef[aIndex] := kvp; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TutlCustomMap.Add(const aKey: TKey; const aValue: TValue); +procedure TutlMapBase.Add(const aKey: TKey; const aValue: TValue); var kvp: TKeyValuePair; begin kvp.Key := aKey; kvp.Value := aValue; - if not fHashSet.Add(kvp) then + if not fHashSetRef.Add(kvp) then raise EutlMapKeyAlreadyExists.Create(); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.IndexOf(const aKey: TKey): Integer; +function TutlMapBase.IndexOf(const aKey: TKey): Integer; var kvp: TKeyValuePair; begin kvp.Key := aKey; - result := fHashSet.IndexOf(kvp); + result := fHashSetRef.IndexOf(kvp); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.Contains(const aKey: TKey): Boolean; +function TutlMapBase.Contains(const aKey: TKey): Boolean; var kvp: TKeyValuePair; begin kvp.Key := aKey; - result := (fHashSet.IndexOf(kvp) >= 0); + result := (fHashSetRef.IndexOf(kvp) >= 0); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TutlCustomMap.Delete(const aKey: TKey); +procedure TutlMapBase.Delete(const aKey: TKey); var kvp: TKeyValuePair; begin kvp.Key := aKey; - if not fHashSet.Remove(kvp) then + if not fHashSetRef.Remove(kvp) then raise EutlMapKeyNotFound.Create; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TutlCustomMap.DeleteAt(const aIndex: Integer); +procedure TutlMapBase.DeleteAt(const aIndex: Integer); begin - fHashSet.Delete(aIndex); + fHashSetRef.Delete(aIndex); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TutlCustomMap.Clear; +procedure TutlMapBase.Clear; begin - fHashSet.Clear; + fHashSetRef.Clear; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -function TutlCustomMap.GetEnumerator: TValueEnumerator; +function TutlMapBase.GetEnumerator: TValueEnumerator; begin - result := TValueEnumerator.Create(fHashSet); + result := TValueEnumerator.Create(fHashSetRef); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -constructor TutlCustomMap.Create(aComparer: IComparer; const aOwnsObjects: Boolean); +constructor TutlMapBase.Create(const aHashSet: THashSet); begin inherited Create; - fComparer := aComparer; - fHashSet := THashSet.Create(TKVPComparer.Create(fComparer), aOwnsObjects); - fKeyWrapper := TKeyWrapper.Create(fHashSet); - fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSet); + fHashSetRef := aHashSet; + fKeyWrapper := TKeyWrapper.Create(fHashSetRef); + fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSetRef); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -destructor TutlCustomMap.Destroy; +destructor TutlMapBase.Destroy; begin FreeAndNil(fKeyValuePairWrapper); FreeAndNil(fKeyWrapper); - FreeAndNil(fHashSet); - fComparer := nil; + fHashSetRef := nil; inherited Destroy; end; diff --git a/uutlObservableGenerics.pas b/uutlObservableGenerics.pas new file mode 100644 index 0000000..6fd18a2 --- /dev/null +++ b/uutlObservableGenerics.pas @@ -0,0 +1,331 @@ +unit uutlObservableGenerics; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, + uutlGenerics; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlEventList = class(specialize TutlHashSetBase) + private type + TComparer = class(TInterfacedObject, IComparer) + public + function Compare(const i1, i2: T): Integer; + end; + + public + function RegisterEvent(const aEvent: T): Boolean; + function UnregisterEvent(const aEvent: T): Boolean; + + constructor Create; + end; + TutlNotifyEventList = specialize TutlEventList; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlObservableCustomList = class(specialize TutlCustomList) + public type + TEvent = procedure(aSender: TObject; const aIndex: Integer; const aItem: T) of object; + TEventList = specialize TutlEventList; + private + fOnAddItem: TEventList; + fOnRemoveItem: TEventList; + protected + procedure InsertIntern(const aIndex: Integer; const aItem: T); override; + procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true); override; + public + property OnAddItem: TEventList read fOnAddItem; + property OnRemoveItem: TEventList read fOnRemoveItem; + + constructor Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean = true); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlObservableList = class(specialize TutlObservableCustomList) + public type + TEqualityComparer = specialize TutlEqualityComparer; + public + constructor Create(const aOwnsObjects: Boolean = true); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlObservableCustomHashSet = class(specialize TutlCustomHashSet) + public type + TEvent = procedure(aSender: TObject; const aItem: T) of object; + TEventList = specialize TutlEventList; + private + fOnAddItem: TEventList; + fOnRemoveItem: TEventList; + protected + procedure InsertIntern(const aIndex: Integer; const aItem: T); override; + procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true); override; + public + property OnAddItem: TEventList read fOnAddItem; + property OnRemoveItem: TEventList read fOnRemoveItem; + + constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlObservableHashSet = class(specialize TutlObservableCustomHashSet) + public type + TComparer = specialize TutlComparer; + public + constructor Create(const aOwnsObjects: Boolean = true); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlObservableCustomMap = class(specialize TutlMapBase) + public type + TEvent = procedure(aSender: TObject; const aKey: TKey; const aValue: TValue) of object; + TEventList = specialize TutlEventList; + TObservableHashSet = class(THashSet) + private + fOwner: TObject; + fOnAddItem: TEventList; + fOnRemoveItem: TEventList; + protected + procedure InsertIntern(const aIndex: Integer; const aItem: TKeyValuePair); override; + procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true); override; + public + property OnAddItem: TEventList read fOnAddItem write fOnAddItem; + property OnRemoveItem: TEventList read fOnRemoveItem write fOnRemoveItem; + constructor Create(const aOwner: TObject; const aComparer: IComparer; const aOwnsObjects: Boolean = true); + end; + + private + fHashSetImpl: TObservableHashSet; + fOnAddItem: TEventList; + fOnRemoveItem: TEventList; + public + property OnAddItem: TEventList read fOnAddItem; + property OnRemoveItem: TEventList read fOnRemoveItem; + + constructor Create(const aComparer: IComparer; const aOwnsObjects: Boolean = true); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + generic TutlObservableMap = class(specialize TutlObservableCustomMap) + public type + TComparer = specialize TutlComparer; + public + constructor Create(const aOwnsObjects: Boolean = true); + end; + +implementation + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlEventList///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TutlEventList.TComparer.Compare(const i1, i2: T): Integer; +var + m1, m2: TMethod; +begin + m1 := TMethod(i1); + m2 := TMethod(i2); + if (m1.Data < m2.Data) then + result := -1 + else if (m1.Data > m2.Data) then + result := 1 + else if (m1.Code < m2.Code) then + result := -1 + else if (m1.Code > m2.Code) then + result := 1 + else + result := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TutlEventList.RegisterEvent(const aEvent: T): Boolean; +var + i: Integer; +begin + result := (SearchItem(0, List.Count-1, aEvent, i) < 0); + if result then + InsertIntern(i, aEvent); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TutlEventList.UnregisterEvent(const aEvent: T): Boolean; +var + i, tmp: Integer; +begin + i := SearchItem(0, List.Count-1, aEvent, tmp); + result := (i >= 0); + if result then + DeleteIntern(i); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlEventList.Create; +begin + inherited Create(TComparer.Create, true); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlObservableCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TutlObservableCustomList.InsertIntern(const aIndex: Integer; const aItem: T); +var + e: TEvent; +begin + inherited InsertIntern(aIndex, aItem); + if Assigned(fOnAddItem) then + for e in fOnAddItem do + e(self, aIndex, aItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TutlObservableCustomList.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean); +var + e: TEvent; +begin + if Assigned(fOnRemoveItem) then + for e in fOnRemoveItem do + e(self, aIndex, GetItem(aIndex)); + inherited DeleteIntern(aIndex, aFreeItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlObservableCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean); +begin + inherited Create(aEqualityComparer, aOwnsObjects); + fOnAddItem := TEventList.Create; + fOnRemoveItem := TEventList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TutlObservableCustomList.Destroy; +begin + FreeAndNil(fOnRemoveItem); + FreeAndNil(fOnAddItem); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlObservableList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlObservableList.Create(const aOwnsObjects: Boolean); +begin + inherited Create(TEqualityComparer.Create, aOwnsObjects); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlObservableCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TutlObservableCustomHashSet.InsertIntern(const aIndex: Integer; const aItem: T); +var + e: TEvent; +begin + inherited InsertIntern(aIndex, aItem); + if Assigned(fOnAddItem) then + for e in fOnAddItem do + e(self, aItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TutlObservableCustomHashSet.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean); +var + e: TEvent; +begin + if Assigned(fOnRemoveItem) then + for e in fOnRemoveItem do + e(self, GetItem(aIndex)); + inherited DeleteIntern(aIndex, aFreeItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlObservableCustomHashSet.Create(aComparer: IComparer; const aOwnsObjects: Boolean); +begin + inherited Create(aComparer, aOwnsObjects); + fOnAddItem := TEventList.Create; + fOnRemoveItem := TEventList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TutlObservableCustomHashSet.Destroy; +begin + inherited Destroy; // calls clear -> Free EventLists after + FreeAndNil(fOnAddItem); + FreeAndNil(fOnRemoveItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlObservableHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlObservableHashSet.Create(const aOwnsObjects: Boolean); +begin + inherited Create(TComparer.Create, aOwnsObjects); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlObservableCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TutlObservableCustomMap.TObservableHashSet.InsertIntern(const aIndex: Integer; const aItem: TKeyValuePair); +var + e: TEvent; +begin + inherited InsertIntern(aIndex, aItem); + if Assigned(fOnAddItem) then begin + for e in fOnAddItem do + e(fOwner, aItem.Key, aItem.Value); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TutlObservableCustomMap.TObservableHashSet.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean); +var + e: TEvent; + tmp: TKeyValuePair; +begin + if Assigned(fOnRemoveItem) then begin + tmp := GetItem(aIndex); + for e in fOnRemoveItem do + e(fOwner, tmp.Key, tmp.Value); + end; + inherited DeleteIntern(aIndex, aFreeItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlObservableCustomMap.TObservableHashSet.Create(const aOwner: TObject; const aComparer: IComparer; const aOwnsObjects: Boolean); +begin + inherited Create(aComparer, aOwnsObjects); + fOwner := aOwner; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlObservableCustomMap.Create(const aComparer: IComparer; const aOwnsObjects: Boolean); +begin + fOnAddItem := TEventList.Create; + fOnRemoveItem := TEventList.Create; + fHashSetImpl := TObservableHashSet.Create(self, aComparer, aOwnsObjects); + fHashSetImpl.OnAddItem := fOnAddItem; + fHashSetImpl.OnRemoveItem := fOnRemoveItem; + inherited Create(fHashSetImpl); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TutlObservableCustomMap.Destroy; +begin + inherited Destroy; + FreeAndNil(fHashSetImpl); + FreeAndNil(fOnAddItem); + FreeAndNil(fOnRemoveItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TutlObservableMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TutlObservableMap.Create(const aOwnsObjects: Boolean); +begin + inherited Create(TComparer.Create, aOwnsObjects); +end; + +end. +