CVS difference for 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