Reputation: 9591
Say we have a type representing a box of a dozen donuts,
type Bakers_Dozen is range 1 to 13; -- Indices from 1 to 6 are donuts
Each Donut has a unique value that's within Bakers_Dozen:
subtype Donut is Bakers_Dozen (Plain, Chocolate, Strawberry, Glazed, Blueberry, Cannabis);
for Donut use (Plain=>1, Chocolate=>2, Strawberry=>3, Glazed=>4, Blueberry=>5, Cannabis=>6);
The intent is to refer to a Donut by either its name or value and ensure it only occupies range 1..6 of an array.
Unfortunately, my code results in an error message "incorrect constraint for this kind of type."
PastriesBox[Plain].Message = "Plain Donut is boring but costs less";
PastriesBox[Donut'Last].Message = "Please read contradictions and disclaimer inside box.";
PastriesBox[12].Message = "A great tasting muffin with fresh goat milk.";
Is there a way of declaring a range of an array as an enumeration?
Upvotes: 1
Views: 621
Reputation: 3641
There are some different means you can go about doing this. The simplest is to declare a constant array using Donuts as the index and Bakers_Dozen as the Element type for the array. Then you just use the array to convert the indexes:
package Indexes is
type Bakers_Dozen is range 1 .. 13; -- Indices from 1 to 6 are donuts
type Donut is
(Plain,
Chocolate,
Strawberry,
Glazed,
Blueberry,
Cannabis);
To_Index : constant array (Donut'Range) of Bakers_Dozen :=
(Plain => 1,
Chocolate => 2,
Strawberry => 3,
Glazed => 4,
Blueberry => 5,
Cannabis => 6);
end Indexes;
Then you can do:
P1 : array(Indexes.Bakers_Dozen'Range) of Integer;
and
P1(Indexes.To_Index(Indexes.Plain)) := 2;
An alternative to this method is to ensure that Donuts is the same size as Bakers_Dozen and then use Ada.Unchecked_Conversion to convert a Donut object to a Bakers_Dozen object
package Conversions is
type Bakers_Dozen is range 1 .. 13; -- Indices from 1 to 6 are donuts
type Donut is
(Plain,
Chocolate,
Strawberry,
Glazed,
Blueberry,
Cannabis)
with Size => Bakers_Dozen'Size;
for Donut use
(Plain => 1,
Chocolate => 2,
Strawberry => 3,
Glazed => 4,
Blueberry => 5,
Cannabis => 6);
function To_Index is new Ada.Unchecked_Conversion(Donut,Bakers_Dozen);
end Conversions;
Then you can do:
P2 : array(Conversions.Bakers_Dozen'Range) of Integer;
and
P2(Conversions.To_Index(Conversions.Chocolate)) := 3;
If you want to get fancy you can also wrap one of those methods into a private type and use more advanced concepts such as "Reference_Type" objects and the aspects Variable_Indexing and Constant_Indexing to make your private type act like an array
package Wrappers is
type Bakers_Dozen is range 1 .. 13; -- Indices from 1 to 6 are donuts
type Donut is
(Plain,
Chocolate,
Strawberry,
Glazed,
Blueberry,
Cannabis);
type Bakers_Array is tagged private
with
Variable_Indexing => Element;
type Element_Holder(Element : access Integer) is null record
with Implicit_Dereference => Element;
function Element
(Self : aliased in out Bakers_Array;
Index : Donut)
return Element_Holder;
function Element
(Self : aliased in out Bakers_Array;
Index : Bakers_Dozen)
return Element_Holder;
private
type Element_Array is array (Bakers_Dozen'Range) of aliased Integer;
type Bakers_Array is tagged record
Elements : Element_Array;
end record;
To_Index : constant array (Donut'Range) of Bakers_Dozen :=
(Plain => 1,
Chocolate => 2,
Strawberry => 3,
Glazed => 4,
Blueberry => 5,
Cannabis => 6);
function Element
(Self : aliased in out Bakers_Array;
Index : Donut)
return Element_Holder
is (Element => Self.Elements(To_Index(Index))'Access);
function Element
(Self : aliased in out Bakers_Array;
Index : Bakers_Dozen)
return Element_Holder
is (Element => Self.Elements(Index)'Access);
end Wrappers;
Then you can do:
P3 : Wrappers.Bakers_Array;
and
P3(Wrappers.Strawberry) := 4;
NOTE: I didn't add the Constant_Indexing aspect to save on typing, but you might want that too. You can look at Ada.Containers.Vectors to see how this is done.
There are probably other methods, but these are just off the top of my head.
Note also that I am just using Integers as the array elements for simplicity. You can always make these arrays of other types.
Upvotes: 3
Reputation: 39808
If your base type is an integer type, the subtype is an integer type. You can't make it an enumeration type.
You can declare constants for your Donuts if you want, then you can refer to them by name. You can instead give the other values names and then have Bakers_Dozen
be an enumeration type. If arithmetic operations do semantically not make sense on values of your type, it shouldn't be an integer type anyway.
Upvotes: 1