Browse Source

* generic set helpers

* some bug fixes
master
bergmann 7 years ago
parent
commit
2fc379f883
7 changed files with 473 additions and 175 deletions
  1. +5
    -4
      tests/tests.lpi
  2. +2
    -2
      tests/tests.lpr
  3. +160
    -147
      tests/tests.lps
  4. +76
    -0
      tests/uutlSetHelperTests.pas
  5. +71
    -8
      uutlCommon.pas
  6. +12
    -4
      uutlEnumerator.pas
  7. +147
    -10
      uutlGenerics.pas

+ 5
- 4
tests/tests.lpi View File

@@ -37,7 +37,7 @@
<PackageName Value="FCL"/>
</Item3>
</RequiredPackages>
<Units Count="37">
<Units Count="38">
<Unit0>
<Filename Value="tests.lpr"/>
<IsPartOfProject Value="True"/>
@@ -186,6 +186,10 @@
<Filename Value="uutlObservableMapTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit36>
<Unit37>
<Filename Value="uutlSetHelperTests.pas"/>
<IsPartOfProject Value="True"/>
</Unit37>
</Units>
</ProjectOptions>
<CompilerOptions>
@@ -214,9 +218,6 @@
<CompilerMessages>
<IgnoredMessages idx5024="True"/>
</CompilerMessages>
<CustomOptions Value="-dUTL_ADVANCED_ENUMERATORS
-dUTL_NESTED_PROCVARS
-dUTL_ENUMERATORS"/>
<OtherDefines Count="3">
<Define0 Value="UTL_ADVANCED_ENUMERATORS"/>
<Define1 Value="UTL_NESTED_PROCVARS"/>


+ 2
- 2
tests/tests.lpr View File

@@ -9,7 +9,7 @@ uses
// test cases
uutlAlgorithmTests, uutlEnumeratorTests, uutlHashSetTests, uutlLinqTests,
uutlListTest, uutlMapTests, uutlQueueTests, uutlStackTests, uutlObservableListTests,
uutlObservableHashSetTests, uutlObservableMapTests
uutlObservableHashSetTests, uutlObservableMapTests,

// test misc
uTestHelper,
@@ -17,7 +17,7 @@ uses
// units unter test
uutlAlgorithm, uutlArrayContainer, uutlCommon, uutlComparer, uutlEnumerator,
uutlFilter, uutlGenerics, uutlInterfaces, uutlLinq, uutlListBase, uutlLogger,
uutlStreamHelper, uutlSyncObjs, uutlTypes, uutlXmlHelper, uutlObservable;
uutlStreamHelper, uutlSyncObjs, uutlTypes, uutlXmlHelper, uutlObservable, uutlSetHelperTests;

{$R *.res}



+ 160
- 147
tests/tests.lps View File

@@ -4,47 +4,43 @@
<PathDelim Value="\"/>
<Version Value="9"/>
<BuildModes Active="Default"/>
<Units Count="62">
<Units Count="65">
<Unit0>
<Filename Value="tests.lpr"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="13"/>
<CursorPos X="33" Y="13"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="54" Y="12"/>
<UsageCount Value="78"/>
</Unit0>
<Unit1>
<Filename Value="..\uutlGenerics.pas"/>
<IsPartOfProject Value="True"/>
<TopLine Value="315"/>
<CursorPos X="5" Y="331"/>
<UsageCount Value="75"/>
<TopLine Value="1668"/>
<CursorPos Y="1692"/>
<UsageCount Value="78"/>
<Loaded Value="True"/>
</Unit1>
<Unit2>
<Filename Value="..\uutlArrayContainer.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="11"/>
<EditorIndex Value="-1"/>
<CursorPos X="11" Y="13"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
<UsageCount Value="78"/>
</Unit2>
<Unit3>
<Filename Value="..\uutlCommon.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="16"/>
<TopLine Value="44"/>
<CursorPos X="3" Y="59"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
<EditorIndex Value="-1"/>
<TopLine Value="206"/>
<CursorPos X="10" Y="225"/>
<UsageCount Value="78"/>
</Unit3>
<Unit4>
<Filename Value="..\uutlListBase.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="2"/>
<EditorIndex Value="-1"/>
<CursorPos X="26" Y="24"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
<UsageCount Value="78"/>
</Unit4>
<Unit5>
<Filename Value="uutlListTest.pas"/>
@@ -53,63 +49,61 @@
<WindowIndex Value="1"/>
<TopLine Value="357"/>
<CursorPos X="7" Y="376"/>
<UsageCount Value="75"/>
<UsageCount Value="78"/>
</Unit5>
<Unit6>
<Filename Value="uutlQueueTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="12"/>
<EditorIndex Value="-1"/>
<TopLine Value="250"/>
<CursorPos X="49" Y="260"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
<UsageCount Value="78"/>
</Unit6>
<Unit7>
<Filename Value="uutlStackTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="6"/>
<EditorIndex Value="-1"/>
<TopLine Value="246"/>
<CursorPos X="24" Y="263"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
<UsageCount Value="78"/>
</Unit7>
<Unit8>
<Filename Value="uTestHelper.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="3" Y="12"/>
<UsageCount Value="75"/>
<UsageCount Value="78"/>
</Unit8>
<Unit9>
<Filename Value="..\uutlComparer.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="90" Y="6"/>
<UsageCount Value="65"/>
<UsageCount Value="68"/>
</Unit9>
<Unit10>
<Filename Value="..\uutlAlgorithm.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="5"/>
<EditorIndex Value="-1"/>
<TopLine Value="138"/>
<CursorPos Y="153"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
<UsageCount Value="78"/>
</Unit10>
<Unit11>
<Filename Value="uutlHashSetTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<CursorPos X="32" Y="13"/>
<UsageCount Value="75"/>
<UsageCount Value="78"/>
</Unit11>
<Unit12>
<Filename Value="uutlAlgorithmTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<EditorIndex Value="4"/>
<TopLine Value="72"/>
<CursorPos X="43" Y="87"/>
<UsageCount Value="74"/>
<UsageCount Value="77"/>
<Loaded Value="True"/>
</Unit12>
<Unit13>
<Filename Value="uutlMapTests.pas"/>
@@ -117,26 +111,24 @@
<EditorIndex Value="-1"/>
<TopLine Value="206"/>
<CursorPos X="66" Y="221"/>
<UsageCount Value="73"/>
<UsageCount Value="76"/>
</Unit13>
<Unit14>
<Filename Value="..\uutlEnumerator.pas"/>
<IsPartOfProject Value="True"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="7"/>
<TopLine Value="323"/>
<CursorPos X="42" Y="338"/>
<UsageCount Value="72"/>
<EditorIndex Value="3"/>
<TopLine Value="122"/>
<CursorPos X="86" Y="124"/>
<UsageCount Value="75"/>
<Loaded Value="True"/>
</Unit14>
<Unit15>
<Filename Value="uutlEnumeratorTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="9"/>
<EditorIndex Value="-1"/>
<TopLine Value="49"/>
<CursorPos X="8" Y="66"/>
<UsageCount Value="72"/>
<Loaded Value="True"/>
<UsageCount Value="75"/>
</Unit15>
<Unit16>
<Filename Value="..\uutlFilter.pas"/>
@@ -144,16 +136,15 @@
<EditorIndex Value="-1"/>
<TopLine Value="17"/>
<CursorPos X="13" Y="159"/>
<UsageCount Value="68"/>
<UsageCount Value="71"/>
</Unit16>
<Unit17>
<Filename Value="..\uutlInterfaces.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="17"/>
<EditorIndex Value="-1"/>
<TopLine Value="22"/>
<CursorPos X="11" Y="37"/>
<UsageCount Value="68"/>
<Loaded Value="True"/>
<UsageCount Value="71"/>
</Unit17>
<Unit18>
<Filename Value="..\uutlLinq.pas"/>
@@ -162,23 +153,21 @@
<WindowIndex Value="-1"/>
<TopLine Value="31"/>
<CursorPos X="3" Y="52"/>
<UsageCount Value="59"/>
<UsageCount Value="62"/>
</Unit18>
<Unit19>
<Filename Value="uutlLinqTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="8"/>
<EditorIndex Value="-1"/>
<TopLine Value="558"/>
<CursorPos X="61" Y="570"/>
<UsageCount Value="59"/>
<Loaded Value="True"/>
<UsageCount Value="62"/>
</Unit19>
<Unit20>
<Filename Value="..\uutlTypes.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="18"/>
<UsageCount Value="59"/>
<Loaded Value="True"/>
<EditorIndex Value="-1"/>
<UsageCount Value="62"/>
</Unit20>
<Unit21>
<Filename Value="..\uutlSyncObjs.pas"/>
@@ -186,7 +175,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="241"/>
<CursorPos X="20" Y="263"/>
<UsageCount Value="53"/>
<UsageCount Value="56"/>
</Unit21>
<Unit22>
<Filename Value="..\uutlLogger.pas"/>
@@ -194,7 +183,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="419"/>
<CursorPos X="55" Y="434"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit22>
<Unit23>
<Filename Value="..\uutlXmlHelper.pas"/>
@@ -202,7 +191,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="188"/>
<CursorPos X="26" Y="203"/>
<UsageCount Value="52"/>
<UsageCount Value="55"/>
</Unit23>
<Unit24>
<Filename Value="..\uutlStreamHelper.pas"/>
@@ -210,7 +199,7 @@
<EditorIndex Value="-1"/>
<TopLine Value="216"/>
<CursorPos X="10" Y="241"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit24>
<Unit25>
<Filename Value="..\uutlCompression.pas"/>
@@ -219,7 +208,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit25>
<Unit26>
<Filename Value="..\uutlEmbeddedProfiler.pas"/>
@@ -228,7 +217,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit26>
<Unit27>
<Filename Value="..\uutlKeyCodes.pas"/>
@@ -237,7 +226,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit27>
<Unit28>
<Filename Value="..\uutlMCF.pas"/>
@@ -246,7 +235,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit28>
<Unit29>
<Filename Value="..\uutlSScanf.pas"/>
@@ -255,7 +244,7 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit29>
<Unit30>
<Filename Value="..\uutlThreads.pas"/>
@@ -264,15 +253,14 @@
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="51"/>
<UsageCount Value="54"/>
</Unit30>
<Unit31>
<Filename Value="..\uutlEvent.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="15"/>
<EditorIndex Value="-1"/>
<CursorPos X="11" Y="35"/>
<UsageCount Value="50"/>
<Loaded Value="True"/>
<UsageCount Value="53"/>
</Unit31>
<Unit32>
<Filename Value="..\uutlEventManager.pas"/>
@@ -280,16 +268,15 @@
<EditorIndex Value="-1"/>
<TopLine Value="246"/>
<CursorPos X="39" Y="264"/>
<UsageCount Value="50"/>
<UsageCount Value="53"/>
</Unit32>
<Unit33>
<Filename Value="..\uutlObservable.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="1"/>
<EditorIndex Value="-1"/>
<TopLine Value="556"/>
<CursorPos X="45" Y="572"/>
<UsageCount Value="50"/>
<Loaded Value="True"/>
<UsageCount Value="53"/>
</Unit33>
<Unit34>
<Filename Value="uutlObservableListTests.pas"/>
@@ -298,7 +285,7 @@
<WindowIndex Value="1"/>
<TopLine Value="49"/>
<CursorPos Y="65"/>
<UsageCount Value="42"/>
<UsageCount Value="45"/>
</Unit34>
<Unit35>
<Filename Value="uutlObservableHashSetTests.pas"/>
@@ -307,15 +294,14 @@
<WindowIndex Value="-1"/>
<TopLine Value="129"/>
<CursorPos Y="146"/>
<UsageCount Value="22"/>
<UsageCount Value="25"/>
</Unit35>
<Unit36>
<Filename Value="uutlObservableMapTests.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="3"/>
<EditorIndex Value="-1"/>
<CursorPos X="3" Y="13"/>
<UsageCount Value="21"/>
<Loaded Value="True"/>
<UsageCount Value="24"/>
</Unit36>
<Unit37>
<Filename Value="..\uutlExceptions.pas"/>
@@ -370,11 +356,10 @@
</Unit43>
<Unit44>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\objpas\objpas.pp"/>
<EditorIndex Value="10"/>
<EditorIndex Value="-1"/>
<TopLine Value="63"/>
<CursorPos X="20" Y="75"/>
<UsageCount Value="14"/>
<Loaded Value="True"/>
<UsageCount Value="15"/>
</Unit44>
<Unit45>
<Filename Value="G:\Eigene Datein\Projekte\_Active Projekte\TotoStarRedesign\utils\uutlAlgorithm.pas"/>
@@ -394,18 +379,17 @@
</Unit46>
<Unit47>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\FPCUnitCompatibleInterface.inc"/>
<EditorIndex Value="4"/>
<TopLine Value="90"/>
<CursorPos Y="105"/>
<UsageCount Value="15"/>
<EditorIndex Value="2"/>
<TopLine Value="54"/>
<CursorPos Y="69"/>
<UsageCount Value="16"/>
<Loaded Value="True"/>
</Unit47>
<Unit48>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\TestFramework.pas"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="1"/>
<TopLine Value="2692"/>
<CursorPos Y="2705"/>
<TopLine Value="2243"/>
<CursorPos Y="2258"/>
<UsageCount Value="10"/>
</Unit48>
<Unit49>
@@ -452,8 +436,8 @@
<Unit55>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\objpas\sysutils\sysutilh.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="97"/>
<CursorPos X="19" Y="112"/>
<TopLine Value="83"/>
<CursorPos X="4" Y="98"/>
<UsageCount Value="14"/>
</Unit55>
<Unit56>
@@ -486,11 +470,10 @@
</Unit59>
<Unit60>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\inc\objpash.inc"/>
<EditorIndex Value="14"/>
<EditorIndex Value="-1"/>
<TopLine Value="190"/>
<CursorPos X="23" Y="205"/>
<UsageCount Value="13"/>
<Loaded Value="True"/>
<UsageCount Value="14"/>
</Unit60>
<Unit61>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\objpas\sysutils\osutilsh.inc"/>
@@ -499,6 +482,30 @@
<CursorPos X="3" Y="62"/>
<UsageCount Value="12"/>
</Unit61>
<Unit62>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\win\wininc\struct.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="5662"/>
<CursorPos X="8" Y="5677"/>
<UsageCount Value="11"/>
</Unit62>
<Unit63>
<Filename Value="C:\Zusatzprogramme\Lazarus\fpc\3.1.1\source\rtl\win\wininc\base.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="448"/>
<CursorPos X="12" Y="463"/>
<UsageCount Value="11"/>
</Unit63>
<Unit64>
<Filename Value="uutlSetHelperTests.pas"/>
<IsPartOfProject Value="True"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="1"/>
<TopLine Value="44"/>
<CursorPos X="85" Y="69"/>
<UsageCount Value="21"/>
<Loaded Value="True"/>
</Unit64>
</Units>
<OtherDefines Count="3">
<Define0 Value="UTL_ADVANCED_ENUMERATORS"/>
@@ -508,133 +515,139 @@
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="514" TopLine="495"/>
<Caret Line="1672" TopLine="1660"/>
</Position1>
<Position2>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1125" TopLine="1092"/>
<Caret Line="1684" TopLine="1666"/>
</Position2>
<Position3>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="502" Column="32" TopLine="497"/>
<Caret Line="1685" TopLine="1666"/>
</Position3>
<Position4>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1134" TopLine="1110"/>
<Caret Line="1686" TopLine="1666"/>
</Position4>
<Position5>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="45" Column="15" TopLine="31"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1687" TopLine="1666"/>
</Position5>
<Position6>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1163" TopLine="1143"/>
<Caret Line="1689" TopLine="1666"/>
</Position6>
<Position7>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1123" Column="39" TopLine="1108"/>
<Filename Value="uutlSetHelperTests.pas"/>
<Caret Line="57" TopLine="41"/>
</Position7>
<Position8>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="44" Column="12" TopLine="31"/>
<Filename Value="uutlSetHelperTests.pas"/>
<Caret Line="52" Column="102" TopLine="44"/>
</Position8>
<Position9>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="45" Column="15" TopLine="31"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\FPCUnitCompatibleInterface.inc"/>
<Caret Line="69" TopLine="54"/>
</Position9>
<Position10>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="105" Column="39" TopLine="90"/>
<Filename Value="uutlSetHelperTests.pas"/>
<Caret Line="60" TopLine="44"/>
</Position10>
<Position11>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="197" Column="39" TopLine="179"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1684" TopLine="1656"/>
</Position11>
<Position12>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="220" Column="39" TopLine="203"/>
<Filename Value="C:\Zusatzprogramme\Lazarus\components\fptest\src\FPCUnitCompatibleInterface.inc"/>
<Caret Line="56" Column="13" TopLine="54"/>
</Position12>
<Position13>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="247" Column="39" TopLine="228"/>
<Caret Line="124" Column="86" TopLine="122"/>
</Position13>
<Position14>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="268" Column="3" TopLine="247"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1672" TopLine="1656"/>
</Position14>
<Position15>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="297" Column="5" TopLine="271"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1673" TopLine="1656"/>
</Position15>
<Position16>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="322" Column="39" TopLine="303"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1674" TopLine="1656"/>
</Position16>
<Position17>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="352" Column="5" TopLine="326"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1684" TopLine="1656"/>
</Position17>
<Position18>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="373" Column="39" TopLine="356"/>
<Filename Value="uutlSetHelperTests.pas"/>
<Caret Line="60" TopLine="44"/>
</Position18>
<Position19>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="286" Column="15" TopLine="271"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1672" TopLine="1656"/>
</Position19>
<Position20>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="524" Column="31" TopLine="509"/>
<Filename Value="uutlSetHelperTests.pas"/>
<Caret Line="59" Column="36" TopLine="44"/>
</Position20>
<Position21>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="542" Column="47" TopLine="521"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1672" TopLine="1665"/>
</Position21>
<Position22>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="1042" TopLine="1017"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1673" TopLine="1665"/>
</Position22>
<Position23>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="980" TopLine="973"/>
<Filename Value="uutlSetHelperTests.pas"/>
<Caret Line="57" TopLine="44"/>
</Position23>
<Position24>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="953" TopLine="925"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1673" TopLine="1665"/>
</Position24>
<Position25>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="897" TopLine="877"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1685" TopLine="1665"/>
</Position25>
<Position26>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="855" TopLine="833"/>
<Filename Value="uutlSetHelperTests.pas"/>
<Caret Line="53" Column="36" TopLine="44"/>
</Position26>
<Position27>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="813" TopLine="789"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1674" TopLine="1665"/>
</Position27>
<Position28>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="767" TopLine="744"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1686" TopLine="1665"/>
</Position28>
<Position29>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="726" TopLine="699"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1688" TopLine="1665"/>
</Position29>
<Position30>
<Filename Value="..\uutlEnumerator.pas"/>
<Caret Line="553" Column="65" TopLine="531"/>
<Filename Value="..\uutlGenerics.pas"/>
<Caret Line="1690" TopLine="1666"/>
</Position30>
</JumpHistory>
</ProjectSession>
<Debugging>
<BreakPointGroups Count="1">
<Item1>
<Name Value="1"/>
<InitialEnabled Value="False"/>
</Item1>
</BreakPointGroups>
<Watches Count="2">
<Item1>
<Expression Value="fCount"/>
<Expression Value="p+i"/>
</Item1>
<Item2>
<Expression Value="fLast"/>
<Expression Value="p + j"/>
</Item2>
</Watches>
</Debugging>


