Bläddra i källkod

* enumerator will track changes on enumerated list

* some small fixes
master
bergmann 7 år sedan
förälder
incheckning
cfeb3da3f4
14 ändrade filer med 684 tillägg och 330 borttagningar
  1. +0
    -4
      tests/tests.lpi
  2. +153
    -144
      tests/tests.lps
  3. +263
    -0
      tests/uutlListTest.pas
  4. +4
    -1
      tests/uutlObservableHashSetTests.pas
  5. +4
    -1
      tests/uutlObservableListTests.pas
  6. +4
    -1
      tests/uutlObservableMapTests.pas
  7. +25
    -10
      uutlCommon.pas
  8. +6
    -6
      uutlComparer.pas
  9. +1
    -0
      uutlEnumerator.pas
  10. +47
    -17
      uutlEvent.pas
  11. +108
    -1
      uutlListBase.pas
  12. +3
    -11
      uutlLogger.pas
  13. +58
    -133
      uutlObservable.pas
  14. +8
    -1
      uutlSyncObjs.pas

+ 0
- 4
tests/tests.lpi Visa fil

@@ -9,10 +9,6 @@
<Title Value="tests"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<XPManifest>
<TextName Value="CompanyName.ProductName.AppName"/>
<TextDesc Value="Your application description."/>
</XPManifest>
<Icon Value="0"/>
</General>
<BuildModes Count="1">


+ 153
- 144
tests/tests.lps Visa fil

@@ -4,20 +4,21 @@
<PathDelim Value="\"/>
<Version Value="10"/>
<BuildModes Active="Default"/>
<Units Count="66">
<Units Count="68">
<Unit0>
<Filename Value="tests.lpr"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="54" Y="12"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
</Unit0>
<Unit1>
<Filename Value="..\uutlGenerics.pas"/>
<IsPartOfProject Value="True"/>
<TopLine Value="173"/>
<CursorPos X="30" Y="188"/>
<UsageCount Value="79"/>
<EditorIndex Value="7"/>
<TopLine Value="1003"/>
<CursorPos Y="1021"/>
<UsageCount Value="81"/>
<Loaded Value="True"/>
</Unit1>
<Unit2>
@@ -25,7 +26,7 @@
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="11" Y="13"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
</Unit2>
<Unit3>
<Filename Value="..\uutlCommon.pas"/>
@@ -33,25 +34,24 @@
<EditorIndex Value="-1"/>
<TopLine Value="206"/>
<CursorPos X="10" Y="225"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
</Unit3>
<Unit4>
<Filename Value="..\uutlListBase.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="1"/>
<TopLine Value="79"/>
<CursorPos X="8" Y="100"/>
<UsageCount Value="79"/>
<TopLine Value="100"/>
<CursorPos X="72" Y="113"/>
<UsageCount Value="81"/>
<Loaded Value="True"/>
</Unit4>
<Unit5>
<Filename Value="uutlListTest.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="357"/>
<CursorPos X="7" Y="376"/>
<UsageCount Value="79"/>
<EditorIndex Value="3"/>
<TopLine Value="573"/>
<CursorPos Y="588"/>
<UsageCount Value="81"/>
<Loaded Value="True"/>
</Unit5>
<Unit6>
<Filename Value="uutlQueueTests.pas"/>
@@ -59,7 +59,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="250"/>
<CursorPos X="49" Y="260"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
</Unit6>
<Unit7>
<Filename Value="uutlStackTests.pas"/>
@@ -67,21 +67,22 @@
<EditorIndex Value="-1"/>
<TopLine Value="246"/>
<CursorPos X="24" Y="263"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
</Unit7>
<Unit8>
<Filename Value="uTestHelper.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<EditorIndex Value="4"/>
<CursorPos X="3" Y="12"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
<Loaded Value="True"/>
</Unit8>
<Unit9>
<Filename Value="..\uutlComparer.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="90" Y="6"/>
<UsageCount Value="69"/>
<UsageCount Value="71"/>
</Unit9>
<Unit10>
<Filename Value="..\uutlAlgorithm.pas"/>
@@ -89,23 +90,22 @@
<EditorIndex Value="-1"/>
<TopLine Value="138"/>
<CursorPos Y="153"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
</Unit10>
<Unit11>
<Filename Value="uutlHashSetTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="32" Y="13"/>
<UsageCount Value="79"/>
<UsageCount Value="81"/>
</Unit11>
<Unit12>
<Filename Value="uutlAlgorithmTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="8"/>
<EditorIndex Value="-1"/>
<TopLine Value="72"/>
<CursorPos X="43" Y="87"/>
<UsageCount Value="78"/>
<Loaded Value="True"/>
<UsageCount Value="80"/>
</Unit12>
<Unit13>
<Filename Value="uutlMapTests.pas"/>
@@ -113,26 +113,24 @@
<EditorIndex Value="-1"/>
<TopLine Value="206"/>
<CursorPos X="66" Y="221"/>
<UsageCount Value="77"/>
<UsageCount Value="79"/>
</Unit13>
<Unit14>
<Filename Value="..\uutlEnumerator.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="6"/>
<TopLine Value="324"/>
<CursorPos X="42" Y="340"/>
<UsageCount Value="76"/>
<EditorIndex Value="1"/>
<TopLine Value="90"/>
<CursorPos X="5" Y="105"/>
<UsageCount Value="78"/>
<Loaded Value="True"/>
</Unit14>
<Unit15>
<Filename Value="uutlEnumeratorTests.pas"/>
<IsPartOfProject Value="True"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="7"/>
<TopLine Value="617"/>
<CursorPos X="74" Y="634"/>
<UsageCount Value="76"/>
<Loaded Value="True"/>
<EditorIndex Value="-1"/>
<TopLine Value="615"/>
<CursorPos X="34" Y="631"/>
<UsageCount Value="78"/>
</Unit15>
<Unit16>
<Filename Value="..\uutlFilter.pas"/>
@@ -140,40 +138,38 @@
<EditorIndex Value="-1"/>
<TopLine Value="17"/>
<CursorPos X="13" Y="159"/>
<UsageCount Value="72"/>
<UsageCount Value="74"/>
</Unit16>
<Unit17>
<Filename Value="..\uutlInterfaces.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="5"/>
<TopLine Value="31"/>
<CursorPos X="70" Y="47"/>
<UsageCount Value="72"/>
<EditorIndex Value="2"/>
<TopLine Value="34"/>
<CursorPos X="5" Y="40"/>
<UsageCount Value="74"/>
<Loaded Value="True"/>
</Unit17>
<Unit18>
<Filename Value="..\uutlLinq.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="3"/>
<EditorIndex Value="-1"/>
<TopLine Value="391"/>
<CursorPos X="31" Y="417"/>
<UsageCount Value="63"/>
<Loaded Value="True"/>
<UsageCount Value="65"/>
</Unit18>
<Unit19>
<Filename Value="uutlLinqTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="4"/>
<EditorIndex Value="-1"/>
<TopLine Value="622"/>
<CursorPos X="23" Y="650"/>
<UsageCount Value="63"/>
<Loaded Value="True"/>
<UsageCount Value="65"/>
</Unit19>
<Unit20>
<Filename Value="..\uutlTypes.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<UsageCount Value="63"/>
<UsageCount Value="65"/>
</Unit20>
<Unit21>
<Filename Value="..\uutlSyncObjs.pas"/>
@@ -181,7 +177,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="241"/>
<CursorPos X="20" Y="263"/>
<UsageCount Value="57"/>
<UsageCount Value="59"/>
</Unit21>
<Unit22>
<Filename Value="..\uutlLogger.pas"/>
@@ -189,7 +185,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="419"/>
<CursorPos X="55" Y="434"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit22>
<Unit23>
<Filename Value="..\uutlXmlHelper.pas"/>
@@ -197,7 +193,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="188"/>
<CursorPos X="26" Y="203"/>
<UsageCount Value="56"/>
<UsageCount Value="58"/>
</Unit23>
<Unit24>
<Filename Value="..\uutlStreamHelper.pas"/>
@@ -205,7 +201,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="216"/>
<CursorPos X="10" Y="241"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit24>
<Unit25>
<Filename Value="..\uutlCompression.pas"/>
@@ -214,7 +210,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit25>
<Unit26>
<Filename Value="..\uutlEmbeddedProfiler.pas"/>
@@ -223,7 +219,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit26>
<Unit27>
<Filename Value="..\uutlKeyCodes.pas"/>
@@ -232,7 +228,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit27>
<Unit28>
<Filename Value="..\uutlMCF.pas"/>
@@ -241,7 +237,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit28>
<Unit29>
<Filename Value="..\uutlSScanf.pas"/>
@@ -250,7 +246,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit29>
<Unit30>
<Filename Value="..\uutlThreads.pas"/>
@@ -259,14 +255,14 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="55"/>
<UsageCount Value="57"/>
</Unit30>
<Unit31>
<Filename Value="..\uutlEvent.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="11" Y="35"/>
<UsageCount Value="54"/>
<UsageCount Value="56"/>
</Unit31>
<Unit32>
<Filename Value="..\uutlEventManager.pas"/>
@@ -274,7 +270,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="246"/>
<CursorPos X="39" Y="264"/>
<UsageCount Value="54"/>
<UsageCount Value="56"/>
</Unit32>
<Unit33>
<Filename Value="..\uutlObservable.pas"/>
@@ -282,41 +278,39 @@
<EditorIndex Value="-1"/>
<TopLine Value="556"/>
<CursorPos X="45" Y="572"/>
<UsageCount Value="54"/>
<UsageCount Value="56"/>
</Unit33>
<Unit34>
<Filename Value="uutlObservableListTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="49"/>
<CursorPos Y="65"/>
<UsageCount Value="46"/>
<TopLine Value="36"/>
<CursorPos X="53" Y="52"/>
<UsageCount Value="48"/>
</Unit34>
<Unit35>
<Filename Value="uutlObservableHashSetTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="-1"/>
<TopLine Value="129"/>
<CursorPos Y="146"/>
<UsageCount Value="26"/>
<TopLine Value="46"/>
<CursorPos X="25" Y="62"/>
<UsageCount Value="28"/>
</Unit35>
<Unit36>
<Filename Value="uutlObservableMapTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="3" Y="13"/>
<UsageCount Value="25"/>
<TopLine Value="46"/>
<CursorPos X="22" Y="51"/>
<UsageCount Value="27"/>
</Unit36>
<Unit37>
<Filename Value="uutlSetHelperTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="2"/>
<EditorIndex Value="-1"/>
<TopLine Value="44"/>
<CursorPos X="64" Y="54"/>
<UsageCount Value="22"/>
<Loaded Value="True"/>
<UsageCount Value="24"/>
</Unit37>
<Unit38>
<Filename Value="..\uutlExceptions.pas"/>
@@ -512,11 +506,29 @@
</Unit64>
<Unit65>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\FPCUnitCompatibleInterface.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="53"/>
<CursorPos X="104" Y="75"/>
<UsageCount Value="10"/>
<EditorIndex Value="5"/>
<TopLine Value="158"/>
<CursorPos Y="185"/>
<UsageCount Value="11"/>
<Loaded Value="True"/>
</Unit65>
<Unit66>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFramework.pas"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="8"/>
<TopLine Value="3311"/>
<CursorPos X="30" Y="3325"/>
<UsageCount Value="11"/>
<Loaded Value="True"/>
</Unit66>
<Unit67>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFrameworkIfaces.pas"/>
<EditorIndex Value="6"/>
<TopLine Value="35"/>
<CursorPos X="3" Y="51"/>
<UsageCount Value="10"/>
<Loaded Value="True"/>
</Unit67>
</Units>
<OtherDefines Count="3">
<Define0 Value="UTL_ADVANCED_ENUMERATORS"/>
@@ -525,124 +537,124 @@
</OtherDefines>
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="561" Column="7" TopLine="554"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="139" TopLine="119"/>
</Position1>
<Position2>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="545" Column="16" TopLine="531"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="143" TopLine="119"/>
</Position2>
<Position3>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="540" Column="13" TopLine="524"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="135" Column="35" TopLine="119"/>
</Position3>
<Position4>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="31" Column="17" TopLine="15"/>
<Filename Value="uutlListTest.pas"/>
<Caret Line="612" Column="42" TopLine="594"/>
</Position4>
<Position5>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="109" Column="5" TopLine="90"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="105" TopLine="89"/>
</Position5>
<Position6>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="748" Column="16" TopLine="745"/>
<Filename Value="uutlListTest.pas"/>
<Caret Line="625" TopLine="610"/>
</Position6>
<Position7>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="105" Column="17" TopLine="89"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\FPCUnitCompatibleInterface.inc"/>
<Caret Line="184" TopLine="158"/>
</Position7>
<Position8>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="55" Column="65" TopLine="35"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFramework.pas"/>
<Caret Line="3327" TopLine="3306"/>
</Position8>
<Position9>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="34" Column="14" TopLine="10"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFramework.pas"/>
<Caret Line="3329" TopLine="3306"/>
</Position9>
<Position10>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="97" Column="54" TopLine="86"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFramework.pas"/>
<Caret Line="3332" TopLine="3306"/>
</Position10>
<Position11>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="182" Column="40" TopLine="164"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFramework.pas"/>
<Caret Line="3333" TopLine="3307"/>
</Position11>
<Position12>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="109" Column="49" TopLine="95"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFramework.pas"/>
<Caret Line="3335" TopLine="3309"/>
</Position12>
<Position13>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="22" Column="36" TopLine="14"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\TestFramework.pas"/>
<Caret Line="3337" TopLine="3311"/>
</Position13>
<Position14>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="60" Column="41" TopLine="37"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components_extra\fptest\src\FPCUnitCompatibleInterface.inc"/>
<Caret Line="185" TopLine="158"/>
</Position14>
<Position15>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="64" Column="13" TopLine="37"/>
<Filename Value="uutlListTest.pas"/>
<Caret Line="626" TopLine="610"/>
</Position15>
<Position16>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="77" TopLine="73"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="396" TopLine="380"/>
</Position16>
<Position17>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="69" Column="34" TopLine="48"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="397" TopLine="380"/>
</Position17>
<Position18>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="543" Column="26" TopLine="522"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="398" TopLine="380"/>
</Position18>
<Position19>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="544" Column="42" TopLine="522"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="402" TopLine="380"/>
</Position19>
<Position20>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="538" Column="23" TopLine="520"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="403" TopLine="380"/>
</Position20>
<Position21>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="33" Column="5" TopLine="15"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="405" TopLine="380"/>
</Position21>
<Position22>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="100" Column="8" TopLine="79"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="407" TopLine="381"/>
</Position22>
<Position23>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="557" Column="8" TopLine="536"/>
<Filename Value="uutlListTest.pas"/>
<Caret Line="627" TopLine="610"/>
</Position23>
<Position24>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="753" Column="8" TopLine="732"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="103" TopLine="89"/>
</Position24>
<Position25>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="82" Column="18" TopLine="57"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="104" TopLine="89"/>
</Position25>
<Position26>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="97" TopLine="97"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="400" Column="28" TopLine="381"/>
</Position26>
<Position27>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="90" Column="27" TopLine="67"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="105" Column="24" TopLine="89"/>
</Position27>
<Position28>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="96" Column="21" TopLine="70"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="110" Column="29" TopLine="100"/>
</Position28>
<Position29>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="110" TopLine="107"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="106" TopLine="100"/>
</Position29>
<Position30>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="640" Column="4" TopLine="616"/>
<Filename Value="..\uutlListBase.pas"/>
<Caret Line="113" Column="72" TopLine="100"/>
</Position30>
</JumpHistory>
</ProjectSession>
@@ -653,13 +665,10 @@
<InitialEnabled Value="False"/>
</Item1>
</BreakPointGroups>
<Watches Count="2">
<Watches Count="1">
<Item1>
<Expression Value="p+i"/>
<Expression Value="fCurrent"/>
</Item1>
<Item2>
<Expression Value="p + j"/>
</Item2>
</Watches>
</Debugging>
</CONFIG>

+ 263
- 0
tests/uutlListTest.pas Visa fil

@@ -20,6 +20,9 @@ type
fIntfList: TIntfList;
fObjList: TObjList;

fEnumerator: TIntList.IutlEnumerator;
procedure AccessCurrentEnueratorItem;

protected
procedure SetUp; override;
procedure TearDown; override;
@@ -48,12 +51,22 @@ type
procedure AddRemoveInterfaces;
procedure AddRemoveObject_OwnedByList;
procedure AddRemoveObject_NotOwnedByList;
procedure AddItemWithinEnumeration;
procedure DeleteItemWithinEnumeration;
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlListTest//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListTest.AccessCurrentEnueratorItem;
var
i: Integer;
begin
i := fEnumerator.Current;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListTest.SetUp;
begin
@@ -423,6 +436,256 @@ begin
AssertEquals(0, IntfObjCounter);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListTest.AddItemWithinEnumeration;

procedure InitList;
var i: Integer;
begin
fIntList.Clear;
for i := 0 to 4 do
fIntList.Add(i);
end;

var
e: TIntList.IutlEnumerator;
begin
e := fIntList.GetUtlEnumerator;

// forward - insert behind current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
fIntList.Insert(2, 999);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(999, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertFalse (e.MoveNext);

// forward - insert before current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
fIntList.Insert(1, 999);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertFalse (e.MoveNext);

// forward - insert current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
fIntList.Insert(1, 999);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertFalse (e.MoveNext);

{$IFDEF UTL_ENUMERATORS}
e := e.Reverse;

// reverse - add after current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
fIntList.Insert(3, 999);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertFalse (e.MoveNext);

// reverse - insert before current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
fIntList.Insert(2, 999);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(999, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertFalse (e.MoveNext);

// reverse - insert current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
fIntList.Insert(3, 999);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(999, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertFalse (e.MoveNext);
{$ENDIF}
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListTest.DeleteItemWithinEnumeration;

procedure InitList;
var i: Integer;
begin
fIntList.Clear;
for i := 0 to 4 do
fIntList.Add(i);
end;

var
e: TIntList.IutlEnumerator;
begin
e := fIntList.GetUtlEnumerator;

// forward - delete behind current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
fIntList.Delete(2);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertFalse (e.MoveNext);

// forward - delete before current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
fIntList.Remove(1);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertFalse (e.MoveNext);

// forward - delete current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
fIntList.Remove(1);
fEnumerator := e;
AssertException('Current does not raise exception after deleting current', EInvalidOperation, @AccessCurrentEnueratorItem);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertFalse (e.MoveNext);

{$IFDEF UTL_ENUMERATORS}
e := e.Reverse;

// reverse - delete after current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
fIntList.Remove(4);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertFalse (e.MoveNext);

// reverse - delete before current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
fIntList.Remove(2);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertFalse (e.MoveNext);

// reverse - delete current
InitList;
e.Reset;
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
fIntList.Remove(3);
fEnumerator := e;
AssertException('Current does not raise exception after deleting current', EInvalidOperation, @AccessCurrentEnueratorItem);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(0, e.Current);
AssertFalse (e.MoveNext);
{$ENDIF}
end;

initialization
RegisterTest(TutlListTest.Suite);



+ 4
- 1
tests/uutlObservableHashSetTests.pas Visa fil

@@ -17,6 +17,7 @@ type
fCaptureEvents: Boolean;
fSet: TObservableIntSet;
fEventArgs: TEventArgList;
fEventListener: IutlEventListener;

procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs);

@@ -48,8 +49,9 @@ begin
inherited SetUp;
fCaptureEvents := false;
fEventArgs := TEventArgList.Create(true);
fEventListener := TutlEventListenerCallback.Create(@EventHandler);
fSet := TObservableIntSet.Create(true);
fSet.RegisterEventHandler(@EventHandler);
fSet.RegisterEventListener(fEventListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -57,6 +59,7 @@ procedure TutlObservableHashSetTests.TearDown;
begin
FreeAndNil(fSet);
FreeAndNil(fEventArgs);
fEventListener := nil;
inherited TearDown;
end;



+ 4
- 1
tests/uutlObservableListTests.pas Visa fil

@@ -17,6 +17,7 @@ type
fCaptureEvents: Boolean;
fList: TObservableIntList;
fEventArgs: TEventArgList;
fEventListener: IutlEventListener;

procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs);

@@ -48,8 +49,9 @@ begin
inherited SetUp;
fCaptureEvents := false;
fEventArgs := TEventArgList.Create(true);
fEventListener := TutlEventListenerCallback.Create(@EventHandler);
fList := TObservableIntList.Create(true);
fList.RegisterEventHandler(@EventHandler);
fList.RegisterEventListener(fEventListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -57,6 +59,7 @@ procedure TutlObservableListTests.TearDown;
begin
FreeAndNil(fList);
FreeAndNil(fEventArgs);
fEventListener := nil;
inherited TearDown;
end;



+ 4
- 1
tests/uutlObservableMapTests.pas Visa fil

@@ -17,6 +17,7 @@ type
fCaptureEvents: Boolean;
fMap: TObservableIntStringMap;
fEventArgs: TEventArgList;
fEventListener: IutlEventListener;

procedure EventHandler(constref aSender: TObject; constref aEventArgs: IutlEventArgs);

@@ -48,8 +49,9 @@ begin
inherited SetUp;
fCaptureEvents := false;
fEventArgs := TEventArgList.Create(true);
fEventListener := TutlEventListenerCallback.Create(@EventHandler);
fMap := TObservableIntStringMap.Create(true, true);
fMap.RegisterEventHandler(@EventHandler);
fMap.RegisterEventListener(fEventListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -57,6 +59,7 @@ procedure TutlObservableMapTests.TearDown;
begin
FreeAndNil(fMap);
FreeAndNil(fEventArgs);
fEventListener := nil;
inherited TearDown;
end;



+ 25
- 10
uutlCommon.pas Visa fil

@@ -10,18 +10,23 @@ uses

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlInterfaceNoRefCount = class(TObject, IUnknown)
TutlInterfacedObject = class(TObject, IUnknown)
protected
fRefCount: longint;
fRefCount: longint;
fAutoFree: Boolean;

{ implement methods of IUnknown }
function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function _AddRef: longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
function _Release: longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
{ implement methods of IUnknown }
function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function _AddRef: longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;
function _Release: longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual;

public
property AutoFree: Boolean read fAutoFree write fAutoFree;
property RefCount: LongInt read fRefCount;

constructor Create;
end;
TutlInterfaceNoRefCount = TutlInterfacedObject;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlCSVList = class(TStringList)
@@ -295,9 +300,9 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlInterfaceNoRefCount///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlInterfacedObject///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlInterfaceNoRefCount.QueryInterface(constref iid: tguid; out obj): longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function TutlInterfacedObject.QueryInterface(constref iid: tguid; out obj): longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
if getinterface(iid,obj) then
result:=S_OK
@@ -306,15 +311,25 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlInterfaceNoRefCount._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function TutlInterfacedObject._AddRef: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
result := InterLockedIncrement(fRefCount);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlInterfaceNoRefCount._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function TutlInterfacedObject._Release: longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
result := InterLockedDecrement(fRefCount);
if (result = 0) and fAutoFree then
Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlInterfacedObject.Create;
begin
inherited Create;
fAutoFree := false;
fRefCount := 0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 6
- 6
uutlComparer.pas Visa fil

@@ -28,7 +28,7 @@ type
generic TutlEqualityCompareEventN<T> = function(constref i1, i2: T): Boolean is nested;
{$ENDIF}

generic TutlCalbackEqualityComparer<T> = class(
generic TutlCallbackEqualityComparer<T> = class(
TInterfacedObject,
specialize IutlEqualityComparer<T>)

@@ -140,9 +140,9 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCalbackEqualityComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCallbackEqualityComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCalbackEqualityComparer.EqualityCompare(constref i1, i2: T): Boolean;
function TutlCallbackEqualityComparer.EqualityCompare(constref i1, i2: T): Boolean;
begin
result := false;
case fType of
@@ -157,7 +157,7 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEvent);
constructor TutlCallbackEqualityComparer.Create(const aEvent: TCompareEvent);
begin
inherited Create;
fType := eetNormal;
@@ -165,7 +165,7 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEventO);
constructor TutlCallbackEqualityComparer.Create(const aEvent: TCompareEventO);
begin
inherited Create;
fType := eetObject;
@@ -174,7 +174,7 @@ end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IFDEF UTL_NESTED_PROCVARS}
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEventN);
constructor TutlCallbackEqualityComparer.Create(const aEvent: TCompareEventN);
begin
inherited Create;
fType := eetNested;


+ 1
- 0
uutlEnumerator.pas Visa fil

@@ -97,6 +97,7 @@ type
protected
property Memory: PT read fMemory write fMemory;
property Reversed: Boolean read fReversed write fReversed;
property Current: Integer read fCurrent write fCurrent;
property First: Integer read fFirst write fFirst;
property Last: Integer read fLast write fLast;



+ 47
- 17
uutlEvent.pas Visa fil

@@ -17,18 +17,18 @@ type
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IutlEventListener = interface(IUnknown)
['{BC45E26B-96F7-4151-87F1-C330C8C668E5}']
procedure DispatchEvent(constref aSender: TObject; constref aEvent: IutlEventArgs);
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlEventHandler = procedure (constref aSender: TObject; constref aEvent: IutlEventArgs) of object;
TutlEventHandler = procedure (constref aSender: TObject; constref aEventArgs: IutlEventArgs) of object;
TutlEventArgs = class(TInterfacedObject, IutlEventArgs);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlObservable<T> = interface(specialize {$IFDEF UTL_ADVANCED_ENUMERATORS}IutlEnumerable{$ELSE}IEnumerable{$ENDIF}<T>)
IutlObservable = interface(IUnknown)
['{C54BD844-8273-4ACF-90C5-05DACF4359AF}']
procedure RegisterEventHandler (const aHandler: TutlEventHandler);
procedure UnregisterEventHandler(const aHandler: TutlEventHandler);
procedure RegisterEventListener (const aListener: IutlEventListener);
procedure UnregisterEventListener(const aListener: IutlEventListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -45,6 +45,18 @@ type
end;
TutlNotifyEventList = specialize TutlEventList<TNotifyEvent>;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlEventHandlerList = class(
specialize TutlEventList<TutlEventHandler>
, IutlEventListener)

public { IutlEventListener }
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);

public
constructor Create;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlEventListenerSet = class(
specialize TutlCustomHashSet<IutlEventListener>
@@ -58,7 +70,7 @@ type
end;

public { IutlEventListener }
procedure DispatchEvent(constref aSender: TObject; constref aEvent: IutlEventArgs);
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);

public
constructor Create; reintroduce;
@@ -73,7 +85,7 @@ type
fHandler: TutlEventHandler;

public { IEventListener }
procedure DispatchEvent(constref aSender: TObject; constref aEvent: IutlEventArgs);
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);

public
constructor Create(const aHandler: TutlEventHandler);
@@ -100,7 +112,7 @@ type
function PopEventPair(out aPair: TEventPair): Boolean;

public { IEventListener }
procedure DispatchEvent(constref aSender: TObject; constref aEvent: IutlEventArgs);
procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);

public
function RegisterListener (const aListener: IutlEventListener): Boolean;
@@ -109,7 +121,7 @@ type
procedure DispatchEvents;

constructor Create;
destructor Destroy; override;
destructor Destroy; override;
end;

implementation
@@ -148,6 +160,24 @@ begin
inherited Create(TComparer.Create, true);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEventHandlerList///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEventHandlerList.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
var
e: TutlEventHandler;
begin
for e in self do
e(aSender, aEventArgs);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlEventHandlerList.Create;
begin
inherited Create;
AutoFree := true;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEventListenerSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -170,12 +200,12 @@ end;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEventListenerSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEventListenerSet.DispatchEvent(constref aSender: TObject; constref aEvent: IutlEventArgs);
procedure TutlEventListenerSet.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
var
l: IutlEventListener;
e: IutlEventListener;
begin
for l in self do
l.DispatchEvent(aSender, aEvent);
for e in self do
e.DispatchEvent(aSender, aEventArgs);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -187,9 +217,9 @@ end;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEventListenerCallback//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEventListenerCallback.DispatchEvent(constref aSender: TObject; constref aEvent: IutlEventArgs);
procedure TutlEventListenerCallback.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
begin
fHandler(aSender, aEvent);
fHandler(aSender, aEventArgs);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -228,12 +258,12 @@ begin
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEventListenerAsync.DispatchEvent(constref aSender: TObject; constref aEvent: IutlEventArgs);
procedure TutlEventListenerAsync.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
var
p: TEventPair;
begin
p.first := aSender;
p.second := aEvent;
p.second := aEventArgs;
fEventLock.Enter;
try
fEvents.Add(p);


