tests.rtti.util.pas 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. unit Tests.Rtti.Util;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Rtti;
  6. {$ifndef fpc}
  7. type
  8. CodePointer = Pointer;
  9. TValueHelper = record helper for TValue
  10. function AsUnicodeString: UnicodeString;
  11. function AsAnsiString: AnsiString;
  12. end;
  13. {$endif}
  14. function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
  15. function EqualValues({$ifdef fpc}constref{$else}const [ref]{$endif} aValue1, aValue2: TValue): Boolean;
  16. function GetIntValue(aValue: SizeInt): TValue;
  17. function GetAnsiString(const aValue: AnsiString): TValue;
  18. function GetShortString(const aValue: ShortString): TValue;
  19. function GetSingleValue(aValue: Single): TValue;
  20. function GetDoubleValue(aValue: Double): TValue;
  21. function GetExtendedValue(aValue: Extended): TValue;
  22. function GetCompValue(aValue: Comp): TValue;
  23. function GetCurrencyValue(aValue: Currency): TValue;
  24. function GetArray(const aArg: array of SizeInt): TValue;
  25. implementation
  26. uses
  27. TypInfo, SysUtils;
  28. {$ifndef fpc}
  29. function TValueHelper.AsUnicodeString: UnicodeString;
  30. begin
  31. Result := UnicodeString(AsString);
  32. end;
  33. function TValueHelper.AsAnsiString: AnsiString;
  34. begin
  35. Result := AnsiString(AsString);
  36. end;
  37. {$endif}
  38. function CopyValue({$ifdef fpc}constref{$else}const [ref]{$endif} aValue: TValue): TValue;
  39. var
  40. arrptr: Pointer;
  41. len, i: SizeInt;
  42. begin
  43. if aValue.Kind = tkDynArray then begin
  44. { we need to decouple the source reference, so we're going to be a bit
  45. cheeky here }
  46. len := aValue.GetArrayLength;
  47. arrptr := Nil;
  48. DynArraySetLength(arrptr, aValue.TypeInfo, 1, @len);
  49. TValue.Make(@arrptr, aValue.TypeInfo, Result);
  50. for i := 0 to len - 1 do
  51. Result.SetArrayElement(i, aValue.GetArrayElement(i));
  52. end else
  53. TValue.Make(aValue.GetReferenceToRawData, aValue.TypeInfo, Result);
  54. end;
  55. function EqualValues({$ifdef fpc}constref{$else}const [ref]{$endif} aValue1, aValue2: TValue): Boolean;
  56. var
  57. td1, td2: PTypeData;
  58. i: SizeInt;
  59. begin
  60. {$ifdef debug}
  61. Writeln('Empty: ', aValue1.IsEmpty, ' ', aValue2.IsEmpty);
  62. Writeln('Kind: ', aValue1.Kind, ' ', aValue2.Kind);
  63. Writeln('Array: ', aValue1.IsArray, ' ', aValue2.IsArray);
  64. {$endif}
  65. if aValue1.IsEmpty and aValue2.IsEmpty then
  66. Result := True
  67. else if aValue1.IsEmpty and not aValue2.IsEmpty then
  68. Result := False
  69. else if not aValue1.IsEmpty and aValue2.IsEmpty then
  70. Result := False
  71. else if aValue1.IsArray and aValue2.IsArray then begin
  72. if aValue1.GetArrayLength = aValue2.GetArrayLength then begin
  73. Result := True;
  74. for i := 0 to aValue1.GetArrayLength - 1 do
  75. if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
  76. Writeln('Element ', i, ' differs: ', HexStr(aValue1.GetArrayElement(i).AsOrdinal, 4), ' ', HexStr(aValue2.GetArrayElement(i).AsOrdinal, 4));
  77. Result := False;
  78. Break;
  79. end;
  80. end else
  81. Result := False;
  82. end else if aValue1.Kind = aValue2.Kind then begin
  83. td1 := aValue1.TypeData;
  84. td2 := aValue2.TypeData;
  85. case aValue1.Kind of
  86. tkBool:
  87. Result := aValue1.AsBoolean xor not aValue2.AsBoolean;
  88. tkSet:
  89. if td1^.SetSize = td2^.SetSize then
  90. if td1^.SetSize < SizeOf(SizeInt) then
  91. Result := aValue1.AsOrdinal = aValue2.AsOrdinal
  92. else
  93. Result := CompareMem(aValue1.GetReferenceToRawData, aValue2.GetReferenceToRawData, td1^.SetSize)
  94. else
  95. Result := False;
  96. tkEnumeration,
  97. tkChar,
  98. tkWChar,
  99. tkUChar,
  100. tkInt64,
  101. tkInteger:
  102. Result := aValue1.AsOrdinal = aValue2.AsOrdinal;
  103. tkQWord:
  104. Result := aValue1.AsUInt64 = aValue2.AsUInt64;
  105. tkFloat:
  106. if td1^.FloatType <> td2^.FloatType then
  107. Result := False
  108. else begin
  109. case td1^.FloatType of
  110. ftSingle,
  111. ftDouble,
  112. ftExtended:
  113. Result := aValue1.AsExtended = aValue2.AsExtended;
  114. ftComp:
  115. Result := aValue1.AsInt64 = aValue2.AsInt64;
  116. ftCurr:
  117. Result := aValue1.AsCurrency = aValue2.AsCurrency;
  118. end;
  119. end;
  120. tkSString,
  121. tkUString,
  122. tkAString,
  123. tkWString:
  124. Result := aValue1.AsString = aValue2.AsString;
  125. tkDynArray,
  126. tkArray:
  127. if aValue1.GetArrayLength = aValue2.GetArrayLength then begin
  128. Result := True;
  129. for i := 0 to aValue1.GetArrayLength - 1 do
  130. if not EqualValues(aValue1.GetArrayElement(i), aValue2.GetArrayElement(i)) then begin
  131. Result := False;
  132. Break;
  133. end;
  134. end else
  135. Result := False;
  136. tkClass,
  137. tkClassRef,
  138. tkInterface,
  139. tkInterfaceRaw,
  140. tkPointer:
  141. Result := PPointer(aValue1.GetReferenceToRawData)^ = PPointer(aValue2.GetReferenceToRawData)^;
  142. tkProcVar:
  143. Result := PCodePointer(aValue1.GetReferenceToRawData)^ = PCodePointer(aValue2.GetReferenceToRawData)^;
  144. tkRecord,
  145. tkObject,
  146. tkMethod,
  147. tkVariant: begin
  148. if aValue1.DataSize = aValue2.DataSize then
  149. Result := CompareMem(aValue1.GetReferenceToRawData, aValue2.GetReferenceToRawData, aValue1.DataSize)
  150. else
  151. Result := False;
  152. end
  153. else
  154. Result := False;
  155. end;
  156. end else
  157. Result := False;
  158. end;
  159. function GetIntValue(aValue: SizeInt): TValue;
  160. begin
  161. Result := TValue.{$ifdef fpc}specialize{$endif}From<SizeInt>(aValue);
  162. end;
  163. function GetAnsiString(const aValue: AnsiString): TValue;
  164. begin
  165. Result := TValue.{$ifdef fpc}specialize{$endif}From<AnsiString>(aValue);
  166. end;
  167. function GetShortString(const aValue: ShortString): TValue;
  168. begin
  169. Result := TValue.{$ifdef fpc}specialize{$endif}From<ShortString>(aValue);
  170. end;
  171. function GetSingleValue(aValue: Single): TValue;
  172. begin
  173. Result := TValue.{$ifdef fpc}specialize{$endif}From<Single>(aValue);
  174. end;
  175. function GetDoubleValue(aValue: Double): TValue;
  176. begin
  177. Result := TValue.{$ifdef fpc}specialize{$endif}From<Double>(aValue);
  178. end;
  179. function GetExtendedValue(aValue: Extended): TValue;
  180. begin
  181. Result := TValue.{$ifdef fpc}specialize{$endif}From<Extended>(aValue);
  182. end;
  183. function GetCompValue(aValue: Comp): TValue;
  184. begin
  185. Result := TValue.{$ifdef fpc}specialize{$endif}From<Comp>(aValue);
  186. end;
  187. function GetCurrencyValue(aValue: Currency): TValue;
  188. begin
  189. Result := TValue.{$ifdef fpc}specialize{$endif}From<Currency>(aValue);
  190. end;
  191. {$ifdef fpc}
  192. function GetArray(const aArg: array of SizeInt): TValue;
  193. begin
  194. Result := specialize OpenArrayToDynArrayValue<SizeInt>(aArg);
  195. end;
  196. {$endif}
  197. end.