===================================================================
@@ -39,7 +39,7 @@
package body Ada.Containers.Ordered_Maps is
- type Iterator is new
+ type Iterator is limited new
Map_Iterator_Interfaces.Reversible_Iterator with record
Container : Map_Access;
Node : Node_Access;
@@ -518,13 +518,24 @@
end First;
function First (Object : Iterator) return Cursor is
- M : constant Map_Access := Object.Container;
- N : constant Node_Access := M.Tree.First;
begin
- if N = null then
- return No_Element;
+ -- The value of the iterator object's Node component influences the
+ -- behavior of the First (and Last) selector function.
+
+ -- When the Node component is null, this means the iterator object was
+ -- constructed without a start expression, in which case the (forward)
+ -- iteration starts from the (logical) beginning of the entire sequence
+ -- of items (corresponding to Container.First, for a forward iterator).
+
+ -- Otherwise, this is iteration over a partial sequence of items. When
+ -- the Node component is non-null, the iterator object was constructed
+ -- with a start expression, that specifies the position from which the
+ -- (forward) partial iteration begins.
+
+ if Object.Node = null then
+ return Object.Container.First;
else
- return Cursor'(Object.Container.all'Unchecked_Access, N);
+ return Cursor'(Object.Container, Object.Node);
end if;
end First;
@@ -534,7 +545,6 @@
function First_Element (Container : Map) return Element_Type is
T : Tree_Type renames Container.Tree;
-
begin
if T.First = null then
raise Constraint_Error with "map is empty";
@@ -827,21 +837,60 @@
end Iterate;
function Iterate
- (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'class
+ (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
is
- Node : constant Node_Access := Container.Tree.First;
- It : constant Iterator := (Container'Unrestricted_Access, Node);
+ begin
+ -- The value of the Node component influences the behavior of the First
+ -- and Last selector functions of the iterator object. When the Node
+ -- component is null (as is the case here), this means the iterator
+ -- object was constructed without a start expression. This is a
+ -- complete iterator, meaning that the iteration starts from the
+ -- (logical) beginning of the sequence of items.
- begin
- return It;
+ -- Note: For a forward iterator, Container.First is the beginning, and
+ -- for a reverse iterator, Container.Last is the beginning.
+
+ return Iterator'(Container'Unrestricted_Access, Node => null);
end Iterate;
function Iterate (Container : Map; Start : Cursor)
- return Map_Iterator_Interfaces.Reversible_Iterator'class
+ return Map_Iterator_Interfaces.Reversible_Iterator'Class
is
- It : constant Iterator := (Container'Unrestricted_Access, Start.Node);
begin
- return It;
+ -- It was formerly the case that when Start = No_Element, the partial
+ -- iterator was defined to behave the same as for a complete iterator,
+ -- and iterate over the entire sequence of items. However, those
+ -- semantics were unintuitive and arguably error-prone (it is too easy
+ -- to accidentally create an endless loop), and so they were changed,
+ -- per the ARG meeting in Denver on 2011/11. However, there was no
+ -- consensus about what positive meaning this corner case should have,
+ -- and so it was decided to simply raise an exception. This does imply,
+ -- however, that it is not possible to use a partial iterator to specify
+ -- an empty sequence of items.
+
+ if Start = No_Element then
+ raise Constraint_Error with
+ "Start position for iterator equals No_Element";
+ end if;
+
+ if Start.Container /= Container'Unrestricted_Access then
+ raise Program_Error with
+ "Start cursor of Iterate designates wrong map";
+ end if;
+
+ pragma Assert (Vet (Container.Tree, Start.Node),
+ "Start cursor of Iterate is bad");
+
+ -- The value of the Node component influences the behavior of the First
+ -- and Last selector functions of the iterator object. When the Node
+ -- component is non-null (as is the case here), it means that this
+ -- is a partial iteration, over a subset of the complete sequence of
+ -- items. The iterator object was constructed with a start expression,
+ -- indicating the position from which the iteration begins. Note that
+ -- the start position has the same value irrespective of whether this
+ -- is a forward or reverse iteration.
+
+ return Iterator'(Container'Unrestricted_Access, Node => Start.Node);
end Iterate;
---------
@@ -876,13 +925,24 @@
end Last;
function Last (Object : Iterator) return Cursor is
- M : constant Map_Access := Object.Container;
- N : constant Node_Access := M.Tree.Last;
begin
- if N = null then
- return No_Element;
+ -- The value of the iterator object's Node component influences the
+ -- behavior of the Last (and First) selector function.
+
+ -- When the Node component is null, this means the iterator object was
+ -- constructed without a start expression, in which case the (reverse)
+ -- iteration starts from the (logical) beginning of the entire sequence
+ -- (corresponding to Container.Last, for a reverse iterator).
+
+ -- Otherwise, this is iteration over a partial sequence of items. When
+ -- the Node component is non-null, the iterator object was constructed
+ -- with a start expression, that specifies the position from which the
+ -- (reverse) partial iteration begins.
+
+ if Object.Node = null then
+ return Object.Container.Last;
else
- return Cursor'(Object.Container.all'Unchecked_Access, N);
+ return Cursor'(Object.Container, Object.Node);
end if;
end Last;
@@ -980,11 +1040,16 @@
Position : Cursor) return Cursor
is
begin
- if Position.Node = null then
+ if Position.Container = null then
return No_Element;
- else
- return (Object.Container, Tree_Operations.Next (Position.Node));
end if;
+
+ if Position.Container /= Object.Container then
+ raise Program_Error with
+ "Position cursor of Next designates wrong map";
+ end if;
+
+ return Next (Position);
end Next;
------------
@@ -1032,12 +1097,18 @@
Position : Cursor) return Cursor
is
begin
- if Position.Node = null then
+ if Position.Container = null then
return No_Element;
- else
- return (Object.Container, Tree_Operations.Previous (Position.Node));
end if;
+
+ if Position.Container /= Object.Container then
+ raise Program_Error with
+ "Position cursor of Previous designates wrong map";
+ end if;
+
+ return Previous (Position);
end Previous;
+
-------------------
-- Query_Element --
-------------------
===================================================================
@@ -203,19 +203,23 @@
(Container : Map;
Process : not null access procedure (Position : Cursor));
+ procedure Reverse_Iterate
+ (Container : Map;
+ Process : not null access procedure (Position : Cursor));
+
+ -- The map container supports iteration in both the forward and reverse
+ -- directions, hence these constructor functions return an object that
+ -- supports the Reversible_Iterator interface.
+
function Iterate
(Container : Map)
- return Map_Iterator_Interfaces.Forward_Iterator'class;
+ return Map_Iterator_Interfaces.Reversible_Iterator'class;
function Iterate
(Container : Map;
Start : Cursor)
return Map_Iterator_Interfaces.Reversible_Iterator'class;
- procedure Reverse_Iterate
- (Container : Map;
- Process : not null access procedure (Position : Cursor));
-
private
pragma Inline (Next);
===================================================================
@@ -39,7 +39,7 @@
package body Ada.Containers.Bounded_Ordered_Maps is
- type Iterator is new
+ type Iterator is limited new
Map_Iterator_Interfaces.Reversible_Iterator with record
Container : Map_Access;
Node : Count_Type;
@@ -579,12 +579,24 @@
end First;
function First (Object : Iterator) return Cursor is
- F : constant Count_Type := Object.Container.First;
begin
- if F = 0 then
- return No_Element;
+ -- The value of the iterator object's Node component influences the
+ -- behavior of the First (and Last) selector function.
+
+ -- When the Node component is 0, this means the iterator object was
+ -- constructed without a start expression, in which case the (forward)
+ -- iteration starts from the (logical) beginning of the entire sequence
+ -- of items (corresponding to Container.First, for a forward iterator).
+
+ -- Otherwise, this is iteration over a partial sequence of items. When
+ -- the Node component is positive, the iterator object was constructed
+ -- with a start expression, that specifies the position from which the
+ -- (forward) partial iteration begins.
+
+ if Object.Node = 0 then
+ return Bounded_Ordered_Maps.First (Object.Container.all);
else
- return Cursor'(Object.Container.all'Unchecked_Access, F);
+ return Cursor'(Object.Container, Object.Node);
end if;
end First;
@@ -886,22 +898,62 @@
end Iterate;
function Iterate
- (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'class
+ (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
is
- It : constant Iterator :=
- (Container'Unrestricted_Access, Container.First);
begin
- return It;
+ -- The value of the Node component influences the behavior of the First
+ -- and Last selector functions of the iterator object. When the Node
+ -- component is 0 (as is the case here), this means the iterator object
+ -- was constructed without a start expression. This is a complete
+ -- iterator, meaning that the iteration starts from the (logical)
+ -- beginning of the sequence of items.
+
+ -- Note: For a forward iterator, Container.First is the beginning, and
+ -- for a reverse iterator, Container.Last is the beginning.
+
+ return Iterator'(Container'Unrestricted_Access, Node => 0);
end Iterate;
function Iterate
(Container : Map;
Start : Cursor)
- return Map_Iterator_Interfaces.Reversible_Iterator'class
+ return Map_Iterator_Interfaces.Reversible_Iterator'Class
is
- It : constant Iterator := (Container'Unrestricted_Access, Start.Node);
begin
- return It;
+
+ -- iterator was defined to behave the same as for a complete iterator,
+ -- and iterate over the entire sequence of items. However, those
+ -- semantics were unintuitive and arguably error-prone (it is too easy
+ -- to accidentally create an endless loop), and so they were changed,
+ -- per the ARG meeting in Denver on 2011/11. However, there was no
+ -- consensus about what positive meaning this corner case should have,
+ -- and so it was decided to simply raise an exception. This does imply,
+ -- however, that it is not possible to use a partial iterator to specify
+ -- an empty sequence of items.
+
+ if Start = No_Element then
+ raise Constraint_Error with
+ "Start position for iterator equals No_Element";
+ end if;
+
+ if Start.Container /= Container'Unrestricted_Access then
+ raise Program_Error with
+ "Start cursor of Iterate designates wrong map";
+ end if;
+
+ pragma Assert (Vet (Container, Start.Node),
+ "Start cursor of Iterate is bad");
+
+ -- The value of the Node component influences the behavior of the First
+ -- and Last selector functions of the iterator object. When the Node
+ -- component is positive (as is the case here), it means that this
+ -- is a partial iteration, over a subset of the complete sequence of
+ -- items. The iterator object was constructed with a start expression,
+ -- indicating the position from which the iteration begins. (Note that
+ -- the start position has the same value irrespective of whether this
+ -- is a forward or reverse iteration.)
+
+ return Iterator'(Container'Unrestricted_Access, Node => Start.Node);
end Iterate;
---------
@@ -935,12 +987,24 @@
end Last;
function Last (Object : Iterator) return Cursor is
- F : constant Count_Type := Object.Container.Last;
begin
- if F = 0 then
- return No_Element;
+ -- The value of the iterator object's Node component influences the
+ -- behavior of the Last (and First) selector function.
+
+ -- When the Node component is 0, this means the iterator object was
+ -- constructed without a start expression, in which case the (reverse)
+ -- iteration starts from the (logical) beginning of the entire sequence
+ -- (corresponding to Container.Last, for a reverse iterator).
+
+ -- Otherwise, this is iteration over a partial sequence of items. When
+ -- the Node component is positive, the iterator object was constructed
+ -- with a start expression, that specifies the position from which the
+ -- (reverse) partial iteration begins.
+
+ if Object.Node = 0 then
+ return Bounded_Ordered_Maps.Last (Object.Container.all);
else
- return Cursor'(Object.Container.all'Unchecked_Access, F);
+ return Cursor'(Object.Container, Object.Node);
end if;
end Last;
@@ -1044,8 +1108,16 @@
(Object : Iterator;
Position : Cursor) return Cursor
is
- pragma Unreferenced (Object);
begin
+ if Position.Container = null then
+ return No_Element;
+ end if;
+
+ if Position.Container /= Object.Container then
+ raise Program_Error with
+ "Position cursor of Next designates wrong map";
+ end if;
+
return Next (Position);
end Next;
@@ -1095,8 +1167,16 @@
(Object : Iterator;
Position : Cursor) return Cursor
is
- pragma Unreferenced (Object);
begin
+ if Position.Container = null then
+ return No_Element;
+ end if;
+
+ if Position.Container /= Object.Container then
+ raise Program_Error with
+ "Position cursor of Previous designates wrong map";
+ end if;
+
return Previous (Position);
end Previous;
===================================================================
@@ -227,18 +227,19 @@
(Container : Map;
Process : not null access procedure (Position : Cursor));
+ procedure Reverse_Iterate
+ (Container : Map;
+ Process : not null access procedure (Position : Cursor));
+
function Iterate
- (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'class;
+ (Container : Map)
+ return Map_Iterator_Interfaces.Reversible_Iterator'Class;
function Iterate
(Container : Map;
Start : Cursor)
- return Map_Iterator_Interfaces.Reversible_Iterator'class;
+ return Map_Iterator_Interfaces.Reversible_Iterator'Class;
- procedure Reverse_Iterate
- (Container : Map;
- Process : not null access procedure (Position : Cursor));
-
private
pragma Inline (Next);
===================================================================
@@ -40,7 +40,7 @@
package body Ada.Containers.Indefinite_Ordered_Maps is
pragma Suppress (All_Checks);
- type Iterator is new
+ type Iterator is limited new
Map_Iterator_Interfaces.Reversible_Iterator with record
Container : Map_Access;
Node : Node_Access;
@@ -558,11 +558,25 @@
end First;
function First (Object : Iterator) return Cursor is
- M : constant Map_Access := Object.Container;
- N : constant Node_Access := M.Tree.First;
begin
- return (if N = null then No_Element
- else Cursor'(Object.Container.all'Unchecked_Access, N));
+ -- The value of the iterator object's Node component influences the
+ -- behavior of the First (and Last) selector function.
+
+ -- When the Node component is null, this means the iterator object was
+ -- constructed without a start expression, in which case the (forward)
+ -- iteration starts from the (logical) beginning of the entire sequence
+ -- of items (corresponding to Container.First for a forward iterator).
+
+ -- Otherwise, this is iteration over a partial sequence of items. When
+ -- the Node component is non-null, the iterator object was constructed
+ -- with a start expression, that specifies the position from which the
+ -- (forward) partial iteration begins.
+
+ if Object.Node = null then
+ return Object.Container.First;
+ else
+ return Cursor'(Object.Container, Object.Node);
+ end if;
end First;
-------------------
@@ -571,13 +585,12 @@
function First_Element (Container : Map) return Element_Type is
T : Tree_Type renames Container.Tree;
-
begin
if T.First = null then
raise Constraint_Error with "map is empty";
+ else
+ return T.First.Element.all;
end if;
-
- return T.First.Element.all;
end First_Element;
---------------
@@ -586,13 +599,12 @@
function First_Key (Container : Map) return Key_Type is
T : Tree_Type renames Container.Tree;
-
begin
if T.First = null then
raise Constraint_Error with "map is empty";
+ else
+ return T.First.Key.all;
end if;
-
- return T.First.Key.all;
end First_Key;
-----------
@@ -864,22 +876,62 @@
end Iterate;
function Iterate
- (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'class
+ (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
is
- Node : constant Node_Access := Container.Tree.First;
- It : constant Iterator := (Container'Unrestricted_Access, Node);
begin
- return It;
+ -- The value of the Node component influences the behavior of the First
+ -- and Last selector functions of the iterator object. When the Node
+ -- component is null (as is the case here), this means the iterator
+ -- object was constructed without a start expression. This is a complete
+ -- iterator, meaning that the iteration starts from the (logical)
+ -- beginning of the sequence of items.
+
+ -- Note: For a forward iterator, Container.First is the beginning, and
+ -- for a reverse iterator, Container.Last is the beginning.
+
+ return Iterator'(Container'Unrestricted_Access, Node => null);
end Iterate;
function Iterate
(Container : Map;
Start : Cursor)
- return Map_Iterator_Interfaces.Reversible_Iterator'class
+ return Map_Iterator_Interfaces.Reversible_Iterator'Class
is
- It : constant Iterator := (Container'Unrestricted_Access, Start.Node);
begin
- return It;
+ -- It was formerly the case that when Start = No_Element, the partial
+ -- iterator was defined to behave the same as for a complete iterator,
+ -- and iterate over the entire sequence of items. However, those
+ -- semantics were unintuitive and arguably error-prone (it is too easy
+ -- to accidentally create an endless loop), and so they were changed,
+ -- per the ARG meeting in Denver on 2011/11. However, there was no
+ -- consensus about what positive meaning this corner case should have,
+ -- and so it was decided to simply raise an exception. This does imply,
+ -- however, that it is not possible to use a partial iterator to specify
+ -- an empty sequence of items.
+
+ if Start = No_Element then
+ raise Constraint_Error with
+ "Start position for iterator equals No_Element";
+ end if;
+
+ if Start.Container /= Container'Unrestricted_Access then
+ raise Program_Error with
+ "Start cursor of Iterate designates wrong map";
+ end if;
+
+ pragma Assert (Vet (Container.Tree, Start.Node),
+ "Start cursor of Iterate is bad");
+
+ -- The value of the Node component influences the behavior of the First
+ -- and Last selector functions of the iterator object. When the Node
+ -- component is non-null (as is the case here), it means that this
+ -- is a partial iteration, over a subset of the complete sequence of
+ -- items. The iterator object was constructed with a start expression,
+ -- indicating the position from which the iteration begins. Note that
+ -- the start position has the same value irrespective of whether this
+ -- is a forward or reverse iteration.
+
+ return Iterator'(Container'Unrestricted_Access, Node => Start.Node);
end Iterate;
---------
@@ -916,11 +968,25 @@
end Last;
function Last (Object : Iterator) return Cursor is
- M : constant Map_Access := Object.Container;
- N : constant Node_Access := M.Tree.Last;
begin
- return (if N = null then No_Element
- else Cursor'(Object.Container.all'Unchecked_Access, N));
+ -- The value of the iterator object's Node component influences the
+ -- behavior of the Last (and First) selector function.
+
+ -- When the Node component is null, this means the iterator object was
+ -- constructed without a start expression, in which case the (reverse)
+ -- iteration starts from the (logical) beginning of the entire sequence
+ -- (corresponding to Container.Last, for a reverse iterator).
+
+ -- Otherwise, this is iteration over a partial sequence of items. When
+ -- the Node component is non-null, the iterator object was constructed
+ -- with a start expression, that specifies the position from which the
+ -- (reverse) partial iteration begins.
+
+ if Object.Node = null then
+ return Object.Container.Last;
+ else
+ return Cursor'(Object.Container, Object.Node);
+ end if;
end Last;
------------------
@@ -1017,8 +1083,16 @@
Position : Cursor) return Cursor
is
begin
- return (if Position.Node = null then No_Element
- else (Object.Container, Tree_Operations.Next (Position.Node)));
+ if Position.Container = null then
+ return No_Element;
+ end if;
+
+ if Position.Container /= Object.Container then
+ raise Program_Error with
+ "Position cursor of Next designates wrong map";
+ end if;
+
+ return Next (Position);
end Next;
------------
@@ -1065,9 +1139,16 @@
Position : Cursor) return Cursor
is
begin
- return
- (if Position.Node = null then No_Element
- else (Object.Container, Tree_Operations.Previous (Position.Node)));
+ if Position.Container = null then
+ return No_Element;
+ end if;
+
+ if Position.Container /= Object.Container then
+ raise Program_Error with
+ "Position cursor of Previous designates wrong map";
+ end if;
+
+ return Previous (Position);
end Previous;
-------------------
@@ -1490,4 +1571,5 @@
begin
raise Program_Error with "attempt to stream reference";
end Write;
+
end Ada.Containers.Indefinite_Ordered_Maps;
===================================================================
@@ -201,14 +201,18 @@
(Container : Map;
Process : not null access procedure (Position : Cursor));
+ -- The map container supports iteration in both the forward and reverse
+ -- directions, hence these constructor functions return an object that
+ -- supports the Reversible_Iterator interface.
+
function Iterate
(Container : Map)
- return Map_Iterator_Interfaces.Forward_Iterator'class;
+ return Map_Iterator_Interfaces.Reversible_Iterator'Class;
function Iterate
(Container : Map;
Start : Cursor)
- return Map_Iterator_Interfaces.Reversible_Iterator'class;
+ return Map_Iterator_Interfaces.Reversible_Iterator'Class;
private