+ 108
- 1
uutlListBase.pas Visa fil

@@ -20,14 +20,25 @@ type
IutlEnumerator = specialize IutlEnumerator<T>;

private type
TEnumeratorAction = (
eaAdded,
eaRemoved,
eaReallocated
);

TEnumerator = class(
specialize TutlMemoryEnumerator<T>
, IEnumerator
, IutlEnumerator)
private
fOwner: TutlListBase;
fCurrentIsInvalid: Boolean;
fNext: TEnumerator;
fPrev: TEnumerator;

protected { IEnumerator }
function GetCurrent: T; override;
function InternalMoveNext: Boolean; override;
procedure InternalReset; override;

{$IFDEF UTL_ENUMERATORS}
@@ -36,11 +47,18 @@ type
{$ENDIF}

public
procedure Update(const aIndex: Integer; const aAction: TEnumeratorAction);

constructor Create(const aOwner: TutlListBase; const aReversed: Boolean); reintroduce;
destructor Destroy; override;
end;

strict private
fCount: Integer;
fFirstEnumerator: TEnumerator;
fLastEnumerator: TEnumerator;

procedure UpdateEnumerator(const aIndex: Integer; const aAction: TEnumeratorAction);

protected
function GetCount: Integer; override;
@@ -48,6 +66,7 @@ type

