Lazarus

Free Pascal => General => Topic started by: Paul_ on June 28, 2019, 02:56:38 pm

Title: Record with different variables - better workaround?
Post by: Paul_ on June 28, 2019, 02:56:38 pm
My goal is to have one "unified" record (TVehicle) which can contains (passed by pointer) different types/variables (TCarParameters or TTruckParameters) like in example.
Could it be (whole structure, passing parameters etc.) somehow simplified? Thanks.

Code: Pascal  [Select][+][-]
  1. //{$mode delphi}
  2. {$mode objfpc}{$H+}
  3. {$modeswitch ADVANCEDRECORDS}
  4.  
  5. Uses crt, sysUtils;
  6.  
  7. Type
  8.   TVehicleType = ( Car , Truck );
  9.  
  10.   PCarParameters = ^TCarParameters;
  11.   TCarParameters = record
  12.     crew : Integer;
  13.   end;
  14.  
  15.   PTruckParameters = ^TTruckParameters;
  16.   TTruckParameters = record
  17.     cargo   : Integer;
  18.     trailer : Boolean;
  19.   end;
  20.  
  21.   PVehicle = ^TVehicle;
  22.   TVehicle = record
  23.     carType    : TVehicleType;
  24.     parameters : Pointer;
  25.   end;
  26.  
  27.   TVehicleDatabase = record
  28.     list       : Array [0..9] of TVehicle;
  29.     count      : Integer;
  30.  
  31.     procedure Init;
  32.     procedure AddVehicle(const _carType: TVehicleType; const _parameters: pointer); // GetMem
  33.     procedure WriteInfo(Index: Integer);
  34.     procedure Free;
  35.   end;
  36.  
  37. Var
  38.   DB : TVehicleDatabase;
  39.  
  40. procedure TVehicleDatabase.Init;
  41. begin
  42.   count := 0;
  43. end;
  44.  
  45. procedure TVehicleDatabase.AddVehicle( const _carType : TVehicleType; const _parameters : pointer );
  46. var
  47.   pT : PTruckParameters;
  48. begin
  49.   if count - 1 = high(list) then exit;
  50.  
  51.   list[count].carType := _carType;
  52.  
  53.   case list[count].carType of
  54.     // First option
  55.     car : begin
  56.       GetMem( list[count].Parameters, SizeOf(TCarParameters) );
  57.       FillChar(list[count].Parameters^, SizeOf(TCarParameters), 0);
  58.  
  59.       TCarParameters( list[count].parameters^ ).crew := TCarParameters( _parameters^ ).crew;
  60.     end;
  61.  
  62.     // Second option
  63.     truck :  begin
  64.       GetMem( list[count].Parameters, SizeOf(TTruckParameters) );
  65.       FillChar(list[count].Parameters^, SizeOf(TTruckParameters), 0);
  66.  
  67.       pT := list[count].parameters;
  68.  
  69.       pT^.cargo := TTruckParameters( _parameters^ ).cargo;
  70.       pT^.trailer := TTruckParameters( _parameters^ ).trailer;
  71.     end;
  72.   end;
  73.  
  74.   inc( count );
  75. end;
  76.  
  77. procedure TVehicleDatabase.WriteInfo( Index : Integer );
  78. begin
  79.   writeln( 'Vehicle[' + IntToStr( Index ) + '].CarType: ', ord( list[index].CarType ) );
  80.  
  81.   case list[index].carType of
  82.     car : With TCarParameters( list[index].Parameters^ ) do
  83.       begin
  84.         Writeln( 'Vehicle[' + IntToStr( Index ) + '].crew:  ', crew );
  85.       end;
  86.  
  87.     truck : With TTruckParameters( list[index].Parameters^ ) do
  88.       begin
  89.         writeln( 'Vehicle[' + IntToStr( Index ) + '].cargo:  ', cargo );
  90.         writeln( 'Vehicle[' + IntToStr( Index ) + '].trailer: ', trailer );
  91.       end;
  92.   end;
  93.  
  94.   writeln( '--------------------------' );
  95.   writeln;
  96. end;
  97.  
  98. procedure TVehicleDatabase.Free;
  99. var
  100.   i  : Integer;
  101. begin
  102.   for i := 0 to count -1 do
  103.     freemem( list[i].parameters );
  104. end;
  105.  
  106. var
  107.   car_params   : TCarParameters;
  108.   truck_params : TTruckParameters;
  109.   i            : Integer;
  110.  
  111. begin
  112.   DB.Init;
  113.  
  114.   car_params.crew := 1;
  115.   DB.AddVehicle( car, @car_params );
  116.  
  117.   car_params.crew := 4;
  118.   DB.AddVehicle( car, @car_params );
  119.  
  120.   truck_params.cargo := 2000;
  121.   truck_params.trailer := true;
  122.   DB.AddVehicle( truck, @truck_params );
  123.  
  124.   truck_params.cargo := 0;
  125.   truck_params.trailer := false;
  126.   DB.AddVehicle( truck, @truck_params );
  127.  
  128.   for i := 0 to DB.count -1 do
  129.     DB.WriteInfo(i);
  130.  
  131.   DB.Free;
  132.  
  133.   readkey;
  134. end.
Title: Re: Record with different variables - better workaround?
Post by: LemonParty on June 28, 2019, 04:31:28 pm
Put TVehicleType variable into TCarParameters and TTruckParameters (and into all other variations) as a first field, than you need to store only raw pointers inside of a hub structure.
After you can check what pointer actually is by checking the first field (use typecast, Luke).

Use New (https://www.freepascal.org/docs-html/rtl/system/new.html) instead of GetMem.

Use Move (https://www.freepascal.org/docs-html/rtl/system/move.html) to make an identical copy of a passing structure. I mean this code:
Code: Pascal  [Select][+][-]
  1.  pT^.cargo := TTruckParameters( _parameters^ ).cargo;
  2.  pT^.trailer := TTruckParameters( _parameters^ ).trailer;
Title: Re: Record with different variables - better workaround?
Post by: engkin on June 28, 2019, 04:57:53 pm
Just to make sure, are you familiar with the variant part (https://www.freepascal.org/docs-html/ref/refsu15.html#x39-550003.3.2) of records?
Title: Re: Record with different variables - better workaround?
Post by: julkas on June 28, 2019, 05:55:52 pm
@Paul_ one question. Why not OOP? Why not classes?
Title: Re: Record with different variables - better workaround?
Post by: Paul_ on June 28, 2019, 07:49:42 pm
@LemonParty: Thanks, I will check it.

@engkin: Problem is that variant takes full size of case segment in memory, it has more specific use then.

@julkas: I'm not good in OOP, with pointers is fun and benefit is in way better performance.   

Title: Re: Record with different variables - better workaround?
Post by: Thaddy on June 28, 2019, 08:16:21 pm
benefit is in way better performance.
That's simply not true.
TinyPortal © 2005-2018