Recent

Author Topic: [CLOSED] type conversion : routine to convert a "set of" into an integer type  (Read 652 times)

devEric69

  • Full Member
  • ***
  • Posts: 247
I searched the Free Pascal documentation without finding anything.

On the web, I found this which works:

Code: Pascal  [Select]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. type
  3.   TmySetof = Set of (so0=0, so1, so2, so3, so4, so5, so6, so7, so8, so9, so10);
  4. var
  5.   aSetof, anotherSetof: TmySetof;
  6.   iResult: integer;
  7.   sDebug: string;
  8.  
  9.         function SetofToInt(const aSetOf; const iSize: integer): integer;
  10.         begin
  11.             result:= 0;
  12.             Move(aSetOf, result, iSize);
  13.         end;
  14.  
  15.         procedure InToSetof(const aValue: integer; var aSetOf; const iSize: integer);
  16.         begin
  17.             Move(aValue, aSetOf, iSize);
  18.         end;
  19.  
  20. begin
  21.     aSetof:= [so0, so1, so9];
  22.     iResult:= SetofToInt(aSetof, SizeOf(aSetof));
  23.     ShowMessage('iResult=' + IntToStr(iResult));
  24.     // for me, it displays 515;
  25.     // now, test if the above hard-coded displayed result is ok:
  26.     InToSetof(515, anotherSetof, SizeOf(aSetof));
  27.     sDebug:= '';
  28.     if anotherSetof * [so0] <> [] then sDebug:= sDebug+',so0';
  29.     if anotherSetof * [so1] <> [] then sDebug:= sDebug+',so1';
  30.     if anotherSetof * [so2] <> [] then sDebug:= sDebug+',so2';
  31.     if anotherSetof * [so3] <> [] then sDebug:= sDebug+',so3';
  32.     if anotherSetof * [so4] <> [] then sDebug:= sDebug+',so4';
  33.     if anotherSetof * [so5] <> [] then sDebug:= sDebug+',so5';
  34.     if anotherSetof * [so6] <> [] then sDebug:= sDebug+',so6';
  35.     if anotherSetof * [so7] <> [] then sDebug:= sDebug+',so7';
  36.     if anotherSetof * [so8] <> [] then sDebug:= sDebug+',so8';
  37.     if anotherSetof * [so9] <> [] then sDebug:= sDebug+',so9';
  38.     if anotherSetof * [so10] <> [] then sDebug:= sDebug+',so10';
  39.     ShowMessage('[setOf]=' + sDebug);
  40. end;

a) is it optimal?
b) if yes, couldn't it be added in an inter-types conversion routine (e.g. useful: passing a "Set of" via a TStream with ReadBuffer)?

Otherwise, if it can help others...
« Last Edit: January 22, 2020, 12:02:30 pm by devEric69 »
use: Linux 64 bits (Ubuntu 18.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

wp

  • Hero Member
  • *****
  • Posts: 6723
Re: type conversion : routine to convert a "set of" into an integer type
« Reply #1 on: January 21, 2020, 07:39:19 pm »
Use type casts to/from integer und SetToString/StringToSet from unit typinfo instead:
Code: Pascal  [Select]
  1. uses
  2.   TypInfo;
  3.  
  4. procedure TForm1.Button3Click(Sender: TObject);
  5. type
  6.   TmySetof = Set of (so0=0, so1, so2, so3, so4, so5, so6, so7, so8, so9, so10);
  7. var
  8.   aSetOf: TmySetOf = [so0, so1, so9];
  9.   anotherSetOf: TmySetOf;
  10.   iResult: Integer;
  11. begin
  12.   iResult := Integer(aSetOf);
  13.   anotherSetOf := TmySetof(iResult);
  14.  
  15.   ShowMessage(
  16.     IntToStr(iResult) + LineEnding +
  17.     SetToString(PTypeInfo(TypeInfo(TmySetOf)), Integer(aSetOf), true) + LineEnding +
  18.     SetToString(PTypeInfo(TypeInfo(TmySetOf)), Integer(anotherSetOf), true) + LineEnding
  19.   );
  20. end;  
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

PascalDragon

  • Hero Member
  • *****
  • Posts: 963
  • Compiler Developer
Re: type conversion : routine to convert a "set of" into an integer type
« Reply #2 on: January 21, 2020, 11:18:49 pm »
a) is it optimal?

In addition/as an explanation to what wp wrote: a set with a size <= 8 Byte can be cast to an integer type of the same size and vice versa (the size of a set depends on the number of elements and the $PackSet directive).

devEric69

  • Full Member
  • ***
  • Posts: 247
Re: type conversion : routine to convert a "set of" into an integer type
« Reply #3 on: January 22, 2020, 12:01:37 pm »
Quote
In addition/as an explanation to what wp wrote: a set with a size <= 8 Byte can be cast to an integer type of the same size and vice versa (the size of a set depends on the number of elements and the $PackSet directive)

Thank you @wp and @PascalDragon.
Inspired by this post too, https://forum.lazarus.freepascal.org/index.php/topic,40761.msg281747.html#msg281747, then, in pseudo-code, I have to test the number of elements in the set, (to know in which "abacus" the number of elements of the "set of" falls, ie to know for example if the set goes over 32 elements "abacus"):

Code: Pascal  [Select]
  1.         iResultInt := Integer(aSetOf);
  2.         .../...
  3.     else if Ord(High(TmySetOf)) > 32 then begin
  4.         {$PACKSET 4}
  5.         iResult64 := Int64(aSetOf);
  6.         .../...
« Last Edit: January 22, 2020, 12:15:17 pm by devEric69 »
use: Linux 64 bits (Ubuntu 18.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

lucamar

  • Hero Member
  • *****
  • Posts: 2403
The directive {$PACKSET 4} only affects subsequent declarations so it should be before the declaration of aSetOf. Otherwise the compiler will assume the set uses whatever packing was in effect at the time it's declared.

Anyway, it's much easier to use SizeOf(), as in:

Code: Pascal  [Select]
  1. if SizeOf(TmySetOf) = SizeOf(Int64) then ...
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.4/2.0.6  - FPC 3.0.4 on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

howardpc

  • Hero Member
  • *****
  • Posts: 3310
And, strictly speaking, should the cast not be QWord() rather than Int64() ?

PascalDragon

  • Hero Member
  • *****
  • Posts: 963
  • Compiler Developer
And, strictly speaking, should the cast not be QWord() rather than Int64() ?

Pascal prefers signed types, so that's what most code uses (e.g. TypInfo.SetToString takes a Integer as well). In the end, as long as the size fits, the compiler doesn't care whether it's signed or unsigned...