function GetItem (const aIndex: Integer): T; virtual;
procedure SetItem (const aIndex: Integer; aValue: T); virtual;
procedure SetCapacity (const aValue: integer); override;

procedure InsertIntern(const aIndex: Integer; constref aValue: T); virtual;
procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean); virtual;
@@ -80,6 +99,21 @@ uses

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlListBase.TEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.TEnumerator.GetCurrent: T;
begin
if fCurrentIsInvalid then
raise EInvalidOperation.Create('current item was deleted, move on with ''MoveNext'' before accessing ''Current''');
result := inherited GetCurrent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.TEnumerator.InternalMoveNext: Boolean;
begin
result := inherited InternalMoveNext;
fCurrentIsInvalid := false;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.TEnumerator.InternalReset;
begin
@@ -99,17 +133,82 @@ begin
end;
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.TEnumerator.Update(const aIndex: Integer; const aAction: TEnumeratorAction);
begin
case aAction of
eaAdded: begin
if (aIndex <= Current) then
Current := Current + 1;
Last := Last + 1;
end;

eaRemoved: begin
fCurrentIsInvalid := (aIndex = Current);
if (aIndex < Current)
or ( (aIndex = Current)
and not Reversed)
then
Current := Current - 1;
Last := Last - 1;
end;

eaReallocated: begin
if (fOwner.Count > 0)
then Memory := fOwner.GetInternalItem(0)
else Memory := nil;
end;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlListBase.TEnumerator.Create(const aOwner: TutlListBase; const aReversed: Boolean);
begin
if not Assigned(aOwner) then
raise EArgumentNilException.Create('aOwner');
fOwner := aOwner;
if not Assigned(fOwner.fLastEnumerator) then begin
fPrev := nil;
fNext := nil;
fOwner.fFirstEnumerator := self;
fOwner.fLastEnumerator := self;
end else begin
fPrev := fOwner.fLastEnumerator;
fNext := nil;
fOwner.fLastEnumerator.fNext := self;
fOwner.fLastEnumerator := self;
end;
inherited Create(nil, aReversed, 0, -1);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TutlListBase.TEnumerator.Destroy;
begin
if (fOwner.fFirstEnumerator = self) then
fOwner.fFirstEnumerator := fNext;
if (fOwner.fLastEnumerator = self) then
fOwner.fLastEnumerator := fPrev;
if Assigned(fPrev) then
fPrev.fNext := fNext;
if Assigned(fNext) then
fNext.fPrev := fPrev;
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.UpdateEnumerator(const aIndex: Integer; const aAction: TEnumeratorAction);
var
e: TEnumerator;
begin
e := fFirstEnumerator;
while Assigned(e) do begin
e.Update(aIndex, aAction);
e := e.fNext;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.GetCount: Integer;
begin
@@ -144,6 +243,12 @@ begin
p^ := aValue;
end;

procedure TutlListBase.SetCapacity(const aValue: integer);
begin
inherited SetCapacity(aValue);
UpdateEnumerator(0, eaReallocated);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.InsertIntern(const aIndex: Integer; constref aValue: T);
var
@@ -158,6 +263,7 @@ begin
System.Move(p^, (p+1)^, (fCount - aIndex) * SizeOf(T));
p^ := aValue;
inc(fCount);
UpdateEnumerator(aIndex, eaAdded);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -174,6 +280,7 @@ begin
if CanShrink and (Capacity > 128) and (fCount < Capacity shr 2) then // only 25% used
SetCapacity(Capacity shr 1); // set to 50% Capacity
FillByte(GetInternalItem(fCount)^, (Capacity-fCount) * SizeOf(T), 0);
UpdateEnumerator(aIndex, eaRemoved);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -183,7 +290,7 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.GetUtlEnumerator: specialize IutlEnumerator<T>;
function TutlListBase.GetUtlEnumerator: IutlEnumerator;
begin
result := TEnumerator.Create(self, false);
end;


+ 3
- 11
uutlLogger.pas Visa fil

