Checking validity of enum value image without exception

Just double checking: is there any way to ascertain that a string can be converted to an enumeration value that does not involve raising an exception, i.e.:

   return Some_Enum'Value ("asdf");
   --  Invalid value, do whatever you must.

I don’t think so as 'Valid takes a variable of the type, but I might be missing something?

If the enumeration only has a few values, consider getting the Image of each and comparing them to the string under consideration, after stripping it of extra whitespace and whatnot.

You would need an error enumeration in that case.

You could try to do a conversion and return true if successful and false on exception, that means you’d also need to do it twice unless you return the enum as an out parameter.

This is one area where an option type would be handy.

You can make a constant indefinite map with a key type of string and element type the enumeration. Then you can call .Contains() with a forced to upper on the input for a Boolean result.

It takes some scaffolding like a custom “&” operator to use to make the constant map and overriding contains to force the to upper but it is not terrible to do. I’ve done it for a compiler keyword search before.

If the enumeration is simple then you just insert the image of the enumeration value as the key

EDIT: Example:

        type Enumeration is (<>);
    package Enumeration_Search is 
        package Maps is new Ada.Containers.Indefinite_Hashed_Maps
            (Key_Type        => String,
             Element_Type    => Enumeration,
             Hash            => Ada.Strings.Hash,
             Equivalent_Keys => Standard."=");
        type Map is new Maps.Map with null record;
        type Option(Valid : Boolean := False) is record
            case Valid is
                when False => null;
                when True  => Value : Enumeration := Enumeration'First;
            end case;
        end record;
        function Contains(Self : Map; Key : String) return Boolean;
        function Find(Self : Map; Key : String) return Option;
        function Make return Map;
        function "&"(L : Map; R : Enumeration) return Map;
        Empty_Map : constant Map := (Maps.Empty_Map with null record);
    end Enumeration_Search;

body file

    package body Enumeration_Search is

        function Contains(Self : Map; Key : String) return Boolean is
            use Ada.Characters.Handling;
            return Maps.Map(Self).Contains(To_Upper(Key));
        end Contains;
        function Find(Self : Map; Key : String) return Option is
            use Ada.Characters.Handling;
            Location : constant Maps.Cursor := Self.Find(To_Upper(Key));
            use type Maps.Cursor;
            if Location = Maps.No_Element then
                return (Valid => False);
                return (Valid => True, Value => Self(Location));
            end if;
        end Find;
        function Make return Map is
            return Result : Map do
                for Value in Enumeration'Range loop
                    (Key      => Value'Image,
                     New_Item => Value);
                end loop;
            end return;
        end Make;
        function "&"(L : Map; R : Enumeration) return Map is
            return Result : Map := L do
                    (Key      => R'Image,
                     New_Item => R);
            end return;
        end "&";
    end Enumeration_Search;


    type My_Type is (Abc, Def, Ghi);
    package My_Type_Search is new Enumeration_Search(My_Type);
    use type My_Type_Search.Map;

    Full_Search : constant My_Type_Search.Map := My_Type_Search.Make;
    Constrained_Search : constant My_Type_Search.Map := My_Type_Search.Empty_Map
        & Abc 
        & Ghi;
1 Like

Something like that didn’t even occur to me. It seems a little heavyweight for something like this, but if he’s willing to do something like that, he could always use a trie for the mapping. I have a library he can use, if he’d be interested.

(for some E in Some_Enum => E'Image = To_Upper (Potential_Value) )
1 Like

Thanks for all the comments, people, and the creativity, but I was hoping there was some simple, ARM-intended way, such a 'Valid attribute that took a string, that I had overlooked.

I think the ARM more often than not tends to go the way of exception propagation for more things than I prefer (but I primarily code in bare metal contexts, so exceptions are less useful to me).

Arnaud Charlet points out that GNAT has a 'Valid_Value attribute function that does what you want: