A.18.18 The Generic Package Containers.Indefinite_Holders
1/3
{
AI05-0069-1}
The language-defined generic package Containers.Indefinite_Holders
provides a private type Holder and a set of operations for that type.
A holder container holds a single element of an indefinite type.
2/3
{
AI05-0069-1}
A holder container allows the declaration of an
object that can be used like an uninitialized variable or component of
an indefinite type.
3/3
{
AI05-0069-1}
A holder container may be empty. An empty
holder does not contain an element.
Static Semantics
4/3
{
AI05-0069-1}
The generic library package Containers.Indefinite_Holders
has the following declaration:
5/3
{
AI05-0069-1}
{
AI05-0084-1}
generic
type Element_Type (<>) is private;
with function "=" (Left, Right : Element_Type) return Boolean is <>;
package Ada.Containers.Indefinite_Holders is
pragma Preelaborate(Indefinite_Holders);
pragma Remote_Types(Indefinite_Holders);
6/3
type Holder is tagged private;
pragma Preelaborable_Initialization (Holder);
7/3
Empty_Holder : constant Holder;
8/3
function "=" (Left, Right : Holder) return Boolean;
9/3
function To_Holder (New_Item : Element_Type) return Holder;
10/3
function Is_Empty (Container : Holder) return Boolean;
11/3
procedure Clear (Container : in out Holder);
12/3
function Element (Container : Holder) return Element_Type;
13/3
procedure Replace_Element (Container : in out Holder;
New_Item : in Element_Type);
14/3
procedure Query_Element
(Container : in Holder;
Process : not null access procedure (Element : in Element_Type));
15/3
{
AI05-0069-1}
{
AI05-0248-1}
procedure Update_Element
(Container : in out Holder;
Process : not null access procedure (Element : in out Element_Type));
16/3
{
AI05-0212-1}
type Constant_Reference_Type
(Element : not null access constant Element_Type) is private
with Implicit_Dereference => Element;
17/3
{
AI05-0212-1}
type Reference_Type (Element : not null access Element_Type) is private
with Implicit_Dereference => Element;
18/3
{
AI05-0212-1}
function Constant_Reference (Container : aliased in Holder)
return Constant_Reference_Type;
19/3
{
AI05-0212-1}
function Reference (Container : aliased in out Holder)
return Reference_Type;
20/3
{
AI05-0001-1}
procedure Assign (Target : in out Holder; Source : in Holder);
21/3
{
AI05-0001-1}
function Copy (Source : Holder) return Holder;
22/3
procedure Move (Target : in out Holder; Source : in out Holder);
23/3
private
24/3
... -- not specified by the language
25/3
end Ada.Containers.Indefinite_Holders;
26/3
{
AI05-0069-1}
The actual function for the generic formal function
"=" on Element_Type values is expected to define a reflexive
and symmetric relationship and return the same result value each time
it is called with a particular pair of values. If it behaves in some
other manner, the function "=" on holder values returns an
unspecified value. The exact arguments and number of calls of this generic
formal function by the function "=" on holder values are unspecified.
26.a/3
Ramification: If
the actual function for "=" is not symmetric and consistent,
the result returned by any of the functions defined to use "="
cannot be predicted. The implementation is not required to protect against
"=" raising an exception, or returning random results, or any
other "bad" behavior. And it can call "=" in whatever
manner makes sense. But note that only the results of the function "="
is unspecified; other subprograms are not allowed to break if "="
is bad.
27/3
{
AI05-0069-1}
The type Holder is used to represent holder containers.
The type Holder needs finalization (see 7.6).
28/3
{
AI05-0069-1}
Empty_Holder represents an empty holder object.
If an object of type Holder is not otherwise initialized, it is initialized
to the same value as Empty_Holder.
29/3
{
AI05-0069-1}
{
AI05-0262-1}
[Some operations of this generic package have access-to-subprogram
parameters. To ensure such operations are well-defined, they guard against
certain actions by the designated subprogram. In particular, some operations
check for “tampering with the element” of a container because
they depend on the element of the container not being replaced.]
30/3
31/3
It clears the element contained
by H, that is, it calls the Clear procedure with H as a
parameter;
32/3
It replaces the element contained
by H, that is, it calls the Replace_Element procedure with H
as a parameter;
33/3
It calls the Move procedure
with H as a parameter;
34/3
It finalizes H.
34.a/3
Reason: Complete
replacement of an element can cause its memory to be deallocated while
another operation is holding onto a reference to it. That can't be allowed.
However, a simple modification of (part of) an element is not a problem,
so Update_Element does not cause a problem.
35/3
{
AI05-0265-1}
If tampering
with the element is prohibited for a particular holder object
H, Program_Error is propagated by any language-defined subprogram
that is defined to tamper with the element of H.
36/3
function "=" (Left, Right : Holder) return Boolean;
37/3
{
AI05-0069-1}
If Left and Right denote the same holder object,
then the function returns True. Otherwise, it compares the element contained
in Left to the element contained in Right using the generic formal equality
operator, returning the result of that operation. Any exception raised
during the evaluation of element equality is propagated.
37.a/3
Implementation Note:
This wording describes the canonical semantics. However, the order
and number of calls on the formal equality function is unspecified,
so an implementation need not call the equality function if the correct
answer can be determined without doing so.
38/3
function To_Holder (New_Item : Element_Type) return Holder;
39/3
{
AI05-0069-1}
Returns a non-empty holder containing an element
initialized to New_Item.
40/3
function Is_Empty (Container : Holder) return Boolean;
41/3
{
AI05-0069-1}
Returns True if the holder is empty, and False
if it contains an element.
42/3
procedure Clear (Container : in out Holder);
43/3
{
AI05-0069-1}
Removes the element from Container. Container is
empty after a successful Clear operation.
44/3
function Element (Container : Holder) return Element_Type;
45/3
{
AI05-0069-1}
If Container is empty, Constraint_Error is propagated.
Otherwise, returns the element stored in Container.
46/3
procedure Replace_Element (Container : in out Holder;
New_Item : in Element_Type);
47/3
{
AI05-0069-1}
Replace_Element assigns the value New_Item into
Container, replacing any preexisting content of Container. Container
is not empty after a successful call to Replace_Element.
48/3
procedure Query_Element
(Container : in Holder;
Process : not null access procedure (Element : in Element_Type));
49/3
{
AI05-0069-1}
{
AI05-0262-1}
{
AI05-0265-1}
If Container is empty, Constraint_Error is propagated.
Otherwise, Query_Element calls Process.all with the contained
element as the argument. Tampering with the element of Container is prohibited
during the execution of Process.all. Any exception raised by Process.all
is propagated.
49.a/3
Implementation Note:
The “tamper with the element” check is intended to prevent
the Element parameter of Process from being modified or deleted outside
of Process. The check prevents data loss (if Element_Type is passed by
copy) or erroneous execution (if Element_Type is an unconstrained type).
50/3
{
AI05-0069-1}
{
AI05-0248-1}
procedure Update_Element
(Container : in out Holder;
Process : not null access procedure (Element : in out Element_Type));
51/3
{
AI05-0069-1}
{
AI05-0262-1}
{
AI05-0265-1}
If Container is empty, Constraint_Error is propagated.
Otherwise, Update_Element calls Process.all with the contained
element as the argument. Tampering with the element of Container is prohibited
during the execution of Process.all. Any exception raised by Process.all
is propagated.
51.a/3
Implementation Note:
The Element parameter of Process.all may be constrained even
if Element_Type is unconstrained.
52/3
{
AI05-0212-1}
type Constant_Reference_Type
(Element : not null access constant Element_Type) is private
with Implicit_Dereference => Element;
53/3
{
AI05-0212-1}
type Reference_Type (Element : not null access Element_Type) is private
with Implicit_Dereference => Element;
54/3
{
AI05-0212-1}
The types Constant_Reference_Type and Reference_Type
need finalization.
55/3
{
AI05-0212-1}
The default initialization of an object of type
Constant_Reference_Type or Reference_Type propagates Program_Error.
55.a/3
Reason: It is expected
that Reference_Type (and Constant_Reference_Type) will be a controlled
type, for which finalization will have some action to terminate the tampering
check for the associated container. If the object is created by default,
however, there is no associated container. Since this is useless, and
supporting this case would take extra work, we define it to raise an
exception.
56/3
{
AI05-0212-1}
function Constant_Reference (Container : aliased in Holder)
return Constant_Reference_Type;
57/3
{
AI05-0212-1}
This function (combined with the Implicit_Dereference
aspect) provides a convenient way to gain read access to the contained
element of a holder container.
58/3
{
AI05-0212-1}
{
AI05-0262-1}
{
AI05-0265-1}
If Container is empty, Constraint_Error is propagated.
Otherwise, Constant_Reference returns an object whose discriminant is
an access value that designates the contained element. Tampering with
the elements of Container is prohibited while the object returned by
Constant_Reference exists and has not been finalized.
59/3
{
AI05-0212-1}
function Reference (Container : aliased in out Holder)
return Reference_Type;
60/3
{
AI05-0212-1}
This function (combined with the Implicit_Dereference
aspects) provides a convenient way to gain read and write access to the
contained element of a holder container.
61/3
{
AI05-0212-1}
{
AI05-0262-1}
{
AI05-0265-1}
If Container is empty, Constraint_Error is propagated.
Otherwise, Reference returns an object whose discriminant is an access
value that designates the contained element. Tampering with the elements
of Container is prohibited while the object returned by Reference exists
and has not been finalized.
62/3
procedure Assign (Target : in out Holder; Source : in Holder);
63/3
{
AI05-0001-1}
If Target denotes the same object as Source, the
operation has no effect. If Source is empty, Clear (Target) is called.
Otherwise, Replace_Element (Target, Element (Source)) is called.
63.a/3
Discussion: {
AI05-0005-1}
This routine exists for compatibility with the
other containers. For a holder, Assign(A, B) and A := B
behave identically.
64/3
function Copy (Source : Holder) return Holder;
65/3
{
AI05-0001-1}
If Source is empty, returns an empty holder; otherwise,
returns To_Holder (Element (Source)).
66/3
procedure Move (Target : in out Holder; Source : in out Holder);
67/3
{
AI05-0069-1}
{
AI05-0248-1}
If Target denotes the same object as Source, then
the operation has no effect. Otherwise, the element contained by Source
(if any) is removed from Source and inserted into Target, replacing any
preexisting content. Source is empty after a successful call to Move.
Bounded (Run-Time) Errors
68/3
{
AI05-0022-1}
{
AI05-0069-1}
{
AI05-0248-1}
{
AI05-0262-1}
It is a bounded error for the
actual function associated with a generic formal subprogram, when called
as part of an operation of this package, to tamper with the element of
any Holder parameter of the operation. Either Program_Error is raised,
or the operation works as defined on the value of the Holder either prior
to, or subsequent to, some or all of the modifications to the Holder.
69/3
{
AI05-0027-1}
{
AI05-0069-1}
It is a bounded error to call
any subprogram declared in the visible part of Containers.Indefinite_Holders
when the associated container has been finalized. If the operation takes
Container as an in out parameter, then it raises Constraint_Error
or Program_Error. Otherwise, the operation either proceeds as it would
for an empty container, or it raises Constraint_Error or Program_Error.
Erroneous Execution
70/3
{
AI05-0212-1}
Execution is erroneous if the holder associated
with the result of a call to Reference or Constant_Reference is finalized
before the result object returned by the call to Reference or Constant_Reference
is finalized.
70.a/3
Reason: {
AI05-0212-1}
Each object of Reference_Type and Constant_Reference_Type
probably contains some reference to the originating container. If that
container is prematurely finalized (which is only possible via Unchecked_Deallocation,
as accessibility checks prevent passing a container to Reference that
will not live as long as the result), the finalization of the object
of Reference_Type will try to access a non-existent object. This is a
normal case of a dangling pointer created by Unchecked_Deallocation;
we have to explicitly mention it here as the pointer in question is not
visible in the specification of the type. (This is the same reason we
have to say this for invalid cursors.)
Implementation Requirements
71/3
{
AI05-0069-1}
No storage associated with a holder object shall
be lost upon assignment or scope exit.
72/3
{
AI05-0069-1}
The execution of an assignment_statement
for a holder shall have the effect of copying the element (if any) from
the source holder object to the target holder object.
72.a/3
Implementation Note:
An assignment of a holder is a “deep” copy; that is the
elements are copied as well as the data structures. We say “effect
of” in order to allow the implementation to avoid copying elements
immediately if it wishes. For instance, an implementation that avoided
copying until one of the containers is modified would be allowed.
Implementation Advice
73/3
{
AI05-0069-1}
Move should not copy elements, and should minimize
copying of internal data structures.
73.a.1/3
Implementation Advice:
Containers.Indefinite_Holders.Move should
not copy elements, and should minimize copying of internal data structures.
73.a/3
Implementation Note:
Usually that can be accomplished simply by moving the pointer(s)
to the internal data structures from the Source holder to the Target
holder.
74/3
{
AI05-0069-1}
If an exception is propagated from a holder operation,
no storage should be lost, nor should the element be removed from a holder
unless specified by the operation.
74.a.1/3
Implementation Advice:
If an exception is propagated from a
holder operation, no storage should be lost, nor should the element be
removed from a holder unless specified by the operation.
74.a/3
Reason: This is
important so that programs can recover from errors. But we don't want
to require heroic efforts, so we just require documentation of cases
where this can't be accomplished.
Extensions to Ada 2005
74.b/3
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe