-
Notifications
You must be signed in to change notification settings - Fork 1
/
typeutils.pas
116 lines (108 loc) · 3.84 KB
/
typeutils.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
{$mode objfpc}
{
TODO:
- Write my own VariantToString for consistency (for string and float point numbers)
- Write multimensional arrays like a table???
}
unit TypeUtils;
interface
uses sysutils, typinfo, variants;
function ToStr(const AValue; ATypeInfo: PTypeInfo): AnsiString;
implementation
function ToStr(const AValue; ATypeInfo: PTypeInfo): AnsiString;
type
TArray = array of Byte;
var
I: LongInt;
FormatSettings: TFormatSettings;
FirstField, Field: PManagedField;
ElementSize: SizeInt;
begin
case ATypeInfo^.Kind of
tkChar: Result := QuotedStr(Char(AValue));
tkWChar: Result := QuotedStr(AnsiString(WChar(AValue)));
tkBool: Result := BoolToStr(Boolean(AValue), True);
tkInt64: Result := IntToStr(Int64(AValue));
tkQWord: Result := IntToStr(QWord(AValue));
tkSString: Result := QuotedStr(ShortString(AValue));
tkAString: Result := QuotedStr(AnsiString(AValue));
tkWString: Result := QuotedStr(AnsiString(WideString(AValue)));
tkUString: Result := QuotedStr(AnsiString(UnicodeString(AValue)));
tkClass: Result := TObject(AValue).ToString;
tkEnumeration: Result := GetEnumName(ATypeInfo, Integer(AValue));
tkSet: Result := SetToString(ATypeInfo, Integer(AValue), True).Replace(',', ', ');
tkVariant: Result := VarToStr(Variant(AValue));
tkInteger:
begin
case GetTypeData(ATypeInfo)^.OrdType of
otSByte: Result := IntToStr(ShortInt(AValue));
otUByte: Result := IntToStr(Byte(AValue));
otSWord: Result := IntToStr(SmallInt(AValue));
otUWord: Result := IntToStr(Word(AValue));
otSLong: Result := IntToStr(LongInt(AValue));
otULong: Result := IntToStr(LongWord(AValue));
end;
end;
tkFloat:
begin
FillByte(FormatSettings, SizeOf(TFormatSettings), 0);
FormatSettings.DecimalSeparator := '.';
case GetTypeData(ATypeInfo)^.FloatType of
ftSingle: Result := FormatFloat('0.######', Single(AValue), FormatSettings);
ftDouble: Result := FormatFloat('0.######', Double(AValue), FormatSettings);
ftExtended: Result := FormatFloat('0.######', Extended(AValue), FormatSettings);
ftComp: Result := FormatFloat('0.######', Comp(AValue), FormatSettings);
ftCurr: Result := FormatFloat('0.######', Currency(AValue), FormatSettings);
end;
end;
tkRecord:
begin
Result := '(';
with GetTypeData(ATypeInfo)^ do
begin
{$IFNDEF VER3_0} //ifdef needed because of a field rename in trunk (ManagedFldCount to TotalFieldCount)
FirstField := PManagedField(PByte(@TotalFieldCount) + SizeOf(TotalFieldCount));
for I := 0 to TotalFieldCount - 1 do
{$ELSE}
FirstField := PManagedField(PByte(@ManagedFldCount) + SizeOf(ManagedFldCount));
for I := 0 to ManagedFldCount - 1 do
{$ENDIF}
begin
if I > 0 then Result += ', ';
Field := PManagedField(PByte(FirstField) + (I * SizeOf(TManagedField)));
Result += ToStr((PByte(@AValue) + Field^.FldOffset)^, Field^.TypeRef);
end;
end;
Result += ')';
end;
tkArray:
begin
Result := '[';
with GetTypeData(ATypeInfo)^ do
begin
ElementSize := ArrayData.Size div ArrayData.ElCount;
for I := 0 to ArrayData.ElCount - 1 do
begin
if I > 0 then Result += ', ';
Result += ToStr((PByte(@AValue) + (I * ElementSize))^, ArrayData.ElType);
end;
end;
Result += ']';
end;
tkDynArray:
begin
Result := '[';
with GetTypeData(ATypeInfo)^ do
begin
for I := 0 to Length(TArray(AValue)) - 1 do
begin
if I > 0 then Result += ', ';
Result += ToStr((PByte(@TArray(AValue)[0]) + (I * ElSize))^, ElType2);
end;
end;
Result += ']';
end;
else Result := Format('%s@%p', [ATypeInfo^.Name, @AValue]);
end;
end;
end.