tests.rtti.util.pas 7.4 KB

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