From 863e81767532713555a0ccd4784d47e6e44fee4d Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Wed, 28 Dec 2005 19:15:17 +0000 Subject: [PATCH] Added: Delphi 2005/2006 compiler versions Added: support for Delphi 2006' for-in construction on hashes Added: ResetCache method for Settings factory --- Test/X2UtilsTest.cfg | 4 +- Test/X2UtilsTest.dof | 55 ++++++++- UnitTests/Units/HashesTest.pas | 60 ++++++++++ UnitTests/X2UtUnitTests.cfg | 4 +- UnitTests/X2UtUnitTests.dpr | 9 +- X2UtCompilerVersion.inc | 29 +++++ X2UtHashes.pas | 204 +++++++++++++++++++++++++++++++-- X2UtSettings.pas | 13 ++- 8 files changed, 355 insertions(+), 23 deletions(-) diff --git a/Test/X2UtilsTest.cfg b/Test/X2UtilsTest.cfg index d55d496..dad04cb 100644 --- a/Test/X2UtilsTest.cfg +++ b/Test/X2UtilsTest.cfg @@ -32,5 +32,5 @@ -M -$M16384,1048576 -K$00400000 --LE"c:\delphi6\Projects\Bpl" --LN"c:\delphi6\Projects\Bpl" +-LE"c:\program files\borland\delphi7\Projects\Bpl" +-LN"c:\program files\borland\delphi7\Projects\Bpl" diff --git a/Test/X2UtilsTest.dof b/Test/X2UtilsTest.dof index 6c2bc26..f211896 100644 --- a/Test/X2UtilsTest.dof +++ b/Test/X2UtilsTest.dof @@ -1,5 +1,5 @@ [FileVersion] -Version=6.0 +Version=7.0 [Compiler] A=8 B=0 @@ -30,6 +30,55 @@ Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +NamespacePrefix= +SymbolDeprecated=1 +SymbolLibrary=1 +SymbolPlatform=1 +UnitLibrary=1 +UnitPlatform=1 +UnitDeprecated=1 +HResultCompat=1 +HidingMember=1 +HiddenVirtual=1 +Garbage=1 +BoundsError=1 +ZeroNilCompat=1 +StringConstTruncated=1 +ForLoopVarVarPar=1 +TypedConstVarPar=1 +AsgToTypedConst=1 +CaseLabelRange=1 +ForVariable=1 +ConstructingAbstract=1 +ComparisonFalse=1 +ComparisonTrue=1 +ComparingSignedUnsigned=1 +CombiningSignedUnsigned=1 +UnsupportedConstruct=1 +FileOpen=1 +FileOpenUnitSrc=1 +BadGlobalSymbol=1 +DuplicateConstructorDestructor=1 +InvalidDirective=1 +PackageNoLink=1 +PackageThreadVar=1 +ImplicitImport=1 +HPPEMITIgnored=1 +NoRetVal=1 +UseBeforeDef=1 +ForLoopVarUndef=1 +UnitNameMismatch=1 +NoCFGFileFound=1 +MessageDirective=1 +ImplicitVariants=1 +UnicodeToLocale=1 +LocaleToUnicode=1 +ImagebaseMultiple=1 +SuspiciousTypecast=1 +PrivatePropAccessor=1 +UnsafeType=1 +UnsafeCode=1 +UnsafeCast=1 [Linker] MapFile=3 OutputObjs=0 @@ -56,10 +105,6 @@ HostApplication= Launcher= UseLauncher=0 DebugCWD= -[Language] -ActiveLang= -ProjectLang= -RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=1 diff --git a/UnitTests/Units/HashesTest.pas b/UnitTests/Units/HashesTest.pas index fecaa26..62b938d 100644 --- a/UnitTests/Units/HashesTest.pas +++ b/UnitTests/Units/HashesTest.pas @@ -19,6 +19,7 @@ type procedure testClear(); procedure testDelete(); virtual; abstract; procedure testIterate(); virtual; abstract; + procedure testEnumerator(); virtual; abstract; end; // Two test cases involving all value managers. @@ -36,6 +37,7 @@ type procedure testGet(); override; procedure testDelete(); override; procedure testIterate(); override; + procedure testEnumerator(); override; end; THashesPOTest = class(THashesTest) @@ -51,6 +53,7 @@ type procedure testGet(); override; procedure testDelete(); override; procedure testIterate(); override; + procedure testEnumerator(); override; end; THashesVariantTest = class(THashesTest) @@ -66,6 +69,7 @@ type procedure testGet(); override; procedure testDelete(); override; procedure testIterate(); override; + procedure testEnumerator(); override; end; implementation @@ -135,6 +139,40 @@ begin CheckTrue(Hash.Exists('Key3'), 'Key3 does not exist!'); end; +procedure THashesSITest.testEnumerator; +var + aPresent: array[1..3] of Boolean; + sKey: String; + +begin + FillTestItems(); + FillChar(aPresent, SizeOf(aPresent), #0); + + for sKey in Hash do + begin + if sKey = 'Key1' then + aPresent[1] := True + else if sKey = 'Key2' then + aPresent[2] := True + else if sKey = 'Key3' then + aPresent[3] := True; + end; + + CheckTrue(aPresent[1], 'Key1 was not in the enumeration!'); + CheckTrue(aPresent[2], 'Key2 was not in the enumeration!'); + CheckTrue(aPresent[3], 'Key3 was not in the enumeration!'); + + { Not supported yet, maybe in the future. + FillChar(aPresent, SizeOf(aPresent), #0); + for iValue in Hash.Values do + aPresent[iValue] := True; + + CheckTrue(aPresent[1], 'Value of Key1 was not in the enumeration!'); + CheckTrue(aPresent[2], 'Value of Key2 was not in the enumeration!'); + CheckTrue(aPresent[3], 'Value of Key3 was not in the enumeration!'); + } +end; + procedure THashesSITest.testIterate; var aPresent: array[1..3] of Boolean; @@ -201,6 +239,23 @@ begin CheckTrue(Hash.Exists(Pointer(2)), 'Key3 does not exist!'); end; +procedure THashesPOTest.testEnumerator; +var + aPresent: array[0..2] of Boolean; + pKey: Pointer; + +begin + FillTestItems(); + FillChar(aPresent, SizeOf(aPresent), #0); + + for pKey in Hash do + aPresent[Integer(pKey)] := True; + + CheckTrue(aPresent[0], 'Key1 was not in the enumeration!'); + CheckTrue(aPresent[1], 'Key2 was not in the enumeration!'); + CheckTrue(aPresent[2], 'Key3 was not in the enumeration!'); +end; + procedure THashesPOTest.testIterate; var aPresent: array[0..2] of Boolean; @@ -271,6 +326,11 @@ begin CheckTrue(Hash.Exists('Key3'), 'Key3 does not exist!'); end; +procedure THashesVariantTest.testEnumerator; +begin + Check(True, 'Not implemented yet.'); +end; + procedure THashesVariantTest.testIterate; var aPresent: array[0..2] of Boolean; diff --git a/UnitTests/X2UtUnitTests.cfg b/UnitTests/X2UtUnitTests.cfg index 4d9f9e5..e5e8130 100644 --- a/UnitTests/X2UtUnitTests.cfg +++ b/UnitTests/X2UtUnitTests.cfg @@ -32,8 +32,8 @@ -M -$M16384,1048576 -K$00400000 --LE"c:\program files\borland\delphi7\Projects\Bpl" --LN"c:\program files\borland\delphi7\Projects\Bpl" +-LE"C:\Documents and Settings\PsychoMark\My Documents\Borland Studio Projects\Bpl" +-LN"C:\Documents and Settings\PsychoMark\My Documents\Borland Studio Projects\Bpl" -w-SYMBOL_PLATFORM -w-UNIT_PLATFORM -w-UNSAFE_TYPE diff --git a/UnitTests/X2UtUnitTests.dpr b/UnitTests/X2UtUnitTests.dpr index 390acab..8d1d7ec 100644 --- a/UnitTests/X2UtUnitTests.dpr +++ b/UnitTests/X2UtUnitTests.dpr @@ -1,17 +1,16 @@ program X2UtUnitTests; uses - MemCheck, TestFramework, GUITestRunner, Variants, BitsTest in 'Units\BitsTest.pas', - HashesTest in 'Units\HashesTest.pas', - SettingsTest in 'Units\SettingsTest.pas', - IniParserTest in 'Units\IniParserTest.pas'; + HashesTest in 'Units\HashesTest.pas'; + //SettingsTest in 'Units\SettingsTest.pas', + //IniParserTest in 'Units\IniParserTest.pas'; begin - MemChk(); +// MemChk(); RunRegisteredTests(); end. \ No newline at end of file diff --git a/X2UtCompilerVersion.inc b/X2UtCompilerVersion.inc index 06b060a..40732d5 100644 --- a/X2UtCompilerVersion.inc +++ b/X2UtCompilerVersion.inc @@ -2,6 +2,33 @@ // being used... {$DEFINE DUNKNOWN} +{$IFDEF VER180} + {$DEFINE D2006} + {$DEFINE D2005} + {$DEFINE D8} + {$DEFINE D7} + {$DEFINE D6} + {$DEFINE D5} + {$DEFINE D4} + {$DEFINE D3} + {$DEFINE D2} + {$DEFINE D1} + {$UNDEF DUNKNOWN} +{$ENDIF} + +{$IFDEF VER170} + {$DEFINE D2005} + {$DEFINE D8} + {$DEFINE D7} + {$DEFINE D6} + {$DEFINE D5} + {$DEFINE D4} + {$DEFINE D3} + {$DEFINE D2} + {$DEFINE D1} + {$UNDEF DUNKNOWN} +{$ENDIF} + {$IFDEF VER160} {$DEFINE D8} {$DEFINE D7} @@ -75,6 +102,8 @@ // so I don't know what defines they have... if you do know, // feel free to send me any changes... {$IFDEF DUNKNOWN} + {$DEFINE D2006} + {$DEFINE D2005} {$DEFINE D8} {$DEFINE D7} {$DEFINE D6} diff --git a/X2UtHashes.pas b/X2UtHashes.pas index 2aeec28..4ccb6e9 100644 --- a/X2UtHashes.pas +++ b/X2UtHashes.pas @@ -14,6 +14,11 @@ :: For example; TX2SOHash indicates that it uses String keys to identify :: Object values. :: + :: As of Delphi 2006, all default hashes support the for...in structure. + :: To enumerate all keys, use "for x in Hash". As of yet, there is no + :: direct support for value enumeration yet; you can use + :: First/Next/CurrentValue for that. + :: :: Last changed: $Date$ :: Revision: $Rev$ :: Author: $Author$ @@ -35,6 +40,10 @@ type //:$ Raised when the cursor is not available EX2HashNoCursor = class(Exception); + // Forward declarations + TX2CustomHash = class; + + {$REGION 'Internal hash structures'} { :$ Internal representation of a hash item. } @@ -83,12 +92,14 @@ type property Current: PX2HashValue read GetCurrent; end; + {$ENDREGION} + {$REGION 'Internal value managers'} { :$ Base value manager. } TX2CustomHashManager = class(TObject) - public + protected procedure Initialize(var AData: Pointer); virtual; procedure Finalize(var AData: Pointer); virtual; @@ -103,7 +114,7 @@ type end; TX2HashPointerManager = class(TX2CustomHashManager) - public + protected function ToPointer(const AValue: Pointer): Pointer; overload; function ToValue(const AData: Pointer): Pointer; overload; end; @@ -112,7 +123,7 @@ type :$ Integer value class. } TX2HashIntegerManager = class(TX2CustomHashManager) - public + protected function ToPointer(const AValue: Integer): Pointer; overload; function ToValue(const AData: Pointer): Integer; overload; end; @@ -123,7 +134,7 @@ type TX2HashObjectManager = class(TX2CustomHashManager) private FOwnsObjects: Boolean; - public + protected procedure Finalize(var AData: Pointer); override; function ToPointer(const AValue: TObject): Pointer; overload; @@ -136,7 +147,7 @@ type :$ String value class. } TX2HashStringManager = class(TX2CustomHashManager) - public + protected procedure Finalize(var AData: Pointer); override; function DataSize(const AData: Pointer): Cardinal; override; @@ -150,7 +161,72 @@ type function Compare(const AData: Pointer; const AValue: Pointer; const ASize: Cardinal): Boolean; override; end; + {$ENDREGION} + {$REGION 'Delphi 2006 enumerator support'} + { + :$ Base enumerator class. + } + TX2HashEnumerator = class(TObject) + private + FCursor: TX2HashCursor; + FManager: TX2CustomHashManager; + FEnumKeys: Boolean; + + function GetCursor(): Pointer; + protected + property Manager: TX2CustomHashManager read FManager; + property Cursor: Pointer read GetCursor; + public + constructor Create(const AHash: TX2CustomHash; + const AEnumKeys: Boolean); + destructor Destroy(); override; + + function MoveNext(): Boolean; + end; + + { + :$ Enumerator for pointer values. + } + TX2HashPointerEnumerator = class(TX2HashEnumerator) + private + function GetCurrent: Pointer; + public + property Current: Pointer read GetCurrent; + end; + + { + :$ Enumerator for integer values. + } + TX2HashIntegerEnumerator = class(TX2HashEnumerator) + private + function GetCurrent: Integer; + public + property Current: Integer read GetCurrent; + end; + + { + :$ Enumerator for object values. + } + TX2HashObjectEnumerator = class(TX2HashEnumerator) + private + function GetCurrent: TObject; + public + property Current: TObject read GetCurrent; + end; + + { + :$ Enumerator for string values + } + TX2HashStringEnumerator = class(TX2HashEnumerator) + private + function GetCurrent(): String; + public + property Current: String read GetCurrent; + end; + {$ENDREGION} + + {$REGION 'Abstract hash implementation'} { :$ Hash implementation. } @@ -162,6 +238,9 @@ type FCursor: TX2HashCursor; FKeyManager: TX2CustomHashManager; FValueManager: TX2CustomHashManager; + + FKeys: TObject; + FValues: TObject; protected function CreateCursor(): TX2HashCursor; virtual; function CreateKeyManager(): TX2CustomHashManager; virtual; abstract; @@ -201,7 +280,9 @@ type property Count: Integer read FCount; end; + {$ENDREGION} + {$REGION 'Base hash classes'} { :$ Base hash implementation for pointer keys. } @@ -213,6 +294,8 @@ type function Find(const AKey: Pointer; const AAllowCreate: Boolean): PX2HashValue; overload; public + function GetEnumerator(): TX2HashPointerEnumerator; + function Exists(const AKey: Pointer): Boolean; overload; function Delete(const AKey: Pointer): Boolean; overload; @@ -230,6 +313,8 @@ type function Find(const AKey: Integer; const AAllowCreate: Boolean): PX2HashValue; overload; public + function GetEnumerator(): TX2HashIntegerEnumerator; + function Exists(const AKey: Integer): Boolean; overload; function Delete(const AKey: Integer): Boolean; overload; @@ -247,6 +332,8 @@ type function Find(const AKey: TObject; const AAllowCreate: Boolean): PX2HashValue; overload; public + function GetEnumerator(): TX2HashObjectEnumerator; + function Exists(const AKey: TObject): Boolean; overload; function Delete(const AKey: TObject): Boolean; overload; @@ -264,13 +351,16 @@ type function Find(const AKey: String; const AAllowCreate: Boolean): PX2HashValue; overload; public + function GetEnumerator(): TX2HashStringEnumerator; + function Exists(const AKey: String): Boolean; overload; function Delete(const AKey: String): Boolean; overload; property CurrentKey: String read GetCurrentKey; end; + {$ENDREGION} - + {$REGION 'Concrete hash classes'} { :$ Pointer-to-Pointer hash. } @@ -530,6 +620,7 @@ type property CurrentValue: String read GetCurrentValue; property Values[Key: String]: String read GetValue write SetValue; default; end; + {$ENDREGION} implementation const @@ -584,6 +675,7 @@ begin end; +{$REGION 'Internal hash structures'} {======================================== TX2HashCursor ========================================} @@ -685,8 +777,10 @@ begin break; until False; end; +{$ENDREGION} +{$REGION 'Internal value managers'} {======================================== TX2CustomHashManager ========================================} @@ -857,8 +951,10 @@ begin Result := CompareMem(pSource, AValue, ASize); end; +{$ENDREGION} +{$REGION 'Abstract hash implementation'} {========================== TX2CustomHash Initialization ========================================} @@ -883,7 +979,9 @@ end; function TX2CustomHash.CreateCursor(): TX2HashCursor; begin - Result := TX2HashCursor.Create(FRoot); + Result := nil; + if Assigned(FRoot) then + Result := TX2HashCursor.Create(FRoot); end; procedure TX2CustomHash.InvalidateCursor(); @@ -1190,9 +1288,77 @@ begin Result := Cursor.Next(); end; +{$ENDREGION} +{$REGION 'Delphi 2006 enumerator support'} +{======================================== + TX2HashEnumerator +========================================} +constructor TX2HashEnumerator.Create(const AHash: TX2CustomHash; + const AEnumKeys: Boolean); +begin + inherited Create(); + FEnumKeys := AEnumKeys; + if AEnumKeys then + FManager := AHash.KeyManager + else + FManager := AHash.ValueManager; + + FCursor := AHash.CreateCursor(); +end; + +destructor TX2HashEnumerator.Destroy(); +begin + FreeAndNil(FCursor); + + inherited; +end; + +function TX2HashEnumerator.GetCursor(): Pointer; +begin + if FEnumKeys then + Result := FCursor.Current^.Key + else + Result := FCursor.Current^.Value; +end; + +function TX2HashEnumerator.MoveNext(): Boolean; +begin + Result := False; + if Assigned(FCursor) then + Result := FCursor.Next(); +end; + + +{ TX2HashPointerEnumerator } +function TX2HashPointerEnumerator.GetCurrent(): Pointer; +begin + Result := TX2HashPointerManager(Manager).ToValue(Cursor); +end; + +{ TX2HashIntegerEnumerator } +function TX2HashIntegerEnumerator.GetCurrent(): Integer; +begin + Result := TX2HashIntegerManager(Manager).ToValue(Cursor); +end; + +{ TX2HashObjectEnumerator } +function TX2HashObjectEnumerator.GetCurrent(): TObject; +begin + Result := TX2HashObjectManager(Manager).ToValue(Cursor); +end; + +{ TX2HashStringEnumerator } +function TX2HashStringEnumerator.GetCurrent(): String; +begin + Result := TX2HashStringManager(Manager).ToValue(Cursor); +end; +{$ENDREGION} + + +{$REGION 'Base hash classes'} {======================================== TX2CustomPointerHash ========================================} @@ -1207,6 +1373,11 @@ begin Result := TX2HashPointerManager(KeyManager).ToValue(Cursor.Current^.Key); end; +function TX2CustomPointerHash.GetEnumerator(): TX2HashPointerEnumerator; +begin + Result := TX2HashPointerEnumerator.Create(Self, True); +end; + function TX2CustomPointerHash.Find(const AKey: Pointer; const AAllowCreate: Boolean): PX2HashValue; begin @@ -1238,6 +1409,11 @@ begin Result := TX2HashIntegerManager(KeyManager).ToValue(Cursor.Current^.Key); end; +function TX2CustomIntegerHash.GetEnumerator(): TX2HashIntegerEnumerator; +begin + Result := TX2HashIntegerEnumerator.Create(Self, True); +end; + function TX2CustomIntegerHash.Find(const AKey: Integer; const AAllowCreate: Boolean): PX2HashValue; begin @@ -1269,6 +1445,11 @@ begin Result := TX2HashObjectManager(KeyManager).ToValue(Cursor.Current^.Key); end; +function TX2CustomObjectHash.GetEnumerator(): TX2HashObjectEnumerator; +begin + Result := TX2HashObjectEnumerator.Create(Self, True); +end; + function TX2CustomObjectHash.Find(const AKey: TObject; const AAllowCreate: Boolean): PX2HashValue; begin @@ -1301,6 +1482,11 @@ begin end; +function TX2CustomStringHash.GetEnumerator(): TX2HashStringEnumerator; +begin + Result := TX2HashStringEnumerator.Create(Self, True); +end; + function TX2CustomStringHash.Find(const AKey: String; const AAllowCreate: Boolean): PX2HashValue; begin @@ -1316,8 +1502,10 @@ function TX2CustomStringHash.Delete(const AKey: String): Boolean; begin Result := inherited Delete(PChar(AKey), Length(AKey)); end; +{$ENDREGION} +{$REGION 'Concrete hash classes'} {======================================== TX2PPHash ========================================} @@ -1873,6 +2061,8 @@ begin inherited SetValue(Find(Key, True), TX2HashStringManager(ValueManager).ToPointer(Value)); end; +{$ENDREGION} + initialization CRC32Init(); diff --git a/X2UtSettings.pas b/X2UtSettings.pas index f5ff1fc..2761341 100644 --- a/X2UtSettings.pas +++ b/X2UtSettings.pas @@ -155,7 +155,7 @@ type //:$ Validates the specified value using the defined callback method //:$ if present. function ValidateValue(const AName: String; const AValue: Variant): Variant; - end deprecated; + end; { :$ Settings factory. @@ -173,6 +173,8 @@ type constructor Create(); destructor Destroy(); override; + procedure ResetCache(); + //:$ Loads a section from the settings. //:: Sub-sections are indicated by seperating the sections with a dot ('.') //:: characters, ex: Sub.Section. The underlying extension will translate @@ -186,7 +188,7 @@ type //:: callback method to perform centralized checks. procedure Define(const ASection, AName: String; const AValue: Variant; const ACallback: TX2SettingsCallback = nil); - end deprecated; + end; implementation @@ -655,4 +657,11 @@ begin FCallback(AAction, ASection, AName, AValue); end; +procedure TX2SettingsFactory.ResetCache(); +begin + FDefines.First(); + while FDefines.Next() do + TX2SettingsDefine(FDefines.CurrentValue).Cached := False; +end; + end.