+ 76
- 0
tests/uutlSetHelperTests.pas View File

@@ -0,0 +1,76 @@
unit uutlSetHelperTests;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, TestFramework;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlSetHelperTests = class(TTestCase)
published
procedure ToString;
procedure TryToSet;
procedure Compare;
end;

implementation

uses
uutlGenerics;

type
TTestEnum = (
teTest0 = 0,
teTest1 = 1,
teTest2 = 2,
teTest3 = 3,
teTest4 = 4,
teTest5 = 5,
teTest8 = 8,
teTest9 = 9
);
TTestSet = set of TTestEnum;
TTestSetH = specialize TutlSetHelper<TTestEnum, TTestSet>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlSetHelperTests////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlSetHelperTests.ToString;
var
str: String;
begin
str := TTestSetH.ToString([teTest0, teTest1, teTest2, teTest3, teTest4, teTest8]);
AssertEquals('teTest0, teTest1, teTest2, teTest3, teTest4, teTest8', str);

str := TTestSetH.ToString([teTest0, teTest1, teTest2, teTest3, teTest4, teTest8], '_');
AssertEquals('teTest0_teTest1_teTest2_teTest3_teTest4_teTest8', str);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlSetHelperTests.TryToSet;
var
s: TTestSet;
begin
AssertTrue(TTestSetH.TryToSet('teTest0, teTest1, teTest2, teTest3, teTest8, teTest9', s));
AssertTrue([teTest0, teTest1, teTest2, teTest3, teTest8, teTest9] = s);

