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