@@ -85,12 +85,12 @@ type
private
fStream: TFileStream;
fAutoFlush: Boolean;
fAutoFree: Boolean;
procedure SetAutoFree(aValue: Boolean);
protected
function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; override;

protected
procedure WriteLog(const aLogger: TutlLogger; const aTime: TDateTime; const aLevel: TutlLogLevel; const aSender: string; const aMessage: String);

public
constructor Create(const aFilename: String; const aMode: TutlFileLoggerMode; const aAutoFree: Boolean = false);
destructor Destroy; override;
@@ -98,7 +98,6 @@ type
procedure Flush(); overload;
published
property AutoFlush: Boolean read fAutoFlush write fAutoFlush;
property AutoFree: Boolean read fAutoFree write SetAutoFree;
end;

{ TutlConsoleLogger }
@@ -186,13 +185,6 @@ begin
Free;
end;

function TutlFileLogger._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
result := inherited _Release;
if (Result <= 0) and fAutoFree then
Free;
end;

procedure TutlFileLogger.WriteLog(const aLogger: TutlLogger; const aTime: TDateTime;
const aLevel: TutlLogLevel; const aSender: string; const aMessage: String);
var


+ 58
- 133
uutlObservable.pas Visa fil

@@ -54,10 +54,7 @@ type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlObservableCustomList<T> = class(
specialize TutlCustomList<T>
, specialize IutlObservable<T>)

private type
TEventHandlerList = specialize TutlEventList<TutlEventHandler>;
, IutlObservable)

public type
TItemEventArgs = class(specialize TutlObservableItemEventArgs<T>)
@@ -77,7 +74,7 @@ type
end;

private
fEventHandler: TEventHandlerList;
fEventListener: TutlEventListenerSet;

protected
procedure InsertIntern(const aIndex: Integer; constref aValue: T); override;
@@ -89,8 +86,8 @@ type
procedure DoClear (); virtual;

public { IutlObservable }
procedure RegisterEventHandler (const aHandler: TutlEventHandler);
procedure UnregisterEventHandler(const aHandler: TutlEventHandler);
procedure RegisterEventListener(const aListener: IutlEventListener);
procedure UnregisterEventListener(const aListener: IutlEventListener);

protected
procedure SetItem(const aIndex: Integer; aValue: T); override;
@@ -114,9 +111,9 @@ type
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlObservableCustomHashSet<T> = class(specialize TutlCustomHashSet<T>)
private type
TEventHandlerList = specialize TutlEventList<TutlEventHandler>;
generic TutlObservableCustomHashSet<T> = class(
specialize TutlCustomHashSet<T>
, IutlObservable)

public type
TItemEventArgs = class(specialize TutlObservableItemEventArgs<T>)
@@ -136,7 +133,7 @@ type
end;

private
fEventHandler: TEventHandlerList;
fEventListener: TutlEventListenerSet;

protected
procedure InsertIntern(const aIndex: Integer; constref aValue: T); override;
@@ -149,8 +146,8 @@ type
procedure DoClear (); virtual;

public { IutlObservable }
procedure RegisterEventHandler (const aHandler: TutlEventHandler);
procedure UnregisterEventHandler(const aHandler: TutlEventHandler);
procedure RegisterEventListener(const aListener: IutlEventListener);
procedure UnregisterEventListener(const aListener: IutlEventListener);

public
procedure Clear; override;
@@ -166,9 +163,9 @@ type
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlObservableCustomMap<TKey, TValue> = class(specialize TutlCustomMap<TKey, TValue>)
private type
TEventHandlerList = specialize TutlEventList<TutlEventHandler>;
generic TutlObservableCustomMap<TKey, TValue> = class(
specialize TutlCustomMap<TKey, TValue>
, IutlObservable)

public type
TObservableHashSet = class(THashSet)
@@ -207,7 +204,7 @@ type
end;

private
fEventHandler: TEventHandlerList;
fEventListener: TutlEventListenerSet;

protected
procedure DoAddItem (const aIndex: Integer; constref aKey: TKey; constref aItem: TValue); virtual;
@@ -216,8 +213,8 @@ type
procedure DoClear (); virtual;

public { IutlObservable }
procedure RegisterEventHandler (const aHandler: TutlEventHandler);
procedure UnregisterEventHandler(const aHandler: TutlEventHandler);
procedure RegisterEventListener(const aListener: IutlEventListener);
procedure UnregisterEventListener(const aListener: IutlEventListener);

public
constructor Create(const aHashSet: TObservableHashSet; const aOwnsKeys: Boolean; const aOwnsValues: Boolean); reintroduce;
@@ -310,66 +307,42 @@ end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomList.DoAddItem(const aIndex: Integer; constref aItem: T);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TItemEventArgs.Create(oetAdd, aIndex, aItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TItemEventArgs.Create(oetAdd, aIndex, aItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomList.DoRemoveItem(const aIndex: Integer; constref aItem: T);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TItemEventArgs.Create(oetRemove, aIndex, aItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TItemEventArgs.Create(oetRemove, aIndex, aItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomList.DoChangeItem(const aIndex: Integer; constref aOldItem: T; constref aNewItem: T);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TReplaceEventArgs.Create(oetReplace, aIndex, aOldItem, aNewItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TReplaceEventArgs.Create(oetReplace, aIndex, aOldItem, aNewItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomList.DoClear;
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TutlObservableEventArgs.Create(oetClear);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TutlObservableEventArgs.Create(oetClear));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomList.RegisterEventHandler(const aHandler: TutlEventHandler);
procedure TutlObservableCustomList.RegisterEventListener(const aListener: IutlEventListener);
begin
fEventHandler.Add(aHandler);
fEventListener.Add(aListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomList.UnregisterEventHandler(const aHandler: TutlEventHandler);
procedure TutlObservableCustomList.UnregisterEventListener(const aListener: IutlEventListener);
begin
fEventHandler.Remove(aHandler);
fEventListener.Remove(aListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -389,7 +362,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlObservableCustomList.Create(aEqualityComparer: IEqualityComparer; aOwnsObjects: Boolean);
begin
fEventHandler := TEventHandlerList.Create;
fEventListener := TutlEventListenerSet.Create;
inherited Create(aEqualityComparer, aOwnsObjects);
end;

@@ -397,7 +370,7 @@ end;
destructor TutlObservableCustomList.Destroy;
begin
inherited Destroy;
FreeAndNil(fEventHandler);
FreeAndNil(fEventListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -458,66 +431,42 @@ end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomHashSet.DoAddItem(const aIndex: Integer; constref aItem: T);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TItemEventArgs.Create(oetAdd, aIndex, aItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TItemEventArgs.Create(oetAdd, aIndex, aItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomHashSet.DoRemoveItem(const aIndex: Integer; constref aItem: T);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TItemEventArgs.Create(oetRemove, aIndex, aItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TItemEventArgs.Create(oetRemove, aIndex, aItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomHashSet.DoChangeItem(const aIndex: Integer; constref aOldItem: T; constref aNewItem: T);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TReplaceEventArgs.Create(oetReplace, aIndex, aOldItem, aNewItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TReplaceEventArgs.Create(oetReplace, aIndex, aOldItem, aNewItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomHashSet.DoClear;
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TutlObservableEventArgs.Create(oetClear);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TutlObservableEventArgs.Create(oetClear));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomHashSet.RegisterEventHandler(const aHandler: TutlEventHandler);
procedure TutlObservableCustomHashSet.RegisterEventListener(const aListener: IutlEventListener);
begin
fEventHandler.Add(aHandler);
fEventListener.Add(aListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomHashSet.UnregisterEventHandler(const aHandler: TutlEventHandler);
procedure TutlObservableCustomHashSet.UnregisterEventListener(const aListener: IutlEventListener);
begin
fEventHandler.Remove(aHandler);
fEventListener.Remove(aListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -530,7 +479,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlObservableCustomHashSet.Create(const aComparer: IComparer; const aOwnsItems: Boolean);
begin
fEventHandler := TEventHandlerList.Create;
fEventListener := TutlEventListenerSet.Create;
inherited Create(aComparer, aOwnsItems);
end;

@@ -538,7 +487,7 @@ end;
destructor TutlObservableCustomHashSet.Destroy;
begin
inherited Destroy;
FreeAndNil(fEventHandler);
FreeAndNil(fEventListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -627,15 +576,9 @@ procedure TutlObservableCustomMap.DoAddItem(
const aIndex: Integer;
constref aKey: TKey;
constref aItem: TValue);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TItemEventArgs.Create(oetAdd, aIndex, aKey, aItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TItemEventArgs.Create(oetAdd, aIndex, aKey, aItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -643,15 +586,9 @@ procedure TutlObservableCustomMap.DoRemoveItem(
const aIndex: Integer;
constref aKey: TKey;
constref aItem: TValue);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TItemEventArgs.Create(oetRemove, aIndex, aKey, aItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TItemEventArgs.Create(oetRemove, aIndex, aKey, aItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -660,40 +597,28 @@ procedure TutlObservableCustomMap.DoChangeItem(
constref aKey: TKey;
constref aOldItem: TValue;
constref aNewItem: TValue);
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TReplaceEventArgs.Create(oetReplace, aIndex, aKey, aOldItem, aNewItem);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TReplaceEventArgs.Create(oetReplace, aIndex, aKey, aOldItem, aNewItem));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomMap.DoClear;
var
args: IutlEventArgs;
e: TutlEventHandler;
begin
if not Assigned(fEventHandler) or fEventHandler.IsEmpty then
exit;
args := TutlObservableEventArgs.Create(oetClear);
for e in fEventHandler do
e(self, args);
if Assigned(fEventListener) and not fEventListener.IsEmpty then
fEventListener.DispatchEvent(self, TutlObservableEventArgs.Create(oetClear));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomMap.RegisterEventHandler(const aHandler: TutlEventHandler);
procedure TutlObservableCustomMap.RegisterEventListener(const aListener: IutlEventListener);
begin
fEventHandler.Add(aHandler);
fEventListener.Add(aListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlObservableCustomMap.UnregisterEventHandler(const aHandler: TutlEventHandler);
procedure TutlObservableCustomMap.UnregisterEventListener(const aListener: IutlEventListener);
begin
fEventHandler.Remove(aHandler);
fEventListener.Remove(aListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -702,7 +627,7 @@ constructor TutlObservableCustomMap.Create(
const aOwnsKeys: Boolean;
const aOwnsValues: Boolean);
begin
fEventHandler := TEventHandlerList.Create;
fEventListener := TutlEventListenerSet.Create;
inherited Create(aHashSet, aOwnsKeys, aOwnsValues);
end;

@@ -710,7 +635,7 @@ end;
destructor TutlObservableCustomMap.Destroy;
begin
inherited Destroy;
FreeAndNil(fEventHandler);
FreeAndNil(fEventListener);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 8
- 1
uutlSyncObjs.pas Visa fil

@@ -9,6 +9,13 @@ uses
uutlGenerics;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IutlLockable = interface(IUnknown)
['{CF01F747-D6A9-405B-8A8D-AC148FA9DABB}']
procedure Lock;
procedure Unlock;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlCheckSynchronizeEvent = class(TObject)
private
@@ -85,7 +92,7 @@ type
function LockedObject: T; inline;

constructor Create(const aLock: TCriticalSection; const aObject: T);
destructor Destroy; override;
destructor Destroy; override;
end;

implementation


Laddar…
Avbryt
Spara