* removed uutlStored * small improvements and bug fixingmaster
| @@ -11,7 +11,7 @@ | |||||
| <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> | <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> | ||||
| </SearchPaths> | </SearchPaths> | ||||
| </CompilerOptions> | </CompilerOptions> | ||||
| <Files Count="31"> | |||||
| <Files Count="30"> | |||||
| <Item1> | <Item1> | ||||
| <Filename Value="uutlAlgorithm.pas"/> | <Filename Value="uutlAlgorithm.pas"/> | ||||
| <UnitName Value="uutlAlgorithm"/> | <UnitName Value="uutlAlgorithm"/> | ||||
| @@ -117,25 +117,21 @@ | |||||
| <UnitName Value="uutlXmlHelper"/> | <UnitName Value="uutlXmlHelper"/> | ||||
| </Item26> | </Item26> | ||||
| <Item27> | <Item27> | ||||
| <Filename Value="uutlStored.pas"/> | |||||
| <UnitName Value="uutlStored"/> | |||||
| </Item27> | |||||
| <Item28> | |||||
| <Filename Value="uutlVariantObject.pas"/> | <Filename Value="uutlVariantObject.pas"/> | ||||
| <UnitName Value="uutlVariantObject"/> | <UnitName Value="uutlVariantObject"/> | ||||
| </Item28> | |||||
| <Item29> | |||||
| </Item27> | |||||
| <Item28> | |||||
| <Filename Value="uutlVariantProperty.pas"/> | <Filename Value="uutlVariantProperty.pas"/> | ||||
| <UnitName Value="uutlVariantProperty"/> | <UnitName Value="uutlVariantProperty"/> | ||||
| </Item29> | |||||
| <Item30> | |||||
| </Item28> | |||||
| <Item29> | |||||
| <Filename Value="uutlVariantEnum.pas"/> | <Filename Value="uutlVariantEnum.pas"/> | ||||
| <UnitName Value="uutlVariantEnum"/> | <UnitName Value="uutlVariantEnum"/> | ||||
| </Item30> | |||||
| <Item31> | |||||
| </Item29> | |||||
| <Item30> | |||||
| <Filename Value="uutlVariantSet.pas"/> | <Filename Value="uutlVariantSet.pas"/> | ||||
| <UnitName Value="uutlVariantSet"/> | <UnitName Value="uutlVariantSet"/> | ||||
| </Item31> | |||||
| </Item30> | |||||
| </Files> | </Files> | ||||
| <RequiredPkgs Count="2"> | <RequiredPkgs Count="2"> | ||||
| <Item1> | <Item1> | ||||
| @@ -11,8 +11,7 @@ uses | |||||
| uutlAlgorithm, uutlArrayContainer, uutlCommon, uutlComparer, uutlCompression, uutlEmbeddedProfiler, uutlEnumerator, | uutlAlgorithm, uutlArrayContainer, uutlCommon, uutlComparer, uutlCompression, uutlEmbeddedProfiler, uutlEnumerator, | ||||
| uutlEvent, uutlEventManager, uutlFilter, uutlGenerics, uutlInterfaces, uutlKeyCodes, uutlLinq, uutlListBase, | uutlEvent, uutlEventManager, uutlFilter, uutlGenerics, uutlInterfaces, uutlKeyCodes, uutlLinq, uutlListBase, | ||||
| uutlLogger, uutlMCF, uutlObservable, uutlSScanf, uutlStreamHelper, uutlSyncObjs, uutlThreads, uutlTypes, | uutlLogger, uutlMCF, uutlObservable, uutlSScanf, uutlStreamHelper, uutlSyncObjs, uutlThreads, uutlTypes, | ||||
| uutlXmlHelper, uutlStored, uutlVariantObject, uutlVariantProperty, uutlVariantEnum, uutlVariantSet, | |||||
| LazarusPackageIntf; | |||||
| uutlXmlHelper, uutlVariantObject, uutlVariantProperty, uutlVariantEnum, uutlVariantSet, LazarusPackageIntf; | |||||
| implementation | implementation | ||||
| @@ -33,7 +33,7 @@ | |||||
| <PackageName Value="FCL"/> | <PackageName Value="FCL"/> | ||||
| </Item3> | </Item3> | ||||
| </RequiredPackages> | </RequiredPackages> | ||||
| <Units Count="40"> | |||||
| <Units Count="41"> | |||||
| <Unit0> | <Unit0> | ||||
| <Filename Value="tests.lpr"/> | <Filename Value="tests.lpr"/> | ||||
| <IsPartOfProject Value="True"/> | <IsPartOfProject Value="True"/> | ||||
| @@ -194,6 +194,10 @@ | |||||
| <Filename Value="uutlVariantSetTest.pas"/> | <Filename Value="uutlVariantSetTest.pas"/> | ||||
| <IsPartOfProject Value="True"/> | <IsPartOfProject Value="True"/> | ||||
| </Unit39> | </Unit39> | ||||
| <Unit40> | |||||
| <Filename Value="uutlHandleManagerTests.pas"/> | |||||
| <IsPartOfProject Value="True"/> | |||||
| </Unit40> | |||||
| </Units> | </Units> | ||||
| </ProjectOptions> | </ProjectOptions> | ||||
| <CompilerOptions> | <CompilerOptions> | ||||
| @@ -17,7 +17,7 @@ uses | |||||
| // units unter test | // units unter test | ||||
| uutlAlgorithm, uutlArrayContainer, uutlCommon, uutlComparer, uutlEnumerator, uutlFilter, uutlGenerics, uutlInterfaces, | uutlAlgorithm, uutlArrayContainer, uutlCommon, uutlComparer, uutlEnumerator, uutlFilter, uutlGenerics, uutlInterfaces, | ||||
| uutlLinq, uutlListBase, uutlLogger, uutlStreamHelper, uutlSyncObjs, uutlTypes, uutlXmlHelper, uutlObservable, | uutlLinq, uutlListBase, uutlLogger, uutlStreamHelper, uutlSyncObjs, uutlTypes, uutlXmlHelper, uutlObservable, | ||||
| uutlSetHelperTests, uutlVariantEnumTest, uutlVariantSetTest; | |||||
| uutlSetHelperTests, uutlVariantEnumTest, uutlVariantSetTest, uutlHandleManagerTests; | |||||
| {$R *.res} | {$R *.res} | ||||
| @@ -0,0 +1,181 @@ | |||||
| unit uutlHandleManagerTests; | |||||
| {$mode objfpc}{$H+} | |||||
| interface | |||||
| uses | |||||
| Classes, SysUtils, TestFramework, | |||||
| uutlGenerics; | |||||
| type | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| TStringHandleManager = specialize TutlHandleManager<String>; | |||||
| TutlHandleManagerTests = class(TTestCase) | |||||
| private | |||||
| fManager: TStringHandleManager; | |||||
| public | |||||
| procedure SetUp; override; | |||||
| procedure TearDown; override; | |||||
| published | |||||
| procedure Add; | |||||
| procedure GetValue; | |||||
| procedure SetValue; | |||||
| procedure ComplexAddAndRemove; | |||||
| procedure Enumerate; | |||||
| end; | |||||
| implementation | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlHandleManagerTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManagerTests.SetUp; | |||||
| begin | |||||
| inherited SetUp; | |||||
| fManager := TStringHandleManager.Create(true); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManagerTests.TearDown; | |||||
| begin | |||||
| FreeAndNil(fManager); | |||||
| inherited TearDown; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManagerTests.Add; | |||||
| var | |||||
| h: TutlHandle; | |||||
| begin | |||||
| h := fManager.Add(0, 0, 'test'); | |||||
| AssertEquals($0000000100000000, h); | |||||
| h := fManager.Add(1, 0, 'test'); | |||||
| AssertEquals($0001000100000001, h); | |||||
| h := fManager.Add(2, 0, 'test'); | |||||
| AssertEquals($0002000100000002, h); | |||||
| h := fManager.Add(0, 1, 'test'); | |||||
| AssertEquals($0100000100000000, h); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManagerTests.GetValue; | |||||
| var | |||||
| h: TutlHandle; | |||||
| s: String; | |||||
| b: Boolean; | |||||
| begin | |||||
| h := fManager.Add(0, 0, 'test'); | |||||
| b := fManager.TryGetValue(h, s); | |||||
| AssertTrue (b); | |||||
| AssertEquals('test', s); | |||||
| b := fManager.TryGetValue(123, s); | |||||
| AssertFalse(b); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManagerTests.SetValue; | |||||
| var | |||||
| b: Boolean; | |||||
| s: String; | |||||
| begin | |||||
| b := fManager.TrySetValue($0000000100000010, 'test'); | |||||
| AssertTrue(b); | |||||
| b := fManager.TryGetValue($0000000100000010, s); | |||||
| AssertTrue (b); | |||||
| AssertEquals('test', s); | |||||
| b := fManager.TrySetValue($0000000100000010, 'hello'); | |||||
| AssertTrue(b); | |||||
| b := fManager.TryGetValue($0000000100000010, s); | |||||
| AssertTrue (b); | |||||
| AssertEquals('hello', s); | |||||
| b := fManager.TrySetValue($0000000200000010, 'blubb'); | |||||
| AssertFalse(b); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManagerTests.ComplexAddAndRemove; | |||||
| var | |||||
| h1, h2, h3, h4, h5: TutlHandle; | |||||
| b: Boolean; | |||||
| begin | |||||
| h1 := fManager.Add(0, 0, '1'); | |||||
| AssertEquals($0000000100000000, h1); | |||||
| h2 := fManager.Add(0, 0, '2'); | |||||
| AssertEquals($0000000100000001, h2); | |||||
| h3 := fManager.Add(0, 0, '3'); | |||||
| AssertEquals($0000000100000002, h3); | |||||
| h4 := fManager.Add(0, 0, '4'); | |||||
| AssertEquals($0000000100000003, h4); | |||||
| h5 := fManager.Add(0, 0, '5'); | |||||
| AssertEquals($0000000100000004, h5); | |||||
| b := fManager.Remove(h2); | |||||
| AssertTrue(b); | |||||
| h2 := fManager.Add(0, 0, '12'); | |||||
| AssertEquals($0000000200000001, h2); | |||||
| b := fManager.Remove(h4); | |||||
| AssertTrue(b); | |||||
| b := fManager.Remove(h3); | |||||
| AssertTrue(b); | |||||
| h3 := fManager.Add(0, 0, '13'); | |||||
| AssertEquals($0000000200000002, h3); | |||||
| h4 := fManager.Add(0, 0, '14'); | |||||
| AssertEquals($0000000200000003, h4); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManagerTests.Enumerate; | |||||
| var | |||||
| h, h1, h2, h3: TutlHandle; | |||||
| b: Boolean; | |||||
| e: TStringHandleManager.IEnumerator; | |||||
| begin | |||||
| e := fManager.GetEnumerator; | |||||
| h1 := fManager.Add(0, 0, '1'); | |||||
| h2 := fManager.Add(0, 0, '2'); | |||||
| h3 := fManager.Add(0, 0, '3'); | |||||
| b := e.MoveNext; | |||||
| AssertTrue(b); | |||||
| h := e.Current; | |||||
| AssertTrue(h1 = h); | |||||
| b := e.MoveNext; | |||||
| AssertTrue(b); | |||||
| h := e.Current; | |||||
| AssertTrue(h2 = h); | |||||
| b := e.MoveNext; | |||||
| AssertTrue(b); | |||||
| h := e.Current; | |||||
| AssertTrue(h3 = h); | |||||
| b := e.MoveNext; | |||||
| AssertFalse(b); | |||||
| end; | |||||
| initialization | |||||
| RegisterTest(TutlHandleManagerTests.Suite); | |||||
| end. | |||||
| @@ -19,7 +19,7 @@ type | |||||
| fEventArgs: TEventArgList; | fEventArgs: TEventArgList; | ||||
| fEventListener: IutlEventListener; | fEventListener: IutlEventListener; | ||||
| procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| public | public | ||||
| procedure SetUp; override; | procedure SetUp; override; | ||||
| @@ -37,7 +37,7 @@ implementation | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlObservableHashSetTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TutlObservableHashSetTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableHashSetTests.EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlObservableHashSetTests.EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| begin | begin | ||||
| if fCaptureEvents then | if fCaptureEvents then | ||||
| fEventArgs.Add(aEventArgs); | fEventArgs.Add(aEventArgs); | ||||
| @@ -19,7 +19,7 @@ type | |||||
| fEventArgs: TEventArgList; | fEventArgs: TEventArgList; | ||||
| fEventListener: IutlEventListener; | fEventListener: IutlEventListener; | ||||
| procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| public | public | ||||
| procedure SetUp; override; | procedure SetUp; override; | ||||
| @@ -37,7 +37,7 @@ implementation | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlObservableListTests/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TutlObservableListTests/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableListTests.EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlObservableListTests.EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| begin | begin | ||||
| if fCaptureEvents then | if fCaptureEvents then | ||||
| fEventArgs.Add(aEventArgs); | fEventArgs.Add(aEventArgs); | ||||
| @@ -19,7 +19,7 @@ type | |||||
| fEventArgs: TEventArgList; | fEventArgs: TEventArgList; | ||||
| fEventListener: IutlEventListener; | fEventListener: IutlEventListener; | ||||
| procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| public | public | ||||
| procedure SetUp; override; | procedure SetUp; override; | ||||
| @@ -37,7 +37,7 @@ implementation | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlObservableMapTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TutlObservableMapTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableMapTests.EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlObservableMapTests.EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| begin | begin | ||||
| if fCaptureEvents then | if fCaptureEvents then | ||||
| fEventArgs.Add(aEventArgs); | fEventArgs.Add(aEventArgs); | ||||
| @@ -154,9 +154,15 @@ begin | |||||
| fMap.Clear; | fMap.Clear; | ||||
| AssertEquals(1, fEventArgs.Count); | |||||
| AssertEquals(4, fEventArgs.Count); | |||||
| AssertTrue (Supports(fEventArgs[0], TutlObservableEventArgs, ea)); | AssertTrue (Supports(fEventArgs[0], TutlObservableEventArgs, ea)); | ||||
| AssertTrue (oetClear = ea.EventType); | AssertTrue (oetClear = ea.EventType); | ||||
| AssertTrue (Supports(fEventArgs[1], TutlObservableEventArgs, ea)); | |||||
| AssertTrue (oetRemove = ea.EventType); | |||||
| AssertTrue (Supports(fEventArgs[2], TutlObservableEventArgs, ea)); | |||||
| AssertTrue (oetRemove = ea.EventType); | |||||
| AssertTrue (Supports(fEventArgs[3], TutlObservableEventArgs, ea)); | |||||
| AssertTrue (oetRemove = ea.EventType); | |||||
| end; | end; | ||||
| initialization | initialization | ||||
| @@ -24,7 +24,12 @@ type | |||||
| property AutoFree: Boolean read fAutoFree write fAutoFree; | property AutoFree: Boolean read fAutoFree write fAutoFree; | ||||
| property RefCount: LongInt read fRefCount; | property RefCount: LongInt read fRefCount; | ||||
| procedure AfterConstruction; override; | |||||
| constructor Create; | constructor Create; | ||||
| public | |||||
| class function NewInstance: TObject; override; | |||||
| end; | end; | ||||
| TutlInterfaceNoRefCount = TutlInterfacedObject; | TutlInterfaceNoRefCount = TutlInterfacedObject; | ||||
| @@ -61,6 +66,7 @@ type | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| EInternal = class(Exception); | |||||
| EOutOfRangeException = class(Exception) | EOutOfRangeException = class(Exception) | ||||
| private | private | ||||
| fMin: Integer; | fMin: Integer; | ||||
| @@ -92,6 +98,7 @@ function GetPlatformIdentitfier(): String; | |||||
| function utlRateLimited (const Reference: QWord; const Interval: QWord): boolean; | function utlRateLimited (const Reference: QWord; const Interval: QWord): boolean; | ||||
| function utlFinalizeObject (var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean): Boolean; | function utlFinalizeObject (var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean): Boolean; | ||||
| function utlFilterBuilder (): IutlFilterBuilder; | function utlFilterBuilder (): IutlFilterBuilder; | ||||
| function utlBitCount (const aValue: DWord): Integer; | |||||
| implementation | implementation | ||||
| @@ -303,6 +310,16 @@ begin | |||||
| result := TFilterBuilderImpl.Create; | result := TFilterBuilderImpl.Create; | ||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function utlBitCount(const aValue: DWord): Integer; | |||||
| var | |||||
| t: DWord; | |||||
| begin | |||||
| t := aValue - ((aValue shr 1) and &33333333333) | |||||
| - ((aValue shr 2) and &11111111111); | |||||
| result := ((t + (t shr 3)) and &30707070707) mod 63; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlInterfacedObject/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TutlInterfacedObject/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -317,23 +334,37 @@ end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TutlInterfacedObject._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; | function TutlInterfacedObject._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; | ||||
| begin | begin | ||||
| result := InterLockedIncrement(fRefCount); | |||||
| _AddRef := interlockedincrement(fRefCount); | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TutlInterfacedObject._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; | function TutlInterfacedObject._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; | ||||
| begin | begin | ||||
| result := InterLockedDecrement(fRefCount); | |||||
| if (result = 0) and fAutoFree then | |||||
| _Release := InterLockedDecrement(fRefCount); | |||||
| if (_Release = 0) and fAutoFree then | |||||
| Destroy; | Destroy; | ||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlInterfacedObject.AfterConstruction; | |||||
| begin | |||||
| inherited AfterConstruction; | |||||
| InterLockedDecrement(fRefCount); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| constructor TutlInterfacedObject.Create; | constructor TutlInterfacedObject.Create; | ||||
| begin | begin | ||||
| inherited Create; | inherited Create; | ||||
| fAutoFree := false; | fAutoFree := false; | ||||
| fRefCount := 0; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| class function TutlInterfacedObject.NewInstance: TObject; | |||||
| begin | |||||
| result := inherited NewInstance; | |||||
| if Assigned(result) then | |||||
| TutlInterfacedObject(result).fRefCount := 1; | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -17,11 +17,11 @@ type | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| IutlEventListener = interface(IUnknown) | IutlEventListener = interface(IUnknown) | ||||
| ['{BC45E26B-96F7-4151-87F1-C330C8C668E5}'] | ['{BC45E26B-96F7-4151-87F1-C330C8C668E5}'] | ||||
| procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| TutlEventHandler = procedure (constref aSender: TObject; constref aEventArgs: IutlEventArgs) of object; | |||||
| TutlEventHandler = procedure (aSender: TObject; aEventArgs: IutlEventArgs) of object; | |||||
| TutlEventArgs = class(TutlInterfacedObject, IutlEventArgs) | TutlEventArgs = class(TutlInterfacedObject, IutlEventArgs) | ||||
| public | public | ||||
| constructor Create; | constructor Create; | ||||
| @@ -30,8 +30,8 @@ type | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| IutlObservable = interface(IUnknown) | IutlObservable = interface(IUnknown) | ||||
| ['{C54BD844-8273-4ACF-90C5-05DACF4359AF}'] | ['{C54BD844-8273-4ACF-90C5-05DACF4359AF}'] | ||||
| procedure RegisterEventListener (constref aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure RegisterEventListener (aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(aListener: IutlEventListener); | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -49,12 +49,12 @@ type | |||||
| TutlNotifyEventList = specialize TutlEventList<TNotifyEvent>; | TutlNotifyEventList = specialize TutlEventList<TNotifyEvent>; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| TutlEventHandlerList = class( | |||||
| TutlEventListenerList = class( | |||||
| specialize TutlEventList<TutlEventHandler> | specialize TutlEventList<TutlEventHandler> | ||||
| , IutlEventListener) | , IutlEventListener) | ||||
| public { IutlEventListener } | public { IutlEventListener } | ||||
| procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| public | public | ||||
| constructor Create; | constructor Create; | ||||
| @@ -63,7 +63,8 @@ type | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| TutlEventListenerSet = class( | TutlEventListenerSet = class( | ||||
| specialize TutlCustomHashSet<IutlEventListener> | specialize TutlCustomHashSet<IutlEventListener> | ||||
| , IutlEventListener) | |||||
| , IutlEventListener | |||||
| , IutlObservable) | |||||
| private type | private type | ||||
| TComparer = class(TInterfacedObject, IComparer) | TComparer = class(TInterfacedObject, IComparer) | ||||
| @@ -73,7 +74,11 @@ type | |||||
| end; | end; | ||||
| public { IutlEventListener } | public { IutlEventListener } | ||||
| procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| public { IutlObservable } | |||||
| procedure RegisterEventListener (aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(aListener: IutlEventListener); | |||||
| public | public | ||||
| constructor Create; reintroduce; | constructor Create; reintroduce; | ||||
| @@ -88,7 +93,7 @@ type | |||||
| fHandler: TutlEventHandler; | fHandler: TutlEventHandler; | ||||
| public { IEventListener } | public { IEventListener } | ||||
| procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| public | public | ||||
| constructor Create(const aHandler: TutlEventHandler); | constructor Create(const aHandler: TutlEventHandler); | ||||
| @@ -114,7 +119,7 @@ type | |||||
| function PopEventPair(out aPair: TEventPair): Boolean; | function PopEventPair(out aPair: TEventPair): Boolean; | ||||
| public { IEventListener } | public { IEventListener } | ||||
| procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| public | public | ||||
| procedure DispatchEvents; | procedure DispatchEvents; | ||||
| @@ -169,9 +174,9 @@ begin | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlEventHandlerList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlEventListenerList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlEventHandlerList.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlEventListenerList.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| var | var | ||||
| e: TutlEventHandler; | e: TutlEventHandler; | ||||
| begin | begin | ||||
| @@ -180,7 +185,7 @@ begin | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| constructor TutlEventHandlerList.Create; | |||||
| constructor TutlEventListenerList.Create; | |||||
| begin | begin | ||||
| inherited Create; | inherited Create; | ||||
| AutoFree := true; | AutoFree := true; | ||||
| @@ -208,7 +213,7 @@ end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlEventListenerSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TutlEventListenerSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlEventListenerSet.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlEventListenerSet.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| var | var | ||||
| e: IutlEventListener; | e: IutlEventListener; | ||||
| begin | begin | ||||
| @@ -216,6 +221,18 @@ begin | |||||
| e.DispatchEvent(aSender, aEventArgs); | e.DispatchEvent(aSender, aEventArgs); | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlEventListenerSet.RegisterEventListener(aListener: IutlEventListener); | |||||
| begin | |||||
| Add(aListener); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlEventListenerSet.UnregisterEventListener(aListener: IutlEventListener); | |||||
| begin | |||||
| Remove(aListener); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| constructor TutlEventListenerSet.Create; | constructor TutlEventListenerSet.Create; | ||||
| begin | begin | ||||
| @@ -225,7 +242,7 @@ end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlEventListenerCallback////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TutlEventListenerCallback////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlEventListenerCallback.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlEventListenerCallback.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| begin | begin | ||||
| fHandler(aSender, aEventArgs); | fHandler(aSender, aEventArgs); | ||||
| end; | end; | ||||
| @@ -266,7 +283,7 @@ begin | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlEventListenerAsync.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlEventListenerAsync.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| var | var | ||||
| p: TEventPair; | p: TEventPair; | ||||
| begin | begin | ||||
| @@ -10,7 +10,7 @@ interface | |||||
| uses | uses | ||||
| Classes, SysUtils, Controls, | Classes, SysUtils, Controls, | ||||
| uutlEvent; | |||||
| uutlEvent, uutlCommon; | |||||
| type | type | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -110,7 +110,10 @@ type | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| TutlWinControlEventManager = class(TutlEventListenerSet) | |||||
| TutlWinControlEventManager = class( | |||||
| TutlInterfacedObject | |||||
| , IutlObservable) | |||||
| public const | public const | ||||
| EVENT_MOUSE_DOWN = 0; | EVENT_MOUSE_DOWN = 0; | ||||
| EVENT_MOUSE_UP = 1; | EVENT_MOUSE_UP = 1; | ||||
| @@ -186,6 +189,7 @@ type | |||||
| fKeyboard: TKeyboardState; | fKeyboard: TKeyboardState; | ||||
| fMouse: TMouseState; | fMouse: TMouseState; | ||||
| fWindow: TWindowState; | fWindow: TWindowState; | ||||
| fEventListener: TutlEventListenerSet; | |||||
| procedure HandlerMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); | procedure HandlerMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); | ||||
| procedure HandlerMouseUp (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); | procedure HandlerMouseUp (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); | ||||
| @@ -204,7 +208,8 @@ type | |||||
| procedure HandlerDeactivate (Sender: TObject); | procedure HandlerDeactivate (Sender: TObject); | ||||
| protected | protected | ||||
| procedure RecordEvent(constref aEventArgs: IutlEventArgs); virtual; | |||||
| procedure RecordEvent(aEventArgs: IutlEventArgs); virtual; | |||||
| procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| function CreateMouseEventArgs( | function CreateMouseEventArgs( | ||||
| aControl: TControl; | aControl: TControl; | ||||
| @@ -226,20 +231,26 @@ type | |||||
| aControl: TControl; | aControl: TControl; | ||||
| aType: TutlEventType): IutlEventArgs; virtual; | aType: TutlEventType): IutlEventArgs; virtual; | ||||
| public { IutlObservable } | |||||
| procedure RegisterEventListener (aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(aListener: IutlEventListener); | |||||
| public | public | ||||
| property Keyboard: TKeyboardState read fKeyboard; | property Keyboard: TKeyboardState read fKeyboard; | ||||
| property Mouse: TMouseState read fMouse; | property Mouse: TMouseState read fMouse; | ||||
| property Window: TWindowState read fWindow; | property Window: TWindowState read fWindow; | ||||
| procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure AttachEvents (const aControl: TWinControl; const aTypes: TutlEventTypes); | |||||
| procedure AttachEvents(const aControl: TWinControl; const aTypes: TutlEventTypes); | |||||
| constructor Create; | |||||
| destructor Destroy; override; | |||||
| end; | end; | ||||
| implementation | implementation | ||||
| uses | uses | ||||
| LCLIntf, Forms, | LCLIntf, Forms, | ||||
| uutlKeyCodes, uutlCommon; | |||||
| uutlKeyCodes; | |||||
| type | type | ||||
| TWinControlVisibilityClass = class(TWinControl) | TWinControlVisibilityClass = class(TWinControl) | ||||
| @@ -416,7 +427,7 @@ begin | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlWinControlEventManager.RecordEvent(constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlWinControlEventManager.RecordEvent(aEventArgs: IutlEventArgs); | |||||
| var | var | ||||
| mea: TutlMouseEventArgs; | mea: TutlMouseEventArgs; | ||||
| kea: TutlKeyEventArgs; | kea: TutlKeyEventArgs; | ||||
| @@ -491,6 +502,13 @@ begin | |||||
| end; | end; | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlWinControlEventManager.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||||
| begin | |||||
| RecordEvent(aEventArgs); | |||||
| fEventListener.DispatchEvent(aSender, aEventArgs); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TutlWinControlEventManager.CreateMouseEventArgs( | function TutlWinControlEventManager.CreateMouseEventArgs( | ||||
| aControl: TControl; | aControl: TControl; | ||||
| @@ -552,10 +570,17 @@ begin | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlWinControlEventManager.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||||
| procedure TutlWinControlEventManager.RegisterEventListener(aListener: IutlEventListener); | |||||
| begin | begin | ||||
| RecordEvent(aEventArgs); | |||||
| inherited DispatchEvent(aSender, aEventArgs); | |||||
| if Assigned(fEventListener) then | |||||
| fEventListener.Add(aListener); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlWinControlEventManager.UnregisterEventListener(aListener: IutlEventListener); | |||||
| begin | |||||
| if Assigned(fEventListener) then | |||||
| fEventListener.Remove(aListener); | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -595,5 +620,19 @@ begin | |||||
| end; | end; | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| constructor TutlWinControlEventManager.Create; | |||||
| begin | |||||
| inherited Create; | |||||
| fEventListener := TutlEventListenerSet.Create; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| destructor TutlWinControlEventManager.Destroy; | |||||
| begin | |||||
| FreeAndNil(fEventListener); | |||||
| inherited Destroy; | |||||
| end; | |||||
| end. | end. | ||||
| @@ -1,6 +1,7 @@ | |||||
| unit uutlGenerics; | unit uutlGenerics; | ||||
| {$mode objfpc}{$H+} | {$mode objfpc}{$H+} | ||||
| {$modeswitch advancedrecords} | |||||
| interface | interface | ||||
| @@ -198,7 +199,7 @@ type | |||||
| function Extract (const aItem: T; const aDefault: T): T; overload; | function Extract (const aItem: T; const aDefault: T): T; overload; | ||||
| function Remove (const aItem: T): Integer; | function Remove (const aItem: T): Integer; | ||||
| constructor Create (const aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||||
| constructor Create (aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||||
| destructor Destroy; override; | destructor Destroy; override; | ||||
| end; | end; | ||||
| @@ -241,7 +242,7 @@ type | |||||
| function Remove (constref aItem: T): Boolean; | function Remove (constref aItem: T): Boolean; | ||||
| procedure Delete (const aIndex: Integer); | procedure Delete (const aIndex: Integer); | ||||
| constructor Create (const aComparer: IComparer; const aOwnsItems: Boolean); | |||||
| constructor Create (aComparer: IComparer; const aOwnsItems: Boolean); | |||||
| destructor Destroy; override; | destructor Destroy; override; | ||||
| end; | end; | ||||
| @@ -287,7 +288,7 @@ type | |||||
| procedure Release(var aItem: TKeyValuePair; const aFreeItem: Boolean); override; | procedure Release(var aItem: TKeyValuePair; const aFreeItem: Boolean); override; | ||||
| public | public | ||||
| constructor Create(const aOwner: TutlCustomMap; const aComparer: IComparer); | |||||
| constructor Create(const aOwner: TutlCustomMap; aComparer: IComparer); | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -479,7 +480,10 @@ type | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| TutlHandle = QWord; | TutlHandle = QWord; | ||||
| generic TutlHandleManager<T> = class(TObject) | |||||
| generic TutlHandleManager<T> = class( | |||||
| TutlInterfacedObject | |||||
| , specialize IutlEnumerable<TutlHandle>) | |||||
| private type | private type | ||||
| THandleData = packed record | THandleData = packed record | ||||
| case Integer of | case Integer of | ||||
| @@ -488,47 +492,124 @@ type | |||||
| ); | ); | ||||
| 1: ( | 1: ( | ||||
| Index: Cardinal; // 0..31 | |||||
| Counter: Word; // 32..47 | |||||
| Identifier: Word // 48..63 | |||||
| Index: Cardinal; // 0..31 index in data array (unique for each priority) | |||||
| Counter: Word; // 32..47 reusage counter | |||||
| TypeID: Byte; // 48..55 Stored Data Type | |||||
| Priority: Byte; // 56..63 Priority to share handles between multiple systems | |||||
| ); | ); | ||||
| end; | end; | ||||
| THandleEntry = bitpacked record | |||||
| Data: T; | |||||
| NextFreeIndex: Cardinal; // 0..31 | |||||
| Counter: Word; // 32..47 | |||||
| IsActive: Boolean; // 48 | |||||
| __reserved: 0..((1 shl 15)-1); // 49..63 | |||||
| TIndex = Cardinal; | |||||
| TEntryStatus = byte; | |||||
| PHandleEntry = ^THandleEntry; | |||||
| THandleEntry = packed record | |||||
| Next: TIndex; // 0..31 next used/free item | |||||
| Prev: TIndex; // 32..63 prev used/free item | |||||
| Counter: Word; // 64..79 current counter value | |||||
| Status: TEntryStatus; // 80..87 item status | |||||
| TypeID: Byte; // 88..95 type id | |||||
| Data: T; // actual data | |||||
| end; | |||||
| THandleEntries = array of THandleEntry; | |||||
| PPriorityItem = ^TPriorityItem; | |||||
| TPriorityItem = packed record | |||||
| FirstFree: TIndex; | |||||
| LastFree: TIndex; | |||||
| FirstUsed: TIndex; | |||||
| LastUsed: TIndex; | |||||
| Handles: THandleEntries; | |||||
| function GetHandleEntry(const aIndex: TIndex): PHandleEntry; | |||||
| procedure Grow(const aSize: Integer = 0); | |||||
| procedure PushFront(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus); | |||||
| procedure PushBack (const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus); | |||||
| procedure Remove (const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus); | |||||
| function PopFront(var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex; | |||||
| function PopBack (var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex; | |||||
| procedure PushFrontFreeIndex(const aIndex: TIndex); inline; | |||||
| procedure PushBackFreeIndex (const aIndex: TIndex); inline; | |||||
| procedure PushFrontUsedIndex(const aIndex: TIndex); inline; | |||||
| procedure PushBackUsedIndex (const aIndex: TIndex); inline; | |||||
| procedure RemoveFreeIndex (const aIndex: TIndex); inline; | |||||
| procedure RemoveUsedIndex (const aIndex: TIndex); inline; | |||||
| function PopFrontFreeIndex: TIndex; | |||||
| function PopBackFreeIndex: TIndex; | |||||
| function PopFrontUsedIndex: TIndex; | |||||
| function PopBackUsedIndex: TIndex; | |||||
| end; | |||||
| TPriorityItems = array of TPriorityItem; | |||||
| TEnumerator = class(specialize TutlEnumerator<TutlHandle>) | |||||
| private | |||||
| fOwner: TutlHandleManager; | |||||
| fPriority: Integer; | |||||
| fIndex: TIndex; | |||||
| fHandle: THandleEntry; | |||||
| protected | |||||
| function InternalMoveNext: Boolean; override; | |||||
| procedure InternalReset; override; | |||||
| public | |||||
| function GetCurrent: TutlHandle; override; | |||||
| constructor Create(const aOwner: TutlHandleManager); | |||||
| end; | end; | ||||
| private const | |||||
| UNKNOWN_INDEX: TIndex = high(TIndex); | |||||
| GROW_SIZE = 100; | |||||
| ENTRY_STATUS_UNKNOWN: byte = 0; | |||||
| ENTRY_STATUS_FREE: byte = 1; | |||||
| ENTRY_STATUS_USED: byte = 2; | |||||
| private | |||||
| class function HighIndex(constref aEntries: THandleEntries): TIndex; inline; | |||||
| public type | |||||
| IEnumerator = specialize IEnumerator<TutlHandle>; | |||||
| IutlEnumerator = specialize IutlEnumerator<TutlHandle>; | |||||
| private | private | ||||
| fCount: Integer; | fCount: Integer; | ||||
| fGrowSize: Integer; | |||||
| fEntries: array of THandleEntry; | |||||
| fFirstFreeIndex: Cardinal; | |||||
| fItems: TPriorityItems; | |||||
| fOwnsValues: Boolean; | fOwnsValues: Boolean; | ||||
| procedure Grow; | |||||
| function GetPriorityItem(const aPriority: Byte): PPriorityItem; | |||||
| public | public | ||||
| function Get (const aHandle: TutlHandle): T; | |||||
| function TryGet (const aHandle: TutlHandle; out aData: T): Boolean; | |||||
| function Add (constref aData: T; const aIdentifier: Word): TutlHandle; | |||||
| function IsValid(const aHandle: TutlHandle): Boolean; inline; | |||||
| procedure Update (const aHandle: TutlHandle; aData: T); | |||||
| procedure Remove (const aHandle: TutlHandle); | |||||
| function GetValue (const aHandle: TutlHandle): T; | |||||
| function TryGetValue (const aHandle: TutlHandle; out aData: T): Boolean; | |||||
| procedure SetValue (const aHandle: TutlHandle; aData: T); | |||||
| function TrySetValue (const aHandle: TutlHandle; aData: T): Boolean; | |||||
| function Add (const aTypeID: Byte; const aPriority: Byte; constref aData: T): TutlHandle; | |||||
| function IsValid (const aHandle: TutlHandle): Boolean; inline; | |||||
| procedure Update (const aHandle: TutlHandle; aData: T); | |||||
| function Remove (const aHandle: TutlHandle): Boolean; | |||||
| procedure Delete (const aHandle: TutlHandle); | |||||
| procedure Clear; | procedure Clear; | ||||
| public { IutlEnumerable } | |||||
| function GetEnumerator: IEnumerator; | |||||
| function GetUtlEnumerator: IutlEnumerator; | |||||
| public | public | ||||
| property Items[const aHandle: TutlHandle]: T read Get write Update; | |||||
| property Items[const aHandle: TutlHandle]: T read GetValue write SetValue; default; | |||||
| property Count: Integer read fCount; | property Count: Integer read fCount; | ||||
| constructor Create(const aOwnsValues: Boolean); | constructor Create(const aOwnsValues: Boolean); | ||||
| destructor Destroy; override; | destructor Destroy; override; | ||||
| public | public | ||||
| class function GetIdentifier(const aHandle: TutlHandle): Word; inline; | |||||
| class function GetTypeID (const aHandle: TutlHandle): Byte; inline; | |||||
| class function GetPriority(const aHandle: TutlHandle): Byte; inline; | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -1180,7 +1261,7 @@ begin | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| constructor TutlCustomList.Create(const aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||||
| constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||||
| begin | begin | ||||
| if not Assigned(aEqualityComparer) then | if not Assigned(aEqualityComparer) then | ||||
| raise EArgumentNilException.Create('aEqualityComparer'); | raise EArgumentNilException.Create('aEqualityComparer'); | ||||
| @@ -1261,7 +1342,7 @@ begin | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| constructor TutlCustomHashSet.Create(const aComparer: IComparer; const aOwnsItems: Boolean); | |||||
| constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsItems: Boolean); | |||||
| begin | begin | ||||
| inherited Create(aOwnsItems); | inherited Create(aOwnsItems); | ||||
| fComparer := aComparer; | fComparer := aComparer; | ||||
| @@ -1295,7 +1376,7 @@ begin | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| constructor TutlCustomMap.THashSet.Create(const aOwner: TutlCustomMap; const aComparer: IComparer); | |||||
| constructor TutlCustomMap.THashSet.Create(const aOwner: TutlCustomMap; aComparer: IComparer); | |||||
| begin | begin | ||||
| inherited Create(aComparer, true); | inherited Create(aComparer, true); | ||||
| fOwner := aOwner; | fOwner := aOwner; | ||||
| @@ -1681,69 +1762,388 @@ begin | |||||
| FreeAndNil(fHashSetImpl); | FreeAndNil(fHashSetImpl); | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlHandleManager.TPriorityItem//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TPriorityItem.GetHandleEntry(const aIndex: TIndex): PHandleEntry; | |||||
| begin | |||||
| if (aIndex > HighIndex(Handles)) then | |||||
| Grow; | |||||
| result := @Handles[aIndex]; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.Grow(const aSize: Integer); | |||||
| var | |||||
| oldIdx, newIdx, i: TIndex; | |||||
| begin | |||||
| oldIdx := Length(Handles); | |||||
| if (aSize = 0) then | |||||
| SetLength(Handles, Length(Handles) + GROW_SIZE) | |||||
| else if (Length(Handles) >= aSize) then | |||||
| exit | |||||
| else | |||||
| SetLength(Handles, aSize); | |||||
| newIdx := High(Handles); | |||||
| for i := oldIdx to newIdx do begin | |||||
| FillByte(Handles[i].Data, SizeOf(T), 0); | |||||
| Handles[i].Counter := 0; | |||||
| Handles[i].Status := ENTRY_STATUS_UNKNOWN; | |||||
| Handles[i].Next := High(TIndex); | |||||
| Handles[i].Prev := High(TIndex); | |||||
| PushBackFreeIndex(i); | |||||
| end; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.PushFront(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; | |||||
| const aStatus: TEntryStatus); | |||||
| begin | |||||
| Assert(aIndex <= HighIndex(Handles)); | |||||
| Assert(Handles[aIndex].Status = ENTRY_STATUS_UNKNOWN); | |||||
| if (FirstIndex <> UNKNOWN_INDEX) | |||||
| and (FirstIndex <= HighIndex(Handles)) | |||||
| and (Handles[FirstIndex].Status = aStatus) | |||||
| then | |||||
| Handles[FirstIndex].Prev := aIndex; | |||||
| with Handles[aIndex] do begin | |||||
| Prev := UNKNOWN_INDEX; | |||||
| Next := FirstIndex; | |||||
| Status := aStatus; | |||||
| end; | |||||
| FirstIndex := aIndex; | |||||
| if (LastIndex = UNKNOWN_INDEX) then | |||||
| LastIndex := aIndex; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.PushBack(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; | |||||
| const aStatus: TEntryStatus); | |||||
| begin | |||||
| Assert(aIndex <= HighIndex(Handles)); | |||||
| Assert(Handles[aIndex].Status = ENTRY_STATUS_UNKNOWN); | |||||
| if (LastIndex <> UNKNOWN_INDEX) | |||||
| and (LastIndex <= HighIndex(Handles)) | |||||
| and (Handles[LastIndex].Status = aStatus) | |||||
| then | |||||
| Handles[LastIndex].Next := aIndex; | |||||
| with Handles[aIndex] do begin | |||||
| Prev := LastIndex; | |||||
| Next := UNKNOWN_INDEX; | |||||
| Status := aStatus; | |||||
| end; | |||||
| LastIndex := aIndex; | |||||
| if (FirstIndex = UNKNOWN_INDEX) then | |||||
| FirstIndex := aIndex; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.Remove(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus); | |||||
| begin | |||||
| Assert(aIndex <> UNKNOWN_INDEX); | |||||
| Assert(aIndex <= HighIndex(Handles)); | |||||
| Assert(Handles[aIndex].Status = aStatus); | |||||
| with Handles[aIndex] do begin | |||||
| if (Prev <> UNKNOWN_INDEX) then begin | |||||
| Assert(Prev <= HighIndex(Handles)); | |||||
| Handles[Prev].Next := Next; | |||||
| end; | |||||
| if (Next <> UNKNOWN_INDEX) then begin | |||||
| Assert(Next <= HighIndex(Handles)); | |||||
| Handles[Next].Prev := Prev; | |||||
| end; | |||||
| if (aIndex = FirstIndex) then | |||||
| FirstIndex := Next; | |||||
| if (aIndex = LastIndex) then | |||||
| LastIndex := Prev; | |||||
| Prev := UNKNOWN_INDEX; | |||||
| Next := UNKNOWN_INDEX; | |||||
| Status := ENTRY_STATUS_UNKNOWN; | |||||
| end; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TPriorityItem.PopFront(var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex; | |||||
| begin | |||||
| if aCanGrow | |||||
| and ( (FirstIndex = UNKNOWN_INDEX) | |||||
| or (FirstIndex > HighIndex(Handles))) | |||||
| then | |||||
| Grow; | |||||
| Assert(FirstIndex <> UNKNOWN_INDEX); | |||||
| Assert(FirstIndex <= HighIndex(Handles)); | |||||
| Assert(Handles[FirstIndex].Status = aStatus); | |||||
| result := FirstIndex; | |||||
| with Handles[result] do begin | |||||
| if (LastIndex = FirstIndex) then | |||||
| LastIndex := Next; | |||||
| FirstIndex := Next; | |||||
| Prev := UNKNOWN_INDEX; | |||||
| Next := UNKNOWN_INDEX; | |||||
| Status := ENTRY_STATUS_UNKNOWN; | |||||
| end; | |||||
| if (FirstIndex <> UNKNOWN_INDEX) | |||||
| and (FirstIndex <= HighIndex(Handles)) | |||||
| and (Handles[FirstIndex].Status = aStatus) | |||||
| then | |||||
| Handles[FirstIndex].Prev := UNKNOWN_INDEX; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TPriorityItem.PopBack(var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex; | |||||
| begin | |||||
| if aCanGrow | |||||
| and ( (LastIndex <> UNKNOWN_INDEX) | |||||
| or (LastIndex <= HighIndex(Handles))) | |||||
| then | |||||
| Grow; | |||||
| Assert(LastIndex <> UNKNOWN_INDEX); | |||||
| Assert(LastIndex <= HighIndex(Handles)); | |||||
| Assert(Handles[LastIndex].Status = aStatus); | |||||
| result := LastIndex; | |||||
| with Handles[result] do begin | |||||
| if (FirstIndex = LastIndex) then | |||||
| FirstIndex := Next; | |||||
| LastIndex := Prev; | |||||
| Prev := UNKNOWN_INDEX; | |||||
| Next := UNKNOWN_INDEX; | |||||
| Status := ENTRY_STATUS_UNKNOWN; | |||||
| end; | |||||
| if (LastIndex <> UNKNOWN_INDEX) | |||||
| and (LastIndex <= HighIndex(Handles)) | |||||
| and (Handles[LastIndex].Status = aStatus) | |||||
| then | |||||
| Handles[LastIndex].Next := UNKNOWN_INDEX; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.PushFrontFreeIndex(const aIndex: TIndex); | |||||
| begin | |||||
| PushFront(aIndex, FirstFree, LastFree, ENTRY_STATUS_FREE); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.PushBackFreeIndex(const aIndex: TIndex); | |||||
| begin | |||||
| PushBack(aIndex, FirstFree, LastFree, ENTRY_STATUS_FREE); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.PushFrontUsedIndex(const aIndex: TIndex); | |||||
| begin | |||||
| PushFront(aIndex, FirstUsed, LastUsed, ENTRY_STATUS_USED); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.PushBackUsedIndex(const aIndex: TIndex); | |||||
| begin | |||||
| PushBack(aIndex, FirstUsed, LastUsed, ENTRY_STATUS_USED); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.RemoveFreeIndex(const aIndex: TIndex); | |||||
| begin | |||||
| Remove(aIndex, FirstFree, LastFree, ENTRY_STATUS_FREE); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TPriorityItem.RemoveUsedIndex(const aIndex: TIndex); | |||||
| begin | |||||
| Remove(aIndex, FirstUsed, LastUsed, ENTRY_STATUS_USED); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TPriorityItem.PopFrontFreeIndex: TIndex; | |||||
| begin | |||||
| result := PopFront(FirstFree, LastFree, ENTRY_STATUS_FREE, true); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TPriorityItem.PopBackFreeIndex: TIndex; | |||||
| begin | |||||
| result := PopBack(FirstFree, LastFree, ENTRY_STATUS_FREE, false); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TPriorityItem.PopFrontUsedIndex: TIndex; | |||||
| begin | |||||
| result := PopFront(FirstUsed, LastUsed, ENTRY_STATUS_USED, false); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TPriorityItem.PopBackUsedIndex: TIndex; | |||||
| begin | |||||
| result := PopBack(FirstUsed, LastUsed, ENTRY_STATUS_USED, false); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlHandleManager.TEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TEnumerator.InternalMoveNext: Boolean; | |||||
| var | |||||
| p: PPriorityItem; | |||||
| begin | |||||
| repeat | |||||
| if (fIndex = UNKNOWN_INDEX) then begin | |||||
| inc(fPriority); | |||||
| if (fPriority > High(fOwner.fItems)) then | |||||
| break; | |||||
| p := fOwner.GetPriorityItem(fPriority); | |||||
| fIndex := p^.FirstUsed; | |||||
| end else begin | |||||
| p := fOwner.GetPriorityItem(fPriority); | |||||
| fIndex := p^.Handles[fIndex].Next; | |||||
| if (fIndex > HighIndex(p^.Handles)) then | |||||
| fIndex := UNKNOWN_INDEX; | |||||
| end; | |||||
| until (fPriority > High(fOwner.fItems)) or (fIndex <> UNKNOWN_INDEX); | |||||
| result := (fPriority <= High(fOwner.fItems)); | |||||
| if result then begin | |||||
| p := fOwner.GetPriorityItem(fPriority); | |||||
| fHandle := p^.Handles[fIndex]; | |||||
| end else | |||||
| FillByte(fHandle, SizeOf(fHandle), 0); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.TEnumerator.InternalReset; | |||||
| begin | |||||
| fPriority := -1; | |||||
| fIndex := UNKNOWN_INDEX; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TEnumerator.GetCurrent: TutlHandle; | |||||
| begin | |||||
| if (fHandle.Status <> ENTRY_STATUS_USED) then | |||||
| raise EInvalidOperation.Create('enumerator not initialized or collection changed'); | |||||
| with THandleData(result) do begin | |||||
| Index := fIndex; | |||||
| Counter := fHandle.Counter; | |||||
| TypeID := fHandle.TypeID; | |||||
| Priority := fPriority; | |||||
| end; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| constructor TutlHandleManager.TEnumerator.Create(const aOwner: TutlHandleManager); | |||||
| begin | |||||
| if not Assigned(aOwner) then | |||||
| raise EArgumentNilException.Create('aOwner'); | |||||
| inherited Create; | |||||
| fOwner := aOwner; | |||||
| FillByte(fHandle, SizeOf(fHandle), 0); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlHandleManager Class Methods//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| class function TutlHandleManager.HighIndex(constref aEntries: THandleEntries): TIndex; | |||||
| begin | |||||
| result := TIndex(High(aEntries)); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //TutlHandleManager////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //TutlHandleManager////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlHandleManager.Grow; | |||||
| function TutlHandleManager.GetPriorityItem(const aPriority: Byte): PPriorityItem; | |||||
| var | var | ||||
| oldIdx, newIdx, i: Integer; | oldIdx, newIdx, i: Integer; | ||||
| begin | begin | ||||
| oldIdx := High(fEntries); | |||||
| SetLength(fEntries, Length(fEntries) + fGrowSize); | |||||
| newIdx := High(fEntries); | |||||
| for i := oldIdx to newIdx do | |||||
| fEntries[i].NextFreeIndex := i + 1; | |||||
| if (aPriority > High(fItems)) then begin | |||||
| oldIdx := Length(fItems); | |||||
| SetLength(fItems, aPriority + 1); | |||||
| newIdx := High(fItems); | |||||
| for i := oldIdx to newIdx do with fItems[i] do begin | |||||
| FirstFree := UNKNOWN_INDEX; | |||||
| LastFree := UNKNOWN_INDEX; | |||||
| FirstUsed := UNKNOWN_INDEX; | |||||
| LastUsed := UNKNOWN_INDEX; | |||||
| SetLength(Handles, 0); | |||||
| end; | |||||
| end; | |||||
| result := @fItems[aPriority]; | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TutlHandleManager.Get(const aHandle: TutlHandle): T; | |||||
| function TutlHandleManager.GetValue(const aHandle: TutlHandle): T; | |||||
| begin | begin | ||||
| if not TryGet(aHandle, result) then | |||||
| if not TryGetValue(aHandle, result) then | |||||
| raise EArgumentException.Create('unknown or invalid handle'); | raise EArgumentException.Create('unknown or invalid handle'); | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TutlHandleManager.TryGet(const aHandle: TutlHandle; out aData: T): Boolean; | |||||
| function TutlHandleManager.TryGetValue(const aHandle: TutlHandle; out aData: T): Boolean; | |||||
| begin | begin | ||||
| result := IsValid(aHandle); | |||||
| with THandleData(aHandle) do begin | with THandleData(aHandle) do begin | ||||
| result := IsValid(aHandle); | |||||
| if result | if result | ||||
| then aData := fEntries[Index].Data | |||||
| then aData := fItems[Priority].Handles[Index].Data | |||||
| else FillByte(aData, SizeOf(T), 0); | else FillByte(aData, SizeOf(T), 0); | ||||
| end; | end; | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TutlHandleManager.Add(constref aData: T; const aIdentifier: Word): TutlHandle; | |||||
| procedure TutlHandleManager.SetValue(const aHandle: TutlHandle; aData: T); | |||||
| begin | |||||
| if not TrySetValue(aHandle, aData) then | |||||
| raise EArgumentException.Create('unknown or invalid handle'); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.TrySetValue(const aHandle: TutlHandle; aData: T): Boolean; | |||||
| var | |||||
| p: PPriorityItem; | |||||
| h: PHandleEntry; | |||||
| begin | |||||
| if not IsValid(aHandle) then with THandleData(aHandle) do begin | |||||
| p := GetPriorityItem(Priority); | |||||
| p^.Grow(Index + 1); | |||||
| h := p^.GetHandleEntry(Index); | |||||
| result := (h^.Status = ENTRY_STATUS_FREE); | |||||
| if result then begin | |||||
| p^.RemoveFreeIndex (Index); | |||||
| p^.PushBackUsedIndex(Index); | |||||
| h^.Counter := Counter; | |||||
| h^.Data := aData; | |||||
| end; | |||||
| end else | |||||
| Update(aHandle, aData); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.Add(const aTypeID: Byte; const aPriority: Byte; constref aData: T): TutlHandle; | |||||
| var | var | ||||
| p: PPriorityItem; | |||||
| h: PHandleEntry; | |||||
| i: Integer; | i: Integer; | ||||
| begin | begin | ||||
| i := fFirstFreeIndex; | |||||
| if (High(fEntries) < i) then | |||||
| Grow; | |||||
| Assert(not fEntries[i].IsActive); | |||||
| fFirstFreeIndex := fEntries[i].NextFreeIndex; | |||||
| fEntries[i].NextFreeIndex := 0; | |||||
| fEntries[i].Counter := fEntries[i].Counter + 1; | |||||
| if (fEntries[i].Counter = 0) then | |||||
| fEntries[i].Counter := 1; | |||||
| fEntries[i].IsActive := true; | |||||
| fEntries[i].Data := aData; | |||||
| inc(fCount); | |||||
| p := GetPriorityItem(aPriority); | |||||
| i := p^.PopFrontFreeIndex; | |||||
| p^.PushBackUsedIndex(i); | |||||
| h := p^.GetHandleEntry(i); | |||||
| h^.TypeID := aTypeID; | |||||
| h^.Counter := h^.Counter + 1; | |||||
| if (h^.Counter = 0) then | |||||
| h^.Counter := 1; | |||||
| h^.Data := aData; | |||||
| with THandleData(result) do begin | with THandleData(result) do begin | ||||
| Index := i; | |||||
| Counter := fEntries[i].Counter; | |||||
| Identifier := aIdentifier; | |||||
| Index := i; | |||||
| Counter := h^.Counter; | |||||
| TypeID := aTypeID; | |||||
| Priority := aPriority; | |||||
| end; | end; | ||||
| inc(fCount); | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| function TutlHandleManager.IsValid(const aHandle: TutlHandle): Boolean; | function TutlHandleManager.IsValid(const aHandle: TutlHandle): Boolean; | ||||
| begin | begin | ||||
| with THandleData(aHandle) do begin | with THandleData(aHandle) do begin | ||||
| result := (fEntries[Index].Counter = Counter) | |||||
| and (fEntries[Index].IsActive) | |||||
| and (h.Index <= High(fEntries)); | |||||
| result := (Priority <= High(fItems)) | |||||
| and (Index <= HighIndex(fItems[Priority].Handles)) | |||||
| and (fItems[Priority].Handles[Index].Counter = Counter) | |||||
| and (fItems[Priority].Handles[Index].Status = ENTRY_STATUS_USED); | |||||
| end; | end; | ||||
| end; | end; | ||||
| @@ -1753,60 +2153,88 @@ begin | |||||
| if not IsValid(aHandle) then | if not IsValid(aHandle) then | ||||
| raise EArgumentException.Create('unknown or invalid handle'); | raise EArgumentException.Create('unknown or invalid handle'); | ||||
| with THandleData(aHandle) do begin | with THandleData(aHandle) do begin | ||||
| if not utlFinalizeObject(fEntries[Index].Data, TypeInfo(T), fOwnsValues) then | |||||
| Finalize(fEntries[Index].Data); | |||||
| fEntries[Index].Data := aData; | |||||
| if not utlFinalizeObject(fItems[Priority].Handles[Index].Data, TypeInfo(T), fOwnsValues) then | |||||
| Finalize(fItems[Priority].Handles[Index].Data); | |||||
| fItems[Priority].Handles[Index].Data := aData; | |||||
| end; | end; | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlHandleManager.Remove(const aHandle: TutlHandle); | |||||
| function TutlHandleManager.Remove(const aHandle: TutlHandle): Boolean; | |||||
| var | |||||
| p: PPriorityItem; | |||||
| begin | begin | ||||
| if not IsValid(aHandle) then | |||||
| raise EArgumentException.Create('unknown or invalid handle'); | |||||
| result := IsValid(aHandle); | |||||
| if not result then | |||||
| exit; | |||||
| with THandleData(aHandle) do begin | with THandleData(aHandle) do begin | ||||
| fEntries[Index].NextFreeIndex := fFirstFreeIndex; | |||||
| fEntries[Index].IsActive := false; | |||||
| fFirstFreeIndex := Index; | |||||
| if not utlFinalizeObject(fEntries[Index].Data, TypeInfo(T), fOwnsValues) then | |||||
| Finalize(fEntries[Index].Data); | |||||
| p := GetPriorityItem(Priority); | |||||
| p^.RemoveUsedIndex(Index); | |||||
| p^.PushFrontFreeIndex(Index); | |||||
| end; | end; | ||||
| dec(fCount); | dec(fCount); | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlHandleManager.Delete(const aHandle: TutlHandle); | |||||
| begin | |||||
| if not Remove(aHandle) then | |||||
| raise EArgumentException.Create('unknown or invalid handle'); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlHandleManager.Clear; | procedure TutlHandleManager.Clear; | ||||
| var | var | ||||
| i: Integer; | |||||
| i, j: Integer; | |||||
| begin | begin | ||||
| for i := low(fEntries) to high(fEntries) do begin | |||||
| if fEntries[i].IsActive and not utlFinalizeObject(fEntries[i].Data, TypeInfo(T), fOwnsValues) then | |||||
| Finalize(fEntries[i].Data); | |||||
| for j := low(fItems) to high(fItems) do begin | |||||
| for i := low(fItems[j].Handles) to high(fItems[j].Handles) do begin | |||||
| if (fItems[j].Handles[i].Status = ENTRY_STATUS_USED) and not utlFinalizeObject(fItems[j].Handles[i].Data, TypeInfo(T), fOwnsValues) then | |||||
| Finalize(fItems[j].Handles[i].Data); | |||||
| FillByte(fItems[j].Handles[i].Data, SizeOf(T), 0); | |||||
| end; | |||||
| SetLength(fItems[j].Handles, 0); | |||||
| end; | end; | ||||
| SetLength(fEntries, 0); | |||||
| SetLength(fItems, 0); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.GetEnumerator: IEnumerator; | |||||
| begin | |||||
| result := TEnumerator.Create(self); | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlHandleManager.GetUtlEnumerator: IutlEnumerator; | |||||
| begin | |||||
| result := TEnumerator.Create(self); | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| constructor TutlHandleManager.Create(const aOwnsValues: Boolean); | constructor TutlHandleManager.Create(const aOwnsValues: Boolean); | ||||
| begin | begin | ||||
| inherited Create; | inherited Create; | ||||
| fGrowSize := 50; | |||||
| fCount := 0; | |||||
| fFirstFreeIndex := 0; | |||||
| fOwnsValues := aOwnsValues; | |||||
| fCount := 0; | |||||
| fOwnsValues := aOwnsValues; | |||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| destructor TutlHandleManager.Destroy; | destructor TutlHandleManager.Destroy; | ||||
| begin | begin | ||||
| Clear; | |||||
| // Clear; | |||||
| inherited Destroy; | inherited Destroy; | ||||
| end; | end; | ||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| class function TutlHandleManager.GetIdentifier(const aHandle: TutlHandle): Word; | |||||
| class function TutlHandleManager.GetTypeID(const aHandle: TutlHandle): Byte; | |||||
| begin | |||||
| result := THandleData(aHandle).TypeID; | |||||
| end; | |||||
| ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| class function TutlHandleManager.GetPriority(const aHandle: TutlHandle): Byte; | |||||
| begin | begin | ||||
| result := THandleData(aHandle).Identifier; | |||||
| result := THandleData(aHandle).Priority; | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| @@ -86,8 +86,8 @@ type | |||||
| procedure DoClear (); virtual; | procedure DoClear (); virtual; | ||||
| public { IutlObservable } | public { IutlObservable } | ||||
| procedure RegisterEventListener (constref aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure RegisterEventListener (aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(aListener: IutlEventListener); | |||||
| protected | protected | ||||
| procedure SetItem(const aIndex: Integer; aValue: T); override; | procedure SetItem(const aIndex: Integer; aValue: T); override; | ||||
| @@ -146,8 +146,8 @@ type | |||||
| procedure DoClear (); virtual; | procedure DoClear (); virtual; | ||||
| public { IutlObservable } | public { IutlObservable } | ||||
| procedure RegisterEventListener (constref aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure RegisterEventListener (aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(aListener: IutlEventListener); | |||||
| public | public | ||||
| procedure Clear; override; | procedure Clear; override; | ||||
| @@ -213,8 +213,8 @@ type | |||||
| procedure DoClear (); virtual; | procedure DoClear (); virtual; | ||||
| public { IutlObservable } | public { IutlObservable } | ||||
| procedure RegisterEventListener (constref aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure RegisterEventListener (aListener: IutlEventListener); | |||||
| procedure UnregisterEventListener(aListener: IutlEventListener); | |||||
| public | public | ||||
| constructor Create(const aHashSet: TObservableHashSet; const aOwnsKeys: Boolean; const aOwnsValues: Boolean); reintroduce; | constructor Create(const aHashSet: TObservableHashSet; const aOwnsKeys: Boolean; const aOwnsValues: Boolean); reintroduce; | ||||
| @@ -350,13 +350,13 @@ begin | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableCustomList.RegisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure TutlObservableCustomList.RegisterEventListener(aListener: IutlEventListener); | |||||
| begin | begin | ||||
| fEventListener.Add(aListener); | fEventListener.Add(aListener); | ||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableCustomList.UnregisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure TutlObservableCustomList.UnregisterEventListener(aListener: IutlEventListener); | |||||
| begin | begin | ||||
| fEventListener.Remove(aListener); | fEventListener.Remove(aListener); | ||||
| end; | end; | ||||
| @@ -490,13 +490,13 @@ begin | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableCustomHashSet.RegisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure TutlObservableCustomHashSet.RegisterEventListener(aListener: IutlEventListener); | |||||
| begin | begin | ||||
| fEventListener.Add(aListener); | fEventListener.Add(aListener); | ||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableCustomHashSet.UnregisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure TutlObservableCustomHashSet.UnregisterEventListener(aListener: IutlEventListener); | |||||
| begin | begin | ||||
| fEventListener.Remove(aListener); | fEventListener.Remove(aListener); | ||||
| end; | end; | ||||
| @@ -659,13 +659,13 @@ begin | |||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableCustomMap.RegisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure TutlObservableCustomMap.RegisterEventListener(aListener: IutlEventListener); | |||||
| begin | begin | ||||
| fEventListener.Add(aListener); | fEventListener.Add(aListener); | ||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| procedure TutlObservableCustomMap.UnregisterEventListener(constref aListener: IutlEventListener); | |||||
| procedure TutlObservableCustomMap.UnregisterEventListener(aListener: IutlEventListener); | |||||
| begin | begin | ||||
| fEventListener.Remove(aListener); | fEventListener.Remove(aListener); | ||||
| end; | end; | ||||
| @@ -1,496 +0,0 @@ | |||||
| unit uutlStored; | |||||
| {$mode objfpc}{$H+} | |||||
| interface | |||||
| uses | |||||
| Classes, SysUtils, | |||||
| DOM, | |||||
| uutlMCF; | |||||
| type | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| IutlStored = interface(IUnknown) | |||||
| ['{1AAA369A-B938-4430-AFAA-E4B5FD9D5A8D}'] | |||||
| function GetStoredCount(): Integer; // returns the number of stored values | |||||
| function GetStoredName (const aIndex: Integer): String; // returns the name of the stored value | |||||
| function GetStoredValue(const aIndex: Integer): Variant; // returns the stored value as string | |||||
| procedure SetStoredValue(const aIndex: Integer; const aValue: Variant); // set the stored value | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| IutlStoredWriter = interface(IUnknown) | |||||
| ['{AE592B18-DDC2-408A-BB26-DAA24E2A7C34}'] | |||||
| procedure Write(constref aObj: IutlStored; const aStream: TStream); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| IutlStoredReader = interface(IUnknown) | |||||
| ['{B596DCD9-5F34-45F9-82C7-790F5407E1E8}'] | |||||
| function Read(constref aObj: IutlStored; const aStream: TStream): Boolean; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| TutlStoredWriter = class( | |||||
| TInterfacedObject | |||||
| , IutlStoredWriter) | |||||
| public { IutlStoredWriter } | |||||
| procedure Write(constref aObj: IutlStored; const aStream: TStream); virtual; | |||||
| constructor Create; virtual; | |||||
| public | |||||
| class function CreateWriter: IutlStoredWriter; | |||||
| end; | |||||
| TutlStoredWriterClass = class of TutlStoredWriter; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| TutlStoredReader = class( | |||||
| TInterfacedObject | |||||
| , IutlStoredReader) | |||||
| public { IutlStoredReader } | |||||
| function Read(constref aObj: IutlStored; const aStream: TStream): Boolean; virtual; | |||||
| constructor Create; virtual; | |||||
| public | |||||
| class function CreateReader: IutlStoredReader; | |||||
| end; | |||||
| TutlStoredReaderClass = class of TutlStoredReader; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| TutlStoredXmlWriter = class(TutlStoredWriter) | |||||
| private | |||||
| fRootName: String; | |||||
| protected | |||||
| property RootName: String read fRootName write fRootName; | |||||
| procedure Write(constref aObj: IutlStored; const aElement: TDOMElement); virtual; | |||||
| public | |||||
| procedure Write(constref aObj: IutlStored; const aStream: TStream); override; | |||||
| constructor Create; override; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| TutlStoredXmlReader = class(TutlStoredReader) | |||||
| protected | |||||
| function CreateObject(constref aOwner: IutlStored; const aElement: TDOMElement): IutlStored; virtual; | |||||
| procedure Read (constref aObj: IutlStored; const aElement: TDOMElement); virtual; | |||||
| public | |||||
| function Read(constref aObj: IutlStored; const aStream: TStream): Boolean; override; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| TutlStoredMcfWriter = class(TutlStoredWriter) | |||||
| protected | |||||
| procedure Write(constref aObj: IutlStored; const aName: String; const aParent: TutlMCFSection); virtual; | |||||
| procedure Write(constref aObj: IutlStored; const aSection: TutlMCFSection); virtual; | |||||
| public | |||||
| procedure Write(constref aObj: IutlStored; const aStream: TStream); override; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| TutlStoredMcfReader = class(TutlStoredReader) | |||||
| private | |||||
| function TryFindStoredName(const aObj: IutlStored; const aName: String; out aIndex: Integer): Boolean; | |||||
| protected | |||||
| function CreateObject(constref aOwner: IutlStored; const aName: String; const aParent: TutlMCFSection): IutlStored; virtual; | |||||
| function ReadValue (constref aOwner: IutlStored; const aName: String; const aParent: TutlMCFSection): Variant; virtual; | |||||
| procedure ReadSection (constref aObj: IutlStored; const aSection: TutlMCFSection); virtual; | |||||
| public | |||||
| function Read(constref aObj: IutlStored; const aStream: TStream): Boolean; override; | |||||
| end; | |||||
| implementation | |||||
| uses | |||||
| XMLWrite, XMLRead, variants, | |||||
| uutlXmlHelper, uutlSyncObjs; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlStoredWriter////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredWriter.Write(constref aObj: IutlStored; const aStream: TStream); | |||||
| begin | |||||
| // DUMMY | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| constructor TutlStoredWriter.Create; | |||||
| begin | |||||
| inherited Create; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| class function TutlStoredWriter.CreateWriter: IutlStoredWriter; | |||||
| begin | |||||
| result := TutlStoredWriterClass(ClassType).Create; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlStoredReader////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlStoredReader.Read(constref aObj: IutlStored; const aStream: TStream): Boolean; | |||||
| begin | |||||
| result := false; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| constructor TutlStoredReader.Create; | |||||
| begin | |||||
| inherited Create; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| class function TutlStoredReader.CreateReader: IutlStoredReader; | |||||
| begin | |||||
| result := TutlStoredReaderClass(ClassType).Create; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlStoredXmlWriter/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredXmlWriter.Write(constref aObj: IutlStored; const aElement: TDOMElement); | |||||
| var | |||||
| i, c: Integer; | |||||
| s: DOMString; | |||||
| v: Variant; | |||||
| vt: TVarType; | |||||
| intf: IUnknown; | |||||
| lock: IutlLockable; | |||||
| stored: IutlStored; | |||||
| begin | |||||
| if not Supports(aObj, IutlLockable, lock) then | |||||
| lock := nil; | |||||
| if Assigned(lock) then | |||||
| lock.Lock; | |||||
| try | |||||
| with TutlXmlHelper.Create(aElement) do begin | |||||
| c := aObj.GetStoredCount; | |||||
| for i := 0 to c-1 do begin | |||||
| s := DOMString(aObj.GetStoredName(i)); | |||||
| v := aObj.GetStoredValue(i); | |||||
| vt := VarType(v); | |||||
| case vt of | |||||
| varunknown: begin | |||||
| intf := IUnknown(v); | |||||
| if Supports(intf, IutlStored, stored) then | |||||
| Write(stored, AppendNode(s)); | |||||
| end; | |||||
| else | |||||
| SetAttribString(s, String(v)); | |||||
| end; | |||||
| end; | |||||
| end; | |||||
| finally | |||||
| if Assigned(lock) then | |||||
| lock.Unlock; | |||||
| end; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredXmlWriter.Write(constref aObj: IutlStored; const aStream: TStream); | |||||
| var | |||||
| doc: TXMLDocument; | |||||
| root: TDOMElement; | |||||
| begin | |||||
| doc := TXMLDocument.Create; | |||||
| try | |||||
| root := doc.CreateElement(DOMString(fRootName)); | |||||
| doc.AppendChild(root); | |||||
| Write(aObj, root); | |||||
| WriteXMLFile(doc, aStream); | |||||
| finally | |||||
| FreeAndNil(doc); | |||||
| end; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| constructor TutlStoredXmlWriter.Create; | |||||
| begin | |||||
| inherited Create; | |||||
| fRootName := 'root'; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlStoredXmlReader/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlStoredXmlReader.CreateObject(constref aOwner: IutlStored; const aElement: TDOMElement): IutlStored; | |||||
| begin | |||||
| result := nil; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredXmlReader.Read(constref aObj: IutlStored; const aElement: TDOMElement); | |||||
| var | |||||
| i, j: Integer; | |||||
| s: DOMString; | |||||
| v: Variant; | |||||
| vt: TVarType; | |||||
| intf: IUnknown; | |||||
| stored: IutlStored; | |||||
| attribs: TDOMNamedNodeMap; | |||||
| attrib: TDOMNode; | |||||
| el: TDOMElement; | |||||
| function TryFindStoredName(const aName: String; out aIndex: Integer): Boolean; | |||||
| var | |||||
| c, i: Integer; | |||||
| begin | |||||
| result := true; | |||||
| c := aObj.GetStoredCount; | |||||
| for i := 0 to c-1 do begin | |||||
| aIndex := i; | |||||
| if (aObj.GetStoredName(aIndex) = aName) then | |||||
| exit; | |||||
| end; | |||||
| aIndex := -1; | |||||
| result := false; | |||||
| end; | |||||
| begin | |||||
| with TutlXmlHelper.Create(aElement) do begin | |||||
| attribs := aElement.Attributes; | |||||
| for i := 0 to attribs.Length-1 do begin | |||||
| attrib := attribs.Item[i]; | |||||
| s := attrib.NodeName; | |||||
| v := attrib.TextContent; | |||||
| if not TryFindStoredName(String(s), j) then | |||||
| continue; | |||||
| aObj.SetStoredValue(j, v); | |||||
| end; | |||||
| for el in Nodes('') do begin | |||||
| s := el.NodeName; | |||||
| v := Unassigned; | |||||
| stored := nil; | |||||
| if TryFindStoredName(String(s), j) then begin | |||||
| v := aObj.GetStoredValue(j); | |||||
| vt := VarType(v); | |||||
| case vt of | |||||
| varunknown: begin | |||||
| intf := v; | |||||
| if not Supports(intf, IutlStored, stored) then | |||||
| stored := nil; | |||||
| end; | |||||
| else | |||||
| raise EInvalidOperation.Create('expected ' + String(s) + ' to be an stored object'); | |||||
| end; | |||||
| end else | |||||
| j := -1; | |||||
| if not Assigned(stored) then | |||||
| stored := CreateObject(aObj, el); | |||||
| if not Assigned(stored) then | |||||
| continue; | |||||
| Read(stored, el); | |||||
| aObj.SetStoredValue(j, stored); | |||||
| end; | |||||
| end; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlStoredXmlReader.Read(constref aObj: IutlStored; const aStream: TStream): Boolean; | |||||
| var | |||||
| doc: TXMLDocument; | |||||
| p: Int64; | |||||
| begin | |||||
| p := aStream.Position; | |||||
| doc := TXMLDocument.Create; | |||||
| try try | |||||
| result := true; | |||||
| ReadXMLFile(doc, aStream); | |||||
| Read(aObj, (doc.FirstChild as TDOMElement)); | |||||
| except | |||||
| result := false; | |||||
| aStream.Position := p; | |||||
| end; | |||||
| finally | |||||
| FreeAndNil(doc); | |||||
| end; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlStoredMcfWriter/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredMcfWriter.Write(constref aObj: IutlStored; const aName: String; const aParent: TutlMCFSection); | |||||
| begin | |||||
| Write(aObj, aParent.Section(aName)); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredMcfWriter.Write(constref aObj: IutlStored; const aSection: TutlMCFSection); | |||||
| var | |||||
| lock: IutlLockable; | |||||
| i, c: Integer; | |||||
| s: String; | |||||
| v: Variant; | |||||
| vt: TVarType; | |||||
| intf: IUnknown; | |||||
| stored: IutlStored; | |||||
| begin | |||||
| if not Supports(aObj, IutlLockable, lock) then | |||||
| lock := nil; | |||||
| if Assigned(lock) then | |||||
| lock.Lock; | |||||
| try | |||||
| c := aObj.GetStoredCount; | |||||
| for i := 0 to c-1 do begin | |||||
| s := aObj.GetStoredName (i); | |||||
| v := aObj.GetStoredValue(i); | |||||
| vt := VarType(v); | |||||
| case vt of | |||||
| varunknown: begin | |||||
| intf := IUnknown(v); | |||||
| if Supports(intf, IutlStored, stored) then | |||||
| Write(stored, s, aSection); | |||||
| end; | |||||
| varboolean: | |||||
| aSection.SetBool(s, v); | |||||
| {$IFNDEF FPUNONE} | |||||
| varsingle, | |||||
| vardouble: | |||||
| aSection.SetFloat(s, v); | |||||
| {$ENDIF} | |||||
| vardecimal, | |||||
| varshortint, | |||||
| varbyte, | |||||
| varword, | |||||
| varlongword, | |||||
| varint64, | |||||
| varqword, | |||||
| varsmallint, | |||||
| varinteger: | |||||
| aSection.SetInt(s, v); | |||||
| else | |||||
| aSection.SetString(s, String(v)); | |||||
| end; | |||||
| end; | |||||
| finally | |||||
| if Assigned(lock) then | |||||
| lock.Unlock; | |||||
| end; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredMcfWriter.Write(constref aObj: IutlStored; const aStream: TStream); | |||||
| var | |||||
| mcf: TutlMCFFile; | |||||
| begin | |||||
| mcf := TutlMCFFile.Create(nil); | |||||
| try | |||||
| Write(aObj, mcf); | |||||
| mcf.SaveToStream(aStream); | |||||
| finally | |||||
| FreeAndNil(mcf); | |||||
| end; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //TutlStoredMcfReader/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlStoredMcfReader.TryFindStoredName(const aObj: IutlStored; const aName: String; out aIndex: Integer): Boolean; | |||||
| var | |||||
| c, i: Integer; | |||||
| begin | |||||
| result := true; | |||||
| c := aObj.GetStoredCount; | |||||
| for i := 0 to c-1 do begin | |||||
| aIndex := i; | |||||
| if (aObj.GetStoredName(aIndex) = aName) then | |||||
| exit; | |||||
| end; | |||||
| aIndex := -1; | |||||
| result := false; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlStoredMcfReader.CreateObject(constref aOwner: IutlStored; const aName: String; const aParent: TutlMCFSection): IutlStored; | |||||
| begin | |||||
| result := nil; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlStoredMcfReader.ReadValue(constref aOwner: IutlStored; const aName: String; const aParent: TutlMCFSection): Variant; | |||||
| begin | |||||
| result := aParent.GetString(aName); | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| procedure TutlStoredMcfReader.ReadSection(constref aObj: IutlStored; const aSection: TutlMCFSection); | |||||
| var | |||||
| i, j, c: Integer; | |||||
| s: String; | |||||
| v: Variant; | |||||
| vt: TVarType; | |||||
| intf: IUnknown; | |||||
| stored: IutlStored; | |||||
| begin | |||||
| c := aSection.ValueCount; | |||||
| for i := 0 to c-1 do begin | |||||
| s := aSection.ValueNameAt[i]; | |||||
| v := ReadValue(aObj, s, aSection); | |||||
| if (VarType(v) <> varempty) and TryFindStoredName(aObj, s, j) then | |||||
| aObj.SetStoredValue(j, v); | |||||
| end; | |||||
| c := aSection.SectionCount; | |||||
| for i := 0 to c-1 do begin | |||||
| s := aSection.SectionNameAt[i]; | |||||
| v := Unassigned; | |||||
| stored := nil; | |||||
| if TryFindStoredName(aObj, s, j) then begin | |||||
| v := aObj.GetStoredValue(j); | |||||
| vt := VarType(v); | |||||
| case vt of | |||||
| varunknown: begin | |||||
| intf := v; | |||||
| if not Supports(intf, IutlStored, stored) then | |||||
| stored := nil; | |||||
| end; | |||||
| else | |||||
| raise EInvalidOperation.Create('expected ' + s + ' to be an stored object'); | |||||
| end; | |||||
| end else | |||||
| j := -1; | |||||
| if not Assigned(stored) then | |||||
| stored := CreateObject(aObj, s, aSection); | |||||
| if not Assigned(stored) then | |||||
| continue; | |||||
| ReadSection(stored, aSection.Section(s)); | |||||
| aObj.SetStoredValue(j, stored); | |||||
| end; | |||||
| end; | |||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
| function TutlStoredMcfReader.Read(constref aObj: IutlStored; const aStream: TStream): Boolean; | |||||
| var | |||||
| p: Int64; | |||||
| mcf: TutlMCFFile; | |||||
| begin | |||||
| p := aStream.Position; | |||||
| mcf := TutlMCFFile.Create(nil); | |||||
| try try | |||||
| result := true; | |||||
| mcf.LoadFromStream(aStream); | |||||
| ReadSection(aObj, mcf); | |||||
| except | |||||
| result := false; | |||||
| aStream.Position := p; | |||||
| end; | |||||
| finally | |||||
| FreeAndNil(mcf); | |||||
| end; | |||||
| end; | |||||
| end. | |||||
| @@ -115,11 +115,10 @@ type | |||||
| public type | public type | ||||
| ILock = specialize IutlLock<T>; | ILock = specialize IutlLock<T>; | ||||
| private | |||||
| protected | |||||
| fLock: IutlLockable; | fLock: IutlLockable; | ||||
| fObject: T; | fObject: T; | ||||
| public | public | ||||
| function LockedObject: T; inline; | function LockedObject: T; inline; | ||||