How do I define and statically initialize a vector index by an enumeration?

Viewed 98

I'm unable to define a vector using an enumeration as an index.

First I define my record:

type contact_name is record
    first    : unbounded_string;
    last     : unbounded_string;
end record;

I define my enumeration:

type profession is (plumber, doctor, lawyer, ombudsman, dealer);

I declare my vector of contact_name using professional as the index type:

package Pro_Vector is new Ada.Containers.Vectors (Index_Type => Profession, Element_Type => contact_name);

Finally, I build my table:

Pro_Table : Pro_Vector.Vector := (plumber, ("Bob","daPlumah")) & 
(doctor, "Felix", "FeelGood"))

When I try to compile it says expect signed integer type of Index_Type. It also claims Pro_Vector is undefined. I substituted profession for natural and it compiled, but my static initialization has errors.

Why won't it accept my enum as an index. I was under the impression that Ada is super safe. By using an unconstrained type like Natural, doesn't it compromise safety. Also, how do I statically initialize my vector?

1 Answers

You can extend a type from the existing vector package and add an indexing function for your enumeration type to get the effect you want. For vectors they use the Reference and Constant_Reference functions for indexing, so you can do an overload of those functions on your new type and it should use those to index your new vector type. For any other operations you want to use with an index value, you'll need to overload those too.

You'll also need to either add code to handle when you have more elements than enumeration values or perhaps consider using an bounded_vectors type so the size is maximized at the number of enumerations you have.

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Containers.Vectors; use Ada.Containers;

procedure Main is

    type profession is (plumber, doctor, lawyer, ombudsman, dealer);
    
    type contact_name is record
        first    : unbounded_string;
        last     : unbounded_string;
    end record;
    
    -- Note the use of Natural here.  That'll correspond
    -- to the Pos values used in the package later
    package Pro_Vector is new Ada.Containers.Vectors 
        (Index_Type   => Natural, 
         Element_Type => contact_name);
         
    -- This package is where the magic happens
    package Vectors is 
        type Vector is new Pro_Vector.Vector with null record;
        function Reference
            (Self  : aliased in out Vector;
             Index : Profession) return Pro_Vector.Reference_Type;
             
    private
        -- Uses Pos to get the "position info" of the enumeration
        -- value
        function Reference
            (Self  : aliased in out Vector;
             Index : Profession) return Pro_Vector.Reference_Type
        is (Self.Reference(Profession'Pos(Index)));
    end Vectors;
    
    v : Vectors.Vector;

begin
    -- Add an item
    v.Append
        (New_Item => 
            Contact_Name'
                (First => To_Unbounded_String("Frank"),
                 Last  => To_Unbounded_String("Dude")));
    
    -- Now you can index it via the profession
    v(Plumber) := 
        (First => To_Unbounded_String("Joe"),
         Last  => To_Unbounded_String("Man"));
    
    
end Main;

This is a bounded vector example:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Containers.Bounded_Vectors; use Ada.Containers;

procedure Main is

    type profession is (plumber, doctor, lawyer, ombudsman, dealer);
    Profession_Count : constant 
        := Profession'Pos(Profession'Last)-Profession'Pos(Profession'First)+1;
    
    type contact_name is record
        first    : unbounded_string;
        last     : unbounded_string;
    end record;
    
    -- Note the use of Natural here.  That'll correspond
    -- to the Pos values used in the package later
    package Pro_Vector is new Ada.Containers.Bounded_Vectors 
        (Index_Type   => Natural, 
         Element_Type => contact_name);
         
    -- This package is where the magic happens
    package Vectors is 
        type Vector is new Pro_Vector.Vector(Profession_Count) with null record;
        function Reference
            (Self  : aliased in out Vector;
             Index : Profession) return Pro_Vector.Reference_Type;
             
    private
        -- Uses Pos to get the "position info" of the enumeration
        -- value
        function Reference
            (Self  : aliased in out Vector;
             Index : Profession) return Pro_Vector.Reference_Type
        is (Self.Reference(Profession'Pos(Index)));
    end Vectors;
    
    v : Vectors.Vector;

begin

    Put_Line(v.Capacity'Image);

    -- Add an item
    v.Append
        (New_Item => 
            Contact_Name'
                (First => To_Unbounded_String("Frank"),
                 Last  => To_Unbounded_String("Dude")));
    
    -- Now you can index it via the profession
    v(Plumber) := 
        (First => To_Unbounded_String("Joe"),
         Last  => To_Unbounded_String("Man"));
    
    
end Main;
Related