Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the representation value of an enumeration type in Ada

I need to get the numeric value asociated with a value of an enumerated type in Ada. Not the position in the enumeration, but the value assigned with the "for TYPE use" clause to every value.

Does anyone know if it is possible?

like image 768
user1240854 Avatar asked Feb 29 '12 17:02

user1240854


People also ask

What is an enumeration in Ada?

An enumeration type is defined as a list of possible values: type Primary_Color is (Red, Green, Blue); Like for numeric types, where e.g. 1 is an integer literal, Red, Green and Blue are called the literals of this type. There are no other values assignable to objects of this type.

What are enumeration values?

An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type. To define an enumeration type, use the enum keyword and specify the names of enum members: C# Copy.

What is enum value type?

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.

Which type of data type is enumeration?

An enumeration is a data type that consists of a set of named values that represent integral constants, known as enumeration constants. An enumeration is also referred to as an enumerated type because you must list (enumerate) each of the values in creating a name for each of them.


2 Answers

There is currently no completely general solution. Enumeration representation clauses seem to be designed to make this information difficult to obtain. (However Ada 2020 will add a solution; see the bottom of this answer for details.)

This:

function Rep is new Ada.Unchecked_Conversion(Enum, Integer);

is likely to work in most cases, but there are some serious caveats: the representation values have to be within the range Integer'First..Integer'Last, and if the sizes of Enum and Integer don't match the result is actually implementation defined (but it works with GNAT).

As Simon Wright says, the RM recommends Unchecked_Conversion, but this is not a very satisfying solution, and determining a consistent target type is difficult.

As of the 2007 RM, the recommended level of support is:

An implementation should support at least the internal codes in the range System.Min_Int..System.Max_Int.

which means that converting to Integer is not always sufficient; a value could be less than Integer'First, or greater than Integer'Last. And even if all the values are in that range, there's no really good way to determine a target type that's the same size as the enumeration type. For example, this:

type Enum is (Ten, Twenty, Thirty);
for Enum use (10, 20, 30);
function Rep is new Ada.Unchecked_Conversion(Enum, Integer);

produces this warning in GNAT:

warning: types for unchecked conversion have different sizes

But after the warning, Rep does return the expected values 10, 20, and 30.

The RM explicitly states that if the source and target sizes in an instance of Unchecked_Conversion don't match, and the result type is scalar, then

the result of the function is implementation defined, and can have an invalid representation

So the fact that the above works for GNAT doesn't mean it's guaranteed to work everywhere.

For an implementation that only supports values in the range System.Min_Int..System.Max_Int, you can do something like this:

type Enum is (...);
for Enum use (...);
type Longest_Integer is range System.Min_Int .. System.Max_Int;
function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Integer);

and ignore the warning. But compilers are allowed to accept values greater than System.Max_Int, as long as they're within the range of some integer type. For example, GNAT rejects this, but another Ada compiler might accept it:

type Longest_Unsigned is mod System.Max_Binary_Modulus;
type Unsigned_Enum is (Zero, Huge);
for Unsigned_Enum use (0, Longest_Unsigned'Last);

and an Unchecked_Conversion from this to any signed integer type will not work. And you still have the potential problem of implementation defined results if the sizes don't match.

Here's a generic solution that should work for any enumeration type if (a) the representation values are in the range System.Min_Int..System.Max_Int, and (b) if the implementation of Unchecked_Conversion is better behaved than the Ada standard requires it to be:

type Longest_Signed is range System.Min_Int .. System.Max_Int;

generic
    type Enum is (<>);
function Generic_Rep(E: Enum) return Longest_Signed;

function Generic_Rep(E: Enum) return Longest_Signed is
    function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Signed);
begin
    return Rep(E);
end Generic_Rep;

Given all this confusion, you might consider using some mechanism other than enumeration representation clauses to do whatever you're trying to do.

UPDATE:

GNAT has implementation-defined attributes 'Enum_Rep and 'Enum_Val. Ada 2020 is expected to adopt them.

http://www.ada-auth.org/standards/2xrm/html/RM-13-4.html#p10.1

like image 186
Keith Thompson Avatar answered Oct 20 '22 17:10

Keith Thompson


What I found to work in GNAT is for:

type MyEnum is (A, B, C);

I had to do:

EVal : MyEnum := B;
IVal : Integer := MyEnum'Enum_Rep(EVal);
like image 20
teeks99 Avatar answered Oct 20 '22 16:10

teeks99