Browse Source

* refactored generic code

master
bergmann 8 years ago
parent
commit
68a9cb7e70
19 changed files with 2544 additions and 1849 deletions
  1. +53
    -12
      tests/tests.lpi
  2. +2
    -1
      tests/tests.lpr
  3. +240
    -168
      tests/tests.lps
  4. +126
    -0
      tests/uutlAlgorithmTests.pas
  5. +151
    -0
      tests/uutlArrayTests.pas
  6. +281
    -0
      tests/uutlEnumeratorTests.pas
  7. +0
    -408
      tests/uutlInterfaces.pas
  8. +0
    -297
      tests/uutlLinkedListTests.pas
  9. +5
    -1
      tests/uutlMapTests.pas
  10. +80
    -25
      uutlAlgorithm.pas
  11. +138
    -0
      uutlArrayContainer.pas
  12. +39
    -1
      uutlCommon.pas
  13. +224
    -0
      uutlComparer.pas
  14. +515
    -0
      uutlEnumerator.pas
  15. +3
    -0
      uutlExceptions.pas
  16. +157
    -0
      uutlFilter.pas
  17. +323
    -787
      uutlGenerics.pas
  18. +41
    -149
      uutlInterfaces.pas
  19. +166
    -0
      uutlListBase.pas

+ 53
- 12
tests/tests.lpi View File

@@ -37,55 +37,91 @@
<PackageName Value="FCL"/>
</Item3>
</RequiredPackages>
<Units Count="12">
<Units Count="21">
<Unit0>
<Filename Value="tests.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="uutlQueueTests.pas"/>
<Filename Value="..\uutlGenerics.pas"/>
<IsPartOfProject Value="True"/>
</Unit1>
<Unit2>
<Filename Value="uTestHelper.pas"/>
<Filename Value="..\uutlArrayContainer.pas"/>
<IsPartOfProject Value="True"/>
</Unit2>
<Unit3>
<Filename Value="uutlStackTests.pas"/>
<Filename Value="..\uutlCommon.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="uutlListTest.pas"/>
<Filename Value="..\uutlExceptions.pas"/>
<IsPartOfProject Value="True"/>
</Unit4>
<Unit5>
<Filename Value="..\uutlAlgorithm.pas"/>
<Filename Value="..\uutlListBase.pas"/>
<IsPartOfProject Value="True"/>
</Unit5>
<Unit6>
<Filename Value="uutlLinkedListTests.pas"/>
<Filename Value="uutlListTest.pas"/>
<IsPartOfProject Value="True"/>
</Unit6>
<Unit7>
<Filename Value="..\uutlGenerics.pas"/>
<Filename Value="uutlQueueTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit7>
<Unit8>
<Filename Value="..\uutlCommon.pas"/>
<Filename Value="uutlStackTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit8>
<Unit9>
<Filename Value="uutlInterfaces.pas"/>
<Filename Value="uTestHelper.pas"/>
<IsPartOfProject Value="True"/>
</Unit9>
<Unit10>
<Filename Value="uutlHashSetTests.pas"/>
<Filename Value="_uutlInterfaces.pas"/>
<IsPartOfProject Value="True"/>
</Unit10>
<Unit11>
<Filename Value="uutlMapTests.pas"/>
<Filename Value="..\uutlComparer.pas"/>
<IsPartOfProject Value="True"/>
</Unit11>
<Unit12>
<Filename Value="..\uutlAlgorithm.pas"/>
<IsPartOfProject Value="True"/>
</Unit12>
<Unit13>
<Filename Value="uutlHashSetTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit13>
<Unit14>
<Filename Value="uutlArrayTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit14>
<Unit15>
<Filename Value="uutlAlgorithmTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit15>
<Unit16>
<Filename Value="uutlMapTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit16>
<Unit17>
<Filename Value="..\uutlEnumerator.pas"/>
<IsPartOfProject Value="True"/>
</Unit17>
<Unit18>
<Filename Value="uutlEnumeratorTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit18>
<Unit19>
<Filename Value="..\uutlFilter.pas"/>
<IsPartOfProject Value="True"/>
</Unit19>
<Unit20>
<Filename Value="..\uutlInterfaces.pas"/>
<IsPartOfProject Value="True"/>
</Unit20>
</Units>
</ProjectOptions>
<CompilerOptions>
@@ -110,6 +146,11 @@
</Win32>
</Options>
</Linking>
<Other>
<CompilerMessages>
<IgnoredMessages idx5024="True"/>
</CompilerMessages>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">


+ 2
- 1
tests/tests.lpr View File

@@ -4,7 +4,8 @@ program tests;

uses
Interfaces, Forms, GUITestRunner,
uutlQueueTests, uutlStackTests, uutlListTest, uutlLinkedListTests, uutlHashSetTests, uutlMapTests;
uutlStackTests, uutlQueueTests, uutlListTest, uutlHashSetTests, uutlArrayTests,
uutlAlgorithmTests, uutlMapTests, uutlEnumeratorTests;

{$R *.res}



+ 240
- 168
tests/tests.lps View File

@@ -4,330 +4,402 @@
<PathDelim Value="\"/>
<Version Value="9"/>
<BuildModes Active="Default"/>
<Units Count="26">
<Units Count="34">
<Unit0>
<Filename Value="tests.lpr"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="7" Y="6"/>
<UsageCount Value="39"/>
<EditorIndex Value="3"/>
<CursorPos X="5" Y="15"/>
<UsageCount Value="30"/>
<Loaded Value="True"/>
</Unit0>
<Unit1>
<Filename Value="uutlQueueTests.pas"/>
<Filename Value="..\uutlGenerics.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos Y="12"/>
<UsageCount Value="39"/>
<EditorIndex Value="1"/>
<TopLine Value="1045"/>
<CursorPos X="25" Y="1060"/>
<UsageCount Value="30"/>
<Loaded Value="True"/>
</Unit1>
<Unit2>
<Filename Value="uTestHelper.pas"/>
<Filename Value="..\uutlArrayContainer.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="16" Y="12"/>
<UsageCount Value="39"/>
<TopLine Value="24"/>
<CursorPos X="14" Y="38"/>
<UsageCount Value="30"/>
</Unit2>
<Unit3>
<Filename Value="uutlStackTests.pas"/>
<Filename Value="..\uutlCommon.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="75" Y="17"/>
<UsageCount Value="39"/>
<TopLine Value="3"/>
<CursorPos X="29" Y="8"/>
<UsageCount Value="30"/>
</Unit3>
<Unit4>
<Filename Value="uutlListTest.pas"/>
<Filename Value="..\uutlExceptions.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="27" Y="16"/>
<UsageCount Value="39"/>
<TopLine Value="9"/>
<CursorPos X="35" Y="14"/>
<UsageCount Value="30"/>
</Unit4>
<Unit5>
<Filename Value="..\uutlAlgorithm.pas"/>
<Filename Value="..\uutlListBase.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<TopLine Value="13"/>
<CursorPos X="68" Y="29"/>
<UsageCount Value="33"/>
<EditorIndex Value="4"/>
<CursorPos X="23" Y="9"/>
<UsageCount Value="30"/>
<Loaded Value="True"/>
</Unit5>
<Unit6>
<Filename Value="uutlLinkedListTests.pas"/>
<Filename Value="uutlListTest.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="2"/>
<TopLine Value="267"/>
<CursorPos X="29" Y="284"/>
<UsageCount Value="32"/>
<Loaded Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="357"/>
<CursorPos X="7" Y="376"/>
<UsageCount Value="30"/>
</Unit6>
<Unit7>
<Filename Value="..\uutlGenerics.pas"/>
<Filename Value="uutlQueueTests.pas"/>
<IsPartOfProject Value="True"/>
<IsVisibleTab Value="True"/>
<TopLine Value="225"/>
<CursorPos X="26" Y="245"/>
<EditorIndex Value="-1"/>
<UsageCount Value="30"/>
<Loaded Value="True"/>
</Unit7>
<Unit8>
<Filename Value="..\uutlCommon.pas"/>
<Filename Value="uutlStackTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<TopLine Value="21"/>
<CursorPos Y="41"/>
<UsageCount Value="28"/>
<CursorPos X="3" Y="9"/>
<UsageCount Value="30"/>
</Unit8>
<Unit9>
<Filename Value="uutlInterfaces.pas"/>
<Filename Value="uTestHelper.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="1"/>
<TopLine Value="118"/>
<CursorPos X="28" Y="139"/>
<UsageCount Value="27"/>
<Loaded Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<CursorPos X="3" Y="12"/>
<UsageCount Value="30"/>
</Unit9>
<Unit10>
<Filename Value="uutlHashSetTests.pas"/>
<Filename Value="_uutlInterfaces.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<TopLine Value="90"/>
<CursorPos X="29" Y="115"/>
<UsageCount Value="27"/>
<CursorPos X="42" Y="6"/>
<UsageCount Value="30"/>
</Unit10>
<Unit11>
<Filename Value="..\test.lpr"/>
<EditorIndex Value="-1"/>
<TopLine Value="55"/>
<CursorPos Y="72"/>
<UsageCount Value="9"/>
<Filename Value="..\uutlComparer.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="6"/>
<CursorPos X="25" Y="13"/>
<UsageCount Value="30"/>
<Loaded Value="True"/>
</Unit11>
<Unit12>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\TestFramework.pas"/>
<Filename Value="..\uutlAlgorithm.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="427"/>
<CursorPos X="3" Y="394"/>
<UsageCount Value="13"/>
<TopLine Value="43"/>
<CursorPos X="33" Y="55"/>
<UsageCount Value="30"/>
</Unit12>
<Unit13>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\FPCUnitCompatibleInterface.inc"/>
<EditorIndex Value="3"/>
<TopLine Value="54"/>
<CursorPos Y="69"/>
<UsageCount Value="14"/>
<Loaded Value="True"/>
<Filename Value="uutlHashSetTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<UsageCount Value="30"/>
</Unit13>
<Unit14>
<Filename Value="G:\Eigene Datein\Projekte\Delphi\TotoStarRedesign\utils\uutlGenerics.pas"/>
<Filename Value="uutlArrayTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="527"/>
<UsageCount Value="12"/>
<TopLine Value="118"/>
<CursorPos X="29" Y="137"/>
<UsageCount Value="29"/>
</Unit14>
<Unit15>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\objpas\fgl.pp"/>
<Filename Value="uutlAlgorithmTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="544"/>
<CursorPos X="15" Y="562"/>
<UsageCount Value="14"/>
<CursorPos Y="77"/>
<UsageCount Value="29"/>
</Unit15>
<Unit16>
<Filename Value="G:\Eigene Datein\Projekte\Delphi\TotoStarRedesign\utils\uutlInterfaces.pas"/>
<Filename Value="..\..\Utils\uutlGenerics2.pas"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="69"/>
<CursorPos Y="88"/>
<UsageCount Value="14"/>
<TopLine Value="1902"/>
<CursorPos Y="1905"/>
<UsageCount Value="11"/>
<Loaded Value="True"/>
</Unit16>
<Unit17>
<Filename Value="..\uutlExceptions.pas"/>
<Filename Value="..\..\Utils\uutlCommon2.pas"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<CursorPos X="3" Y="15"/>
<UsageCount Value="10"/>
<TopLine Value="9"/>
<CursorPos X="15" Y="26"/>
<UsageCount Value="11"/>
</Unit17>
<Unit18>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\inc\objpash.inc"/>
<Filename Value="..\..\Utils\uutlExceptions.pas"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="437"/>
<CursorPos X="5" Y="453"/>
<TopLine Value="77"/>
<CursorPos X="3" Y="18"/>
<UsageCount Value="9"/>
</Unit18>
<Unit19>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\inc\objpas.inc"/>
<Filename Value="..\..\Utils\tests\uutlInterfaces2.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="999"/>
<CursorPos X="19" Y="1017"/>
<UsageCount Value="9"/>
<WindowIndex Value="1"/>
<TopLine Value="49"/>
<CursorPos X="35" Y="60"/>
<UsageCount Value="11"/>
</Unit19>
<Unit20>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\TestFrameworkIfaces.pas"/>
<Filename Value="..\..\Utils\uutlComparer.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="36"/>
<CursorPos X="3" Y="51"/>
<UsageCount Value="9"/>
<WindowIndex Value="1"/>
<TopLine Value="84"/>
<CursorPos X="28" Y="28"/>
<UsageCount Value="11"/>
</Unit20>
<Unit21>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\objpas\sysutils\intfh.inc"/>
<Filename Value="..\..\Utils\uutlAlgorithm2.pas"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="6"/>
<CursorPos X="26" Y="18"/>
<UsageCount Value="9"/>
<TopLine Value="66"/>
<CursorPos X="5" Y="93"/>
<UsageCount Value="11"/>
</Unit21>
<Unit22>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\objpas\sysutils\sysuintf.inc"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\objpas\objpas.pp"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="15"/>
<CursorPos X="3" Y="17"/>
<UsageCount Value="9"/>
<TopLine Value="62"/>
<CursorPos X="5" Y="77"/>
<UsageCount Value="13"/>
</Unit22>
<Unit23>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\inc\systemh.inc"/>
<Filename Value="..\..\Utils\uutlInterfaces.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="770"/>
<CursorPos X="11" Y="785"/>
<UsageCount Value="11"/>
<WindowIndex Value="1"/>
<TopLine Value="31"/>
<CursorPos X="22" Y="45"/>
<UsageCount Value="12"/>
</Unit23>
<Unit24>
<Filename Value="G:\Eigene Datein\Projekte\Delphi\TotoStarRedesign\utils\uutlObservableGenerics.pas"/>
<Filename Value="G:\Eigene Datein\Projekte\_Active Projekte\TotoStarRedesign\utils\uutlAlgorithm.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="115"/>
<CursorPos X="32" Y="101"/>
<UsageCount Value="10"/>
<WindowIndex Value="1"/>
<TopLine Value="48"/>
<CursorPos X="45" Y="56"/>
<UsageCount Value="11"/>
</Unit24>
<Unit25>
<Filename Value="uutlMapTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="9" Y="24"/>
<UsageCount Value="23"/>
<TopLine Value="65"/>
<CursorPos X="60" Y="75"/>
<UsageCount Value="28"/>
</Unit25>
<Unit26>
<Filename Value="..\..\Utils\uutlEnumerator2.pas"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="126"/>
<CursorPos X="22" Y="128"/>
<UsageCount Value="10"/>
</Unit26>
<Unit27>
<Filename Value="..\uutlEnumerator.pas"/>
<IsPartOfProject Value="True"/>
<TopLine Value="76"/>
<CursorPos X="39" Y="90"/>
<UsageCount Value="27"/>
<Loaded Value="True"/>
</Unit27>
<Unit28>
<Filename Value="uutlEnumeratorTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="2"/>
<TopLine Value="247"/>
<CursorPos X="29" Y="262"/>
<UsageCount Value="27"/>
<Loaded Value="True"/>
</Unit28>
<Unit29>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\FPCUnitCompatibleInterface.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="90"/>
<CursorPos X="16" Y="97"/>
<UsageCount Value="10"/>
</Unit29>
<Unit30>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\TestFramework.pas"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="2964"/>
<CursorPos Y="2979"/>
<UsageCount Value="9"/>
</Unit30>
<Unit31>
<Filename Value="..\uutlFilter.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="7"/>
<TopLine Value="19"/>
<CursorPos X="40" Y="62"/>
<UsageCount Value="23"/>
<Loaded Value="True"/>
</Unit31>
<Unit32>
<Filename Value="..\uutlInterfaces.pas"/>
<IsPartOfProject Value="True"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="5"/>
<CursorPos X="21" Y="10"/>
<UsageCount Value="23"/>
<Loaded Value="True"/>
</Unit32>
<Unit33>
<Filename Value="..\internal_uutlInterfaces.pas"/>
<EditorIndex Value="-1"/>
<CursorPos Y="11"/>
<UsageCount Value="10"/>
</Unit33>
</Units>
<JumpHistory Count="29" HistoryIndex="28">
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1485" TopLine="1470"/>
<Filename Value="..\uutlFilter.pas"/>
<Caret Line="52" Column="24" TopLine="29"/>
</Position1>
<Position2>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1486" TopLine="1470"/>
<Filename Value="..\uutlFilter.pas"/>
<Caret Line="71" Column="17" TopLine="58"/>
</Position2>
<Position3>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1487" TopLine="1470"/>
<Filename Value="..\uutlFilter.pas"/>
<Caret Line="78" TopLine="63"/>
</Position3>
<Position4>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1217" TopLine="1202"/>
<Filename Value="..\uutlFilter.pas"/>
<Caret Line="69" Column="43" TopLine="55"/>
</Position4>
<Position5>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1219" TopLine="1202"/>
<Filename Value="..\uutlFilter.pas"/>
<Caret Line="144" Column="11" TopLine="123"/>
</Position5>
<Position6>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1220" TopLine="1202"/>
<Filename Value="..\uutlFilter.pas"/>
<Caret Line="60" Column="58" TopLine="43"/>
</Position6>
<Position7>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1221" TopLine="1202"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="156" Column="82" TopLine="133"/>
</Position7>
<Position8>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="478" Column="83" TopLine="464"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="478" Column="12" TopLine="453"/>
</Position8>
<Position9>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="71" Column="25" TopLine="60"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="151" Column="30" TopLine="136"/>
</Position9>
<Position10>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="97" Column="60" TopLine="74"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="476" Column="44" TopLine="453"/>
</Position10>
<Position11>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="93" Column="77" TopLine="74"/>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="26" Column="37" TopLine="9"/>
</Position11>
<Position12>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="73" Column="15" TopLine="69"/>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="273" Column="19" TopLine="244"/>
</Position12>
<Position13>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="123" Column="35" TopLine="105"/>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="263" Column="75" TopLine="248"/>
</Position13>
<Position14>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="641" Column="24" TopLine="618"/>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="253" Column="35" TopLine="248"/>
</Position14>
<Position15>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="130" Column="40" TopLine="111"/>
<Filename Value="uutlEnumeratorTests.pas"/>
<Caret Line="262" Column="29" TopLine="247"/>
</Position15>
<Position16>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="138" Column="34" TopLine="111"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="158" Column="41" TopLine="137"/>
</Position16>
<Position17>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="265" Column="24" TopLine="241"/>
<Filename Value="..\uutlInterfaces.pas"/>
<Caret Line="44" Column="39" TopLine="29"/>
</Position17>
<Position18>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="171" Column="30" TopLine="150"/>
<Filename Value="..\uutlInterfaces.pas"/>
<Caret Line="48" Column="51" TopLine="28"/>
</Position18>
<Position19>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="188" Column="23" TopLine="173"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="37" Column="39" TopLine="22"/>
</Position19>
<Position20>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="194" Column="22" TopLine="173"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="90" Column="39" TopLine="77"/>
</Position20>
<Position21>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="266" Column="49" TopLine="247"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="343" Column="27" TopLine="338"/>
</Position21>
<Position22>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="39" Column="32" TopLine="24"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="344" Column="11" TopLine="338"/>
</Position22>
<Position23>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="282" Column="29" TopLine="259"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="348" Column="19" TopLine="338"/>
</Position23>
<Position24>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="96" Column="14" TopLine="81"/>
<Caret Line="393" Column="20" TopLine="373"/>
</Position24>
<Position25>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="19" Column="5" TopLine="3"/>
<Caret Line="1369" Column="30" TopLine="1347"/>
</Position25>
<Position26>
<Filename Value="uutlInterfaces.pas"/>
<Caret Line="169" Column="35" TopLine="151"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="9" Column="92"/>
</Position26>
<Position27>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="279" Column="78" TopLine="263"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="401" Column="48" TopLine="377"/>
</Position27>
<Position28>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\FPCUnitCompatibleInterface.inc"/>
<Caret Line="69" TopLine="54"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1352" Column="15" TopLine="1337"/>
</Position28>
<Position29>
<Filename Value="uutlLinkedListTests.pas"/>
<Caret Line="290" Column="27" TopLine="264"/>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="90" Column="39" TopLine="76"/>
</Position29>
<Position30>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1060" Column="25" TopLine="1045"/>
</Position30>
</JumpHistory>
</ProjectSession>
<Debugging>
<Watches Count="1">
<Item1>
<Expression Value="aElement^.data"/>
<Expression Value="fCurrentSkip"/>
</Item1>
</Watches>
</Debugging>


+ 126
- 0
tests/uutlAlgorithmTests.pas View File

@@ -0,0 +1,126 @@
unit uutlAlgorithmTests;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, TestFramework,
uutlComparer;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlAlgorithmTest = class(TTestCase)
published
procedure BinarySearch;
procedure QuickSort;
end;

implementation

uses
uutlGenerics, uutlAlgorithm;

type
TIntArray = specialize TutlArray<Integer>;
TQuickSort = specialize TutlQuickSort<Integer>;
TBinarySearch = specialize TutlBinarySearch<Integer>;
TIntComparer = specialize TutlComparer<Integer>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlAlgorithmTest/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlAlgorithmTest.BinarySearch;
var
arr: TIntArray;
index: Integer;
ret: Boolean;
begin
arr := TIntArray.Create;
arr.Count := 10;
arr[0] := 1;
arr[1] := 4;
arr[2] := 5;
arr[3] := 6;
arr[4] := 10;
arr[5] := 11;
arr[6] := 13;
arr[7] := 20;
arr[8] := 21;
arr[9] := 22;

ret := TBinarySearch.Search(arr, TIntComparer.Create, 4, index);
AssertTrue (ret);
AssertEquals(1, index);

ret := TBinarySearch.Search(arr, TIntComparer.Create, 7, index);
AssertFalse (ret);
AssertEquals(4, index);