AssertTrue(TTestSetH.TryToSet('teTest0_asd_teTest1_asd_teTest2_asd_teTest3_asd_teTest8_asd_teTest9', '_asd_', s));
AssertTrue([teTest0, teTest1, teTest2, teTest3, teTest8, teTest9] = s);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlSetHelperTests.Compare;
begin
AssertEquals( 0, TTestSetH.Compare([teTest0, teTest1, teTest2], [teTest0, teTest1, teTest2]));
AssertEquals(-1, TTestSetH.Compare([ teTest1, teTest2], [teTest0, teTest1, teTest2]));
AssertEquals( 1, TTestSetH.Compare([teTest0, teTest1, teTest2], [teTest0, teTest2]));
end;

initialization
RegisterTest(TutlSetHelperTests.Suite);

end.


+ 71
- 8
uutlCommon.pas View File

@@ -79,9 +79,10 @@ type
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function Supports (const aInstance: TObject; const aClass: TClass; out aObj): Boolean;
function GetTickCount64 (): QWord;
function GetMicroTime (): QWord;
function Supports (const aInstance: TObject; const aClass: TClass; out aObj): Boolean;
function GetTickCount64 (): QWord;
function GetMicroTime (): QWord;
function GetPlatformIdentitfier(): String;

function utlRateLimited (const Reference: QWord; const Interval: QWord): boolean;
procedure utlFinalizeObject (var obj; const aTypeInfo: PTypeInfo; const aFreeObject: Boolean);
@@ -150,7 +151,7 @@ var
begin
pc := 0;
QueryPerformanceCounter(pc);
Result:= (pc * 1000*1000) div PERF_FREQ;
result := (pc * 1000*1000) div PERF_FREQ;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -186,6 +187,68 @@ begin
end;
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function GetPlatformIdentitfier: String;

