Today I will present some handy classes, they are all located in BB.Utils.* namespace.
This class will swap any kind of value:
TSwap<T> = class
public
class procedure Swap(var a, b: T);
end;
Implementation:
class procedure TSwap<T>.Swap(var a, b: T);
var
tmp: T;
begin
tmp := a;
a := b;
b := tmp;
end
Example:
var
a, b: integer;
begin
a := 1;
b := 2;
TSwap<integer>.Swap(a, b);
//Now a=2 & b=1
end;
This class let you do dynamic calls:
TCaller = class
public
class procedure Call(aMethod: TMethod); overload;
class procedure Call(aMethod: TMethod; aSender: TObject); overload;
class procedure Call(aObject: TObject; const aMethod: string); overload;
end;
The implementation:
class procedure TCaller.Call(aMethod: TMethod);
begin
TMethodPointer(aMethod)();
end;
class procedure TCaller.Call(aObject: TObject; const aMethod: string);
var
m: TMethod;
begin
m.Data := aObject;
m.Code := aObject.MethodAddress(aMethod);
Call(m);
end;
class procedure TCaller.Call(aMethod: TMethod; aSender: TObject);
begin
TNotifyEvent(aMethod)(aSender);
end;
Example:
begin
TCaller.Call(Button1, 'click');
//This will dinamically call the click method of a button.
//This enables you to persist method names and use them
//for your own purpose (by configuration you dedice
//which action calls which method
end;
This class behaves like a bit container:
TBitSet = record
private
FData: int64;
public
constructor Create(aValue: int64);
procedure ClearBit(aBit: integer); inline;
function GetBit(aBit: integer): boolean; inline;
procedure SetBit(aBit: integer); inline;
function AsByte: byte; inline;
function AsWord: word; inline;
function AsInt: integer; inline;
function AsInt64: int64; inline;
end;
Implementation
{ TBitSet }
//Bit64: array [0..63] of int64 =
//is an int64 precalculated array (it does not look good when I paste the values)
function TBitSet.AsByte: byte;
begin
Exit(byte(FData));
end;
function TBitSet.AsInt: integer;
begin
Exit(integer(FData));
end;
function TBitSet.AsInt64: int64;
begin
Exit(FData);
end;
function TBitSet.AsWord: word;
begin
Exit(word(FData));
end;
procedure TBitSet.ClearBit(aBit: integer);
begin
FData := FData and ($FFFFFFFFFFFFFFFF xor Bit64[aBit]);
end;
constructor TBitSet.Create(aValue: int64);
begin
FData := aValue;
end;
function TBitSet.GetBit(aBit: integer): boolean;
begin
Exit(FData and Bit64[aBit] <> 0);
end;
procedure TBitSet.SetBit(aBit: integer);
begin
FData := FData or Bit64[aBit];
end;
Example:
var
t: TBitSet;
i: integer;
begin
t := TBitSet.Create($ffff);
t.ClearBit(15);
i := t.AsInt; //Now i = $fff
end;
And the last class is a time helper, is used also in ChessKISS for the Winboard protocol.
TTimeSpan = class
public
class function Make(aDays, aHours, aMinutes, aSeconds, aMilliseconds: cardinal): cardinal;
class procedure Unmake(aValue: cardinal; out aDays, aHours, aMinutes, aSeconds, aMilliseconds: cardinal);
class function MillisecondsToDays(aValue: cardinal): cardinal;
class function MillisecondsToHours(aValue: cardinal): cardinal;
class function MillisecondsToMinutes(aValue: cardinal): cardinal;
class function MillisecondsToSeconds(aValue: cardinal): cardinal;
class function Milliseconds(aValue: cardinal): cardinal;
class function SecondsToMilliseconds(aValue: cardinal): cardinal; inline;
class function MinutesToMilliseconds(aValue: cardinal): cardinal; inline;
class function HoursToMilliseconds(aValue: cardinal): cardinal; inline;
class function DaysToMilliseconds(aValue: cardinal): cardinal; inline;
end;
Implementation
{ TTimeSpan }
class function TTimeSpan.DaysToMilliseconds(aValue: cardinal): cardinal;
begin
result := HoursToMilliseconds(aValue) * 24;
end;
class function TTimeSpan.HoursToMilliseconds(aValue: cardinal): cardinal;
begin
result := MinutesToMilliseconds(aValue) * 60;
end;
class function TTimeSpan.MinutesToMilliseconds(aValue: cardinal): cardinal;
begin
result := SecondsToMilliseconds(aValue) * 60;
end;
class function TTimeSpan.SecondsToMilliseconds(aValue: cardinal): cardinal;
begin
result := aValue * 1000;
end;
class procedure TTimeSpan.Unmake(aValue: cardinal; out aDays, aHours, aMinutes, aSeconds, aMilliseconds: cardinal);
begin
aDays := MillisecondsToDays(aValue);
Dec(aValue, DaysToMilliseconds(aDays));
aHours := MillisecondsToHours(aValue);
Dec(aValue, HoursToMilliseconds(aHours));
aMinutes := MillisecondsToMinutes(aValue);
Dec(aValue, MinutesToMilliseconds(aMinutes));
aSeconds := MillisecondsToSeconds(aValue);
Dec(aValue, SecondsToMilliseconds(aSeconds));
aMilliseconds := aValue;
end;
class function TTimeSpan.Make(aDays, aHours, aMinutes, aSeconds, aMilliseconds: cardinal): cardinal;
begin
result := Milliseconds(aMilliseconds) + SecondsToMilliseconds(aSeconds) + MinutesToMilliseconds(aMinutes) + HoursToMilliseconds(aHours) + DaysToMilliseconds(aDays);
end;
class function TTimeSpan.MillisecondsToDays(aValue: cardinal): cardinal;
begin
Result := aValue div (1000 * 60 * 60 * 24);
end;
class function TTimeSpan.MillisecondsToHours(aValue: cardinal): cardinal;
begin
Result := aValue div (1000 * 60 * 60);
end;
class function TTimeSpan.Milliseconds(aValue: cardinal): cardinal;
begin
Result := aValue;
end;
class function TTimeSpan.MillisecondsToMinutes(aValue: cardinal): cardinal;
begin
Result := aValue div (1000 * 60);
end;
class function TTimeSpan.MillisecondsToSeconds(aValue: cardinal): cardinal;
begin
Result := aValue div 1000;
end
Example:
if Pos('level', cmd) = 1 then
begin
//level 40 30 0 (40 moves, 30 minutes, 0)
SplitString(cmd, ' ', list);
FEngine.SetTimePerGame(TTimeSpan.MinutesToMilliseconds(StrToInt(list[2])));
{ TODO : 40 moves 5 minutes }
Exit(True);
end;
Enjoy it?