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
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
"Glynn Owen" <SandNOTREALLYSpeakerATcrestviewcable.com> wrote in message
news:47a2...@newsgroups.borland.com...
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,
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
> 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
> 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));
> 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
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.
---------------------
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...
> procedure SaveProperty(value: TMyProperties);
> var
> v: integer; // <--- different
> begin
> v := byte(value); // *** should be fine ***
> showmessage(inttostr(v));
> end;
> 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);
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...
> 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
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 :-)