{$IFDEF WINDOWS}
function GetWindowsVersionStr(const aDefault: String): string;
var
osv: TOSVERSIONINFO;
ver: cardinal;
begin
result := aDefault;
osv.dwOSVersionInfoSize := SizeOf(osv);
if GetVersionEx(osv) then begin
ver := MAKELONG(osv.dwMinorVersion, osv.dwMajorVersion);
// positive overflow: if system is newer, always detect as newest we knew instead of failing
if ver >= $000A0000 then
result := '10'
else if ver >= $00060003 then
result := '8_1'
else if ver >= $00060002 then
result := '8'
else if ver >= $00060001 then
result := '7'
else if ver >= $00060000 then
result := 'Vista'
else if ver >= $00050002 then
result := '2003'
else if ver >= $00050001 then
result := 'XP'
else if ver >= $00050000 then
result := '2000'
else if ver >= $00040000 then
result := 'NT4';
// ignore NT3, hmkay?;
end;
end;
{$ENDIF}

var
os,ver,arch: string;
begin
result := '';
os := '';
ver := 'generic';
arch := '';
{$IF DEFINED(WINDOWS)}
os := 'mswin';
ver := GetWindowsVersionStr(ver);
{$ELSEIF DEFINED(LINUX)}
os := 'linux';
{$Warning System Version String missing!}
{$ENDIF}

