I have written the following record type with implicit operators to cast between this record type and a string. It represents a standard weather code which briefly describes current weather conditions:
type
TDayNight = (dnDay, dnNight);
TCloudCode = (ccClear = 0, ccAlmostClear = 1, ccHalfCloudy = 2, ccBroken = 3,
ccOvercast = 4, ccThinClouds = 5, ccFog = 6);
TPrecipCode = (pcNone = 0, pcSlight = 1, pcShowers = 2, pcPrecip = 3, pcThunder = 4);
TPrecipTypeCode = (ptRain = 0, ptSleet = 1, ptSnow = 2);
TWeatherCode = record
public
DayNight: TDayNight;
Clouds: TCloudCode;
Precip: TPrecipCode;
PrecipType: TPrecipTypeCode;
class operator Implicit(const Value: TWeatherCode): String;
class operator Implicit(const Value: String): TWeatherCode;
function Description: String;
function DayNightStr: String;
end;
implementation
{ TWeatherCode }
class operator TWeatherCode.Implicit(const Value: TWeatherCode): String;
begin
case Value.DayNight of
dnDay: Result:= 'd';
dnNight: Result:= 'n';
end;
Result:= Result + IntToStr(Integer(Value.Clouds));
Result:= Result + IntToStr(Integer(Value.Precip));
Result:= Result + IntToStr(Integer(Value.PrecipType));
end;
class operator TWeatherCode.Implicit(const Value: String): TWeatherCode;
begin
if Length(Value) <> 4 then raise Exception.Create('Value must be 4 characters.');
case Value[1] of
'd','D': Result.DayNight:= TDayNight.dnDay;
'n','N': Result.DayNight:= TDayNight.dnNight;
else raise Exception.Create('First value must be either d, D, n, or N.');
end;
if Value[2] in ['0'..'6'] then
Result.Clouds:= TCloudCode(StrToIntDef(Value[2], 0))
else
raise Exception.Create('Second value must be between 0 and 6.');
if Value[3] in ['0'..'4'] then
Result.Precip:= TPrecipCode(StrToIntDef(Value[3], 0))
else
raise Exception.Create('Third value must be between 0 and 4.');
if Value[4] in ['0'..'2'] then
Result.PrecipType:= TPrecipTypeCode(StrToIntDef(Value[4], 0))
else
raise Exception.Create('Fourth value must be between 0 and 2.');
end;
function TWeatherCode.DayNightStr: String;
begin
case DayNight of
dnDay: Result:= 'Day';
dnNight: Result:= 'Night';
end;
end;
function TWeatherCode.Description: String;
begin
case Clouds of
ccClear: Result:= 'Clear';
ccAlmostClear: Result:= 'Mostly Clear';
ccHalfCloudy: Result:= 'Partly Cloudy';
ccBroken: Result:= 'Cloudy';
ccOvercast: Result:= 'Overcast';
ccThinClouds: Result:= 'Thin High Clouds';
ccFog: Result:= 'Fog';
end;
case PrecipType of
ptRain: begin
case Precip of
pcNone: Result:= Result + '';
pcSlight: Result:= Result + ' with Light Rain';
pcShowers: Result:= Result + ' with Rain Showers';
pcPrecip: Result:= Result + ' with Rain';
pcThunder: Result:= Result + ' with Rain and Thunderstorms';
end;
end;
ptSleet: begin
case Precip of
pcNone: Result:= Result + '';
pcSlight: Result:= Result + ' with Light Sleet';
pcShowers: Result:= Result + ' with Sleet Showers';
pcPrecip: Result:= Result + ' with Sleet';
pcThunder: Result:= Result + ' with Sleet and Thunderstorms';
end;
end;
ptSnow: begin
case Precip of
pcNone: Result:= Result + '';
pcSlight: Result:= Result + ' with Light Snow';
pcShowers: Result:= Result + ' with Snow Showers';
pcPrecip: Result:= Result + ' with Snow';
pcThunder: Result:= Result + ' with Snow and Thunderstorms';
end;
end;
end;
end;
Examples of strings that can be cast to and from this type are...
d310
= Cloudy and Light Rain (Day)d440
= Overcast with Rain and Thunderstorms (Day)n100
= Mostly Clear (Night)
This string will always be in this format, and will always be 4 characters: 1 letter and 3 numbers. In reality, you can look at it as the following options:
- 0, 1
- 0, 1, 2, 3, 4, 5, 6
- 0, 1, 2, 3, 4
- 0, 1, 2
What I would like to do is also provide an option to implicitly cast it to an integer, or even byte, if I can get it small enough. I would hate however to have to add a ton of if/then/else or case statements.
I know that it is possible to take a given (small) set of characters and cast them to a single value. However, I have no idea how it's done. I do know, for example, that this technique is used in places such as the flags on DrawTextEx
and other similar WinAPI calls. I think this may relate to the usage of shr
/ shl
but I have no idea how to use those, and am terrible at that type of math.
How can I cast these 4 attributes combined into a single integer or byte, and cast them back?