* removed uutlStored * small improvements and bug fixingmaster
@@ -11,7 +11,7 @@ | |||
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> | |||
</SearchPaths> | |||
</CompilerOptions> | |||
<Files Count="31"> | |||
<Files Count="30"> | |||
<Item1> | |||
<Filename Value="uutlAlgorithm.pas"/> | |||
<UnitName Value="uutlAlgorithm"/> | |||
@@ -117,25 +117,21 @@ | |||
<UnitName Value="uutlXmlHelper"/> | |||
</Item26> | |||
<Item27> | |||
<Filename Value="uutlStored.pas"/> | |||
<UnitName Value="uutlStored"/> | |||
</Item27> | |||
<Item28> | |||
<Filename Value="uutlVariantObject.pas"/> | |||
<UnitName Value="uutlVariantObject"/> | |||
</Item28> | |||
<Item29> | |||
</Item27> | |||
<Item28> | |||
<Filename Value="uutlVariantProperty.pas"/> | |||
<UnitName Value="uutlVariantProperty"/> | |||
</Item29> | |||
<Item30> | |||
</Item28> | |||
<Item29> | |||
<Filename Value="uutlVariantEnum.pas"/> | |||
<UnitName Value="uutlVariantEnum"/> | |||
</Item30> | |||
<Item31> | |||
</Item29> | |||
<Item30> | |||
<Filename Value="uutlVariantSet.pas"/> | |||
<UnitName Value="uutlVariantSet"/> | |||
</Item31> | |||
</Item30> | |||
</Files> | |||
<RequiredPkgs Count="2"> | |||
<Item1> | |||
@@ -11,8 +11,7 @@ uses | |||
uutlAlgorithm, uutlArrayContainer, uutlCommon, uutlComparer, uutlCompression, uutlEmbeddedProfiler, uutlEnumerator, | |||
uutlEvent, uutlEventManager, uutlFilter, uutlGenerics, uutlInterfaces, uutlKeyCodes, uutlLinq, uutlListBase, | |||
uutlLogger, uutlMCF, uutlObservable, uutlSScanf, uutlStreamHelper, uutlSyncObjs, uutlThreads, uutlTypes, | |||
uutlXmlHelper, uutlStored, uutlVariantObject, uutlVariantProperty, uutlVariantEnum, uutlVariantSet, | |||
LazarusPackageIntf; | |||
uutlXmlHelper, uutlVariantObject, uutlVariantProperty, uutlVariantEnum, uutlVariantSet, LazarusPackageIntf; | |||
implementation | |||
@@ -33,7 +33,7 @@ | |||
<PackageName Value="FCL"/> | |||
</Item3> | |||
</RequiredPackages> | |||
<Units Count="40"> | |||
<Units Count="41"> | |||
<Unit0> | |||
<Filename Value="tests.lpr"/> | |||
<IsPartOfProject Value="True"/> | |||
@@ -194,6 +194,10 @@ | |||
<Filename Value="uutlVariantSetTest.pas"/> | |||
<IsPartOfProject Value="True"/> | |||
</Unit39> | |||
<Unit40> | |||
<Filename Value="uutlHandleManagerTests.pas"/> | |||
<IsPartOfProject Value="True"/> | |||
</Unit40> | |||
</Units> | |||
</ProjectOptions> | |||
<CompilerOptions> | |||
@@ -17,7 +17,7 @@ uses | |||
// units unter test | |||
uutlAlgorithm, uutlArrayContainer, uutlCommon, uutlComparer, uutlEnumerator, uutlFilter, uutlGenerics, uutlInterfaces, | |||
uutlLinq, uutlListBase, uutlLogger, uutlStreamHelper, uutlSyncObjs, uutlTypes, uutlXmlHelper, uutlObservable, | |||
uutlSetHelperTests, uutlVariantEnumTest, uutlVariantSetTest; | |||
uutlSetHelperTests, uutlVariantEnumTest, uutlVariantSetTest, uutlHandleManagerTests; | |||
{$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; | |||
fEventListener: IutlEventListener; | |||
procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||
public | |||
procedure SetUp; override; | |||
@@ -37,7 +37,7 @@ implementation | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TutlObservableHashSetTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableHashSetTests.EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlObservableHashSetTests.EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||
begin | |||
if fCaptureEvents then | |||
fEventArgs.Add(aEventArgs); | |||
@@ -19,7 +19,7 @@ type | |||
fEventArgs: TEventArgList; | |||
fEventListener: IutlEventListener; | |||
procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||
public | |||
procedure SetUp; override; | |||
@@ -37,7 +37,7 @@ implementation | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TutlObservableListTests/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableListTests.EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlObservableListTests.EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||
begin | |||
if fCaptureEvents then | |||
fEventArgs.Add(aEventArgs); | |||
@@ -19,7 +19,7 @@ type | |||
fEventArgs: TEventArgList; | |||
fEventListener: IutlEventListener; | |||
procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||
public | |||
procedure SetUp; override; | |||
@@ -37,7 +37,7 @@ implementation | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TutlObservableMapTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableMapTests.EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlObservableMapTests.EventHandler(aSender: TObject; aEventArgs: IutlEventArgs); | |||
begin | |||
if fCaptureEvents then | |||
fEventArgs.Add(aEventArgs); | |||
@@ -154,9 +154,15 @@ begin | |||
fMap.Clear; | |||
AssertEquals(1, fEventArgs.Count); | |||
AssertEquals(4, fEventArgs.Count); | |||
AssertTrue (Supports(fEventArgs[0], TutlObservableEventArgs, ea)); | |||
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; | |||
initialization | |||
@@ -24,7 +24,12 @@ type | |||
property AutoFree: Boolean read fAutoFree write fAutoFree; | |||
property RefCount: LongInt read fRefCount; | |||
procedure AfterConstruction; override; | |||
constructor Create; | |||
public | |||
class function NewInstance: TObject; override; | |||
end; | |||
TutlInterfaceNoRefCount = TutlInterfacedObject; | |||
@@ -61,6 +66,7 @@ type | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
EInternal = class(Exception); | |||
EOutOfRangeException = class(Exception) | |||
private | |||
fMin: Integer; | |||
@@ -92,6 +98,7 @@ function GetPlatformIdentitfier(): String; | |||
function utlRateLimited (const Reference: QWord; const Interval: QWord): boolean; | |||
function utlFinalizeObject (var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean): Boolean; | |||
function utlFilterBuilder (): IutlFilterBuilder; | |||
function utlBitCount (const aValue: DWord): Integer; | |||
implementation | |||
@@ -303,6 +310,16 @@ begin | |||
result := TFilterBuilderImpl.Create; | |||
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/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -317,23 +334,37 @@ end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TutlInterfacedObject._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; | |||
begin | |||
result := InterLockedIncrement(fRefCount); | |||
_AddRef := interlockedincrement(fRefCount); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TutlInterfacedObject._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; | |||
begin | |||
result := InterLockedDecrement(fRefCount); | |||
if (result = 0) and fAutoFree then | |||
_Release := InterLockedDecrement(fRefCount); | |||
if (_Release = 0) and fAutoFree then | |||
Destroy; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlInterfacedObject.AfterConstruction; | |||
begin | |||
inherited AfterConstruction; | |||
InterLockedDecrement(fRefCount); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlInterfacedObject.Create; | |||
begin | |||
inherited Create; | |||
fAutoFree := false; | |||
fRefCount := 0; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
class function TutlInterfacedObject.NewInstance: TObject; | |||
begin | |||
result := inherited NewInstance; | |||
if Assigned(result) then | |||
TutlInterfacedObject(result).fRefCount := 1; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -17,11 +17,11 @@ type | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
IutlEventListener = interface(IUnknown) | |||
['{BC45E26B-96F7-4151-87F1-C330C8C668E5}'] | |||
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
TutlEventHandler = procedure (constref aSender: TObject; constref aEventArgs: IutlEventArgs) of object; | |||
TutlEventHandler = procedure (aSender: TObject; aEventArgs: IutlEventArgs) of object; | |||
TutlEventArgs = class(TutlInterfacedObject, IutlEventArgs) | |||
public | |||
constructor Create; | |||
@@ -30,8 +30,8 @@ type | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
IutlObservable = interface(IUnknown) | |||
['{C54BD844-8273-4ACF-90C5-05DACF4359AF}'] | |||
procedure RegisterEventListener (constref aListener: IutlEventListener); | |||
procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||
procedure RegisterEventListener (aListener: IutlEventListener); | |||
procedure UnregisterEventListener(aListener: IutlEventListener); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -49,12 +49,12 @@ type | |||
TutlNotifyEventList = specialize TutlEventList<TNotifyEvent>; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
TutlEventHandlerList = class( | |||
TutlEventListenerList = class( | |||
specialize TutlEventList<TutlEventHandler> | |||
, IutlEventListener) | |||
public { IutlEventListener } | |||
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
public | |||
constructor Create; | |||
@@ -63,7 +63,8 @@ type | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
TutlEventListenerSet = class( | |||
specialize TutlCustomHashSet<IutlEventListener> | |||
, IutlEventListener) | |||
, IutlEventListener | |||
, IutlObservable) | |||
private type | |||
TComparer = class(TInterfacedObject, IComparer) | |||
@@ -73,7 +74,11 @@ type | |||
end; | |||
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 | |||
constructor Create; reintroduce; | |||
@@ -88,7 +93,7 @@ type | |||
fHandler: TutlEventHandler; | |||
public { IEventListener } | |||
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
public | |||
constructor Create(const aHandler: TutlEventHandler); | |||
@@ -114,7 +119,7 @@ type | |||
function PopEventPair(out aPair: TEventPair): Boolean; | |||
public { IEventListener } | |||
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
public | |||
procedure DispatchEvents; | |||
@@ -169,9 +174,9 @@ begin | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TutlEventHandlerList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TutlEventListenerList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlEventHandlerList.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlEventListenerList.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
var | |||
e: TutlEventHandler; | |||
begin | |||
@@ -180,7 +185,7 @@ begin | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlEventHandlerList.Create; | |||
constructor TutlEventListenerList.Create; | |||
begin | |||
inherited Create; | |||
AutoFree := true; | |||
@@ -208,7 +213,7 @@ end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TutlEventListenerSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlEventListenerSet.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlEventListenerSet.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
var | |||
e: IutlEventListener; | |||
begin | |||
@@ -216,6 +221,18 @@ begin | |||
e.DispatchEvent(aSender, aEventArgs); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlEventListenerSet.RegisterEventListener(aListener: IutlEventListener); | |||
begin | |||
Add(aListener); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlEventListenerSet.UnregisterEventListener(aListener: IutlEventListener); | |||
begin | |||
Remove(aListener); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlEventListenerSet.Create; | |||
begin | |||
@@ -225,7 +242,7 @@ end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TutlEventListenerCallback////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlEventListenerCallback.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlEventListenerCallback.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
begin | |||
fHandler(aSender, aEventArgs); | |||
end; | |||
@@ -266,7 +283,7 @@ begin | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlEventListenerAsync.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlEventListenerAsync.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
var | |||
p: TEventPair; | |||
begin | |||
@@ -10,7 +10,7 @@ interface | |||
uses | |||
Classes, SysUtils, Controls, | |||
uutlEvent; | |||
uutlEvent, uutlCommon; | |||
type | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -110,7 +110,10 @@ type | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
TutlWinControlEventManager = class(TutlEventListenerSet) | |||
TutlWinControlEventManager = class( | |||
TutlInterfacedObject | |||
, IutlObservable) | |||
public const | |||
EVENT_MOUSE_DOWN = 0; | |||
EVENT_MOUSE_UP = 1; | |||
@@ -186,6 +189,7 @@ type | |||
fKeyboard: TKeyboardState; | |||
fMouse: TMouseState; | |||
fWindow: TWindowState; | |||
fEventListener: TutlEventListenerSet; | |||
procedure HandlerMouseDown (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); | |||
protected | |||
procedure RecordEvent(constref aEventArgs: IutlEventArgs); virtual; | |||
procedure RecordEvent(aEventArgs: IutlEventArgs); virtual; | |||
procedure DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
function CreateMouseEventArgs( | |||
aControl: TControl; | |||
@@ -226,20 +231,26 @@ type | |||
aControl: TControl; | |||
aType: TutlEventType): IutlEventArgs; virtual; | |||
public { IutlObservable } | |||
procedure RegisterEventListener (aListener: IutlEventListener); | |||
procedure UnregisterEventListener(aListener: IutlEventListener); | |||
public | |||
property Keyboard: TKeyboardState read fKeyboard; | |||
property Mouse: TMouseState read fMouse; | |||
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; | |||
implementation | |||
uses | |||
LCLIntf, Forms, | |||
uutlKeyCodes, uutlCommon; | |||
uutlKeyCodes; | |||
type | |||
TWinControlVisibilityClass = class(TWinControl) | |||
@@ -416,7 +427,7 @@ begin | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlWinControlEventManager.RecordEvent(constref aEventArgs: IutlEventArgs); | |||
procedure TutlWinControlEventManager.RecordEvent(aEventArgs: IutlEventArgs); | |||
var | |||
mea: TutlMouseEventArgs; | |||
kea: TutlKeyEventArgs; | |||
@@ -491,6 +502,13 @@ begin | |||
end; | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlWinControlEventManager.DispatchEvent(aSender: TObject; aEventArgs: IutlEventArgs); | |||
begin | |||
RecordEvent(aEventArgs); | |||
fEventListener.DispatchEvent(aSender, aEventArgs); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TutlWinControlEventManager.CreateMouseEventArgs( | |||
aControl: TControl; | |||
@@ -552,10 +570,17 @@ begin | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlWinControlEventManager.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs); | |||
procedure TutlWinControlEventManager.RegisterEventListener(aListener: IutlEventListener); | |||
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; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -595,5 +620,19 @@ begin | |||
end; | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlWinControlEventManager.Create; | |||
begin | |||
inherited Create; | |||
fEventListener := TutlEventListenerSet.Create; | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
destructor TutlWinControlEventManager.Destroy; | |||
begin | |||
FreeAndNil(fEventListener); | |||
inherited Destroy; | |||
end; | |||
end. | |||
@@ -1,6 +1,7 @@ | |||
unit uutlGenerics; | |||
{$mode objfpc}{$H+} | |||
{$modeswitch advancedrecords} | |||
interface | |||
@@ -198,7 +199,7 @@ type | |||
function Extract (const aItem: T; const aDefault: T): T; overload; | |||
function Remove (const aItem: T): Integer; | |||
constructor Create (const aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||
constructor Create (aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||
destructor Destroy; override; | |||
end; | |||
@@ -241,7 +242,7 @@ type | |||
function Remove (constref aItem: T): Boolean; | |||
procedure Delete (const aIndex: Integer); | |||
constructor Create (const aComparer: IComparer; const aOwnsItems: Boolean); | |||
constructor Create (aComparer: IComparer; const aOwnsItems: Boolean); | |||
destructor Destroy; override; | |||
end; | |||
@@ -287,7 +288,7 @@ type | |||
procedure Release(var aItem: TKeyValuePair; const aFreeItem: Boolean); override; | |||
public | |||
constructor Create(const aOwner: TutlCustomMap; const aComparer: IComparer); | |||
constructor Create(const aOwner: TutlCustomMap; aComparer: IComparer); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -479,7 +480,10 @@ type | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
TutlHandle = QWord; | |||
generic TutlHandleManager<T> = class(TObject) | |||
generic TutlHandleManager<T> = class( | |||
TutlInterfacedObject | |||
, specialize IutlEnumerable<TutlHandle>) | |||
private type | |||
THandleData = packed record | |||
case Integer of | |||
@@ -488,47 +492,124 @@ type | |||
); | |||
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; | |||
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; | |||
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 | |||
fCount: Integer; | |||
fGrowSize: Integer; | |||
fEntries: array of THandleEntry; | |||
fFirstFreeIndex: Cardinal; | |||
fItems: TPriorityItems; | |||
fOwnsValues: Boolean; | |||
procedure Grow; | |||
function GetPriorityItem(const aPriority: Byte): PPriorityItem; | |||
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; | |||
public { IutlEnumerable } | |||
function GetEnumerator: IEnumerator; | |||
function GetUtlEnumerator: IutlEnumerator; | |||
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; | |||
constructor Create(const aOwnsValues: Boolean); | |||
destructor Destroy; override; | |||
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; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -1180,7 +1261,7 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlCustomList.Create(const aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||
constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean); | |||
begin | |||
if not Assigned(aEqualityComparer) then | |||
raise EArgumentNilException.Create('aEqualityComparer'); | |||
@@ -1261,7 +1342,7 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlCustomHashSet.Create(const aComparer: IComparer; const aOwnsItems: Boolean); | |||
constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsItems: Boolean); | |||
begin | |||
inherited Create(aOwnsItems); | |||
fComparer := aComparer; | |||
@@ -1295,7 +1376,7 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlCustomMap.THashSet.Create(const aOwner: TutlCustomMap; const aComparer: IComparer); | |||
constructor TutlCustomMap.THashSet.Create(const aOwner: TutlCustomMap; aComparer: IComparer); | |||
begin | |||
inherited Create(aComparer, true); | |||
fOwner := aOwner; | |||
@@ -1681,69 +1762,388 @@ begin | |||
FreeAndNil(fHashSetImpl); | |||
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////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlHandleManager.Grow; | |||
function TutlHandleManager.GetPriorityItem(const aPriority: Byte): PPriorityItem; | |||
var | |||
oldIdx, newIdx, i: Integer; | |||
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; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TutlHandleManager.Get(const aHandle: TutlHandle): T; | |||
function TutlHandleManager.GetValue(const aHandle: TutlHandle): T; | |||
begin | |||
if not TryGet(aHandle, result) then | |||
if not TryGetValue(aHandle, result) then | |||
raise EArgumentException.Create('unknown or invalid handle'); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TutlHandleManager.TryGet(const aHandle: TutlHandle; out aData: T): Boolean; | |||
function TutlHandleManager.TryGetValue(const aHandle: TutlHandle; out aData: T): Boolean; | |||
begin | |||
result := IsValid(aHandle); | |||
with THandleData(aHandle) do begin | |||
result := IsValid(aHandle); | |||
if result | |||
then aData := fEntries[Index].Data | |||
then aData := fItems[Priority].Handles[Index].Data | |||
else FillByte(aData, SizeOf(T), 0); | |||
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 | |||
p: PPriorityItem; | |||
h: PHandleEntry; | |||
i: Integer; | |||
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 | |||
Index := i; | |||
Counter := fEntries[i].Counter; | |||
Identifier := aIdentifier; | |||
Index := i; | |||
Counter := h^.Counter; | |||
TypeID := aTypeID; | |||
Priority := aPriority; | |||
end; | |||
inc(fCount); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TutlHandleManager.IsValid(const aHandle: TutlHandle): Boolean; | |||
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; | |||
@@ -1753,60 +2153,88 @@ begin | |||
if not IsValid(aHandle) then | |||
raise EArgumentException.Create('unknown or invalid handle'); | |||
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; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlHandleManager.Remove(const aHandle: TutlHandle); | |||
function TutlHandleManager.Remove(const aHandle: TutlHandle): Boolean; | |||
var | |||
p: PPriorityItem; | |||
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 | |||
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; | |||
dec(fCount); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlHandleManager.Delete(const aHandle: TutlHandle); | |||
begin | |||
if not Remove(aHandle) then | |||
raise EArgumentException.Create('unknown or invalid handle'); | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlHandleManager.Clear; | |||
var | |||
i: Integer; | |||
i, j: Integer; | |||
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; | |||
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; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TutlHandleManager.Create(const aOwnsValues: Boolean); | |||
begin | |||
inherited Create; | |||
fGrowSize := 50; | |||
fCount := 0; | |||
fFirstFreeIndex := 0; | |||
fOwnsValues := aOwnsValues; | |||
fCount := 0; | |||
fOwnsValues := aOwnsValues; | |||
end; | |||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
destructor TutlHandleManager.Destroy; | |||
begin | |||
Clear; | |||
// Clear; | |||
inherited Destroy; | |||
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 | |||
result := THandleData(aHandle).Identifier; | |||
result := THandleData(aHandle).Priority; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -86,8 +86,8 @@ type | |||
procedure DoClear (); virtual; | |||
public { IutlObservable } | |||
procedure RegisterEventListener (constref aListener: IutlEventListener); | |||
procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||
procedure RegisterEventListener (aListener: IutlEventListener); | |||
procedure UnregisterEventListener(aListener: IutlEventListener); | |||
protected | |||
procedure SetItem(const aIndex: Integer; aValue: T); override; | |||
@@ -146,8 +146,8 @@ type | |||
procedure DoClear (); virtual; | |||
public { IutlObservable } | |||
procedure RegisterEventListener (constref aListener: IutlEventListener); | |||
procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||
procedure RegisterEventListener (aListener: IutlEventListener); | |||
procedure UnregisterEventListener(aListener: IutlEventListener); | |||
public | |||
procedure Clear; override; | |||
@@ -213,8 +213,8 @@ type | |||
procedure DoClear (); virtual; | |||
public { IutlObservable } | |||
procedure RegisterEventListener (constref aListener: IutlEventListener); | |||
procedure UnregisterEventListener(constref aListener: IutlEventListener); | |||
procedure RegisterEventListener (aListener: IutlEventListener); | |||
procedure UnregisterEventListener(aListener: IutlEventListener); | |||
public | |||
constructor Create(const aHashSet: TObservableHashSet; const aOwnsKeys: Boolean; const aOwnsValues: Boolean); reintroduce; | |||
@@ -350,13 +350,13 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableCustomList.RegisterEventListener(constref aListener: IutlEventListener); | |||
procedure TutlObservableCustomList.RegisterEventListener(aListener: IutlEventListener); | |||
begin | |||
fEventListener.Add(aListener); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableCustomList.UnregisterEventListener(constref aListener: IutlEventListener); | |||
procedure TutlObservableCustomList.UnregisterEventListener(aListener: IutlEventListener); | |||
begin | |||
fEventListener.Remove(aListener); | |||
end; | |||
@@ -490,13 +490,13 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableCustomHashSet.RegisterEventListener(constref aListener: IutlEventListener); | |||
procedure TutlObservableCustomHashSet.RegisterEventListener(aListener: IutlEventListener); | |||
begin | |||
fEventListener.Add(aListener); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableCustomHashSet.UnregisterEventListener(constref aListener: IutlEventListener); | |||
procedure TutlObservableCustomHashSet.UnregisterEventListener(aListener: IutlEventListener); | |||
begin | |||
fEventListener.Remove(aListener); | |||
end; | |||
@@ -659,13 +659,13 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableCustomMap.RegisterEventListener(constref aListener: IutlEventListener); | |||
procedure TutlObservableCustomMap.RegisterEventListener(aListener: IutlEventListener); | |||
begin | |||
fEventListener.Add(aListener); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TutlObservableCustomMap.UnregisterEventListener(constref aListener: IutlEventListener); | |||
procedure TutlObservableCustomMap.UnregisterEventListener(aListener: IutlEventListener); | |||
begin | |||
fEventListener.Remove(aListener); | |||
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 | |||
ILock = specialize IutlLock<T>; | |||
private | |||
protected | |||
fLock: IutlLockable; | |||
fObject: T; | |||
public | |||
function LockedObject: T; inline; | |||