Reputation: 7958
I have an Ada enum with 2 values type Polarity is (Normal, Reversed)
, and I would like to convert them to 0, 1 (or True, False--as Boolean seems to implicitly play nice as binary) respectively, so I can store their values as specific bits in a byte. How can I accomplish this?
Upvotes: 4
Views: 1160
Reputation: 7958
It seems all I needed to do was pragma Pack([type name]);
(in which 'type name' is the type composed of Polarity) to compress the value down to a single bit.
Upvotes: 0
Reputation: 44824
Two points here:
1) Enumerations are already stored as binary. Everything is. In particular, your enumeration, as defined above, will be stored as a 0
for Normal
and a 1
for Reversed
, unless you go out of your way to tell the compiler to use other values.
If you want to get that value out of the enumeration as an Integer
rather than an enumeration value, you have two options. The 'pos()
attribute will return a 0-based number for that enumeration's position in the enumeration, and Unchecked_Conversion
will return the actual value the computer stores for it. (There is no difference in the value, unless an enumeration representation clause was used).
2) Enumerations are nice, but don't reinvent Boolean
. If your enumeration can only ever have two values, you don't gain anything useful by making a custom enumeration, and you lose a lot of useful properties that Boolean
has. Booleans can be directly selected off of in loops and if
checks. Booleans have and
, or
, xor
, etc. defined for them. Booleans can be put into packed arrays, and then those same operators are defined bitwise across the whole array.
A particular pet peeve of mine is when people end up defining themselves a custom boolean with the logic reversed (so its true condition is 0). If you do this, the ghost of Ada Lovelace will come back from the grave and force you to listen to an exhaustive explanation of how to calculate Bernoulli sequences with a Difference Engine. Don't let this happen to you!
So if it would never make sense to have a third enumeration value, you just name objects something appropriate describing the True
condition (eg: Reversed_Polarity : Boolean;
), and go on your merry way.
Upvotes: 1
Reputation: 205885
3.5.5 Operations of Discrete Types include the function S'Pos(Arg : S'Base)
, which "returns the position number of the value of Arg
, as a value of type universal integer." Hence,
Polarity'Pos(Normal) = 0
Polarity'Pos(Reversed) = 1
You can change the numbering using 13.4 Enumeration Representation Clauses.
...and, of course:
Boolean'Val(Polarity'Pos(Normal)) = False
Boolean'Val(Polarity'Pos(Reversed)) = True
Upvotes: 3
Reputation:
An easy way is a lookup table:
Bool_Polarity : constant Array(Polarity) of Boolean
:= (Normal=>False, Reversed => True);
then use it as
B Boolean := Bool_Polarity(P);
Of course there is nothing wrong with using the 'Pos attribute, but the LUT makes the mapping readable and very obvious.
As it is constant, you'd like to hope it optimises away during the constant folding stage, and it seems to: I have used similar tricks compiling for AVR with very acceptable executable sizes (down to 0.6k to independently drive 2 stepper motors)
Upvotes: 3
Reputation:
I think what you are looking for is a record type with a representation clause:
procedure Main is
type Byte_T is mod 2**8-1;
for Byte_T'Size use 8;
type Filler7_T is mod 2**7-1;
for Filler7_T'Size use 7;
type Polarity_T is (Normal,Reversed);
for Polarity_T use (Normal => 0, Reversed => 1);
for Polarity_T'Size use 1;
type Byte_As_Record_T is record
Filler : Filler7_T;
Polarity : Polarity_T;
end record;
for Byte_As_Record_T use record
Filler at 0 range 0 .. 6;
Polarity at 0 range 7 .. 7;
end record;
for Byte_As_Record_T'Size use 8;
function Convert is new Ada.Unchecked_Conversion
(Source => Byte_As_Record_T,
Target => Byte_T);
function Convert is new Ada.Unchecked_Conversion
(Source => Byte_T,
Target => Byte_As_Record_T);
begin
-- TBC
null;
end Main;
As Byte_As_Record_T
& Byte_T
are the same size, you can use unchecked conversion
to convert between the types safely.
The representation clause for Byte_As_Record_T
allows you to specify which bits/bytes to place your polarity_t
in. (i chose the 8th bit)
My definition of Byte_T
might not be what you want, but as long as it is 8 bits long the principle should still be workable. From Byte_T you can also safely upcast to Integer
or Natural
or Positive
. You can also use the same technique to go directly to/from a 32 bit Integer to/from a 32 bit record type.
Upvotes: 2