Learn Object Pascal

Part 7 - Custom datatypes

We have seen the basic datatypes in the third tutorial of our series.
Now we will see how from these basic datatypes we can create new more complex datatypes.
In this tutorial we will see how we can construct "smaller" datatypes from one that we already know.
For example the smaller datatype in Pascal is a byte (byte datatype).
One byte contains 8 bits.
So a byte can hold 2^n_bits=2^8 values = 256 values.


Let's imagine this use case.
We need to store the data on an apartment.
Each apartment has a scale (maximum scales = 4)
Each apartment has a floor (up to 8 floors)
and finally each apartment has a internal number (up to 8 apartments for each floor).

We could say :
var
  apartment_scale : integer;
  apartment_floor : integer;
  apartment_internal : integer;
If we see carefully in our example we need :
for scale only 2 bits since 2^2=4
for the floor only 3 bits since 2^3=8
and for internal number again also 3 bits since 2^3=8.
So in total for each apartment we need only 2+3+3 = 8 bits = 1 byte !
We can define a local variable apartment as a byte like this :
var
  apartment: byte;
The apartment byte has three regions :
AB - CDE - FGH bits.
The AB is the scale number
The CDE is the floor number and the
FGH is the internal number


Using the bitwise operators AND, OR, shr, shl we can parse and store the bits into the apartment byte. The important things you should remember are :
0 AND X = 0 / 1 AND X = X [masking]
0 OR X = X
ABCDEFGH shr 1 = 0ABCDEFG
ABCDEFGH shl 1 = BCDEFGH0
Let's see how this can be done in our example.
Please read the comments the code in posted below.
function GetScale(a:byte):byte;
begin
  result := a shr 6; //ABCDEFGH -> 000000AB
end;

function SetScale(a,scale:byte):byte;
begin

  //remove the old scale from the apartment
  a := a and %00111111; // 0 AND X = 0 / 1 AND X = X
  //ABCDEFGH and %00111111 = 00CDEFGH

  scale := scale shl 6; //scale uses only two bits since max_scale=4 so
  //000000AB -> AB000000 position the scale correctly

  result := a or scale; // 0 OR X = X
  //00CDEFGH or AB000000 = ABCDEFGH
end;


function GetFloor(a:byte):byte;
begin
  a := a and %00111000; //get floor 0 AND X = 0 / 1 AND X = X
  //ABCDEFGH and %00111000; = 00CDE000
  
  result := a shr 3; //00CDE000 -> 00000CDE
end;


function SetFloor(a,floor:byte):byte;
begin

  //remove the old floor from the apartment
  a := a and %11000111; // 0 AND X = 0 / 1 AND X = X
  //ABCDEFGH and %11000111 = AB000FGH

  floor := floor shl 3; //(max_floor=8 so we use at most 3 bits)
  //00000CDE -> 00CDE000 position the floor correctly

  result := a or floor; // 0 OR X = X
  //AB000FGH or 00CDE000 = ABCDEFGH
  
end;


function GetInternal(a:byte):byte;
begin
  result := a and %00000111; //get internal 0 AND X = 0 / 1 AND X = X
  //ABCDEFGH and %00000111; = 00000FGH
end;

function SetInternal(a,internal:byte):byte;
begin

  //remove the old internal from the apartment
  a := a and %11111000; // 0 AND X = 0 / 1 AND X = X
  //ABCDEFGH and %11111000 = ABCDE000

  //internal is positioned well : 00000FGH

  result := a or internal; // 0 OR X = X
  //ABCDE000 OR 00000FGH = ABCDEFGH
  
end;  
Now it is time to test our functions. We have created two apartments.
Notice that : scale takes values from 0 to 3
floor takes values from 0 to 7
and internal number from 0 to 7

As always we use a form a button and a memo component.
Our program is triggered by OnClick Button event
procedure TForm1.Button1Click(Sender: TObject);
{
max_values = 2^bits
A byte contain 8 bits
A appartment is characterized by  :
  scale number (up to 4) : (two bits needed 2^2=4)
  floor number (up to 8) : (three bits needed 2^3=8)
  internal number (up to 8 appartments per floor) :  (three bits needed 2^3=8)

So apartment for us is :
AB-CDE-FGH
[1-2 bits : scale number] [3-5 bits : floor number] [6-8 : internal number]
}

var apartment, apartment2 : byte;
begin
  apartment:=%00000000; //initialize

  //set apartment : second scale , sixth floor , eight apartment
  apartment:=SetScale(apartment,1); //set second scale [0,1,2,3]
  apartment:=SetFloor(apartment,5); //set sixth floor [0,1,2,3,4,5,6,7]
  apartment:=SetInternal(apartment,7); //set eight internal apartment [0,1,2,3,4,5,6,7]

  Memo1.Lines.Add('See full apartment byte : ' + binStr(apartment,8));
  Memo1.Lines.Add('Scale :' + IntToStr(GetScale(apartment)));
  Memo1.Lines.Add('Floor :' + IntToStr(GetFloor(apartment)));
  Memo1.Lines.Add('Internal :' + IntToStr(GetInternal(apartment)));

  Memo1.Lines.Add('---------------');

  //change apartment's floor
  apartment:=SetFloor(apartment,4); //fifth sixth floor [0,1,2,3,4,5,6,7]
  Memo1.Lines.Add('See full apartment byte : ' + binStr(apartment,8));
  Memo1.Lines.Add('Scale :' + IntToStr(GetScale(apartment)));
  Memo1.Lines.Add('Floor :' + IntToStr(GetFloor(apartment)));
  Memo1.Lines.Add('Internal :' + IntToStr(GetInternal(apartment)));


  Memo1.Lines.Add('---------------');

  //set another apartment : third scale , second floor , forth apartment
  apartment2:=SetScale(apartment2,2); //set third scale
  apartment2:=SetFloor(apartment2,1); //set second floor
  apartment2:=SetInternal(apartment2,3); //set forth internal apartment

  Memo1.Lines.Add('See full apartment2 byte : ' + binStr(apartment2,8));
  Memo1.Lines.Add('Scale :' + IntToStr(GetScale(apartment2)));
  Memo1.Lines.Add('Floor :' + IntToStr(GetFloor(apartment2)));
  Memo1.Lines.Add('Internal :' + IntToStr(GetInternal(apartment2)));

end;
In the next tutorial we will talk about Enumerated types, subranges and sets.
You can download the program of this section from here



Part 1: Introduction - Part 2: Hello World - Part 3: Data types, constants and variables - Part 4: Operators - Part 5: Decisions and Loops - Part 6: Procedures and Functions - [[ Part 7: Custom datatypes ]] - Part 8: Enumerations, subranges and sets - Part 9: Records


Copyright © TrustFm.net 1998-2024 - Made by TrustFm - All Rights Reserved Worldwide