Thursday, October 28, 2010

Some utils...

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?

No comments:

Post a Comment