Generics

Display Array

Goal: create a generic procedure that displays the elements of an array.

Steps:

  1. Implement the generic procedure Display_Array.

Requirements:

  1. Generic procedure Display_Array displays the elements of an array.

    1. It uses the following scheme:

      • First, it displays a header.

      • Then, it displays the elements of the array.

    2. When displaying the elements, it must:

      • use one line per element, and

      • include the corresponding index of the array.

    3. This is the expected format:

      <HEADER>
      <index #1>: <element #1>
      <index #2>: <element #2>
      ...
      
    4. For example:

      • For the following code:

        procedure Test is
           A : Int_Array (1 .. 2) := (1, 5);
        begin
           Display_Int_Array ("Elements of A", A);;
        end Test;
        
      • The output is:

        Elements of A
         1:  1
         2:  5
        
  2. These are the formal parameters of the procedure:

    1. a range type T_Range for the the array;

    2. a formal type T_Element for the elements of the array;

      • This type must be declared in such a way that it can be mapped to any type in the instantiation — including record types.

    3. an array type T_Array using the T_Range and T_Element types;

    4. a function Image that converts a variable of T_Element type to a String.

generic procedure Display_Array (Header : String; A : T_Array);
with Ada.Text_IO; use Ada.Text_IO; procedure Display_Array (Header : String; A : T_Array) is begin null; end Display_Array;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Display_Array; procedure Main is type Test_Case_Index is (Int_Array_Chk, Point_Array_Chk); procedure Test_Int_Array is type Int_Array is array (Positive range <>) of Integer; procedure Display_Int_Array is new Display_Array (T_Range => Positive, T_Element => Integer, T_Array => Int_Array, Image => Integer'Image); A : constant Int_Array (1 .. 5) := (1, 2, 5, 7, 10); begin Display_Int_Array ("Integers", A); end Test_Int_Array; procedure Test_Point_Array is type Point is record X : Float; Y : Float; end record; type Point_Array is array (Natural range <>) of Point; function Image (P : Point) return String is begin return "(" & Float'Image (P.X) & ", " & Float'Image (P.Y) & ")"; end Image; procedure Display_Point_Array is new Display_Array (T_Range => Natural, T_Element => Point, T_Array => Point_Array, Image => Image); A : constant Point_Array (0 .. 3) := ((1.0, 0.5), (2.0, -0.5), (5.0, 2.0), (-0.5, 2.0)); begin Display_Point_Array ("Points", A); end Test_Point_Array; procedure Check (TC : Test_Case_Index) is begin case TC is when Int_Array_Chk => Test_Int_Array; when Point_Array_Chk => Test_Point_Array; 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;

Average of Array of Float

Goal: create a generic function that calculates the average of an array of floating-point elements.

Steps:

  1. Declare and implement the generic function Average.

Requirements:

  1. Generic function Average calculates the average of an array containing floating-point values of arbitrary precision.

  2. Generic function Average must contain the following formal parameters:

    1. a range type T_Range for the array;

    2. a formal type T_Element that can be mapped to floating-point types of arbitrary precision;

    3. an array type T_Array using T_Range and T_Element;

Remarks:

  1. You should use the Float type for the accumulator.

generic function Average (A : T_Array) return T_Element;
function Average (A : T_Array) return T_Element is begin return 0.0; end Average;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Average; procedure Main is type Test_Case_Index is (Float_Array_Chk, Digits_7_Float_Array_Chk); procedure Test_Float_Array is type Float_Array is array (Positive range <>) of Float; function Average_Float is new Average (T_Range => Positive, T_Element => Float, T_Array => Float_Array); A : constant Float_Array (1 .. 5) := (1.0, 3.0, 5.0, 7.5, -12.5); begin Put_Line ("Average: " & Float'Image (Average_Float (A))); end Test_Float_Array; procedure Test_Digits_7_Float_Array is type Custom_Float is digits 7 range 0.0 .. 1.0; type Float_Array is array (Integer range <>) of Custom_Float; function Average_Float is new Average (T_Range => Integer, T_Element => Custom_Float, T_Array => Float_Array); A : constant Float_Array (-1 .. 3) := (0.5, 0.0, 1.0, 0.6, 0.5); begin Put_Line ("Average: " & Custom_Float'Image (Average_Float (A))); end Test_Digits_7_Float_Array; procedure Check (TC : Test_Case_Index) is begin case TC is when Float_Array_Chk => Test_Float_Array; when Digits_7_Float_Array_Chk => Test_Digits_7_Float_Array; 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;

Average of Array of Any Type

Goal: create a generic function that calculates the average of an array of elements of any arbitrary type.

Steps:

  1. Declare and implement the generic function Average.

  2. Implement the test procedure Test_Item.

    1. Declare the F_IO package.

    2. Implement the Get_Total function for the Item type.

    3. Implement the Get_Price function for the Item type.

    4. Declare the Average_Total function.

    5. Declare the Average_Price function.

Requirements:

  1. Generic function Average calculates the average of an array containing elements of any arbitrary type.

  2. Generic function Average has the same formal parameters as in the previous exercise, except for:

    1. T_Element, which is now a formal type that can be mapped to any arbitrary type.

    2. To_Float, which is an additional formal parameter.

      • To_Float is a function that converts the arbitrary element of T_Element type to the Float type.

  3. Procedure Test_Item is used to test the generic Average procedure for a record type (Item).

    1. Record type Item contains the Quantity and Price components.

  4. The following functions have to implemented to be used for the formal To_Float function parameter:

    1. For the Decimal type, the function is pretty straightforward: it simply returns the floating-point value converted from the decimal type.

    2. For the Item type, two functions must be created to convert to floating-point type:

      1. Get_Total, which returns the multiplication of the quantity and the price components of the Item type;

      2. Get_Price, which returns just the price.

  5. The generic function Average must be instantiated as follows:

    1. For the Item type, you must:

      1. declare the Average_Total function (as an instance of Average) using the Get_Total for the To_Float parameter;

      2. declare the Average_Price function (as an instance of Average) using the Get_Price for the To_Float parameter.

  6. You must use the Put procedure from Ada.Text_IO.Float_IO.

    1. The generic standard package Ada.Text_IO.Float_IO must be instantiated as F_IO in the test procedures.

    2. This is the specification of the Put procedure, as described in the appendix A.10.9 of the Ada Reference Manual:

      procedure Put(Item : in Num;
                    Fore : in Field := Default_Fore;
                    Aft  : in Field := Default_Aft;
                    Exp  : in Field := Default_Exp);
      
    3. This is the expected format when calling Put from Float_IO:

      Function

      Fore

      Aft

      Exp

      Test_Item

      3

      2

      0

Remarks:

  1. In this exercise, you'll abstract the Average function from the previous exercises a step further.

    1. In this case, the function shall be able to calculate the average of any arbitrary type — including arrays containing elements of record types.

    2. Since record types can be composed by many components of different types, we need to provide a way to indicate which component (or components) of the record will be used when calculating the average of the array.

    3. This problem is solved by specifying a To_Float function as a formal parameter, which converts the arbitrary element of T_Element type to the Float type.

    4. In the implementation of the Average function, we use the To_Float function and calculate the average using a floating-point variable.

generic function Average (A : T_Array) return Float;
function Average (A : T_Array) return Float is begin null; end Average;
procedure Test_Item;
with Ada.Text_IO; use Ada.Text_IO; with Average; procedure Test_Item is type Amount is delta 0.01 digits 12; type Item is record Quantity : Natural; Price : Amount; end record; type Item_Array is array (Positive range <>) of Item; A : constant Item_Array (1 .. 4) := ((Quantity => 5, Price => 10.00), (Quantity => 80, Price => 2.50), (Quantity => 40, Price => 5.00), (Quantity => 20, Price => 12.50)); begin Put ("Average per item & quantity: "); F_IO.Put (Average_Total (A)); New_Line; Put ("Average price: "); F_IO.Put (Average_Price (A)); New_Line; end Test_Item;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Test_Item; procedure Main is type Test_Case_Index is (Item_Array_Chk); procedure Check (TC : Test_Case_Index) is begin case TC is when Item_Array_Chk => Test_Item; 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;

Generic list

Goal: create a system based on a generic list to add and displays elements.

Steps:

  1. Declare and implement the generic package Gen_List.

    1. Implement the Init procedure.

    2. Implement the Add procedure.

    3. Implement the Display procedure.

Requirements:

  1. Generic package Gen_List must have the following subprograms:

    1. Procedure Init initializes the list.

    2. Procedure Add adds an item to the list.

      1. This procedure must contain a Status output parameter that is set to False when the list was full — i.e. if the procedure failed while trying to add the item;

    3. Procedure Display displays the complete list.

      1. This includes the name of the list and its elements — using one line per element.

      2. This is the expected format:

        <NAME>
        <element #1>
        <element #2>
        ...
        
  2. Generic package Gen_List has these formal parameters:

    1. an arbitrary formal type Item;

    2. an unconstrained array type Items of Item element with positive range;

    3. the Name parameter containing the name of the list;

      • This must be a formal input object of String type.

      • It must be used in the Display procedure.

    4. an actual array List_Array to store the list;

      • This must be a formal in out object of Items type.

    5. the variable Last to store the index of the last element;

      • This must be a formal in out object of Natural type.

    6. a procedure Put for the Item type.

      • This procedure is used in the Display procedure to display individual elements of the list.

  3. The test procedure Test_Int is used to test a list of elements of Integer type.

  4. For both test procedures, you must:

    1. add missing type declarations;

    2. declare and implement a Put procedure for individual elements of the list;

    3. declare instances of the Gen_List package.

      • For the Test_Int procedure, declare the Int_List package.

Remarks:

  1. In previous labs, you've been implementing lists for a variety of types.

    • The List of Names exercise from the Arrays labs is an example.

    • In this exercise, you have to abstract those implementations to create the generic Gen_List package.

generic package Gen_List is procedure Init; procedure Add (I : Item; Status : out Boolean); procedure Display; end Gen_List;
with Ada.Text_IO; use Ada.Text_IO; package body Gen_List is procedure Init is begin null; end Init; procedure Add (I : Item; Status : out Boolean) is begin null; end Add; procedure Display is begin null; end Display; end Gen_List;
procedure Test_Int;
with Ada.Text_IO; use Ada.Text_IO; with Gen_List; procedure Test_Int is type Integer_Array is array (Positive range <>) of Integer; A : Integer_Array (1 .. 3); L : Natural; Success : Boolean; procedure Display_Add_Success (Success : Boolean) is begin if Success then Put_Line ("Added item successfully!"); else Put_Line ("Couldn't add item!"); end if; end Display_Add_Success; begin Int_List.Init; Int_List.Add (2, Success); Display_Add_Success (Success); Int_List.Add (5, Success); Display_Add_Success (Success); Int_List.Add (7, Success); Display_Add_Success (Success); Int_List.Add (8, Success); Display_Add_Success (Success); Int_List.Display; end Test_Int;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Test_Int; procedure Main is type Test_Case_Index is (Int_Chk); procedure Check (TC : Test_Case_Index) is begin case TC is when Int_Chk => Test_Int; 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;