Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Set as integer value

132 views
Skip to first unread message

Alexander Halser

unread,
Jan 31, 2008, 5:41:36 PM1/31/08
to
I need to save a set as an integer value and I would like to convert this more
easyily than I do now. The set is a set of constants, something like this:


TMyProperty = (mpValueA, mpValueB, mpValueC, ...);
TMyProperties = set of TMyProperties;


To save that, I use this:

function SaveProperties(value: TMyProperties);
var
v: integer;
begin
v := 0;
if (mpValueA in Value) then inc(v, integer(mpValueA));
if (mpValueB in Value) then inc(v, integer(mpValueB));
if (mpValueC in Value) then inc(v, integer(mpValueC));

... save integer value v
end;


Is there a more elegant way to do that? Something like an integer typecast on
TMyProperties?

--
Alexander Halser

Glynn Owen

unread,
Jan 31, 2008, 5:20:37 PM1/31/08
to
Alexander Halser wrote:


An enumeration with 0..7 values fits into 1 byte. One with 0..15 values
fits into a Word. One with 0..31 values fits into a 32-bit integer.
Larger enums require bigger collections of bytes, up to 32, which is
the max that Delphi will handle. You can find out exactly how many by
using sizeof(TMyProperties). If the result is 1, 2, or 4, you store the
set as an integer directly.

If your enumeration has, for example, 11 members, it will fit into a
word as a set, so you can do this -

Var IntSet:Integer;

IntSet := word(Value);

Save(IntSet);

In the other direction, you can do this -

Var W:word;

W := IntSet;

Value := TMyProperties(W);

HTH,
Glynn


--
We do not see things as they are; we see them as we are - David Zindell
in Neverness

Alexander Halser

unread,
Feb 1, 2008, 11:46:19 AM2/1/08
to
In theory, yes. I understand the concept of sets so far.
It's just that the compiler refuses to compile this kind of typecast... and
that's my problem ;-)

--
Alexander

"Glynn Owen" <SandNOTREALLYSpeakerATcrestviewcable.com> wrote in message
news:47a2...@newsgroups.borland.com...

Glynn Owen

unread,
Feb 1, 2008, 11:46:36 AM2/1/08
to
Glynn Owen wrote:

Your code is trying to cast enumerations as integers. The proper way to
do this is (using your example) -

inc(v, ord(mpValueA))

However, I don't see that this accomplishes what you seem to intend.
What version of Delphi are you using? This compiles on my D7 machine -

Type
TFruit = (Apple, Orange, Banana);
TFruitBasket = set of TFruit;

Procedure SaveBasket(aBasket:Integer);
Var Basket:TFruitBasket;
Begin
byte(Basket) := byte(aBasket);
End;

Procedure Test;
Var Basket:TFruitBasket;
IntBasket:Integer;
Begin
Basket := [Apple,Orange];
IntBasket := byte(Basket);
SaveBasket(IntBasket);
End;

Regards,

John Herbster

unread,
Feb 1, 2008, 12:56:09 PM2/1/08
to
"Alexander Halser" <my....@ec-software.com> wrote

> I understand the concept of sets so far.

Alexander,

Does the storage size of the set variable match the size of
what you are trying to cast it to?

> It's just that the compiler refuses to compile this kind of typecast... and

>> TMyProperty = (mpValueA, mpValueB, mpValueC, ...);

Exactly how many elements does your set contain?

Rgds, JohnH

Jens Gruschel

unread,
Feb 1, 2008, 1:21:02 PM2/1/08
to
Here is a solution that works without any knowledge about how sets are
stored internally...

> TMyProperty = (mpValueA, mpValueB, mpValueC, ...);
> TMyProperties = set of TMyProperties;

function SaveProperties(value: TMyProperties);
var
v: TMyProperty;
i, r: integer;
begin
r := 0;
i := 1;
for v := Low(TMyProperty) to High(TMyProperty) do begin
if (v in Value) then inc(r, i);
inc(i, i);
end;

... save integer value r
end;


--
Jens Gruschel
http://www.pegtop.net

Jens Gruschel

unread,
Feb 1, 2008, 1:23:12 PM2/1/08
to
or maybe...

> TMyProperty = (mpValueA, mpValueB, mpValueC, ...);
> TMyProperties = set of TMyProperties;

function SaveProperties(value: TMyProperties);
var
v: TMyProperty;

r: integer;
begin
r := 0;

for v := Low(TMyProperty) to High(TMyProperty) do begin

if (v in Value) then inc(r, 1 shl Ord(v));

Marc Rohloff [TeamB]

unread,
Feb 1, 2008, 1:37:15 PM2/1/08
to
On Fri, 1 Feb 2008 17:46:19 +0100, Alexander Halser wrote:

> In theory, yes. I understand the concept of sets so far.
> It's just that the compiler refuses to compile this kind of typecast... and
> that's my problem ;-)

Glen's code compiles for me. Can you paste your exact code?

--
Marc Rohloff [TeamB]
marc -at- marc rohloff -dot- com

Glynn Owen

unread,
Feb 1, 2008, 1:44:30 PM2/1/08
to
Jens Gruschel wrote:

Very neat. This would do for a 64-bit integer as well, and would be a
better solution, in that it does not depend so entirely on how a set is
implemented.

Alexander Halser

unread,
Feb 1, 2008, 2:52:37 PM2/1/08
to
I must be doing something wrong... is there a compiler switch that prevents
this typecast?
I'm using Delphi 2007 and this is a Win32 VCL project. This is the code:

---------------------
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TMyProperty = (mpValueA, mpValueB, mpValueC);
TMyProperties = set of TMyProperty;

procedure SaveProperty(value: TMyProperties);

implementation

procedure SaveProperty(value: TMyProperties);
var
v: word;
begin
v := word(value); // <== [DCC Error]: E2089 Invalid typecast
showmessage(inttostr(v));
end;

end.
---------------------

Alexander

"John Herbster" <herb-sci1_AT_sbcglobal.net> wrote in message
news:47a35d30$1...@newsgroups.borland.com...

Glynn Owen

unread,
Feb 1, 2008, 2:41:21 PM2/1/08
to

As I told you, different enumerations require a different number of
bytes to hold them as a set. It this case, only 1 byte is required. You
would have seen that had you tried sizeof(TMyProperties) as I
recommended. Try this instead -

> procedure SaveProperty(value: TMyProperties);
> var
> v: integer; // <--- different
> begin
> v := byte(value); // *** should be fine ***
> showmessage(inttostr(v));
> end;

Marc Rohloff [TeamB]

unread,
Feb 1, 2008, 4:18:26 PM2/1/08
to
On Fri, 1 Feb 2008 20:52:37 +0100, Alexander Halser wrote:

> I must be doing something wrong... is there a compiler switch that prevents
> this typecast?

As someone mentioned already for sets up to 8 elements you need to use
a cast to byte, up to 16 use a word, 32 use integer and for 64 use an
Int64.

var
v: byte;
begin
v := byte(value);

If you want something that will work when set sizes change you can do:

type
TSet = (a,b,c,d);
{$if sizeof(TSet)=1}
TSetCast = byte;
{$elseif sizeof(TSet)=2}
TSetCast = word;
{$elseif sizeof(TSet)=4}
TSetCast = longword;
{$elseif sizeof(TSet)=4}
TSetCast = int64;
{$else}
Houston, we have a problem
{$ifend}

var
v: TSetCast;
begin
v := TSetCast(value);

Alexander Halser

unread,
Feb 1, 2008, 4:26:06 PM2/1/08
to
Thank you VERY much!

I didn't realize the typecast had to match the set size exactly. With your
hint, it works :-)

--
Alexander

"Glynn Owen" <SandNOTREALLYSpeakerATcrestviewcable.com> wrote in message

news:47a383f1$1...@newsgroups.borland.com...

Glynn Owen

unread,
Feb 1, 2008, 4:19:33 PM2/1/08
to
Alexander Halser wrote:

> Thank you VERY much!
>
> I didn't realize the typecast had to match the set size exactly. With
> your hint, it works :-)

I could have been more explicit about that point, but I think you have
it now. Enumerated sets are one of my favorite features in Delphi.

Regards,
Glynn

Jens Gruschel

unread,
Feb 2, 2008, 8:44:13 AM2/2/08
to
> Very neat. This would do for a 64-bit integer as well, and would be a
> better solution, in that it does not depend so entirely on how a set is
> implemented.

Yes, from the language point of view it's very clean, however if you
take the asm code generated it might look a bit stupid compared to
typecasting :-)

0 new messages