user2040158
user2040158

Reputation:

How do I cast an enum to an Integer to handle overflow/wraparound?

I'm learning ada and I'm trying to implement an addition overload for an enum.

Basically I want to be able to add an Integer to a Day type and get the resulting Day value. So MONDAY + 2 => WEDNESDAY.

Here is my simplified code:

procedure overload is                                                                                                             
    type Day is (                                                                                                                 
        Sunday,                                                                                                                   
        Monday,                                                                                                                   
        Tuesday,                                                                                                                  
        Wednesday,                                                                                                                
        Thursday,                                                                                                                 
        Friday,                                                                                                                   
        Saturday                                                                                                                  
    );
    day1 : Day := Monday;
    function "+" (left: Day; right: Integer) return Day is                                                                        
        -- how would I handle this here? I want to basically say
        -- if Day + Integer > Saturday then
        --   wraparound back to Sunday
        return DayValue;
    begin
       for x in 0 .. 7 loop
          Ada.text_io.put_line("Monday + " & Integer'Image(x) & " = " & Day'Image(day1 + x));
       end loop;
end overload;

Upvotes: 5

Views: 550

Answers (3)

Jeffrey R. Carter
Jeffrey R. Carter

Reputation: 3358

I would use PragmARC.Wrapping:

with PragmARC.Wrapping;

function "+" (Left : Day; Right : Integer) return Day is
   package Wrapping is new PragmARC.Wrapping (Item => Day);
   use Wrapping;

   Result : Day := Left;
begin -- "+"
   Change : for I in 1 .. abs Right loop
      Result := (if Right < 0 then Wrap_Pred (Result) else Wrap_Succ (Result) );
   end loop Change;

   return Result;
end "+";

Upvotes: 2

Jim Rogers
Jim Rogers

Reputation: 5051

While you have an answer to get the position value associated with a enumeration value, do not think this is the same as an enum in C. Ada enumerations are not numeric types.

You can iterate through a range of enumeration values using a for loop as in

for the_day in Day loop in loop
   Put_Line(Day'Image(the_day));
end loop;

If you want to print the current day and the next day you can use the 'Succ attribute.

for the_day in Day loop
   Put(Day'Image(the_day) & " the next day is ");
   if the_day = Day'Last then
      Put_Line(Day'Image(Day'First));
   else
      Put_Line(Day'Image(the_day'Succ));
   end if;
end loop;

Upvotes: 3

Jere
Jere

Reputation: 3641

You can use the 'Pos and 'Val attributes to do it. 'Pos returns the position of the supplied day relative to the first option (0 indexed) while 'Val takes a Pos value and returns the day type value:

return Day'Val(Day'Pos(Left) + Right);

For wraparound check the 'Pos value of Saturday vs the 'Pos value of left + the right value and use Day'Val(0) for Sunday

Or switch your input type of Right from Integer to Natural and use modulus math:

return Day'Val((Day'Pos(left) + Right) mod 7);

You can even get fancy and make a constant for the 7:

Day_Mod : constant := Day'Pos(Day'Last) - Day'Pos(Day'First) + 1;

and then it becomes

return Day'Val((Day'Pos(left) + Right) mod Day_Mod);

Upvotes: 6

Related Questions