{$IF DEFINED(CPUX86)}
arch := 'x86';
{$ELSEIF DEFINED(cpux86_64)}
arch := 'x64';
{$ELSE}
{$ERROR Unknown Architecture!}
{$ENDIF}
result := Format('%s-%s-%s', [os, ver, arch]);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function utlRateLimited(const Reference: QWord; const Interval: QWord): boolean;
begin
@@ -413,7 +476,7 @@ var
s: String;
e: TFilterEntry;
begin
Result:= '';
result := '';
if (aIncludeAllSupported>'') and (fFilters.Count > 0) then begin
s:= '';
for e in fFilters do begin
@@ -442,7 +505,7 @@ function TFilterBuilderImpl.Add(aDescr, aMask: string; const aAppendFilterToDesc
var
e: TFilterEntry;
begin
Result:= Self;
result := Self;
e:= TFilterEntry.Create;
if aAppendFilterToDesc then
e.Descr:= Format('%s (%s)', [aDescr, aMask])
@@ -459,9 +522,9 @@ var
begin
c:= Pos('|', aFilter);
if c > 0 then
Result:= (Self as IutlFilterBuilder).Add(Copy(aFilter, 1, c-1), Copy(aFilter, c+1, Maxint))
result := (Self as IutlFilterBuilder).Add(Copy(aFilter, 1, c-1), Copy(aFilter, c+1, Maxint))
else
Result:= (Self as IutlFilterBuilder).Add(aFilter, aFilter, false);
result := (Self as IutlFilterBuilder).Add(aFilter, aFilter, false);
end;

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


+ 12
- 4
uutlEnumerator.pas View File

@@ -234,6 +234,7 @@ type
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IFDEF UTL_ENUMERATORS}
generic TutlSkipTakeEnumerator<T> = class(
specialize TutlEnumerator<T>)

