|
|
@@ -416,12 +416,17 @@ type |
|
|
|
generic TutlEnumHelper<T> = class(TObject) |
|
|
|
private type |
|
|
|
TValueArray = array of T; |
|
|
|
private class var |
|
|
|
FTypeInfo: PTypeInfo; |
|
|
|
FValues: TValueArray; |
|
|
|
public |
|
|
|
class constructor Initialize; |
|
|
|
class function ToString(aValue: T): String; reintroduce; |
|
|
|
class function TryToEnum(aStr: String; out aValue: T): Boolean; |
|
|
|
class function ToEnum(aStr: String): T; overload; |
|
|
|
class function ToEnum(aStr: String; const aDefault: T): T; overload; |
|
|
|
class function Values: TValueArray; |
|
|
|
class function TypeInfo: PTypeInfo; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
@@ -1662,78 +1667,86 @@ end; |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//TutlEnumHelper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class function TutlEnumHelper.ToString(aValue: T): String; |
|
|
|
Var |
|
|
|
PS: PShortString; |
|
|
|
TI: PTypeInfo; |
|
|
|
PT: PTypeData; |
|
|
|
num: Integer; |
|
|
|
begin |
|
|
|
TI := TypeInfo(T); |
|
|
|
PT := GetTypeData(TI); |
|
|
|
if TI^.Kind = tkBool then begin |
|
|
|
case Integer(aValue) of |
|
|
|
0,1: |
|
|
|
Result:=BooleanIdents[Boolean(aValue)]; |
|
|
|
else |
|
|
|
Result:=''; |
|
|
|
end; |
|
|
|
end else begin |
|
|
|
num := Integer(aValue); |
|
|
|
if (num >= PT^.MinValue) and (num <= PT^.MaxValue) then begin |
|
|
|
PS := @PT^.NameList; |
|
|
|
dec(num, PT^.MinValue); |
|
|
|
while num > 0 do begin |
|
|
|
PS := PShortString(pointer(PS) + PByte(PS)^ + 1); |
|
|
|
Dec(Num); |
|
|
|
end; |
|
|
|
Result := PS^; |
|
|
|
end else |
|
|
|
Result := ''; |
|
|
|
class constructor TutlEnumHelper.Initialize; |
|
|
|
var |
|
|
|
tiArray: PTypeInfo; |
|
|
|
tdArray, tdEnum: PTypeData; |
|
|
|
aName: PShortString; |
|
|
|
i: integer; |
|
|
|
en: T; |
|
|
|
begin |
|
|
|
{ |
|
|
|
See FPC Bug http://bugs.freepascal.org/view.php?id=27622 |
|
|
|
For Sparse Enums, the compiler won't give us TypeInfo, because it contains some wrong data. This is |
|
|
|
safe, but sadly we don't even get the *correct* fields (TypeName, NameList), even though they are |
|
|
|
generated in any case. |
|
|
|
Fortunately, arrays do know this type info segment as their Element Type (and we declared one anyway). |
|
|
|
} |
|
|
|
tiArray := System.TypeInfo(TValueArray); |
|
|
|
tdArray := GetTypeData(tiArray); |
|
|
|
FTypeInfo:= tdArray^.elType2; |
|
|
|
|
|
|
|
{ |
|
|
|
Now that we have the TypeInfo, fill our values from it. This is safe because while the *values* in |
|
|
|
TypeData are wrong for Sparse Enums, the *names* are always correct. |
|
|
|
} |
|
|
|
tdEnum:= GetTypeData(FTypeInfo); |
|
|
|
aName:= @tdEnum^.NameList; |
|
|
|
SetLength(FValues, 0); |
|
|
|
i:= 0; |
|
|
|
While Length(aName^) > 0 do begin |
|
|
|
SetLength(FValues, i+1); |
|
|
|
{ |
|
|
|
Memory layout for TTypeData has the declaring EnumUnitName after the last NameList entry. |
|
|
|
This can normally not be the same as a valid enum value, because it is in the same identifier |
|
|
|
namespace. However, with scoped enums we might have the same name for module and element, because |
|
|
|
the full identifier for the element would be TypeName.ElementName. |
|
|
|
In either case, the next PShortString will point to a zero-length string, and the loop is left |
|
|
|
with the last element being invalid (either empty or whatever value the unit-named element has). |
|
|
|
} |
|
|
|
if TryToEnum(aName^, en) then |
|
|
|
FValues[i]:= en; |
|
|
|
inc(i); |
|
|
|
inc(PByte(aName), Length(aName^) + 1); |
|
|
|
end; |
|
|
|
// remove the EnumUnitName item |
|
|
|
SetLength(FValues, Length(FValues) - 1); |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class function TutlEnumHelper.ToString(aValue: T): String; |
|
|
|
begin |
|
|
|
{$Push} |
|
|
|
{$IOChecks OFF} |
|
|
|
WriteStr(Result, aValue); |
|
|
|
if IOResult = 107 then |
|
|
|
Result:= ''; |
|
|
|
{$Pop} |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class function TutlEnumHelper.TryToEnum(aStr: String; out aValue: T): Boolean; |
|
|
|
Var |
|
|
|
PS: PShortString; |
|
|
|
PT: PTypeData; |
|
|
|
Count: longint; |
|
|
|
sName: shortstring; |
|
|
|
TI: PTypeInfo; |
|
|
|
begin |
|
|
|
TI := TypeInfo(T); |
|
|
|
PT := GetTypeData(TI); |
|
|
|
Result := False; |
|
|
|
var |
|
|
|
a: T; |
|
|
|
begin |
|
|
|
Result:= false; |
|
|
|
if Length(aStr) = 0 then |
|
|
|
exit; |
|
|
|
sName := aStr; |
|
|
|
|
|
|
|
if TI^.Kind = tkBool then begin |
|
|
|
If CompareText(BooleanIdents[false], aStr) = 0 then |
|
|
|
aValue := T(0) |
|
|
|
else if CompareText(BooleanIdents[true], aStr) = 0 then |
|
|
|
aValue := T(1); |
|
|
|
Result := true; |
|
|
|
end else begin |
|
|
|
PS := @PT^.NameList; |
|
|
|
Count := 0; |
|
|
|
While (PByte(PS)^ <> 0) do begin |
|
|
|
If ShortCompareText(PS^, sName) = 0 then begin |
|
|
|
aValue := T(Count + PT^.MinValue); |
|
|
|
exit(true); |
|
|
|
end; |
|
|
|
PS := PShortString(pointer(PS) + PByte(PS)^ + 1); |
|
|
|
Inc(Count); |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
{$Push} |
|
|
|
{$IOChecks OFF} |
|
|
|
ReadStr(aStr, a); |
|
|
|
Result:= IOResult <> 106; |
|
|
|
{$Pop} |
|
|
|
if Result then |
|
|
|
aValue:= a; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class function TutlEnumHelper.ToEnum(aStr: String): T; |
|
|
|
begin |
|
|
|
if not TryToEnum(aStr, result) then |
|
|
|
raise EutlEnumConvert.Create(aStr, PTypeInfo(TypeInfo(T))^.Name); |
|
|
|
raise EutlEnumConvert.Create(aStr, TypeInfo^.Name); |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
@@ -1745,25 +1758,14 @@ end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class function TutlEnumHelper.Values: TValueArray; |
|
|
|
Var |
|
|
|
TI: PTypeInfo; |
|
|
|
PT: PTypeData; |
|
|
|
i,j: integer; |
|
|
|
begin |
|
|
|
TI := TypeInfo(T); |
|
|
|
PT := GetTypeData(TI); |
|
|
|
if TI^.Kind = tkBool then begin |
|
|
|
SetLength(Result, 2); |
|
|
|
Result[0]:= T(true); |
|
|
|
Result[1]:= T(false); |
|
|
|
end else begin |
|
|
|
SetLength(Result, PT^.MaxValue - PT^.MinValue + 1); |
|
|
|
j:= 0; |
|
|
|
for i:= PT^.MinValue to PT^.MaxValue do begin |
|
|
|
Result[j]:= T(i); |
|
|
|
inc(j); |
|
|
|
end; |
|
|
|
end; |
|
|
|
begin |
|
|
|
Result:= FValues; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class function TutlEnumHelper.TypeInfo: PTypeInfo; |
|
|
|
begin |
|
|
|
Result:= FTypeInfo; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|