2
0

tests.rtti.util.pas 7.2 KB

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