@@ -255,6 +256,7 @@ type
constructor Create(aEnumerator: IutlEnumerator; const aSkip: Integer; const aTake: Integer);
destructor Destroy; override;
end;
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
@@ -360,6 +362,7 @@ type
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IFDEF UTL_ENUMERATORS}
generic TutlConcatEnumerator<T> = class(
specialize TutlEnumerator<T>)

@@ -381,6 +384,7 @@ type
constructor Create(aEnumerators: TEnumerators);
destructor Destroy; override;
end;
{$ENDIF}

implementation

@@ -696,6 +700,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlDistinctEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlDistinctEnumerator.InternalMoveNext: Boolean;
type
TBinarySearch = specialize TutlBinarySearch<T>;
@@ -723,7 +728,6 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlDistinctEnumerator.GetCurrent: T;
begin
result := fCurrent;
@@ -741,6 +745,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlIntersectWithoutEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlIntersectWithoutEnumerator.InternalMoveNext: Boolean;
type
TBinarySearch = specialize TutlBinarySearch<T>;
@@ -764,7 +769,6 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlIntersectWithoutEnumerator.GetCurrent: T;
begin
result := fCurrent;
@@ -788,6 +792,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlSkipTakeEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IFDEF UTL_ENUMERATORS}
function TutlSkipTakeEnumerator.InternalMoveNext: Boolean;
begin
while (fCurrentSkip > 0) and fEnumerator.MoveNext do
@@ -834,10 +839,12 @@ begin
fEnumerator := nil;
inherited Destroy;
end;
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlWhereEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlWhereEnumerator.InternalMoveNext: Boolean;
begin
repeat
@@ -852,7 +859,6 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlWhereEnumerator.GetCurrent: T;
begin
result := fEnumerator.Current;
@@ -882,6 +888,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlSelectEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlSelectEnumerator.InternalMoveNext: Boolean;
begin
result := fEnumerator.MoveNext;
@@ -894,7 +901,6 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IF DEFINED(UTL_ENUMERATORS) AND DEFINED(UTL_ADVANCED_ENUMERATORS)}
function TutlSelectEnumerator.GetCurrent: Tout;
begin
result := fSelector.Select(fEnumerator.Current);
@@ -1017,6 +1023,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlConcatEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IFDEF UTL_ENUMERATORS}
function TutlConcatEnumerator.InternalMoveNext: Boolean;
begin
if (fCurrent < 0) then begin
@@ -1065,6 +1072,7 @@ begin
SetLength(fEnumerators, 0);
inherited Destroy;
end;
{$ENDIF}

end.


+ 147
- 10
uutlGenerics.pas View File

@@ -466,13 +466,14 @@ type
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EutlEnumConvert = class(EConvertError)
EEnumConvertException = class(EConvertError)
public
constructor Create(const aValue, aExpectedType: String);
end;

generic TutlEnumHelper<T> = class
public type
TEnumType = T;
TValueArray = array of T;
TStringArray = array of String;

@@ -482,18 +483,39 @@ type
fNames: TStringArray;

public
class function ToString(aValue: T): String; reintroduce;
class function TryToEnum(aStr: String; out aValue: T): Boolean;
class function ToEnum(aStr: String): T; overload;
class function ToEnum(aStr: String; const aDefault: T): T; overload;
class function ToString (aValue: T): String; reintroduce;
class function TryToEnum (aStr: String; out aValue: T): Boolean;
class function ToEnum (aStr: String): T; overload;
class function ToEnum (aStr: String; const aDefault: T): T; overload;

class function Values: TValueArray; inline;
class function Names: TStringArray; inline;
class function TypeInfo: PTypeInfo; inline;
class function Values: TValueArray; inline;
class function Names: TStringArray; inline;
class function TypeInfo: PTypeInfo; inline;

class constructor Initialize;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlSetHelper<TEnum, TSet> = class
public type
TEnumHelper = specialize TutlEnumHelper<TEnum>;
TEnumType = TEnum;
TSetType = TSet;

private
class function IsSet (constref aSet: TSet; aEnum: TEnum): Boolean;
class procedure SetValue (var aSet: TSet; aEnum: TEnum);
class procedure ClearValue(var aSet: TSet; aEnum: TEnum);

