Arrays

Constrained Array

Goal: declare a constrained array and implement operations on it.

Steps:

  1. Implement the Constrained_Arrays package.

    1. Declare the range type My_Index.

    2. Declare the array type My_Array.

    3. Declare and implement the Init function.

    4. Declare and implement the Double procedure.

    5. Declare and implement the First_Elem function.

    6. Declare and implement the Last_Elem function.

    7. Declare and implement the Length function.

    8. Declare the object A of My_Array type.

Requirements:

  1. Range type My_Index has a range from 1 to 10.

  2. My_Array is a constrained array of Integer type.

    1. It must make use of the My_Index type.

    2. It is therefore limited to 10 elements.

  3. Function Init returns an array where each element is initialized with the corresponding index.

  4. Procedure Double doubles the value of each element of an array.

  5. Function First_Elem returns the first element of the array.

  6. Function Last_Elem returns the last element of the array.

  7. Function Length returns the length of the array.

  8. Object A of My_Array type is initialized with:

    1. the values 1 and 2 for the first two elements, and

    2. 42 for all other elements.

    
        
    
    
    
        
package Constrained_Arrays is -- Complete the type and subprogram declarations: -- -- type My_Index is [...] -- -- type My_Array is [...] -- -- function Init ... -- -- procedure Double ... -- -- function First_Elem ... -- -- function Last_Elem ... -- -- function Length ... -- -- A : ... end Constrained_Arrays;
package body Constrained_Arrays is -- Create the implementation of the subprograms! -- end Constrained_Arrays;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Constrained_Arrays; use Constrained_Arrays; procedure Main is type Test_Case_Index is (Range_Chk, Array_Range_Chk, A_Obj_Chk, Init_Chk, Double_Chk, First_Elem_Chk, Last_Elem_Chk, Length_Chk); procedure Check (TC : Test_Case_Index) is AA : My_Array; procedure Display (A : My_Array) is begin for I in A'Range loop Put_Line (Integer'Image (A (I))); end loop; end Display; procedure Local_Init (A : in out My_Array) is begin A := (100, 90, 80, 10, 20, 30, 40, 60, 50, 70); end Local_Init; begin case TC is when Range_Chk => for I in My_Index loop Put_Line (My_Index'Image (I)); end loop; when Array_Range_Chk => for I in My_Array'Range loop Put_Line (My_Index'Image (I)); end loop; when A_Obj_Chk => Display (A); when Init_Chk => AA := Init; Display (AA); when Double_Chk => Local_Init (AA); Double (AA); Display (AA); when First_Elem_Chk => Local_Init (AA); Put_Line (Integer'Image (First_Elem (AA))); when Last_Elem_Chk => Local_Init (AA); Put_Line (Integer'Image (Last_Elem (AA))); when Length_Chk => Put_Line (Integer'Image (Length (AA))); end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

Colors: Lookup-Table

Goal: rewrite a package to represent HTML colors in RGB format using a lookup table.

Steps:

  1. Implement the Color_Types package.

    1. Declare the array type HTML_Color_RGB.

    2. Declare the To_RGB_Lookup_Table object and initialize it.

    3. Adapt the implementation of the To_RGB function.

Requirements:

  1. Array type HTML_Color_RGB is used for the table.

  2. The To_RGB_Lookup_Table object of HTML_Color_RGB type contains the lookup table.

    • This table must be implemented as an array of constant values.

  3. The implementation of the To_RGB function must use the To_RGB_Lookup_Table object.

Remarks:

  1. This exercise is based on the HTML colors exercise from a previous lab (Records).

  2. In the previous implementation, you could use a case statement to implement the To_RGB function. Here, you must rewrite the function using a look-up table.

    1. The implementation of the To_RGB function below includes the case statement as commented-out code. You can use this as your starting point: you just need to copy it and convert the case statement to an array declaration.

    1. Don't use a case statement to implement the To_RGB function. Instead, write code that accesses To_RGB_Lookup_Table to get the correct value.

  3. The following table contains the HTML colors and the corresponding value in hexadecimal form for each color element:

    Color

    Red

    Green

    Blue

    Salmon

    #FA

    #80

    #72

    Firebrick

    #B2

    #22

    #22

    Red

    #FF

    #00

    #00

    Darkred

    #8B

    #00

    #00

    Lime

    #00

    #FF

    #00

    Forestgreen

    #22

    #8B

    #22

    Green

    #00

    #80

    #00

    Darkgreen

    #00

    #64

    #00

    Blue

    #00

    #00

    #FF

    Mediumblue

    #00

    #00

    #CD

    Darkblue

    #00

    #00

    #8B

    
        
    
    
    
        
package Color_Types is type HTML_Color is (Salmon, Firebrick, Red, Darkred, Lime, Forestgreen, Green, Darkgreen, Blue, Mediumblue, Darkblue); subtype Int_Color is Integer range 0 .. 255; type RGB is record Red : Int_Color; Green : Int_Color; Blue : Int_Color; end record; function To_RGB (C : HTML_Color) return RGB; function Image (C : RGB) return String; -- Declare array type for lookup table here: -- -- type HTML_Color_RGB is ... -- Declare lookup table here: -- -- To_RGB_Lookup_Table : ... end Color_Types;
with Ada.Integer_Text_IO; package body Color_Types is function To_RGB (C : HTML_Color) return RGB is begin -- Implement To_RGB using To_RGB_Lookup_Table return (0, 0, 0); -- Use the code below from the previous version of the To_RGB -- function to declare the To_RGB_Lookup_Table: -- -- case C is -- when Salmon => return (16#FA#, 16#80#, 16#72#); -- when Firebrick => return (16#B2#, 16#22#, 16#22#); -- when Red => return (16#FF#, 16#00#, 16#00#); -- when Darkred => return (16#8B#, 16#00#, 16#00#); -- when Lime => return (16#00#, 16#FF#, 16#00#); -- when Forestgreen => return (16#22#, 16#8B#, 16#22#); -- when Green => return (16#00#, 16#80#, 16#00#); -- when Darkgreen => return (16#00#, 16#64#, 16#00#); -- when Blue => return (16#00#, 16#00#, 16#FF#); -- when Mediumblue => return (16#00#, 16#00#, 16#CD#); -- when Darkblue => return (16#00#, 16#00#, 16#8B#); -- end case; end To_RGB; function Image (C : RGB) return String is subtype Str_Range is Integer range 1 .. 10; SR : String (Str_Range); SG : String (Str_Range); SB : String (Str_Range); begin Ada.Integer_Text_IO.Put (To => SR, Item => C.Red, Base => 16); Ada.Integer_Text_IO.Put (To => SG, Item => C.Green, Base => 16); Ada.Integer_Text_IO.Put (To => SB, Item => C.Blue, Base => 16); return ("(Red => " & SR & ", Green => " & SG & ", Blue => " & SB &")"); end Image; end Color_Types;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Color_Types; use Color_Types; procedure Main is type Test_Case_Index is (Color_Table_Chk, HTML_Color_To_Integer_Chk); procedure Check (TC : Test_Case_Index) is begin case TC is when Color_Table_Chk => Put_Line ("Size of HTML_Color_RGB: " & Integer'Image (HTML_Color_RGB'Length)); Put_Line ("Firebrick: " & Image (To_RGB_Lookup_Table (Firebrick))); when HTML_Color_To_Integer_Chk => for I in HTML_Color'Range loop Put_Line (HTML_Color'Image (I) & " => " & Image (To_RGB (I)) & "."); end loop; end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

Unconstrained Array

Goal: declare an unconstrained array and implement operations on it.

Steps:

  1. Implement the Unconstrained_Arrays package.

    1. Declare the My_Array type.

    2. Declare and implement the Init procedure.

    3. Declare and implement the Init function.

    4. Declare and implement the Double procedure.

    5. Declare and implement the Diff_Prev_Elem function.

Requirements:

  1. My_Array is an unconstrained array (with a Positive range) of Integer elements.

  2. Procedure Init initializes each element with the index starting with the last one.

    • For example, for an array of 3 elements where the index of the first element is 1 (My_Array (1 .. 3)), the values of these elements after a call to Init must be (3, 2, 1).

  3. Function Init returns an array based on the length L and start index I provided to the Init function.

    1. I indicates the index of the first element of the array.

    2. L indicates the length of the array.

    3. Both I and L must be positive.

    4. This is its declaration: function Init (I, L : Positive) return My_Array;.

    5. You must initialize the elements of the array in the same manner as for the Init procedure described above.

  4. Procedure Double doubles each element of an array.

  5. Function Diff_Prev_Elem returns — for each element of an input array A — an array with the difference between an element of array A and the previous element.

    1. For the first element, the difference must be zero.

    2. For example:

      • INPUT: (2, 5, 15)

      • RETURN of Diff_Prev_Elem: (0, 3, 10), where

        • 0 is the constant difference for the first element;

        • 5 - 2 = 3 is the difference between the second and the first elements of the input array;

        • 15 - 5 = 10 is the difference between the third and the second elements of the input array.

Remarks:

  1. For an array A, you can retrieve the index of the last element with the attribute 'Last.

    1. For example: Y : Positive := A'Last;

    2. This can be useful during the implementation of procedure Init.

  2. For the implementation of the Init function, you can call the Init procedure to initialize the elements. By doing this, you avoid code duplication.

  3. Some hints about attributes:

    1. You can use the range attribute (A'Range) to retrieve the range of an array A.

    2. You can also use the range attribute in the declaration of another array (e.g.: B : My_Array (A'Range)).

    3. Alternatively, you can use the A'First and A'Last attributes in an array declaration.

    
        
    
    
    
        
package Unconstrained_Arrays is -- Complete the type and subprogram declarations: -- -- type My_Array is ...; -- -- procedure Init ...; function Init (I, L : Positive) return My_Array; -- procedure Double ...; -- -- function Diff_Prev_Elem ...; end Unconstrained_Arrays;
package body Unconstrained_Arrays is -- Implement the subprograms: -- -- procedure Init is... -- function Init (L : Positive) return My_Array is... -- procedure Double ... is... -- function Diff_Prev_Elem ... is... end Unconstrained_Arrays;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Unconstrained_Arrays; use Unconstrained_Arrays; procedure Main is type Test_Case_Index is (Init_Chk, Init_Proc_Chk, Double_Chk, Diff_Prev_Chk, Diff_Prev_Single_Chk); procedure Check (TC : Test_Case_Index) is AA : My_Array (1 .. 5); AB : My_Array (5 .. 9); procedure Display (A : My_Array) is begin for I in A'Range loop Put_Line (Integer'Image (A (I))); end loop; end Display; procedure Local_Init (A : in out My_Array) is begin A := (1, 2, 5, 10, -10); end Local_Init; begin case TC is when Init_Chk => AA := Init (AA'First, AA'Length); AB := Init (AB'First, AB'Length); Display (AA); Display (AB); when Init_Proc_Chk => Init (AA); Init (AB); Display (AA); Display (AB); when Double_Chk => Local_Init (AB); Double (AB); Display (AB); when Diff_Prev_Chk => Local_Init (AB); AB := Diff_Prev_Elem (AB); Display (AB); when Diff_Prev_Single_Chk => declare A1 : My_Array (1 .. 1) := (1 => 42); begin A1 := Diff_Prev_Elem (A1); Display (A1); end; end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

Product info

Goal: create a system to keep track of quantities and prices of products.

Steps:

  1. Implement the Product_Info_Pkg package.

    1. Declare the array type Product_Infos.

    2. Declare the array type Currency_Array.

    3. Implement the Total procedure.

    4. Implement the Total function returning an array of Currency_Array type.

    5. Implement the Total function returning a single value of Currency type.

Requirements:

  1. Quantity of an individual product is represented by the Quantity subtype.

  2. Price of an individual product is represented by the Currency subtype.

  3. Record type Product_Info deals with information for various products.

  4. Array type Product_Infos is used to represent a list of products.

  5. Array type Currency_Array is used to represent a list of total values of individual products (see more details below).

  6. Procedure Total receives an input array of products.

    1. It outputs an array with the total value of each product using the Currency_Array type.

    2. The total value of an individual product is calculated by multiplying the quantity for this product by its price.

  7. Function Total returns an array of Currency_Array type.

    1. This function has the same purpose as the procedure Total.

    2. The difference is that the function returns an array instead of providing this array as an output parameter.

  8. The second function Total returns a single value of Currency type.

    1. This function receives an array of products.

    2. It returns a single value corresponding to the total value for all products in the system.

Remarks:

  1. You can use Currency (Q) to convert from an element Q of Quantity type to the Currency type.

    1. As you might remember, Ada requires an explicit conversion in calculations where variables of both integer and floating-point types are used.

    2. In our case, the Quantity subtype is based on the Integer type and the Currency subtype is based on the Float type, so a conversion is necessary in calculations using those types.

    
        
    
    
    
        
package Product_Info_Pkg is subtype Quantity is Natural; subtype Currency is Float; type Product_Info is record Units : Quantity; Price : Currency; end record; -- Complete the type declarations: -- -- type Product_Infos is ... -- -- type Currency_Array is ... procedure Total (P : Product_Infos; Tot : out Currency_Array); function Total (P : Product_Infos) return Currency_Array; function Total (P : Product_Infos) return Currency; end Product_Info_Pkg;
package body Product_Info_Pkg is -- Complete the subprogram implementations: -- -- procedure Total (P : Product_Infos; -- Tot : out Currency_Array) is ... -- function Total (P : Product_Infos) return Currency_Array is ... -- function Total (P : Product_Infos) return Currency is ... end Product_Info_Pkg;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Product_Info_Pkg; use Product_Info_Pkg; procedure Main is package Currency_IO is new Ada.Text_IO.Float_IO (Currency); type Test_Case_Index is (Total_Func_Chk, Total_Proc_Chk, Total_Value_Chk); procedure Check (TC : Test_Case_Index) is subtype Test_Range is Positive range 1 .. 5; P : Product_Infos (Test_Range); Tots : Currency_Array (Test_Range); Tot : Currency; procedure Display (Tots : Currency_Array) is begin for I in Tots'Range loop Currency_IO.Put (Tots (I)); New_Line; end loop; end Display; procedure Local_Init (P : in out Product_Infos) is begin P := ((1, 0.5), (2, 10.0), (5, 40.0), (10, 10.0), (10, 20.0)); end Local_Init; begin Currency_IO.Default_Fore := 1; Currency_IO.Default_Aft := 2; Currency_IO.Default_Exp := 0; case TC is when Total_Func_Chk => Local_Init (P); Tots := Total (P); Display (Tots); when Total_Proc_Chk => Local_Init (P); Total (P, Tots); Display (Tots); when Total_Value_Chk => Local_Init (P); Tot := Total (P); Currency_IO.Put (Tot); New_Line; end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

String_10

Goal: work with constrained string types.

Steps:

  1. Implement the Strings_10 package.

    1. Declare the String_10 type.

    2. Implement the To_String_10 function.

Requirements:

  1. The constrained string type String_10 is an array of ten characters.

  2. Function To_String_10 returns constrained strings of String_10 type based on an input parameter of String type.

    • For strings that are more than 10 characters, omit everything after the 11th character.

    • For strings that are fewer than 10 characters, pad the string with ' ' characters until it is 10 characters.

Remarks:

  1. Declaring String_10 as a subtype of String is the easiest way.

    • You may declare it as a new type as well. However, this requires some adaptations in the Main test procedure.

  2. You can use Integer'Min to calculate the minimum of two integer values.

    
        
    
    
    
        
package Strings_10 is -- Complete the type and subprogram declarations: -- -- subtype String_10 is ...; -- Using "type String_10 is..." is possible, too. However, it -- requires a custom Put_Line procedure that is called in Main: -- procedure Put_Line (S : String_10); -- function To_String_10 ...; end Strings_10;
package body Strings_10 is -- Complete the subprogram declaration and implementation: -- -- function To_String_10 ... is end Strings_10;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Strings_10; use Strings_10; procedure Main is type Test_Case_Index is (String_10_Long_Chk, String_10_Short_Chk); procedure Check (TC : Test_Case_Index) is SL : constant String := "And this is a long string just for testing..."; SS : constant String := "Hey!"; S_10 : String_10; begin case TC is when String_10_Long_Chk => S_10 := To_String_10 (SL); Put_Line (String (S_10)); when String_10_Short_Chk => S_10 := (others => ' '); S_10 := To_String_10 (SS); Put_Line (String (S_10)); end case; end Check; begin if Argument_Count < 1 then Ada.Text_IO.Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Ada.Text_IO.Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

List of Names

Goal: create a system for a list of names and ages.

Steps:

  1. Implement the Names_Ages package.

    1. Declare the People_Array array type.

    2. Complete the declaration of the People record type with the People_A element of People_Array type.

    3. Implement the Add procedure.

    4. Implement the Reset procedure.

    5. Implement the Get function.

    6. Implement the Update procedure.

    7. Implement the Display procedure.

Requirements:

  1. Each person is represented by the Person type, which is a record containing the name and the age of that person.

  2. People_Array is an unconstrained array of Person type with a positive range.

  3. The Max_People constant is set to 10.

  4. Record type People contains:

    1. The People_A element of People_Array type.

    2. This array must be constrained by the Max_People constant.

  5. Procedure Add adds a person to the list.

    1. By default, the age of this person is set to zero in this procedure.

  6. Procedure Reset resets the list.

  7. Function Get retrieves the age of a person from the list.

  8. Procedure Update updates the age of a person in the list.

  9. Procedure Display shows the complete list using the following format:

    1. The first line must be LIST OF NAMES:. It is followed by the name and age of each person in the next lines.

    2. For each person on the list, the procedure must display the information in the following format:

      NAME: XXXX
      AGE: YY
      

Remarks:

  1. In the implementation of procedure Add, you may use an index to indicate the last valid position in the array — see Last_Valid in the code below.

  2. In the implementation of procedure Display, you should use the Trim function from the Ada.Strings.Fixed package to format the person's name — for example: Trim (P.Name, Right).

  3. You may need the Integer'Min (A, B) and the Integer'Max (A, B) functions to get the minimum and maximum values in a comparison between two integer values A and B.

  4. Fixed-length strings can be initialized with whitespaces using the others syntax. For example: S : String_10 := (others => ' ');

  5. You may implement additional subprograms to deal with other types declared in the Names_Ages package below, such as the Name_Type and the Person type.

    1. For example, a function To_Name_Type to convert from String to Name_Type might be useful.

    2. Take a moment to reflect on which additional subprograms could be useful as well.

    
        
    
    
    
        
package Names_Ages is Max_People : constant Positive := 10; subtype Name_Type is String (1 .. 50); type Age_Type is new Natural; type Person is record Name : Name_Type; Age : Age_Type; end record; -- Add type declaration for People_Array record: -- -- type People_Array is ...; -- Replace type declaration for People record. You may use the -- following template: -- -- type People is record -- People_A : People_Array ...; -- Last_Valid : Natural; -- end record; -- type People is null record; procedure Reset (P : in out People); procedure Add (P : in out People; Name : String); function Get (P : People; Name : String) return Age_Type; procedure Update (P : in out People; Name : String; Age : Age_Type); procedure Display (P : People); end Names_Ages;
with Ada.Text_IO; use Ada.Text_IO; with Ada.Strings; use Ada.Strings; with Ada.Strings.Fixed; use Ada.Strings.Fixed; package body Names_Ages is procedure Reset (P : in out People) is begin null; end Reset; procedure Add (P : in out People; Name : String) is begin null; end Add; function Get (P : People; Name : String) return Age_Type is begin return 0; end Get; procedure Update (P : in out People; Name : String; Age : Age_Type) is begin null; end Update; procedure Display (P : People) is begin null; end Display; end Names_Ages;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Names_Ages; use Names_Ages; procedure Main is type Test_Case_Index is (Names_Ages_Chk, Get_Age_Chk); procedure Check (TC : Test_Case_Index) is P : People; begin case TC is when Names_Ages_Chk => Reset (P); Add (P, "John"); Add (P, "Patricia"); Add (P, "Josh"); Display (P); Update (P, "John", 18); Update (P, "Patricia", 35); Update (P, "Josh", 53); Display (P); when Get_Age_Chk => Reset (P); Add (P, "Peter"); Update (P, "Peter", 45); Put_Line ("Peter is " & Age_Type'Image (Get (P, "Peter")) & " years old."); end case; end Check; begin if Argument_Count < 1 then Ada.Text_IO.Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Ada.Text_IO.Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;