CVS difference for ai05s/ai05-0212-1.txt

Differences between 1.1 and version 1.2
Log of other versions for file ai05s/ai05-0212-1.txt

--- ai05s/ai05-0212-1.txt	2010/04/27 05:35:36	1.1
+++ ai05s/ai05-0212-1.txt	2011/01/23 04:37:32	1.2
@@ -1,4 +1,4 @@
-!standard A.18.2(9/2)                                  10-04-26  AI05-0212-1/01
+!standard A.18.2(9/2)                                  11-01-22  AI05-0212-1/02
 !class Amendment 10-04-26
 !status work item 10-04-26
 !status received 10-02-27
@@ -20,21 +20,53 @@
 
 Add accessors and iterators to the containers packages.
 
-
 !wording
+
+[Editor's note: The following is based on AI05-0139-2/07.]
+
+Add the following with to each container package:
+
+   with Ada.Iterator_Interfaces;
+
+
+Modify the definition of the cursor and container types for each of the containers
+(with suitable substitutions for the names of types) as follows:
+
+      type Vector;
+
+      package Cursors is
+         type Cursor is private;
+         pragma Preelaborable_Initialization(Cursor);
+
+         No_Element : constant Cursor;
+      private
+         ... -- not specified by the language
+      end Cursors;
+      subtype Cursor is Cursors.Cursor;
+      No_Element : Cursor renames Cursors.No_Element;
+
+      package Iterators is new
+          Ada.Iterator_Interfaces (Cursors, No_Element);
 
-[Editor's note: The following does not yet use most of the AI05-0139-2 features.
-Version /04 only contains a rough proposal, and alomst nothing for the form of the
-accessors magic.]
+      type Vector is new Iterators with private with
+          Constant_Indexing => Constant_Reference,
+          Variable_Indexing => Reference,
+          Default_Iterator  => Iterate,
+          Iterator_Element  => Element_Type;
 
+      pragma Preelaborable_Initialization(Vectors);
+
+
 Add the following to each Ada.Containers package immediately after
 Update_Element (with suitable substitutions for the names of types).
 
     type Constant_Reference_Type (Element : not null access constant Element_Type) is
-        limited new Ada.Reference.References with private;
+        limited new Ada.Reference.References with private with
+        Implicit_Dereference => Element;
 
     type Reference_Type (Element : not null access Element_Type) is
-        limited new Ada.Reference.References with private;
+        limited new Ada.Reference.References with private with
+        Implicit_Dereference => Element;
 
 Constant_Reference_Type and Reference_Type need finalization.
 
@@ -51,6 +83,10 @@
     function Constant_Reference (Container : aliased in Vector; Position : in Cursor)
        return Constant_Reference_Type;
 
+This function (combined with the Constant_Indexing and Implicit_Dereference aspects)
+provides a convinient way to get read access to the individual elements of
+a container starting with a cursor.
+
 If Position equals No_Element, then Constraint_Error is propagated; if Position
 does not designate an element in Container, then Program_Error is propagated.
 Otherwise, Constant_Reference returns an object whose discriminant is an access
@@ -58,12 +94,13 @@
 if any operation tampers with the elements of Container while the object returned
 by Constant_Reference exists and has not been finalized.
 
-[Editor's note: We want to say something about the accessor capability here, not sure
-what exactly.]
-
     function Reference (Container : aliased in out Vector; Position : in Cursor)
        return Reference_Type;
 
+This function (combined with the Variable_Indexing and Implicit_Dereference aspects)
+provides a convinient way to get read and write access to the individual elements of
+a container starting with a cursor.
+
 If Position equals No_Element, then Constraint_Error is propagated; if Position
 does not designate an element in Container, then Program_Error is propagated.
 Otherwise, Reference returns an object whose discriminant is an access value
@@ -74,11 +111,15 @@
 The element designated by Position is not an empty element after successful
 completion of this operation. [This is only needed for the Vectors case. - ED]
 
-Add the following to Ada.Containers.Vectors and its relatives.
+Add the following to Ada.Containers.Vectors and its relatives:
 
     function Constant_Reference (Container : aliased in Vector; Index : in Index_Type)
        return Constant_Reference_Type;
 
+This routine (combined with the Constant_Indexing and Implicit_Dereference aspects)
+provides a convinient way to get read access to the individual elements of
+a container starting with an index value.
+
 If Index is not in the range First_Index (Container) .. Last_Index (Container),
 then Constraint_Error is propagated. Otherwise, Constant_Reference returns an object
 whose discriminant is an access value that designates the element at position Index.
@@ -88,6 +129,10 @@
     function Reference (Container : aliased in out Vector; Index : in Index_Type)
        return Reference_Type;
 
+This function (combined with the Variable_Indexing and Implicit_Dereference aspects)
+provides a convinient way to get read and write access to the individual elements of
+a container starting with an index value.
+
 If Index is not in the range First_Index (Container) .. Last_Index (Container),
 then Constraint_Error is propagated. Otherwise, Reference returns an object whose
 discriminant is an access value that designates the element at position Index.
@@ -97,6 +142,98 @@
 The element designated by Position is not an empty element after successful
 completion of this operation.
 
+Add the following to Ada.Containers.Hashed_Maps and the various other Map containers:
+
+    function Constant_Reference (Container : aliased in Map; Key : in Key_Type)
+       return Constant_Reference_Type;
+
+This routine (combined with the Constant_Indexing and Implicit_Dereference aspects)
+provides a convinient way to get read access to the individual elements of
+a container starting with a key value.
+
+Equivalent to Constant_Reference (Container, Find (Container, Key)).
+
+    function Reference (Container : aliased in out Map; Key : in Key_Type)
+       return Reference_Type;
+
+This function (combined with the Variable_Indexing and Implicit_Dereference aspects)
+provides a convinient way to get read and write access to the individual elements of
+a container starting with an index value.
+
+Equivalent to Reference (Container, Find (Container, Key).
+
+
+After the existing procedure Reverse_Iterate of each container that has Reverse_Iterate,
+add a new function:
+
+   function Iterate (Container : in Vector) return Iterators.Reversible_Iterator'Class;
+
+      Iterate returns an object that can be used in a loop_statement to loop
+      with a loop parameter designating each node in Container, starting with
+      the first node and moving the cursor as per the Next function if the reserved word
+      *reverse* is not used in the iterator_specification, and starting
+      with the last node and moving the cursor as per the Previous function otherwise.
+      Program_Error is propagated if any operation (in particular, the sequence_of_statements
+      of the loop_statement whose iterator_specification denotes this object) tampers
+      with the cursors of Container while the returned object exists.
+
+[Note: This wording will need to be adjusted for containers that don't have Next, like
+Maps. The wording will be parallel to that of the existing Iterate procedure.]
+
+After the existing procedure Iterate of each container that does not have a procedure
+Reverse_Iterate (for example, Hashed_Sets), add a new function:
+
+   function Iterate (Container : in Set) return Iterators.Forward_Iterator'Class;
+
+      Iterate returns an object that can be used in a loop_statement to loop
+      with a loop parameter designating each node in Container, starting
+      with the first node and moving the cursor as per the Next function.
+      Program_Error is propagated if any operation (in particular, the sequence_of_statements
+      of the loop_statement whose iterator_specification denotes this object) tampers
+      with the cursors of Container while the returned object exists.
+
+
+Instead of the above, the Multiway_Tree containers would have:
+
+   function Iterate (Container : in Tree) return Iterators.Forward_Iterator'Class;
+
+      Iterate returns an object that can be used in a loop_statement to loop
+      with a loop parameter designating each node in Container, starting with the root node and
+      proceeding in a depth-first order. Program_Error is propagated if any operation (in particular,
+      the sequence_of_statements of the loop_statement whose iterator_specification denotes
+      this object) tampers with the cursors of Container while the returned object exists.
+
+   function Iterate_Subtree (Position : in Cursor) return Iterators.Forward_Iterator'Class;
+
+      Iterate returns an object that can be used in a loop_statement to loop
+      with a loop parameter designating each element in the subtree rooted by the node designated by
+      Position, starting with the node designated by Position and
+      proceeding in a depth-first order. If Position equals No_Element, then Constraint_Error is
+      propagated. Program_Error is propagated if any operation (in particular,
+      the sequence_of_statements of the loop_statement whose iterator_specification denotes
+      this object) tampers with the cursors of the container in which the node designated by Position
+      exists while the returned object exists.
+
+   function Iterate_Children (Container : in Tree; Parent : in Cursor) return Iterators.Reversible_Iterator'Class;
+
+      Iterate returns an object that can be used in a loop_statement to loop
+      with a loop parameter designating each child node of Parent. If Parent equals No_Element, then
+      Constraint_Error is propagated. If Parent does not designate a node in Container, then
+      Program_Error is propagated. Otherwise, if the reserved word *reverse* is not used in the
+      iterator_specification, the nodes are designated starting with the first child node and
+      moving the cursor as per the function Next_Sibling; if reserved word *reverse* is used, the
+      nodes are designated starting with the last child node and moving the cursor as per the
+      function Previous_Sibling. Program_Error is propagated if any operation (in particular,
+      the sequence_of_statements of the loop_statement whose iterator_specification denotes
+      this object) tampers with the cursors of Container while the returned object exists.
+
+
+[Question: Should we have other kinds of iterators for containers? In particular, should
+the vectors and linked lists support an iterator where the start and end cursors are specified
+(to allow iterating over a slice?).]
+
+
+
 Add the following to the Erroneous Execution section of each container package:
 
 Execution is erroneous if the vector associated with the result of a call to
@@ -113,6 +250,28 @@
 question is not visible in the specification of the type. (This is the same
 reason we have to say this for invalid cursors.)
 
+Add an Example subpart to each container (with suitable changes to the type names):
+
+For the following declarations:
+
+    type Point is record
+        X, Y : Natural;
+    end record;
+    subtype Short is Natural range 1 .. 100;
+    package Point_Vectors is new Ada.Containers.Vectors (Short, Point);
+    use Point_Vectors;
+    Obj : Point_Vectors.Vector;
+    Cur : Point_Vectors.Cursor;
+
+the effect of the Variable_Indexing and Implicit_Dereference aspects is that
+
+    Obj(Cur).X := 10;
+
+has the effect of calling the Reference function and dereferencing the result, as in the
+following expression:
+
+    Point_Vectors.Reference (Obj, Cur).Element.all.X := 10;
+
 
 !discussion
 
@@ -254,8 +413,8 @@
 
 !examples
 
-The new Reference function could be used (based on a recent example from
-comp.lang.ada):
+The new Reference function can be used to update an element directly.
+For example (based on a recent example from comp.lang.ada):
 
    with Ada.Containers.Vectors;
    procedure Check is
@@ -275,17 +434,34 @@
    begin
       IV.Append(42);
       NV.Append(IV);
-      NV.Reference(0).Element.Append(43);
+      NV.Reference(0).Element.all.Append(43);
    end Check;
 
 The dereference does not need to be explicitly given in this case, and the fact
 that the object returned by Reference is limited and (probably) controlled is not
-visible in the code as the function call is used directly as a prefix.
+visible in the code as the function call is used directly as a prefix. So the call
+can be just:
+
+      NV.Reference(0).Element.Append(43);
+
+The "Implicit_Dereference" aspect of the returned object allows us to drop the
+".Element" as well. That leave us with:
+
+      NV.Reference(0).Append(43);
 
+Since containers have the "Variable_Indexing" aspect set to the Reference function,
+directly indexing the container is equivalent to a call to Reference. So we also
+could have written:
+
+      NV(0).Append(43);
+
+This is essentially the same as what we could have written had the type of NV been
+an array type.
+
 You could also save the entire object as long as needed:
 
    declare
-      My_IV : Nested_Vectors.Reference_Type := NV.Reference(0);
+      My_IV : Nested_Vectors.Reference_Type := NV.Reference(0); -- Or just NV(0).
    begin
 
 (since My_NV would be built-in-place).
@@ -330,6 +506,60 @@
 or
 
     Munge (NV.Reference(0).Element.all);
+
+For Maps, we define indexing by the key as well as by cursors. So if we have:
+
+    type Point is record
+       X, Y : Natural;
+    end record;
+    package Point_Maps is new Ada.Containers.Indefinite_Ordered_Maps (String, Point);
+
+    Locations : Point_Maps.Map;
+
+    Locations.Insert ("Tucker", (X | Y => 0));
+    Locations.Insert ("Randy", (X => 10, Y => 5));
+    Locations.Insert ("Steve", (X | Y => 20));
+    Locations.Insert ("John", (X => 50, Y => 100));
+
+we can reference the elements directly via the keys:
+
+    if Locations("Randy").X > 10 then ...
+    if Locations("Tucker").all = (X | Y => 0) then ...
+    Locations ("Steve").X := 15;
+    Locations ("John").all := (X | Y => 60);
+
+
+The iterator functions can be used directly in a for loop:
+
+    for C in My_Vector.Iterator loop
+        if My_Vector(C).B then
+            My_Vector(C).Cnt := My_Vector(C).Cnt + 1;
+        end if;
+    end loop;
+
+Note that the Reference and Constant_Reference functions (implicitly called above)
+are very helpful in writing the body of this sort of loop.
+
+When reasonable, the keyword "reverse" is supported with the usual meaning:
+
+    for C in reverse My_Vector.Iterator loop
+
+Containers have the "Iterator" function as their default iterator. This is
+always the iterator that unconditionally iterates the entire contents of the
+container. These iterators can be used with the "of" syntax to directly access
+the elements of a container. This means that the first loop above can be written:
+
+    for E of My_Vector loop
+        if E.B then
+            E.Cnt := E.Cnt + 1;
+        end if;
+    end loop;
+
+Note however that the cursor form is more powerful. For instance, for a Map, the
+default iterator can only access the elements and not the keys, while the cursor
+form can access both. Similarly, for a tree, the element form does not allow the
+loop body to know where in the tree the element exists; the cursor form allows
+querying Depth, Parent, and many other useful functions.
 
 
 !ACATS test

Questions? Ask the ACAA Technical Agent