public
class function ToString (const aValue: TSet; const aSeperator: String = ', '): String; reintroduce;
class function TryToSet (const aStr: String; out aValue: TSet): Boolean; overload;
class function TryToSet (const aStr: String; const aSeperator: String; out aValue: TSet): Boolean; overload;
class function ToSet (const aStr: String; const aDefault: TSet): TSet; overload;
class function ToSet (const aStr: String): TSet; overload;
class function Compare (const aSet1, aSet2: TSet): Integer;
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1464,7 +1486,7 @@ end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EutlEnumConvert///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EutlEnumConvert.Create(const aValue, aExpectedType: String);
constructor EEnumConvertException.Create(const aValue, aExpectedType: String);
begin
inherited Create(Format('%s is not a %s', [aValue, aExpectedType]));
end;
@@ -1505,7 +1527,7 @@ end;
class function TutlEnumHelper.ToEnum(aStr: String): T;
begin
if not TryToEnum(aStr, result) then
raise EutlEnumConvert.Create(aStr, TypeInfo^.Name);
raise EEnumConvertException.Create(aStr, TypeInfo^.Name);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1585,5 +1607,120 @@ begin
SetLength(fNames, High(fNames));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlSetHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlSetHelper.IsSet(constref aSet: TSet; aEnum: TEnum): Boolean;
begin
result := ((PByte(@aSet)[Integer(aEnum) shr 3] and (1 shl (Integer(aEnum) and 7))) <> 0);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class procedure TutlSetHelper.SetValue(var aSet: TSet; aEnum: TEnum);
begin
PByte(@aSet)[Integer(aEnum) shr 3] := PByte(@aSet)[Integer(aEnum) shr 3] or (1 shl (Integer(aEnum) and 7));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class procedure TutlSetHelper.ClearValue(var aSet: TSet; aEnum: TEnum);
begin
PByte(@aSet)[Integer(aEnum) shr 3] := PByte(@aSet)[Integer(aEnum) shr 3] and not (1 shl (Integer(aEnum) and 7));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlSetHelper.ToString(const aValue: TSet; const aSeperator: String): String;
var
e: TEnum;
i: Integer;
p: PByte;
begin
result := '';
p := @aValue;
for e in TEnumHelper.Values do begin
i := Integer(e);
if IsSet(aValue, e) then begin
if result > '' then
result := result + aSeperator;
result := result + TEnumHelper.ToString(e);
end;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlSetHelper.TryToSet(const aStr: String; out aValue: TSet): Boolean;
begin
result := TryToSet(aStr, ',', aValue);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlSetHelper.TryToSet(const aStr: String; const aSeperator: String; out aValue: TSet): Boolean;
var
i, j: Integer;
p: PAnsiChar;
s: String;
e: TEnum;
begin
if (aSeperator = '') then
raise EArgumentException.Create('''aSeperator'' can not be empty');

result := true;
aValue := [];
i := 1;
j := 1;

while (i <= Length(aStr)) do begin
if (Copy(aStr, i, Length(aSeperator)) = aSeperator) then begin
s := Trim(copy(aStr, j, i - j));
if (s <> '') then begin
result := result and TEnumHelper.TryToEnum(s, e);
if not result then
exit;
SetValue(aValue, e);
j := i + Length(aSeperator);
end;
end;
inc(i);
end;

s := Trim(copy(aStr, j, i - j));
if (s <> '') then begin
result := result and TEnumHelper.TryToEnum(s, e);
if not result then
exit;
SetValue(aValue, e);
end
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlSetHelper.ToSet(const aStr: String; const aDefault: TSet): TSet;
begin
if not TryToSet(aStr, result) then
result := aDefault;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlSetHelper.ToSet(const aStr: String): TSet;
begin
if not TryToSet(aStr, result) then
raise EEnumConvertException.CreateFmt('"%s" is an invalid value', [aStr]);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlSetHelper.Compare(const aSet1, aSet2: TSet): Integer;
var
e: TEnum;
begin
result := 0;
for e in TEnumHelper.Values do begin
if IsSet(aSet1, e) and not IsSet(aSet2, e) then begin
result := 1;
break;
end else if not IsSet(aSet1, e) and IsSet(aSet2, e) then begin
result := -1;
break;
end;
end;
end;

end.


Loading…
Cancel
Save