diff mbox

[Ada] Iterator subtypes

Message ID 20151023122129.GA46613@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Oct. 23, 2015, 12:21 p.m. UTC
THis patch fixes an omission in the handling of iterators over containers.
The code now handles properly an iterator type that is a subtype of the
type obtained from an instantiation of the predefined iterator interfaces.

Compiling and executing main.adb must yield:

Element_T.F: 42
Element_T.F: 42
Element_T.F: 42
Element_T.F: 42
Element_T.F: 42
Element_T.F: 42
Element_T.F: 42
Element_T.F: 42
V.Element (C).F: 42
V.Element (C).F: 42
V.Element (C).F: 42
V.Element (C).F: 42

---
with Ada.Text_Io; use Ada.Text_Io;
with Containers;

procedure Main is

  type Index is range 1 .. 4;
  type Element_T is
    record
      F : Integer := 42;
    end record;

  package Vectors is new Containers.Vectors (Index, Element_T);

  V : Vectors.Vector;

begin

  for E of V loop
    Put_Line ("Element_T.F:" & Integer'Image (E.F));
  end loop;

  for E of reverse V loop
    Put_Line ("Element_T.F:" & Integer'Image (E.F));
  end loop;

  for C in V.Iterate loop
    Put_Line ("V.Element (C).F:" & Integer'Image (V.Element (C).F));
  end loop;
end Main;
---

with Ada.Iterator_Interfaces;

package Containers is

  generic
    type Index is (<>);
    type Element_T is private;
  package Vectors is

    type Vector is tagged private
      with
        Constant_Indexing => Constant_Reference,
        Default_Iterator => Iterate,
        Iterator_Element => Element_T;

    type Cursor is private;

    function Has_Element (Position : Cursor) return Boolean;

    function Element (Container : in Vector; Position : Cursor)
       return Element_T;

    package Vector_Iterator_Interfaces is
       new Ada.Iterator_Interfaces (Cursor, Has_Element);

    subtype Iterator_Class is
       Vector_Iterator_Interfaces.Reversible_Iterator'Class;

    function Iterate (Container : in Vector) return Iterator_Class;

    function Iterate (Container : in Vector; Start : in Cursor)
       return Iterator_Class;

    type Constant_Reference_Type
      (Element : not null access constant Element_T) is private
      with Implicit_Dereference => Element;

    function Constant_Reference
      (Container : aliased in Vector;
       Position  : in Cursor)
       return Constant_Reference_Type;

  private

    type Rep is array (Index) of aliased Element_T;

    type Vector is tagged
      record
        A : aliased Rep;
      end record;

    type Cursor (Going : Boolean := False) is
      record
        case Going is
          when False =>
            null;
          when True =>
            I : Index;
        end case;
      end record;

    type Constant_Reference_Type
      (Element : not null access constant Element_T) is
      record
        null;
      end record;

    type Iterator is new Vector_Iterator_Interfaces.Reversible_Iterator with
      record
        C : Cursor;
      end record;

    function First (Object : Iterator) return Cursor;
    function Next (Object : Iterator; Position : Cursor) return Cursor;

    function Last (Object : Iterator) return Cursor;
    function Previous (Object : Iterator; Position : Cursor) return Cursor;

  end Vectors;

end Containers;
---
package body Containers is
  package body Vectors is

    function Has_Element (Position : Cursor) return Boolean is
    begin
      return Position.Going;
    end Has_Element;

    function Element (Container : in Vector; Position : Cursor)
      return Element_T is
    begin
      return Container.A (Position.I);
    end Element;

    function Iterate (Container : in Vector) return Iterator_Class is
    begin
      return Iterator_Class
         (Iterator'(C => (Going => True, I => Index'First)));
    end Iterate;

    function Iterate (Container : in Vector; Start: in Cursor)
      return Iterator_Class is
    begin
      return Iterator_Class (Iterator'(C => Start));
    end Iterate;

    function Constant_Reference
      (Container : aliased in Vector;
       Position  : in Cursor)
       return Constant_Reference_Type is
    begin
      return (Element => Container.A (Position.I)'Access);
    end Constant_Reference;

    function First (Object : Iterator) return Cursor is
    begin
      return (Going => True, I => Index'First);
    end First;

    function Next (Object : Iterator; Position : Cursor) return Cursor is
    begin
      if Position.I /= Index'Last then
        return (Going => True, I => Index'Succ (Position.I));
      else
        return (Going => False);
      end if;
    end Next;

    function Last (Object : Iterator) return Cursor is
    begin
      return (Going => True, I => Index'Last);
    end Last;

    function Previous (Object : Iterator; Position : Cursor) return Cursor is
    begin
      if Position.I /= Index'First then
        return (Going => True, I => Index'Pred (Position.I));
      else
        return (Going => False);
      end if;
    end Previous;

  end Vectors;
end Containers;

Tested on x86_64-pc-linux-gnu, committed on trunk

2015-10-23  Ed Schonberg  <schonberg@adacore.com>

	* sem_util.adb (Is_Iterator, Is_Reversible_iterator): Use
	root type to determine whether the type is a descendant of the
	corresponding interface type, so take into account multiple
	levels of subtypes and derivations.
diff mbox

Patch

Index: sem_util.adb
===================================================================
--- sem_util.adb	(revision 229238)
+++ sem_util.adb	(working copy)
@@ -12119,12 +12119,16 @@ 
       Iface       : Entity_Id;
 
    begin
+      --  The type may be a subtype of a descendant of the proper instance of
+      --  the predefined interface type, so we must use the root type of the
+      --  given type. The same us done for Is_Reversible_Iterator.
+
       if Is_Class_Wide_Type (Typ)
-        and then Nam_In (Chars (Etype (Typ)), Name_Forward_Iterator,
+        and then Nam_In (Chars (Root_Type (Typ)), Name_Forward_Iterator,
                                               Name_Reversible_Iterator)
         and then
           Is_Predefined_File_Name
-            (Unit_File_Name (Get_Source_Unit (Etype (Typ))))
+            (Unit_File_Name (Get_Source_Unit (Root_Type (Typ))))
       then
          return True;
 
@@ -13009,9 +13013,9 @@ 
 
    begin
       if Is_Class_Wide_Type (Typ)
-        and then Chars (Etype (Typ)) = Name_Reversible_Iterator
+        and then Chars (Root_Type (Typ)) = Name_Reversible_Iterator
         and then Is_Predefined_File_Name
-                   (Unit_File_Name (Get_Source_Unit (Etype (Typ))))
+                   (Unit_File_Name (Get_Source_Unit (Root_Type (Typ))))
       then
          return True;