Skip to content

Instantly share code, notes, and snippets.

@gabr42
Last active February 1, 2019 15:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gabr42/1d61c118143d96f5994ac7c78865635c to your computer and use it in GitHub Desktop.
Save gabr42/1d61c118143d96f5994ac7c78865635c to your computer and use it in GitHub Desktop.
class properties as per-type cache
program MetaClassCache;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.TypInfo,
System.SysUtils;
type
Range<T> = record
private
class function MaxIntVal: Integer; static; inline;
class function MinIntVal: Integer; static; inline;
public
class function Check(const value: Integer): T; static;
end;
{ Range<T> }
class function Range<T>.Check(const value: Integer): T;
begin
if (value < MinIntVal) or (value > MaxIntVal) then
raise Exception.CreateFmt('Value %d lies outside allowed range for %s (%d .. %d)',
[value, PTypeInfo(TypeInfo(T)).Name, MinIntVal, MaxIntVal]);
Move(value, Result, SizeOf(Result));
end;
class function Range<T>.MaxIntVal: Integer;
var
ti: PTypeInfo;
typeData: PTypeData;
isSet: Boolean;
i: Integer;
begin
ti := TypeInfo(T);
isSet := ti.Kind = tkSet;
if isSet then
ti := GetTypeData(ti).CompType^;
typeData := GetTypeData(ti);
if isSet then
begin
Result := 0;
for i := typeData.MinValue to typeData.MaxValue do
Result := Result or (1 shl i);
end
else
Result := typeData.MaxValue;
end;
class function Range<T>.MinIntVal: Integer;
var
ti: PTypeInfo;
typeData: PTypeData;
begin
ti := TypeInfo(T);
if ti.Kind = tkSet then
ti := GetTypeData(ti).CompType^;
typeData := GetTypeData(ti);
Result:= typeData.MinValue;
end;
type
TEnum = (en1, en2, en3);
TEnumSet = set of TEnum;
var
en: TEnum;
ens: TEnumSet;
begin
try
en := Range<TEnum>.Check(0);
en := Range<TEnum>.Check(2);
try
en := Range<TEnum>.Check(3);
except
on E: Exception do
Writeln('Expected exception: ', E.ClassName, ' ', E.Message);
end;
ens := Range<TEnumSet>.Check(0);
ens := Range<TEnumSet>.Check(7);
try
ens := Range<TEnumSet>.Check(8);
except
on E: Exception do
Writeln('Expected exception: ', E.ClassName, ' ', E.Message);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
if DebugHook <> 0 then
Readln;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment