Delphi: Binary Data Storage

When developing software you’ll often have to store data for some purpose, whether this being int he form of files that your program outputs, settings or other things. One of the things you’ll certainly almost always have to store are boolean values, True or False. This can be done in various ways, the worst way to tackle the problem would be to create a delimited string with the boolean values as strings ‘True’ and ‘False’, which would result in a string like ‘True|True|False|True|False|False|False|True’. The reason this is the worst way to handle the problem is simply because it takes up so much space. A boolean is a single bit value, meaning it contains a value that can be stored in 1 bit. By storing it in the previous manner you will be using 4 bytes or 32 bits for “True’ and 5 bytes or 40 bits for False and an additional 1 byte or 8 bits for each delimiter.

Another way to store the booleans is simple by converting them to byte values. Bytes are the smallest primitive datatypes in the Delphi programming language, they are 1 byte or 8-bit unsigned values. So by converting the booleans to this datatype, you can store a boolean as a single byte. This can be done by casting it to Byte and preferably convert it to a Char and back to Byte so you get the characters 0 and 1 as result Byte(Chr(Byte(MyBoolean))). Because the length of True and False is now the same, you can append this into a single string without delimiters, so your result will be something like ‘11010001’.

If you’ve counted the number of booleans in my previous examples you probably see where this is going. The previous method is ok to use but if you really want to conserve file size you should take it even a step further. The previous method uses a byte value to store a boolean, a byte contains 8 bits and as I mentioned before a boolean can be stored in a single bit as it can only be 2 values. so in theory this would let us store 8 booleans in a single byte. to do this we will have to write a bit more complex code. We will use bitshiting to shift up to 8 boolean values into a single byte and then reverse the process.

Selecting the most right bit in a value can be done by applying the bitwise and operator to the value along with the value 1. When you do this to a bit you can cast it directly to Boolean. If you want the next bit, you use a right bitshift of a single position to shift the value and then you can select that first bit again, only this time it will be the bit that used to be next in line. The same is true the other way around, to shift bits into a single value, you just convert a boolean to an integer and apply it to the value with a bitwise or, then you shift the value 1 position to the left with a left bitshift and you can repeat the process.

Here’s an example:

program BoolsTest;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TBooleanArray = array of Boolean;

function BoolToChar(const Bools: TBooleanArray): Char;
var
  Buffer: Byte;
  i, l: Integer;
begin
  Buffer := 0;
  i := 0;
  l := Length(Bools);
  while (i < l) and (i <> 8) do
  begin
    Buffer := (Buffer shl 1) or Integer(Bools[i]);
    Inc(i);
  end;
  Result := Chr(Buffer);
end;

procedure CharToBool(const c: Char; out Bools: TBooleanArray;
  const Len: Integer = 8);
var
  Buffer: Byte;
  i: Integer;
begin
  Buffer := Ord(c);
  SetLength(Bools, Len);
  for i := Len - 1 downto 0 do
  begin
    Bools[i] := Boolean(Buffer and 1);
    Buffer := Buffer shr 1;
  end;
end;

var
  Booleans: TBooleanArray;
  c: Char;
begin
  // Initialize boolean array
  SetLength(Booleans, 8);
  Booleans[0] := True;
  Booleans[1] := False;
  Booleans[2] := True;
  Booleans[3] := False;
  Booleans[4] := False;
  Booleans[5] := True;
  Booleans[6] := True;
  Booleans[7] := False;
  // Convert booleans to char
  c := BoolToChar(Booleans);
  WriteLn(c);
  // Set the boolean array to False
  FillChar(Booleans, 8, 0);
  // Convert char back to boolean array
  CharToBool(c, Booleans);
  // Convert back to char to show the output is the same
  c := BoolToChar(Booleans);
  WriteLn(c);
  ReadLn; // Prevent window from closing
end.

Read More

Delphi: Operator Overloading

Delphi has the ability to include operator overloading for structured types, this allows you to use any standard operator on your structured type. The Delphi documentation on the subject states that you can apply operator overloading to both structured types and classes, however this is wrong, it can only be applied to structured types. Here’s an example of it being used:

program OperatorsTest;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TIntValue = record
  private
    FValue: Integer;
  public
    class operator Add(const a, b: TIntValue): TIntValue;
    class operator Implicit(const a: Integer): TIntValue;
    class operator Implicit(const a: TIntValue): Integer;
    property Value: Integer read FValue;
  end;

{ TIntValue }

class operator TIntValue.Add(const a, b: TIntValue): TIntValue;
begin
  Result.FValue := a.FValue + b.FValue;
end;

class operator TIntValue.Implicit(const a: Integer): TIntValue;
begin
  Result.FValue := a;
end;

class operator TIntValue.Implicit(const a: TIntValue): Integer;
begin
  Result := a.FValue;
end;

var
  Int: TIntValue;

begin
  Int := 5;
  Int := Int + 10;
  WriteLn(IntToStr(Int));
  Readln; // Prevent window from closing
end.

The documentation shows you all of the operators you can overload and has some extra examples as well.

Read More

Delphi: Singleton Patterns

I’m a big fan of singleton patterns, basically a singleton pattern lets a class maintain a single instance of itself which you can then reuse as often as you want without having to create a new instance. This is achieved by creating a private static field inside the class that can hold an instance of itself, when the user wants to retrieve the instance for the first time, a new one is created and stored in the field, if there’s already one present, the class will return that instance. The implementation I usually use also has automated cleaning of the instance once the application terminates by adding a shared constructor. It’s also possible to add a private constructor to the class to disable the coder to create any instances of it directly without using the singleton pattern or subclassing it.

Here’s an example of the singleton pattern with cleaning:

type
  TTestClass = class
  private
    class var FInstance: TTestClass;
  public                               
    class function GetInstance: TTestClass;
    class destructor DestroyClass;
  end;

{ TTestClass }

class destructor TTestClass.DestroyClass;
begin
  if Assigned(FInstance) then
    FInstance.Free;
end;

class function TTestClass.GetInstance: TTestClass;
begin
  if not Assigned(FInstance) then
    FInstance := TTestClass.Create;
  Result := FInstance;
end;

It’s also possible to add a property named Instance or something even shorter that will get the instance from the GetInstance method which you would then make private, this will shorten the amount of code you have to write when using it.

Read More

Delphi: Static Members

Delphi comes with support for both OOP and procedural code, something you come across less every day as more languages move over to an OOP-only structure. Because of this static code in Delphi is often added as procedural code, which makes sense of course. However, Delphi also has the ability to add static members to classes which can be quite useful at times.

Delphi features several different kinds of static members. The first are fields and properties. A Delphi class can contain any number of static fields and properties which work the exact same way as a regular member would, however they can only be accessed in a static context. Same as with regular properties a static property can retrieve values by calling methods, however all of these accessors and mutators have to be static members as well.

Aside from fields, properties and methods, Delphi classes can also hold shared constructors/destructors. A shared constructor is called when the application is started and allows you to initialize static fields or other stuff you might want to initialize from a static context in or possibly outside of the class. A shared destructor is called when your application is terminated, this allows you to clean up static resources and such. This is similar to the initialization and finalization clauses, but part of a class instead of the entire unit.

Static fields have to be added by adding the keywords “class var” as prefix. For properties you just add “class”. Static methods need to have prefix “class” and they can also take a “static;” at the end, this isn’t required for regular methods, but it is for mutators and accessors. Shared constructors/destructors also only need to have “class” added in front of them. Note that static contructors/destructors can take any name, even Create/Destroy, but i personally prefer the names CreateClass/DestroyClass.

Here’s an example that will show you all of these features:

program StaticTest;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

type
  TTestClass = class
  private
    class var FStaticField: TStrings;
    class function GetStaticField: string; static;
    class procedure SetStaticField(const Value: string); static;
  public
    class property StaticField: string read GetStaticField write SetStaticField;
    class constructor CreateClass;
    class destructor DestroyClass;
  end;

{ TTestClass }

class constructor TTestClass.CreateClass;
begin
  FStaticField := TStringList.Create;
  FStaticField.Text := 'Hello world!';
end;

class destructor TTestClass.DestroyClass;
begin
  FStaticField.Free;
end;

class function TTestClass.GetStaticField: string;
begin
  Result := FStaticField.Text;
end;

class procedure TTestClass.SetStaticField(const Value: string);
begin
  FStaticField.Text := Value;
end;

begin
  WriteLn(TTestClass.StaticField);
  ReadLn; // Stop window from closing
end.

Read More

Delphi: Thread Variables

A somewhat less known feature of Delphi is thread variables. Thread variables are variables that can contain a different value for each thread in the application. They are defined like regular variables, the only difference is that the “var” keyword is replaced with “threadvar”. In the example below I’ll show you how they work in a small console application. Note that I used the TThread class for convenience, however in reality you’ll only ever need this for procedural code as you can add fields to your TThread subclass to store data in for each thread. The example uses the main thread and a separated thread to show you how it works.

program ThreadVarTest;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

type
  TTestThread = class(TThread)
  protected
    procedure Execute; override;
  public
    constructor Create;
  end;

threadvar
  TestVar: string;

var
  i: Integer;

procedure Test;
begin
  WriteLn('Original TestVar: ' + TestVar);
  TestVar := 'Asdf' + IntToStr(i);
  Inc(i);
  WriteLn('New TestVar: ' + TestVar);
end;

{ TTestThread }

constructor TTestThread.Create;
begin
  inherited Create(False);
  FreeOnTerminate := True;
end;

procedure TTestThread.Execute;
begin
  Test;
end;

begin
  i := 0;
  Test;
  WriteLn('Starting thread.');
  TTestThread.Create;
  ReadLn;
  WriteLn(TestVar);
  ReadLn; // Prevent window from closing
end.

As you can see when running it, even though the content of the thread variable was changed, the variable was still empty when accessed by the new thread. I’ve added the incremental number to show you that when after you press a key when the thread has exited and you check the thread variable content for the main thread, it will show Adsf0 as it was stored by the main thread originaly.

Read More

Delphi: Decimal color to RGB and back

Converting a decimal color value (24-bit) to RGB in Delphi is easy using bitshifts, the reverse is true as well. Here’s how it’s done:

procedure ColorToRGB(const Color: Integer; out R, G, B: Byte);
begin
  R := Color and $FF;
  G := (Color shr 8) and $FF;
  B := (Color shr 16) and $FF;
end;

function RGBToColor(const R, G, B: Byte): Integer;
begin
  Result := R or (G shl 8) or (B shl 16);
end;

Take in mind that Delphi TColor is a 24-bit integer decimal color representation.

Read More