Enumerations, Subranges & Sets
Subranges document intent and, with {$R+}, catch invalid values at run time.
16.1 Enumerated types
Ord(Wed) = 2 Successor / predecessor Succ(Mon) = Tue, Pred(Sun) = Sat Low(TDay) = Mon, High(TDay) = Sun
TFlag = (fNone = 0, fRead = 1, fWrite = 2, fExec = 4); (no Succ/Pred/for over gaps)
{$SCOPEDENUMS ON} then TStatus.Active is required TDay.Mon is allowed even without scoping (Delphi and FPC 3.x) Name as string
GetEnumName(TypeInfo(TDay), Ord(D)) (unit TypInfo); FPC also Writeln(D) and WriteStr(S, D)
type
TDay = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
TTrafficLight = (tlRed, tlYellow, tlGreen);
var
D: TDay;
begin
D := Wed;
Writeln(Ord(D)); // 2
D := Succ(D); // Thu
D := Pred(D); // Wed
if D < Sat then Writeln('weekday');
for D := Low(TDay) to High(TDay) do
Write(Ord(D), ' ');
D := TDay(4); // Fri — unchecked cast
end.uses TypInfo;
...
Writeln(GetEnumName(TypeInfo(TDay), Ord(Fri))); // Fri
D := TDay(GetEnumValue(TypeInfo(TDay), 'Sun')); // string to enum16.2 Subrange types
Subranges document intent and, with {$R+}, catch invalid values at run time. Assigning an out-of-range constant is a compile-time error.
type
TPercent = 0..100;
TWeekday = Mon..Fri;
TLower = 'a'..'z';
var
P: TPercent;
begin
{$R+}
P := 50;
P := P + 60; // run-time range-check error 201 (ERangeError with SysUtils)
end.16.3 Sets
A set holds any combination of values from an ordinal base type with at most 256 values (ordinals 0..255):
symmetric difference (FPC) equality, inequality subset, superset membership (element in set) Include(S, X), Exclude(S, X) add / remove an element in place
Sets are implemented as bit vectors (one bit per possible element), so operations are very fast. They are perfect for flags (TFontStyles = set of TFontStyle), character classes, and state machines.
type
TDays = set of TDay;
TCharSet = set of Char; // AnsiChar in Delphi 2009+ (a warning reminds you)
const
Weekend: TDays = [Sat, Sun];
Digits = ['0'..'9'];
var
Work, Free, Busy: TDays;
D: TDay;
begin
Work := [Mon..Fri];
Free := Weekend + [Wed]; // union
Busy := Work - Free; // difference: [Mon, Tue, Thu, Fri]
if Wed in Free then Writeln('Wednesday is free');
Include(Busy, Sat);
Exclude(Busy, Mon);
for D in Busy do Write(Ord(D), ' ');
Writeln;
if [Sat, Sun] <= Free then Writeln('whole weekend free');
end.16.4 Example: flags with sets
type
TPermission = (pRead, pWrite, pExecute, pDelete);
TPermissions = set of TPermission;
function PermissionString(P: TPermissions): string;
const
Letters: array[TPermission] of Char = ('r', 'w', 'x', 'd');
var
Perm: TPermission;
begin
Result := '';
for Perm := Low(TPermission) to High(TPermission) do
if Perm in P then
Result := Result + Letters[Perm]
else
Result := Result + '-';
end;
begin
Writeln(PermissionString([pRead, pExecute])); // r-x-
end.