ret := TBinarySearch.Search(arr, TIntComparer.Create, 13, index);
AssertTrue (ret);
AssertEquals(6, index);

ret := TBinarySearch.Search(arr, TIntComparer.Create, 19, index);
AssertFalse (ret);
AssertEquals(7, index);

ret := TBinarySearch.Search(arr, TIntComparer.Create, 25, index);
AssertFalse (ret);
AssertEquals(10, index);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlAlgorithmTest.QuickSort;
var
arr: TIntArray;
begin
arr := TIntArray.Create;
arr.Count := 20;
arr[ 0] := 134;
arr[ 1] := 314;
arr[ 2] := 721;
arr[ 3] := 672;
arr[ 4] := 831;
arr[ 5] := 163;
arr[ 6] := 126;
arr[ 7] := 732;
arr[ 8] := 175;
arr[ 9] := 274;
arr[10] := 462;
arr[11] := 627;
arr[12] := 633;
arr[13] := 672;
arr[14] := 752;
arr[15] := 367;
arr[16] := 263;
arr[17] := 456;
arr[18] := 678;
arr[19] := 832;
TQuickSort.Sort(arr, TIntComparer.Create);
AssertEquals(126, arr[ 0]);
AssertEquals(134, arr[ 1]);
AssertEquals(163, arr[ 2]);
AssertEquals(175, arr[ 3]);
AssertEquals(263, arr[ 4]);
AssertEquals(274, arr[ 5]);
AssertEquals(314, arr[ 6]);
AssertEquals(367, arr[ 7]);
AssertEquals(456, arr[ 8]);
AssertEquals(462, arr[ 9]);
AssertEquals(627, arr[10]);
AssertEquals(633, arr[11]);
AssertEquals(672, arr[12]);
AssertEquals(672, arr[13]);
AssertEquals(678, arr[14]);
AssertEquals(721, arr[15]);
AssertEquals(732, arr[16]);
AssertEquals(752, arr[17]);
AssertEquals(831, arr[18]);
AssertEquals(832, arr[19]);
end;

initialization
RegisterTest(TutlAlgorithmTest.Suite);
end.


+ 151
- 0
tests/uutlArrayTests.pas View File

@@ -0,0 +1,151 @@
unit uutlArrayTests;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, TestFramework,
uutlGenerics;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TIntArray = specialize TutlArray<Integer>;

TutlArrayTest = class(TTestCase)
published
procedure Prop_Get_Count;
procedure Prop_Set_Count;
procedure Prop_Get_Items;
procedure Prop_Set_Items;
procedure Prop_Get_Data;
procedure Prop_Set_Data;

procedure Meth_Ctor;
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlArrayTest/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayTest.Prop_Get_Count;
var
arr: TIntArray;
begin
arr := TIntArray.Create;
try
AssertEquals(0, arr.Count);
finally
FreeAndNil(arr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayTest.Prop_Set_Count;
var
arr: TIntArray;
begin
arr := TIntArray.Create;
try
AssertEquals(0, arr.Count);
arr.Count := 1;
AssertEquals(1, arr.Count);
arr.Count := 5;
AssertEquals(5, arr.Count);
finally
FreeAndNil(arr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayTest.Prop_Get_Items;
var
arr: TIntArray;
begin
arr := TIntArray.Create;
try
arr.Count := 1;
AssertEquals(0, arr[0]);
finally
FreeAndNil(arr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayTest.Prop_Set_Items;
var
arr: TIntArray;
begin
arr := TIntArray.Create;
try
arr.Count := 3;
arr[0] := 1;
arr[1] := 3;
arr[2] := 5;
AssertEquals(1, arr[0]);
AssertEquals(3, arr[1]);
AssertEquals(5, arr[2]);
finally
FreeAndNil(arr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayTest.Prop_Get_Data;
var
arr: TIntArray;
data: TIntArray.TData;
begin
arr := TIntArray.Create;
try
arr.Count := 3;
arr[0] := 1;
arr[1] := 3;
arr[2] := 5;
data := arr.Data;
AssertEquals(3, Length(data));
AssertEquals(1, data[0]);
AssertEquals(3, data[1]);
AssertEquals(5, data[2]);
finally
FreeAndNil(arr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayTest.Prop_Set_Data;
var
arr: TIntArray;
data: TIntArray.TData;
begin
arr := TIntArray.Create;
try
SetLength(data, 5);
arr.Data := data;
AssertEquals(5, arr.Count);
finally
FreeAndNil(arr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayTest.Meth_Ctor;
var
arr: TIntArray;
data: TIntArray.TData;
begin
SetLength(data, 5);
arr := TIntArray.Create(data);
try
AssertEquals(5, arr.Count);
finally
FreeAndNil(arr);
end;
end;

initialization
RegisterTest(TutlArrayTest.Suite);

end.


+ 281
- 0
tests/uutlEnumeratorTests.pas View File

@@ -0,0 +1,281 @@
unit uutlEnumeratorTests;

{$mode objfpc}{$H+}
{$modeswitch nestedprocvars}

interface

uses
Classes, SysUtils, TestFramework,
uutlEnumerator;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlEnumeratorTests = class(TTestCase)
published
procedure ArrayEnumerator;
procedure ArrayEnumerator_Reverse;
procedure ArrayEnumerator_Count;
procedure ArrayEnumerator_Skip;
procedure ArrayEnumerator_Take;
procedure ArrayEnumerator_Skip_Reverse;
procedure ArrayEnumerator_Take_Reverse;
procedure ArrayEnumerator_Reverse_Skip;
procedure ArrayEnumerator_Reverse_Take;
procedure ArrayEnumerator_Where;
procedure ArrayEnumerator_Select;
end;

implementation

uses
uutlFilter;

type
TIntCalbackFilter = specialize TutlCalbackFilter<Integer>;
TIntArrEnumerator = specialize TutlArrayEnumerator<Integer>;
TFloatArrEnumerator = specialize TutlArrayEnumerator<Single>;

function CreateArrayEnumerator(const aSize: Integer): TIntArrEnumerator.IEnumerator;
var
arr: array of Integer;
i: Integer;
begin
SetLength(arr, aSize);
for i := low(arr) to high(arr) do
arr[i] := i + 1;
result := TIntArrEnumerator.Create(arr);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEnumeratorTests///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(5);
AssertTrue (e.MoveNext);
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);
AssertTrue (e.MoveNext);
AssertEquals(5, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Reverse;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(5)
.Reverse;
AssertTrue (e.MoveNext);
AssertEquals(5, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Count;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(5);
AssertEquals(5, e.Count);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Skip;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(10)
.Skip(5);
AssertTrue (e.MoveNext);
AssertEquals(6, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(7, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(8, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(9, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(10, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Take;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(10)
.Take(5);
AssertTrue (e.MoveNext);
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);
AssertTrue (e.MoveNext);
AssertEquals(5, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Skip_Reverse;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(10)
.Skip(5)
.Reverse;
AssertTrue (e.MoveNext);
AssertEquals(10, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(9, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(8, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(7, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(6, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Take_Reverse;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(10)
.Take(5)
.Reverse;
AssertTrue (e.MoveNext);
AssertEquals(5, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Reverse_Skip;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(10)
.Reverse
.Skip(5);
AssertTrue (e.MoveNext);
AssertEquals(5, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(1, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Reverse_Take;
var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(10)
.Reverse
.Take(5);
AssertTrue (e.MoveNext);
AssertEquals(10, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(9, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(8, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(7, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(6, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Where;

function IsEven(constref i: Integer): Boolean;
begin
result := (i mod 2) = 0;
end;

var
e: TIntArrEnumerator.IEnumerator;
begin
e := CreateArrayEnumerator(10)
.Where(TIntCalbackFilter.Create(@IsEven));
AssertTrue (e.MoveNext);
AssertEquals(2, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(6, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(8, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(10, e.Current);
AssertFalse (e.MoveNext);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlEnumeratorTests.ArrayEnumerator_Select;

function ConvertToFloat(constref a: Integer): Single;
begin
result := Single(a);
end;

var
e: TFloatArrEnumerator.IEnumerator;
begin
e := specialize TutlSelectEnumerator<Integer, Single>.Create(
CreateArrayEnumerator(5),
specialize TutlCalbackSelector<Integer, Single>.Create(@ConvertToFloat));
AssertTrue (e.MoveNext);
AssertEquals(1.0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(2.0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(3.0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(4.0, e.Current);
AssertTrue (e.MoveNext);
AssertEquals(5.0, e.Current);
AssertFalse (e.MoveNext);
end;

initialization
RegisterTest(TutlEnumeratorTests.Suite);

end.


+ 0
- 408
tests/uutlInterfaces.pas View File

@@ -1,408 +0,0 @@
unit uutlInterfaces;

{$mode objfpc}{$H+}
{$modeswitch nestedprocvars}

interface

uses
Classes, SysUtils;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Container/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlEnumerator<T> = interface(specialize IEnumerator<T>)
['{134FAC2F-3F23-4BD8-88FB-4B3BD2253E03}']
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlEnumerable<T> = interface(specialize IEnumerable<T>)
['{B6B43A0E-754C-43D0-829A-6632F922A2DE}']
function GetUtlEnumerator: specialize IutlEnumerator<T>;

property Enumerator: specialize IutlEnumerator<T> read GetUtlEnumerator;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlReadOnlyIndexer<T> = interface(IUnknown)
['{9E502CF8-3223-4784-8DB7-614187FFFE68}']
function GetCount: Integer;
function GetItem(const aIndex: Integer): T;

property Count: Integer read GetCount;
property Items[const aIndex: Integer]: T read GetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlIndexer<T> = interface(specialize IutlReadOnlyIndexer<T>)
['{4CA50BE2-A1DF-48BE-9E83-0C94015BA873}']
procedure SetItem(const aIndex: Integer; aItem: T);

property Items[const aIndex: Integer]: T read GetItem write SetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Comparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlEqualityComparer<T> = interface(IUnknown)
['{C0FB90CC-D071-490F-BFEE-BAA5C94D1A5B}']
function EqualityCompare(constref i1, i2: T): Boolean;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlComparer<T> = interface(specialize IutlEqualityComparer<T>)
['{7D2EC014-2878-4F60-9E43-4CFB54268995}']
function Compare(constref i1, i2: T): Integer;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
public
function EqualityCompare(constref i1, i2: T): Boolean;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlEqualityCompareEvent<T> = function(constref i1, i2: T): Boolean;
generic TutlEqualityCompareEventO<T> = function(constref i1, i2: T): Boolean of object;
generic TutlEqualityCompareEventN<T> = function(constref i1, i2: T): Boolean is nested;

generic TutlCalbackEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
private type
TEqualityCompareEventType = (eetNormal, eetObject, eetNested);

public type
TCompareEvent = specialize TutlEqualityCompareEvent<T>;
TCompareEventO = specialize TutlEqualityCompareEventO<T>;
TCompareEventN = specialize TutlEqualityCompareEventN<T>;

strict private
fType: TEqualityCompareEventType;
fEvent: TCompareEvent;
fEventO: TCompareEventO;
fEventN: TCompareEventN;

public
function EqualityCompare(constref i1, i2: T): Boolean;

{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
constructor Create(const aEvent: TCompareEvent);
constructor Create(const aEvent: TCompareEventO);
constructor Create(const aEvent: TCompareEventN);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlComparer<T> = class(specialize TutlEqualityComparer<T>, specialize IutlComparer<T>)
public
function Compare(constref i1, i2: T): Integer;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlCompareEvent<T> = function(constref i1, i2: T): Integer;
generic TutlCompareEventO<T> = function(constref i1, i2: T): Integer of object;
generic TutlCompareEventN<T> = function(constref i1, i2: T): Integer is nested;

generic TutlCallbackComparer<T> = class(TInterfacedObject, specialize IutlComparer<T>)
private type
TCompareEventType = (cetNormal, cetObject, cetNested);

public type
TCompareEvent = specialize TutlCompareEvent<T>;
TCompareEventO = specialize TutlCompareEventO<T>;
TCompareEventN = specialize TutlCompareEventN<T>;

strict private
fType: TCompareEventType;
fEvent: TCompareEvent;
fEventO: TCompareEventO;
fEventN: TCompareEventN;

public
function Compare(constref i1, i2: T): Integer;
function EqualityCompare(constref i1, i2: T): Boolean;

{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
constructor Create(const aEvent: TCompareEvent);
constructor Create(const aEvent: TCompareEventO);
constructor Create(const aEvent: TCompareEventN);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Iterators/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IutlIterator = interface(IUnknown)
['{327E7628-C9D8-4C47-9630-E979D9C3293D}']
function MoveNext: Boolean;
function Clone: IutlIterator;
function Equals(const aOther: IutlIterator): Boolean;
function GetIsValid: Boolean;

property IsValid: Boolean read GetIsValid;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IutlBidirectionalIterator = interface(IutlIterator)
['{31D1E828-52CC-467F-8254-2C1384B28DEE}']
function MovePrev: Boolean;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IutlRandomAccessIterator = interface(IutlBidirectionalIterator)
['{AE06BAB6-BB17-4E46-AE88-583EB853233E}']
function Increment (const aCount: Integer): Boolean;
function Decrement (const aCount: Integer): Boolean;
function Compare (constref aOther: IutlRandomAccessIterator): Integer;
function GetDifference(constref aOther: IutlRandomAccessIterator): Integer;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlInputIterator<T> = interface(IutlIterator)
['{BD4ED39B-2BBA-41F7-BDC7-E1B45F41AA84}']
function GetItem: T;

property Item: T read GetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlOutputIterator<T> = interface(IutlIterator)
['{132642C1-5235-4450-8956-2092D3F2F83D}']
procedure SetItem(aValue: T);

property Item: T write SetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlInputOutputIterator<T> = interface(IutlIterator)
['{5367DA1F-F98C-4EE7-A454-E8978E2A9B46}']
function GetItem: T;
procedure SetItem(aValue: T);

property Item: T read GetItem write SetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlBidirectionalInputIterator<T> = interface(IutlBidirectionalIterator)
['{B2423828-F187-4620-8DA2-9C4EF68B81E3}']
function GetItem: T;

property Item: T read GetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlBidirectionalOutputIterator<T> = interface(IutlBidirectionalIterator)
['{1A13E581-200B-41E7-BC7D-9AD5192DEF0F}']
procedure SetItem(aValue: T);

property Item: T write SetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlBidirectionalInputOutputIterator<T> = interface(IutlBidirectionalIterator)
['{BD8A6D08-7980-45D1-86A6-838402F5CBA6}']
function GetItem: T;
procedure SetItem(aItem: T);

property Item: T read GetItem write SetItem;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlRandomAccessInputIterator<T> = interface(IutlRandomAccessIterator)
['{47880DCC-49D4-45C7-90CB-D8E915B7CB0D}']
function GetItem: T;
function GetItems(const aIndex: Integer): T;

property Item: T read GetItem;
property Items[const aIndex: Integer]: T read GetItems;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlRandomAccessOutputIterator<T> = interface(IutlRandomAccessIterator)
['{E768DA58-E666-47F1-B7D8-61EB6C33C379}']
procedure SetItem(aValue: T);
procedure SetItems(const aIndex: Integer; aValue: T);

property Item: T write SetItem;
property Items[const aIndex: Integer]: T write SetItems;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlRandomAccessInputOutputIterator<T> = interface(IutlRandomAccessIterator)
['{3A8D3C5D-1085-4073-B1D4-DF1886827B6A}']
function GetItem: T;
function GetItems(const aIndex: Integer): T;

procedure SetItem (const aValue: T);
procedure SetItems(const aIndex: Integer; aValue: T);

property Item: T read GetItem write SetItem;
property Items[const aIndex: Integer]: T read GetItems write SetItems;
end;


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IncIt(aIterator: IutlIterator): Boolean; overload;
function DecIt(aIterator: IutlBidirectionalIterator): Boolean; overload;
function IncIt(aIterator: IutlRandomAccessIterator; const a: Integer): Boolean; overload;
function DecIt(aIterator: IutlRandomAccessIterator; const a: Integer): Boolean; overload;
operator +(aIterator: IutlRandomAccessIterator; const a: Integer): IutlRandomAccessIterator;
operator -(aIterator: IutlRandomAccessIterator; const a: Integer): IutlRandomAccessIterator;
operator < (const i1, i2: TObject): Boolean; inline;
operator > (const i1, i2: TObject): Boolean; inline;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IncIt(aIterator: IutlIterator): Boolean;
begin
result := aIterator.MoveNext;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function DecIt(aIterator: IutlBidirectionalIterator): Boolean;
begin
result := aIterator.MovePrev;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IncIt(aIterator: IutlRandomAccessIterator; const a: Integer): Boolean;
begin
result := aIterator.Increment(a);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function DecIt(aIterator: IutlRandomAccessIterator; const a: Integer): Boolean;
begin
result := aIterator.Decrement(a);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator + (aIterator: IutlRandomAccessIterator; const a: Integer): IutlRandomAccessIterator;
begin
result := IutlRandomAccessIterator(aIterator.Clone);
result.Increment(a);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator - (aIterator: IutlRandomAccessIterator; const a: Integer): IutlRandomAccessIterator;
begin
result := IutlRandomAccessIterator(aIterator.Clone);
result.Decrement(a);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator < (const i1, i2: TObject): Boolean;
begin
result := Pointer(i1) < Pointer(i2);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator > (const i1, i2: TObject): Boolean;
begin
result := Pointer(i1) > Pointer(i2);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEqualityComparer.EqualityCompare(constref i1, i2: T): Boolean;
begin
result := (i1 = i2);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCalbackEqualityComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCalbackEqualityComparer.EqualityCompare(constref i1, i2: T): Boolean;
begin
case fType of
eetNormal: result := fEvent (i1, i2);
eetObject: result := fEventO(i1, i2);
eetNested: result := fEventN(i1, i2);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEvent);
begin
inherited Create;
fType := eetNormal;
fEvent := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEventO);
begin
inherited Create;
fType := eetObject;
fEventO := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEventN);
begin
inherited Create;
fType := eetNested;
fEventN := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlComparer.Compare(constref i1, i2: T): Integer;
begin
if (i1 < i2) then
result := -1
else if (i1 > i2) then
result := 1
else
result := 0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCallbackComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCallbackComparer.Compare(constref i1, i2: T): Integer;
begin
case fType of
cetNormal: result := fEvent (i1, i2);
cetObject: result := fEventO(i1, i2);
cetNested: result := fEventN(i1, i2);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCallbackComparer.EqualityCompare(constref i1, i2: T): Boolean;
begin
result := (Compare(i1, i2) = 0);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCallbackComparer.Create(const aEvent: TCompareEvent);
begin
inherited Create;
fType := cetNormal;
fEvent := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCallbackComparer.Create(const aEvent: TCompareEventO);
begin
inherited Create;
fType := cetObject;
fEventO := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCallbackComparer.Create(const aEvent: TCompareEventN);
begin
inherited Create;
fType := cetNested;
fEventN := aEvent;
end;

end.


+ 0
- 297
tests/uutlLinkedListTests.pas View File

@@ -1,297 +0,0 @@
unit uutlLinkedListTests;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, TestFramework,
uutlGenerics, uutlExceptions;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TIntList = specialize TutlLinkedList<Integer>;
TutlLinkedListTests = class(TTestCase)
private
fIntList: TIntList;

procedure AccessPropFirst;
procedure AccessPropLast;

protected
procedure SetUp; override;
procedure TearDown; override;

published
procedure Prop_Count;
procedure Prop_IsEmpty;
procedure Prop_First;
procedure Prop_Last;

procedure Meth_PushFirst_PopFirst;
procedure Meth_PushLast_PopLast;
procedure Meth_InsertBefore;
procedure Meth_InsertAfter;
procedure Meth_Remove;
procedure Meth_Clear;

procedure Iterator;
procedure CompleteIteration;
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlLinkedListTests///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.AccessPropFirst;
begin
fIntList.First;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.AccessPropLast;
begin
fIntList.Last;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.SetUp;
begin
inherited SetUp;
fIntList := TIntList.Create(true);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.TearDown;
begin
FreeAndNil(fIntList);
inherited TearDown;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Prop_Count;
begin
AssertEquals(0, fIntList.Count);
fIntList.PushFirst(123);
AssertEquals(1, fIntList.Count);
fIntList.PushFirst(234);
AssertEquals(2, fIntList.Count);
fIntList.PopFirst(true);
AssertEquals(1, fIntList.Count);
fIntList.PopFirst(true);
AssertEquals(0, fIntList.Count);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Prop_IsEmpty;
begin
AssertEquals(true, fIntList.IsEmpty);
fIntList.PushFirst(123);
AssertEquals(false, fIntList.IsEmpty);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Prop_First;
begin
AssertException('empty list does not raise exception when accessing First property', EutlInvalidOperation, @AccessPropFirst);
fIntList.PushLast(123);
fIntList.PushLast(234);
AssertEquals(123, fIntList.First);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Prop_Last;
begin
AssertException('empty list does not raise exception when accessing First property', EutlInvalidOperation, @AccessPropLast);
fIntList.PushLast(123);
fIntList.PushLast(234);
AssertEquals(234, fIntList.Last);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Meth_PushFirst_PopFirst;
begin
fIntList.PushFirst(123);
AssertEquals(123, fIntList.First);
fIntList.PushFirst(234);
AssertEquals(234, fIntList.First);
fIntList.PushFirst(345);
AssertEquals(345, fIntList.First);
fIntList.PushFirst(456);
AssertEquals(456, fIntList.First);

AssertEquals(456, fIntList.PopFirst(false));
AssertEquals(345, fIntList.First);
AssertEquals( 0, fIntList.PopFirst(true));
AssertEquals(234, fIntList.First);
AssertEquals(234, fIntList.PopFirst(false));
AssertEquals(123, fIntList.First);
AssertEquals( 0, fIntList.PopFirst(true));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Meth_PushLast_PopLast;
begin
fIntList.PushLast(123);
AssertEquals(123, fIntList.Last);
fIntList.PushLast(234);
AssertEquals(234, fIntList.Last);
fIntList.PushLast(345);
AssertEquals(345, fIntList.Last);
fIntList.PushLast(456);
AssertEquals(456, fIntList.Last);

AssertEquals(456, fIntList.PopLast(false));
AssertEquals(345, fIntList.Last);
AssertEquals( 0, fIntList.PopLast(true));
AssertEquals(234, fIntList.Last);
AssertEquals(234, fIntList.PopLast(false));
AssertEquals(123, fIntList.Last);
AssertEquals( 0, fIntList.PopLast(true));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Meth_InsertBefore;
var
it: TIntList.Iterator;
begin
fIntList.PushLast(123);
fIntList.PushLast(234);
fIntList.PushLast(345);
fIntList.PushLast(456);

it := fIntList.FirstIterator;
fIntList.InsertBefore(it, 999);
AssertTrue(it.MovePrev);
AssertEquals(999, it.Item);
AssertEquals(5, fIntList.Count);

it := fIntList.LastIterator;
fIntList.InsertBefore(it, 888);
AssertTrue(it.MovePrev);
AssertEquals(888, it.Item);
AssertEquals(6, fIntList.Count);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Meth_InsertAfter;
var
it: TIntList.Iterator;
begin
fIntList.PushLast(123);
fIntList.PushLast(234);
fIntList.PushLast(345);
fIntList.PushLast(456);

it := fIntList.FirstIterator;
fIntList.InsertAfter(it, 999);
AssertTrue(it.MoveNext);
AssertEquals(999, it.Item);
AssertEquals(5, fIntList.Count);

it := fIntList.LastIterator;
fIntList.InsertAfter(it, 888);
AssertTrue(it.MoveNext);
AssertEquals(888, it.Item);
AssertEquals(6, fIntList.Count);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Meth_Remove;
var
it: TIntList.Iterator;
begin
fIntList.PushLast(123);
fIntList.PushLast(234);
fIntList.PushLast(345);
fIntList.PushLast(456);

it := fIntList.FirstIterator;
it.MoveNext;
fIntList.Remove(it);

AssertEquals(3, fIntList.Count);
AssertEquals(123, fIntList.First);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Meth_Clear;
begin
fIntList.PushLast(123);
fIntList.PushLast(234);
fIntList.PushLast(345);
fIntList.PushLast(456);

AssertEquals(4, fIntList.Count);
fIntList.Clear;

AssertEquals(0, fIntList.Count);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.Iterator;
var
it1: TIntList.Iterator;
begin
fIntList.PushLast(123);
fIntList.PushLast(234);
fIntList.PushLast(345);
fIntList.PushLast(456);

it1 := fIntList.FirstIterator;
AssertEquals(123, it1.Item);
AssertTrue (it1.IsValid);
AssertTrue (it1.Equals(fIntList.FirstIterator));
AssertTrue (it1.MoveNext);
AssertEquals(234, it1.Item);
AssertTrue (it1.MoveNext);
AssertEquals(345, it1.Item);
AssertTrue (it1.MoveNext);
AssertEquals(456, it1.Item);
AssertTrue (it1.Equals(fIntList.LastIterator));
AssertFalse (it1.MoveNext);
fIntList.PopLast;
AssertFalse (it1.IsValid);

it1 := fIntList.LastIterator;
AssertEquals(345, it1.Item);
AssertTrue (it1.IsValid);
AssertTrue (it1.Equals(fIntList.LastIterator));
AssertTrue (it1.MovePrev);
AssertEquals(234, it1.Item);
AssertTrue (it1.MovePrev);
AssertEquals(123, it1.Item);
AssertTrue (it1.Equals(fIntList.FirstIterator));
AssertFalse (it1.MovePrev);
fIntList.PopFirst;
AssertFalse (it1.IsValid);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlLinkedListTests.CompleteIteration;
var
i: Integer;
it, itEnd: TIntList.Iterator;
begin
for i := 0 to 10 do
fIntList.PushLast(i);

i := 0;
it := fIntList.FirstIterator;
itEnd := fIntList.LastIterator;
AssertTrue(itEnd.MovePrev);
repeat
AssertEquals(i, it.Item);
inc(i);
until not it.MoveNext or it.Equals(itEnd);

AssertTrue(it.MoveNext);
AssertEquals(10, it.Item);
end;

initialization
RegisterTest(TutlLinkedListTests.Suite);

end.


+ 5
- 1
tests/uutlMapTests.pas View File

@@ -9,6 +9,7 @@ uses
uTestHelper, uutlGenerics;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TIntMap = specialize TutlMap<Integer, Integer>;
TObjMap = specialize TutlMap<TIntfObj, TIntfObj>;
TutlMapTests = class(TIntfObjOwner)
@@ -48,6 +49,9 @@ type

implementation

uses
uutlExceptions;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlMapTests//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -217,7 +221,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlMapTests.Prop_AutoCreate;
begin
AssertException('autocreate false does not throw exception', EutlMap, @AssignNonExistsingItem);
AssertException('autocreate false does not throw exception', EutlInvalidOperation, @AssignNonExistsingItem);
fIntMap.AutoCreate := true;
AssignNonExistsingItem;
end;


+ 80
- 25
uutlAlgorithm.pas View File

@@ -10,14 +10,14 @@ uses

type
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlBinarySearch<T> = class(TObject)
generic TutlBinarySearch<T> = class
public type
IReadOnlyIndexer = specialize IutlReadOnlyIndexer<T>;
IComparer = specialize IutlComparer<T>;
IReadOnlyArray = specialize IutlReadOnlyArray<T>;
IComparer = specialize IutlComparer<T>;

private
class function DoSearch(
constref aIndexer: IReadOnlyIndexer;
constref aArray: IReadOnlyArray;
constref aComparer: IComparer;
const aMin: Integer;
const aMax: Integer;
@@ -25,38 +25,43 @@ type
out aIndex: Integer): Boolean;

public
// search aItem in aIndexer using aComparer
// search aItem in aList using aComparer
// aList needs to bee sorted
// aIndex is the index the item was found or should be inserted
// returns TRUE when found, FALSE otherwise
class function Search(
constref aIndexer: IReadOnlyIndexer;
constref aArray: IReadOnlyArray;
constref aComparer: IComparer;
constref aItem: T;
out aIndex: Integer): Boolean;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function Supports(const aInstance: TObject; const aClass: TClass; out aObj): Boolean; overload;
generic TutlQuickSort<T> = class
public type
IArray = specialize IutlArray<T>;
IComparer = specialize IutlComparer<T>;

implementation
private
class procedure DoSort(
constref aArray: IArray;
constref aComparer: IComparer;
aLow: Integer;
aHigh: Integer);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function Supports(const aInstance: TObject; const aClass: TClass; out aObj): Boolean;
begin
result := Assigned(aInstance) and aInstance.InheritsFrom(aClass);
if result then
TObject(aObj) := aInstance
else
TObject(aObj) := nil;
end;
public
class procedure Sort(
constref aArray: IArray;
constref aComparer: IComparer);
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlBinarySearch//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlBinarySearch.DoSearch(
constref aIndexer: IReadOnlyIndexer;
constref aArray: IReadOnlyArray;
constref aComparer: IComparer;
const aMin: Integer;
const aMax: Integer;
@@ -67,14 +72,14 @@ var
begin
if (aMin <= aMax) then begin
i := aMin + Trunc((aMax - aMin) / 2);
cmp := aComparer.Compare(aItem, aIndexer.Items[i]);
cmp := aComparer.Compare(aItem, aArray[i]);
if (cmp = 0) then begin
result := true;
aIndex := i;
end else if (cmp < 0) then
result := DoSearch(aIndexer, aComparer, aMin, i-1, aItem, aIndex)
result := DoSearch(aArray, aComparer, aMin, i-1, aItem, aIndex)
else if (cmp > 0) then
result := DoSearch(aIndexer, aComparer, i+1, aMax, aItem, aIndex);
result := DoSearch(aArray, aComparer, i+1, aMax, aItem, aIndex);
end else begin
result := false;
aIndex := aMin;
@@ -83,12 +88,62 @@ end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlBinarySearch.Search(
constref aIndexer: IReadOnlyIndexer;
constref aArray: IReadOnlyArray;
constref aComparer: IComparer;
constref aItem: T;
out aIndex: Integer): Boolean;
begin
result := DoSearch(aIndexer, aComparer, 0, aIndexer.Count-1, aItem, aIndex);
result := DoSearch(aArray, aComparer, 0, aArray.Count-1, aItem, aIndex);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlQuickSort/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class procedure TutlQuickSort.DoSort(
constref aArray: IArray;
constref aComparer: IComparer;
aLow: Integer;
aHigh: Integer);
var
lo, hi: Integer;
p, tmp: T;
begin
repeat
lo := aLow;
hi := aHigh;
p := aArray[(aLow + aHigh) div 2];
repeat
while (aComparer.Compare(p, aArray[lo]) > 0) do
lo := lo + 1;
while (aComparer.Compare(p, aArray[hi]) < 0) do
hi := hi - 1;
if (lo <= hi) then begin
tmp := aArray[lo];
aArray[lo] := aArray[hi];
aArray[hi] := tmp;
lo := lo + 1;
hi := hi - 1;
end;
until (lo > hi);

if (hi - aLow < aHigh - lo) then begin
if (aLow < hi) then
DoSort(aArray, aComparer, aLow, hi);
aLow := lo;
end else begin
if (lo < aHigh) then
DoSort(aArray, aComparer, lo, aHigh);
aHigh := hi;
end;
until (aLow >= aHigh);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class procedure TutlQuickSort.Sort(
constref aArray: IArray;
constref aComparer: IComparer);
begin
DoSort(aArray, aComparer, 0, aArray.GetCount-1);
end;

end.


+ 138
- 0
uutlArrayContainer.pas View File

@@ -0,0 +1,138 @@
unit uutlArrayContainer;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils,
uutlCommon;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlArrayContainer<T> = class(TutlInterfaceNoRefCount)
protected type
PT = ^T;

strict private
fList: PT;
fCapacity: Integer;
fOwnsItems: Boolean;
fCanShrink: Boolean;
fCanExpand: Boolean;

function GetIsEmpty: Boolean; inline;

protected
function GetCount: Integer; virtual; abstract;
procedure SetCount (const aValue: Integer); virtual; abstract;
function GetInternalItem (const aIndex: Integer): PT;
procedure SetCapacity (const aValue: integer); virtual;

procedure Release (var aItem: T; const aFreeItem: Boolean); virtual;

procedure Shrink (const aExactFit: Boolean);
procedure Expand;

protected
property Count: Integer read GetCount write SetCount;
property IsEmpty: Boolean read GetIsEmpty;
property Capacity: Integer read fCapacity write SetCapacity;
property CanShrink: Boolean read fCanShrink write fCanShrink;
property CanExpand: Boolean read fCanExpand write fCanExpand;
property OwnsItems: Boolean read fOwnsItems write fOwnsItems;

public
constructor Create(const aOwnsItems: Boolean);
destructor Destroy; override;
end;

implementation

uses
uutlExceptions;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlArrayContainer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayContainer.GetIsEmpty: Boolean;
begin
result := (Count = 0);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayContainer.GetInternalItem(const aIndex: Integer): PT;
begin
if (aIndex < 0) or (aIndex >= fCapacity) then
raise EutlOutOfRange.Create('capacity out of range', aIndex, 0, fCapacity-1);
result := fList + aIndex;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayContainer.SetCapacity(const aValue: integer);
begin
if (fCapacity = aValue) then
exit;
if (aValue < Count) then
raise EutlArgument.Create('can not reduce capacity below count', 'Capacity');
ReAllocMem(fList, aValue * SizeOf(T));
FillByte((fList + fCapacity)^, (aValue - fCapacity) * SizeOf(T), 0);
fCapacity := aValue;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayContainer.Release(var aItem: T; const aFreeItem: Boolean);
begin
utlFinalizeObject(aItem, TypeInfo(aItem), fOwnsItems and aFreeItem);
FillByte(aItem, SizeOf(aItem), 0);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayContainer.Shrink(const aExactFit: Boolean);
begin
if not fCanShrink then
raise EutlInvalidOperation.Create('shrinking is not allowed');
if (aExactFit) then
SetCapacity(Count)
else if (fCapacity > 128) and (Count < fCapacity shr 2) then // less than 25% used
SetCapacity(fCapacity shr 1); // shrink to 50%
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayContainer.Expand;
begin
if (Count < fCapacity) then
exit;
if not fCanExpand then
raise EutlInvalidOperation.Create('expanding is not allowed');
if (fCapacity <= 0) then
SetCapacity(4)
else if (fCapacity < 128) then
SetCapacity(fCapacity shl 1) // + 100%
else
SetCapacity(fCapacity + fCapacity shr 2); // + 25%
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlArrayContainer.Create(const aOwnsItems: Boolean);
begin
inherited Create;
fOwnsItems := aOwnsItems;
fList := nil;
fCapacity := 0;
fCanExpand := true;
fCanShrink := true;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TutlArrayContainer.Destroy;
begin
if Assigned(fList) then begin
FreeMem(fList);
fList := nil;
end;
inherited Destroy;
end;

end.


+ 39
- 1
uutlCommon.pas View File

@@ -5,7 +5,7 @@ unit uutlCommon;
interface

uses
Classes, SysUtils;
Classes, SysUtils, typinfo;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -22,8 +22,46 @@ type
property RefCount: LongInt read fRefCount;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure utlFinalizeObject(var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean);

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Helper Methods////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure utlFinalizeObject(var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean);
var
o: TObject;
begin
case aTypeInfo^.Kind of
tkClass: begin
if (aFreeObject) then begin
o := TObject(obj);
Pointer(obj) := nil;
if Assigned(o) then
o.Free;
end;
end;

tkInterface: begin
IUnknown(obj) := nil;
end;

tkAString: begin
AnsiString(Obj) := '';
end;

tkUString: begin
UnicodeString(Obj) := '';
end;

tkString: begin
String(Obj) := '';
end;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlInterfaceNoRefCount///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 224
- 0
uutlComparer.pas View File

@@ -0,0 +1,224 @@
unit uutlComparer;

{$mode objfpc}{$H+}
{$modeswitch nestedprocvars}

interface

uses
Classes, SysUtils,
uutlInterfaces;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlEqualityComparer<T> = class(
TInterfacedObject,
specialize IutlEqualityComparer<T>)

public
function EqualityCompare(constref i1, i2: T): Boolean;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlEqualityCompareEvent<T> = function(constref i1, i2: T): Boolean;
generic TutlEqualityCompareEventO<T> = function(constref i1, i2: T): Boolean of object;
generic TutlEqualityCompareEventN<T> = function(constref i1, i2: T): Boolean is nested;

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

private type
TEqualityCompareEventType = (eetNormal, eetObject, eetNested);

public type
TCompareEvent = specialize TutlEqualityCompareEvent<T>;
TCompareEventO = specialize TutlEqualityCompareEventO<T>;
TCompareEventN = specialize TutlEqualityCompareEventN<T>;

strict private
fType: TEqualityCompareEventType;
fEvent: TCompareEvent;
fEventO: TCompareEventO;
fEventN: TCompareEventN;

public
function EqualityCompare(constref i1, i2: T): Boolean;

{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
constructor Create(const aEvent: TCompareEvent); overload;
constructor Create(const aEvent: TCompareEventO); overload;
constructor Create(const aEvent: TCompareEventN); overload;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlComparer<T> = class(
specialize TutlEqualityComparer<T>,
specialize IutlEqualityComparer<T>,
specialize IutlComparer<T>)

public
function Compare(constref i1, i2: T): Integer;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlCompareEvent<T> = function(constref i1, i2: T): Integer;
generic TutlCompareEventO<T> = function(constref i1, i2: T): Integer of object;
generic TutlCompareEventN<T> = function(constref i1, i2: T): Integer is nested;

generic TutlCallbackComparer<T> = class(
TInterfacedObject,
specialize IutlEqualityComparer<T>,
specialize IutlComparer<T>)

private type
TCompareEventType = (cetNormal, cetObject, cetNested);

public type
TCompareEvent = specialize TutlCompareEvent<T>;
TCompareEventO = specialize TutlCompareEventO<T>;
TCompareEventN = specialize TutlCompareEventN<T>;

strict private
fType: TCompareEventType;
fEvent: TCompareEvent;
fEventO: TCompareEventO;
fEventN: TCompareEventN;

public
function Compare(constref i1, i2: T): Integer;
function EqualityCompare(constref i1, i2: T): Boolean;

{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
constructor Create(const aEvent: TCompareEvent); overload;
constructor Create(const aEvent: TCompareEventO); overload;
constructor Create(const aEvent: TCompareEventN); overload;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator <(const i1, i2: TObject): Boolean; inline;
operator >(const i1, i2: TObject): Boolean; inline;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator <(const i1, i2: TObject): Boolean; inline;
begin
result := Pointer(i1) < Pointer(i2);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator >(const i1, i2: TObject): Boolean; inline;
begin
result := Pointer(i1) > Pointer(i2);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEqualityComparer.EqualityCompare(constref i1, i2: T): Boolean;
begin
result := (i1 = i2);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCalbackEqualityComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCalbackEqualityComparer.EqualityCompare(constref i1, i2: T): Boolean;
begin
result := false;
case fType of
eetNormal: result := fEvent (i1, i2);
eetObject: result := fEventO(i1, i2);
eetNested: result := fEventN(i1, i2);
else
raise Exception.Create('invalid or unknown callback type');
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEvent);
begin
inherited Create;
fType := eetNormal;
fEvent := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEventO);
begin
inherited Create;
fType := eetObject;
fEventO := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackEqualityComparer.Create(const aEvent: TCompareEventN);
begin
inherited Create;
fType := eetNested;
fEventN := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlComparer.Compare(constref i1, i2: T): Integer;
begin
if (i1 < i2) then
result := -1
else if (i1 > i2) then
result := 1
else
result := 0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCallbackComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCallbackComparer.Compare(constref i1, i2: T): Integer;
begin
result := 0;
case fType of
cetNormal: result := fEvent (i1, i2);
cetObject: result := fEventO(i1, i2);
cetNested: result := fEventN(i1, i2);
else
raise Exception.Create('invalid or unknown callback type');
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCallbackComparer.EqualityCompare(constref i1, i2: T): Boolean;
begin
result := (Compare(i1, i2) = 0);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCallbackComparer.Create(const aEvent: TCompareEvent);
begin
inherited Create;
fType := cetNormal;
fEvent := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCallbackComparer.Create(const aEvent: TCompareEventO);
begin
inherited Create;
fType := cetObject;
fEventO := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCallbackComparer.Create(const aEvent: TCompareEventN);
begin
inherited Create;
fType := cetNested;
fEventN := aEvent;
end;

end.


+ 515
- 0
uutlEnumerator.pas View File

@@ -0,0 +1,515 @@
unit uutlEnumerator;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils,
uutlInterfaces;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlEnumerator<T> = class(
TInterfacedObject,
specialize IutlEnumerator<T>)

public type
IEnumerator = specialize IutlEnumerator<T>;
IFilter = specialize IutlFilter<T>;
TArray = specialize TGenericArray<T>;

public { IEnumerator }
function GetCurrent: T; virtual; abstract;
function MoveNext: Boolean; virtual; abstract;
procedure Reset; virtual; abstract;

public { IutlEnumerator }
function GetEnumerator: IEnumerator; virtual;

function Count: Integer; virtual;

function Reverse: IEnumerator; virtual;
function Skip (const aCount: Integer): IEnumerator; virtual;
function Take (const aCount: Integer): IEnumerator; virtual;
function Where(const aFilter: IFilter): IEnumerator; virtual;

function ToArray: TArray; virtual;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlMemoryEnumerator<T> = class(
specialize TutlEnumerator<T>)

public type
PT = ^T;

strict private
fReverse: Boolean;
fMemory: PT;
fCurrent: Integer;
fCount: Integer;

public { IEnumerator }
function GetCurrent: T; override;
function MoveNext: Boolean; override;
procedure Reset; override;

public { IutlEnumerator }
function Count: Integer; override;
function Reverse: IEnumerator; override;

public
constructor Create(const aMemory: PT; const aCount: Integer); overload;
constructor Create(const aMemory: PT; const aCount: Integer; const aReverse: Boolean); overload;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlArrayEnumerator<T> = class(
specialize TutlEnumerator<T>)

strict private
fArray: TArray;
fReverse: Boolean;
fCurrent: Integer;
fFirst: Integer;
fLast: Integer;

public { IEnumerator }
function GetCurrent: T; override;
function MoveNext: Boolean; override;
procedure Reset; override;

public { IutlEnumerator }
function Count: Integer; override;

function Reverse: IEnumerator; override;
function Skip(const aCount: Integer): IEnumerator; override;
function Take(const aCount: Integer): IEnumerator; override;

function ToArray: TArray; override;

public
constructor Create(
const aArray: TArray); overload;
constructor Create(
const aArray: TArray;
const aReverse: Boolean;
const aFirst: Integer;
const aLast: Integer); overload;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlSkipTakeEnumerator<T> = class(
specialize TutlEnumerator<T>)

strict private
fEnumerator: IEnumerator;
fSkip: Integer; // greater than 0: skip X; lower than 0: skip none
fTake: Integer; // greater than 0: take X; lower than 0: take all
fCurrentSkip: Integer;
fCurrentTake: Integer;

public { IEnumerator }
function GetCurrent: T; override;
function MoveNext: Boolean; override;
procedure Reset; override;

public
constructor Create(const aEnumerator: IEnumerator; const aSkip: Integer; const aTake: Integer);
destructor Destroy; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlWhereEnumerator<T> = class(
specialize TutlEnumerator<T>)

strict private
fEnumerator: IEnumerator;
fFilter: IFilter;

public { IEnumerator }
function GetCurrent: T; override;
function MoveNext: Boolean; override;
procedure Reset; override;

public
constructor Create(const aEnumerator: IEnumerator; const aFilter: IFilter);
destructor Destroy; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlSelectEnumerator<Tin, Tout> = class(
specialize TutlEnumerator<Tout>)

public type
IInEnumerator = specialize IutlEnumerator<Tin>;
ISelector = specialize IutlSelector<Tin, Tout>;

strict private
fEnumerator: IInEnumerator;
fSelector: ISelector;

public { IEnumerator }
function GetCurrent: Tout; override;
function MoveNext: Boolean; override;
procedure Reset; override;

public
constructor Create(const aEnumerator: IInEnumerator; const aSelector: ISelector);
destructor Destroy; override;
end;

implementation

uses
uutlExceptions;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEnumerator.GetEnumerator: IEnumerator;
begin
result := self;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEnumerator.Reverse: IEnumerator;
var
arr: TArray;
begin
arr := ToArray;
result := specialize TutlArrayEnumerator<T>.Create(arr, true, low(arr), high(arr));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEnumerator.Skip(const aCount: Integer): IEnumerator;
begin
result := specialize TutlSkipTakeEnumerator<T>.Create(self, aCount, -1);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEnumerator.Take(const aCount: Integer): IEnumerator;
begin
result := specialize TutlSkipTakeEnumerator<T>.Create(self, -1, aCount);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEnumerator.Where(const aFilter: IFilter): IEnumerator;
begin
result := specialize TutlWhereEnumerator<T>.Create(self, aFilter);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEnumerator.ToArray: TArray;
var
i: Integer;
arr: array of T;
begin
i := 0;
SetLength(arr, i);
Reset;
while MoveNext do begin
inc(i);
SetLength(arr, i);
arr[i-1] := GetCurrent;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEnumerator.Count: Integer;
begin
result := 0;
Reset;
while MoveNext do
inc(result);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlMemoryEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlMemoryEnumerator.GetCurrent: T;
var
p: PT;
begin
if (fCurrent < 0) or (fCurrent >= fCount) then
raise EutlInvalidOperation.Create('enumerator is not initialized');
p := fMemory;
if fReverse
then inc(p, fCount - fCurrent - 1)
else inc(p, fCurrent);
result := p^;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlMemoryEnumerator.MoveNext: Boolean;
begin
inc(fCurrent);
result := (fCurrent < fCount);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlMemoryEnumerator.Reset;
begin
fCurrent := -1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlMemoryEnumerator.Count: Integer;
begin
result := fCount;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlMemoryEnumerator.Reverse: IEnumerator;
begin
result := TutlMemoryEnumerator.Create(fMemory, fCount, not fReverse);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlMemoryEnumerator.Create(const aMemory: PT; const aCount: Integer);
begin
Create(aMemory, aCount, false);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlMemoryEnumerator.Create(const aMemory: PT; const aCount: Integer; const aReverse: Boolean);
begin
inherited Create;
fMemory := aMemory;
fCount := aCount;
fReverse := aReverse;
fCurrent := -1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlArrayEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayEnumerator.GetCurrent: T;
begin
if (fCurrent < fFirst) or (fCurrent > fLast) then
raise EutlInvalidOperation.Create('enumerator is not initialized');
result := fArray[fCurrent];
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayEnumerator.MoveNext: Boolean;
begin
if fReverse
then dec(fCurrent)
else inc(fCurrent);
result := (fFirst <= fCurrent) and (fCurrent <= fLast);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlArrayEnumerator.Reset;
begin
if fReverse
then fCurrent := fLast + 1
else fCurrent := fFirst - 1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayEnumerator.Count: Integer;
begin
result := fLast - fFirst + 1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayEnumerator.Reverse: IEnumerator;
begin
result := specialize TutlArrayEnumerator<T>.Create(fArray, not fReverse, fFirst, fLast);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayEnumerator.Skip(const aCount: Integer): IEnumerator;
begin
if fReverse
then result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fFirst, fLast - aCount)
else result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fFirst + aCount, fLast);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayEnumerator.Take(const aCount: Integer): IEnumerator;
begin
if fReverse
then result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fLast - aCount + 1, fLast)
else result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fFirst, fFirst + aCount - 1);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlArrayEnumerator.ToArray: TArray;
var
i: Integer;
begin
SetLength(result, fLast - fFirst + 1);
if fReverse then begin
for i := fFirst to fLast do
result[i-fFirst] := fArray[i];
end else
System.Move(fArray[fFirst], result[0], Length(result));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlArrayEnumerator.Create(const aArray: TArray);
begin
Create(aArray, false, low(aArray), high(aArray));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlArrayEnumerator.Create(
const aArray: TArray;
const aReverse: Boolean;
const aFirst: Integer;
const aLast: Integer);
begin
inherited Create;
fArray := aArray;
fReverse := aReverse;
fFirst := aFirst;
fLast := aLast;

if (fFirst < low(fArray)) then
fFirst := low(fArray);
if (fLast > high(fArray)) then
fLast := high(fArray);

if fReverse
then fCurrent := fLast + 1
else fCurrent := fFirst - 1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlSkipTakeEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlSkipTakeEnumerator.GetCurrent: T;
begin
result := fEnumerator.Current;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlSkipTakeEnumerator.MoveNext: Boolean;
begin
while (fCurrentSkip > 0) and fEnumerator.MoveNext do
dec(fCurrentSkip);
result :=
(fCurrentSkip <= 0)
and (fCurrentTake <> 0)
and fEnumerator.MoveNext;

if (fCurrentTake > 0) then
dec(fCurrentTake);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlSkipTakeEnumerator.Reset;
begin
fEnumerator.Reset;
fCurrentSkip := fSkip;
fCurrentTake := fTake;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlSkipTakeEnumerator.Create(const aEnumerator: IEnumerator; const aSkip: Integer; const aTake: Integer);
begin
if not Assigned(aEnumerator) then
raise EutlArgumentNil.Create('aEnumerator');
inherited Create;
fEnumerator := aEnumerator;
fSkip := aSkip;
fTake := aTake;
fCurrentSkip := aSkip;
fCurrentTake := aTake;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TutlSkipTakeEnumerator.Destroy;
begin
fEnumerator := nil;
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlWhereEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlWhereEnumerator.GetCurrent: T;
begin
result := fEnumerator.Current;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlWhereEnumerator.MoveNext: Boolean;
begin
repeat
result := fEnumerator.MoveNext;
until not result or fFilter.Filter(fEnumerator.Current);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlWhereEnumerator.Reset;
begin
fEnumerator.Reset;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlWhereEnumerator.Create(const aEnumerator: IEnumerator; const aFilter: IFilter);
begin
if not Assigned(aEnumerator) then
raise EutlArgumentNil.Create('aEnumerator');
if not Assigned(aFilter) then
raise EutlArgumentNil.Create('aFilter');
inherited Create;
fEnumerator := aEnumerator;
fFilter := aFilter;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TutlWhereEnumerator.Destroy;
begin
fEnumerator := nil;
fFilter := nil;
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlSelectEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlSelectEnumerator.GetCurrent: Tout;
begin
result := fSelector.Select(fEnumerator.Current);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlSelectEnumerator.MoveNext: Boolean;
begin
result := fEnumerator.MoveNext;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlSelectEnumerator.Reset;
begin
fEnumerator.Reset;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlSelectEnumerator.Create(const aEnumerator: IInEnumerator; const aSelector: ISelector);
begin
if not Assigned(aEnumerator) then
raise EutlArgumentNil.Create('aEnumerator');
if not Assigned(aSelector) then
raise EutlArgumentNil.Create('aSelector');
inherited Create;
fEnumerator := aEnumerator;
fSelector := aSelector;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TutlSelectEnumerator.Destroy;
begin
fEnumerator := nil;
fSelector := nil;
inherited Destroy;
end;

end.


+ 3
- 0
uutlExceptions.pas View File

@@ -14,6 +14,9 @@ type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EutlInvalidOperation = class(Exception);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EutlNotSupported = class(Exception);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EutlOutOfRange = class(EutlException)
private


+ 157
- 0
uutlFilter.pas View File

@@ -0,0 +1,157 @@
unit uutlFilter;

{$mode objfpc}{$H+}
{$modeswitch nestedprocvars}

interface

uses
Classes, SysUtils,
uutlInterfaces;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlFilterEvent<T> = function(constref i: T): Boolean;
generic TutlFilterEventO<T> = function(constref i: T): Boolean of object;
generic TutlFilterEventN<T> = function(constref i: T): Boolean is nested;

generic TutlCalbackFilter<T> = class(
TInterfacedObject,
specialize IutlFilter<T>)

private type
TFilterEventType = (fetNormal, fetObject, fetNested);

public type
TFilterEvent = specialize TutlFilterEvent<T>;
TFilterEventO = specialize TutlFilterEventO<T>;
TFilterEventN = specialize TutlFilterEventN<T>;

strict private
fType: TFilterEventType;
fEvent: TFilterEvent;
fEventO: TFilterEventO;
fEventN: TFilterEventN;

public
function Filter(constref i: T): Boolean;

{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
constructor Create(const aEvent: TFilterEvent); overload;
constructor Create(const aEvent: TFilterEventO); overload;
constructor Create(const aEvent: TFilterEventN); overload;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlSelectEvent <Tin, Tout> = function(constref i: Tin): Tout;
generic TutlSelectEventO<Tin, Tout> = function(constref i: Tin): Tout of object;
generic TutlSelectEventN<Tin, Tout> = function(constref i: Tin): Tout is nested;

generic TutlCalbackSelector<Tin, Tout> = class(
TInterfacedObject,
specialize IutlSelector<Tin, Tout>)

private type
TSelectEventType = (setNormal, setObject, setNested);

public type
TSelectEvent = specialize TutlSelectEvent <Tin, Tout>;
TSelectEventO = specialize TutlSelectEventO<Tin, Tout>;
TSelectEventN = specialize TutlSelectEventN<Tin, Tout>;

strict private
fType: TSelectEventType;
fEvent: TSelectEvent;
fEventO: TSelectEventO;
fEventN: TSelectEventN;

public
function Select(constref i: Tin): Tout;

{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
constructor Create(const aEvent: TSelectEvent); overload;
constructor Create(const aEvent: TSelectEventO); overload;
constructor Create(const aEvent: TSelectEventN); overload;
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCalbackFilter/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCalbackFilter.Filter(constref i: T): Boolean;
begin
result := false;
case fType of
fetNormal: result := fEvent (i);
fetObject: result := fEventO(i);
fetNested: result := fEventN(i);
else
raise Exception.Create('invalid or unknown callback type');
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackFilter.Create(const aEvent: TFilterEvent);
begin
inherited Create;
fType := fetNormal;
fEvent := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackFilter.Create(const aEvent: TFilterEventO);
begin
inherited Create;
fType := fetObject;
fEventO := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackFilter.Create(const aEvent: TFilterEventN);
begin
inherited Create;
fType := fetNested;
fEventN := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlCalbackSelector///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlCalbackSelector.Select(constref i: Tin): Tout;
begin
case fType of
setNormal: result := fEvent (i);
setObject: result := fEventO(i);
setNested: result := fEventN(i);
else
raise Exception.Create('invalid or unknown callback type');
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackSelector.Create(const aEvent: TSelectEvent);
begin
inherited Create;
fType := setNormal;
fEvent := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackSelector.Create(const aEvent: TSelectEventO);
begin
inherited Create;
fType := setObject;
fEventO := aEvent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlCalbackSelector.Create(const aEvent: TSelectEventN);
begin
inherited Create;
fType := setNested;
fEventN := aEvent;
end;

end.


+ 323
- 787
uutlGenerics.pas
File diff suppressed because it is too large
View File


+ 41
- 149
uutlInterfaces.pas View File

@@ -1,7 +1,6 @@
unit uutlInterfaces;

{$mode objfpc}{$H+}
{$modeswitch nestedprocvars}

interface

@@ -10,181 +9,74 @@ uses

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlEqualityComparer<T> = interface
function EqualityCompare(const i1, i2: T): Boolean;
end;

generic TutlEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
public
function EqualityCompare(const i1, i2: T): Boolean;
end;

generic TutlEventEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
public type
TEqualityEvent = function(const i1, i2: T): Boolean;
TEqualityEventO = function(const i1, i2: T): Boolean of object;
TEqualityEventN = function(const i1, i2: T): Boolean is nested;
private type
TEqualityEventType = (eetNormal, eetObject, eetNested);
private
fEvent: TEqualityEvent;
fEventO: TEqualityEventO;
fEventN: TEqualityEventN;
fEventType: TEqualityEventType;
public
function EqualityCompare(const i1, i2: T): Boolean;
constructor Create(const aEvent: TEqualityEvent); overload;
constructor Create(const aEvent: TEqualityEventO); overload;
constructor Create(const aEvent: TEqualityEventN); overload;
{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
generic IutlEqualityComparer<T> = interface(IUnknown)
['{C0FB90CC-D071-490F-BFEE-BAA5C94D1A5B}']
function EqualityCompare(constref i1, i2: T): Boolean;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlComparer<T> = interface
function Compare(const i1, i2: T): Integer;
end;

generic TutlComparer<T> = class(TInterfacedObject, specialize IutlComparer<T>)
public
function Compare(const i1, i2: T): Integer;
end;

generic TutlEventComparer<T> = class(TInterfacedObject, specialize IutlComparer<T>)
public type
TEvent = function(const i1, i2: T): Integer;
TEventO = function(const i1, i2: T): Integer of object;
TEventN = function(const i1, i2: T): Integer is nested;
private type
TEventType = (etNormal, etObject, etNested);
private
fEvent: TEvent;
fEventO: TEventO;
fEventN: TEventN;
fEventType: TEventType;
public
function Compare(const i1, i2: T): Integer;
constructor Create(const aEvent: TEvent); overload;
constructor Create(const aEvent: TEventO); overload;
constructor Create(const aEvent: TEventN); overload;
{ HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
generic IutlComparer<T> = interface(specialize IutlEqualityComparer<T>)
['{7D2EC014-2878-4F60-9E43-4CFB54268995}']
function Compare(constref i1, i2: T): Integer;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlReadOnlyList<T> = interface(IUnknown)
function GetCount: Integer;
function GetItem(const aIndex: Integer): T;
generic IutlFilter<T> = interface(IUnknown)
function Filter(constref i: T): Boolean;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic IutlList<T> = interface(specialize IutlReadOnlyList<T>)
procedure SetItem(const aIndex: Integer; const aItem: T);
generic IutlSelector<Tin, Tout> = interface(IUnknown)
function Select(constref i: Tin): Tout;
end;

operator < (const i1, i2: TObject): Boolean; inline;
operator > (const i1, i2: TObject): Boolean; inline;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator < (const i1, i2: TObject): Boolean;
begin
result := Pointer(i1) < Pointer(i2);
end;
generic TGenericArray<T> = array of T;
generic IutlEnumerator<T> = interface(specialize IEnumerator<T>)
function GetEnumerator: specialize IutlEnumerator<T>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
operator > (const i1, i2: TObject): Boolean;
begin
result := Pointer(i1) > Pointer(i2);
end;
function Count: Integer;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
begin
result := (i1 = i2);
end;
function Reverse: specialize IutlEnumerator<T>;
function Skip (const aCount: Integer): specialize IutlEnumerator<T>;
function Take (const aCount: Integer): specialize IutlEnumerator<T>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEventEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
begin
case fEventType of
eetNormal: result := fEvent(i1, i2);
eetObject: result := fEventO(i1, i2);
eetNested: result := fEventN(i1, i2);
end;
end;
function Where (const aComparer: specialize IutlFilter<T>): specialize IutlEnumerator<T>;
// TODO generic function Select<S> (const aSelector: specialize IutlSelector<T, S>): specialize IutlEnumerator<S>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEvent);
begin
inherited Create;
fEvent := aEvent;
fEventType := eetNormal;
end;
function ToArray: specialize TGenericArray<T>;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventO);
begin
inherited Create;
fEventO := aEvent;
fEventType := eetObject;
end;
generic IutlEnumerable<T> = interface(specialize IEnumerable<T>)
['{963214EB-EF7C-4785-8B48-8DD9DE0ABDAF}']
function GetUtlEnumerator: specialize IutlEnumerator<T>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventN);
begin
inherited Create;
fEventN := aEvent;
fEventType := eetNested;
end;
property UtlEnumerator: specialize IutlEnumerator<T> read GetUtlEnumerator;
property Enumerator: specialize IEnumerator<T> read GetEnumerator;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlComparer.Compare(const i1, i2: T): Integer;
begin
if (i1 < i2) then
result := -1
else if (i1 > i2) then
result := 1
else
result := 0;
end;
generic IutlReadOnlyArray<T> = interface(IUnknown)
['{B0938B6F-4E0D-45E3-A813-056AD4C0A2F2}']
function GetCount: Integer;
function GetItem(const aIndex: Integer): T;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlEventComparer.Compare(const i1, i2: T): Integer;
begin
case fEventType of
etNormal: result := fEvent(i1, i2);
etObject: result := fEventO(i1, i2);
etNested: result := fEventN(i1, i2);
property Count: Integer read GetCount;
property Items[const aIndex: Integer]: T read GetItem; default;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlEventComparer.Create(const aEvent: TEvent);
begin
inherited Create;
fEvent := aEvent;
fEventType := etNormal;
end;
generic IutlArray<T> = interface(specialize IutlReadOnlyArray<T>)
['{D3618E88-3BF7-4E63-850F-6893A334564A}']
procedure SetCount(const aValue: Integer);
procedure SetItem(const aIndex: Integer; aItem: T);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlEventComparer.Create(const aEvent: TEventO);
begin
inherited Create;
fEventO := aEvent;
fEventType := etObject;
end;
property Count: Integer read GetCount write SetCount;
property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlEventComparer.Create(const aEvent: TEventN);
begin
inherited Create;
fEventN := aEvent;
fEventType := etNested;
end;
implementation

end.


+ 166
- 0
uutlListBase.pas View File

@@ -0,0 +1,166 @@
unit uutlListBase;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils,
uutlArrayContainer, uutlInterfaces;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlListBase<T> = class(
specialize TutlArrayContainer<T>,
specialize IutlEnumerable<T>)
strict private
fCount: Integer;

protected
function GetCount: Integer; override;
procedure SetCount(const aValue: Integer); override;

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

procedure InsertIntern(const aIndex: Integer; constref aValue: T); virtual;
procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean); virtual;

public { IutlEnumerable }
function GetEnumerator: specialize IEnumerator<T>;
function GetUtlEnumerator: specialize IutlEnumerator<T>;

public
property Count;
property IsEmpty;
property Capacity;
property CanShrink;
property CanExpand;
property OwnsItems;

procedure Clear;
procedure ShrinkToFit;

constructor Create(const aOwnsItems: Boolean);
destructor Destroy; override;
end;

implementation

uses
uutlExceptions;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.GetCount: Integer;
begin
result := fCount;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.SetCount(const aValue: Integer);
begin
if (aValue < Capacity) then
Capacity := aValue;
fCount := aValue;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.GetItem(const aIndex: Integer): T;
begin
if (aIndex < 0) or (aIndex >= Count) then
raise EutlOutOfRange.Create(aIndex, 0, Count-1);
result := GetInternalItem(aIndex)^;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.SetItem(const aIndex: Integer; aValue: T);
var
p: PT;
begin
if (aIndex < 0) or (aIndex >= Count) then
raise EutlOutOfRange.Create(aIndex, 0, Count-1);
p := GetInternalItem(aIndex);
Release(p^, true);
p^ := aValue;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.InsertIntern(const aIndex: Integer; constref aValue: T);
var
p: PT;
begin
if (aIndex < 0) or (aIndex > fCount) then
raise EutlOutOfRange.Create(aIndex, 0, fCount);
if (fCount = Capacity) then
Expand;
p := GetInternalItem(aIndex);
if (aIndex < fCount) then
System.Move(p^, (p+1)^, (fCount - aIndex) * SizeOf(T));
p^ := aValue;
inc(fCount);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean);
var
p: PT;
begin
if (aIndex < 0) or (aIndex >= fCount) then
raise EutlOutOfRange.Create(aIndex, 0, fCount-1);
dec(fCount);
p := GetInternalItem(aIndex);
Release(p^, aFreeItem);
System.Move((p+1)^, p^, SizeOf(T) * (fCount - aIndex));
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);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.GetEnumerator: specialize IEnumerator<T>;
begin
result := GetUtlEnumerator;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlListBase.GetUtlEnumerator: specialize IutlEnumerator<T>;
begin
// TODO
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.Clear;
begin
while (Count > 0) do begin
dec(fCount);
Release(GetInternalItem(fCount)^, true);
end;
fCount := 0;
if CanShrink then
ShrinkToFit;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlListBase.ShrinkToFit;
begin
Shrink(true);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlListBase.Create(const aOwnsItems: Boolean);
begin
inherited Create(aOwnsItems);
fCount := 0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TutlListBase.Destroy;
begin
Clear;
inherited Destroy;
end;

end.


Loading…
Cancel
Save