13.13.1 The Streams Subsystem
Static Semantics
The abstract type Root_Stream_Type is the root type
of the class of stream types. The types in this class represent different
kinds of streams. A new stream type is defined by extending the root
type (or some other stream type), overriding the Read and Write operations,
and optionally defining additional primitive subprograms, according to
the requirements of the particular kind of stream. The predefined stream-oriented
attributes like T'Read and T'Write make dispatching calls on the Read
and Write procedures of the Root_Stream_Type. (User-defined T'Read and
T'Write attributes can also make such calls, or can call the Read and
Write attributes of other types.)
{
AI12-0293-1}
The library package Ada.Streams has the following declaration:
{
AI12-0241-1}
package Ada.Streams
with Pure, Nonblocking => False
is
{
AI95-00161-01}
type Root_Stream_Type
is abstract tagged limited private
with Preelaborable_Initialization;
{
8652/0044}
{
AI95-00181-01}
type Stream_Element
is mod implementation-defined;
type Stream_Element_Offset
is range implementation-defined;
subtype Stream_Element_Count
is
Stream_Element_Offset
range 0..Stream_Element_Offset'Last;
type Stream_Element_Array
is
array(Stream_Element_Offset
range <>)
of aliased Stream_Element;
procedure Read(
Stream :
in out Root_Stream_Type;
Item :
out Stream_Element_Array;
Last :
out Stream_Element_Offset)
is abstract;
procedure Write(
Stream :
in out Root_Stream_Type;
Item :
in Stream_Element_Array)
is abstract;
private
... -- not specified by the language
end Ada.Streams;
Reason: {
AI12-0241-1}
This package must allow blocking (Nonblocking => False) for compatibility.
The purpose of this package is to provide a template for overriding user-defined
routines; and such routines can only allow blocking if the root type
does so. Users can still declare their overridding routines nonblocking
if they wish.
{
AI95-00227-01}
The Read operation transfers stream elements from the specified stream
to fill the array Item. Elements are transferred until Item'Length elements
have been transferred, or until the end of the stream is reached. If
any elements are transferred, the index of the last stream element transferred
is returned in Last. Otherwise, Item'First - 1 is returned in Last. Last
is less than Item'Last only if the end of the stream is reached.
The Write operation appends Item to the specified
stream.
Discussion: {
AI95-00114-01}
The index subtype of Stream_Element_Array is Stream_Element_Offset because
we wish to allow maximum flexibility. Most Stream_Element_Arrays will
probably have a lower bound of 0 or 1, but other lower bounds, including
negative ones, make sense in some situations.
{
AI95-00114-01}
{
AI05-0005-1}
Note that there are some language-defined subprograms that fill part
of a Stream_Element_Array, and return the index of the last element filled
as a Stream_Element_Offset. The Read procedures declared here, Streams.Stream_IO
(see
A.12.1), and System.RPC (see
E.5)
behave in this manner. These will raise Constraint_Error if the resulting
Last value is not in Stream_Element_Offset. This implies that the Stream_Element_Array
passed to these subprograms should not have a lower bound of Stream_Element_Offset'First,
because then a read of 0 elements would always raise Constraint_Error.
A better choice of lower bound is 0 or 1.
{
AI12-0293-1}
Three additional packages provide stream implementations that do not
make use of any file operations. These packages provide the same operations,
with Streams.Storage providing an abstract interface, and two child packages
providing implementations of that interface. The difference is that for
Streams.Storage.Bounded, the maximum storage is bounded.
{
AI12-0293-1}
The library package Ada.Streams.Storage has the following declaration:
package Ada.Streams.Storage
with Pure, Nonblocking
is
type Storage_Stream_Type
is abstract new Root_Stream_Type
with private;
function Element_Count (Stream : Storage_Stream_Type)
return Stream_Element_Count
is abstract;
procedure Clear (Stream :
in out Storage_Stream_Type)
is abstract;
private
... -- not specified by the language
end Ada.Streams.Storage;
{
AI12-0293-1}
The library package Ada.Streams.Storage.Unbounded has the following declaration:
package Ada.Streams.Storage.Unbounded
with Prelaborated, Nonblocking, Global =>
in out synchronized is
type Stream_Type
is new Storage_Stream_Type
with private
with Default_Initial_Condition =>
Element_Count (Stream_Type) = 0;
overriding
procedure Read (
Stream :
in out Stream_Type;
Item :
out Stream_Element_Array;
Last :
out Stream_Element_Offset)
with Post =>
(
declare
Num_Read :
constant Stream_Element_Count :=
Stream_Element_Count'Min
(Element_Count(Stream)'Old, Item'Length);
begin
Last = Num_Read + Item'First - 1
and
Element_Count (Stream) =
Element_Count (Stream)'Old - Num_Read);
Discussion: Num_Read is the number of
elements read; this is the minimum of Item'Length and the number of available
elements. Last then is determined by that, and the Element_Count decreases
by the number of elements read.
overriding
procedure Write (
Stream :
in out Stream_Type;
Item :
in Stream_Element_Array)
with Post =>
Element_Count (Stream) =
Element_Count (Stream)'Old + Item'Length;
overriding
function Element_Count (Stream : Stream_Type)
return Stream_Element_Count;
overriding
procedure Clear (Stream :
in out Stream_Type)
with Post => Element_Count (Stream) = 0;
private
... -- not specified by the language
end Ada.Streams.Storage.Unbounded;
{
AI12-0293-1}
The library package Ada.Streams.Storage.Bounded has the following declaration:
package Ada.Streams.Storage.Bounded
with Pure, Nonblocking
is
type Stream_Type (Max_Elements : Stream_Element_Count)
is new Storage_Stream_Type
with private
with Default_Initial_Condition =>
Element_Count (Stream_Type) = 0;
overriding
procedure Read (
Stream :
in out Stream_Type;
Item :
out Stream_Element_Array;
Last :
out Stream_Element_Offset)
with Post =>
(
declare
Num_Read :
constant Stream_Element_Count :=
Stream_Element_Count'Min
(Element_Count(Stream)'Old, Item'Length);
begin
Last = Num_Read + Item'First - 1
and
Element_Count (Stream) =
Element_Count (Stream)'Old - Num_Read);
overriding
procedure Write (
Stream :
in out Stream_Type;
Item :
in Stream_Element_Array)
with Pre =>
Element_Count (Stream) + Item'Length <= Stream.Max_Elements
or else (
raise Constraint_Error),
Post =>
Element_Count (Stream) =
Element_Count (Stream)'Old + Item'Length;
overriding
function Element_Count (Stream : Stream_Type)
return Stream_Element_Count
with Post => Element_Count'Result <= Stream.Max_Elements;
overriding
procedure Clear (Stream :
in out Stream_Type)
with Post => Element_Count (Stream) = 0;
private
... -- not specified by the language
end Ada.Streams.Storage.Bounded;
{
AI12-0293-1}
The Element_Count functions return the number of stream elements that
are available for reading from the given stream.
{
AI12-0293-1}
The Read and Write procedures behave as described for package Ada.Streams
above. Stream elements are read in FIFO (first-in, first-out) order;
stream elements are available for reading immediately after they are
written.
{
AI12-0293-1}
The Clear procedures remove any available stream elements from the given
stream.
Implementation Permissions
{
8652/0044}
{
AI95-00181-01}
{
AI12-0444-1}
If Stream_Element'Size is not a multiple of System.Storage_Unit, then
the components of Stream_Element_Array will not be aliased.
Ramification: {
AI95-00114-01}
If the Stream_Element'Size is less than the size of System.Storage_Unit,
then components of Stream_Element_Array need not be aliased. This is
necessary as the components of type Stream_Element size might not be
addressable on the target architecture.
Implementation Advice
{
AI12-0293-1}
Streams.Storage.Bounded.Stream_Type objects should be implemented without
implicit pointers or dynamic allocation.
Implementation Advice: Streams.Storage.Bounded.Stream_Type
objects should be implemented without implicit pointers or dynamic allocation.
Reason: The Streams.Storage.Bounded package
is provided in order to make available an alternative to the Streams.Storage.Unbounded
package which gives more predictable memory usage.
NOTE 2 {
AI95-00227-01}
If the end of stream has been reached, and Item'First is Stream_Element_Offset'First,
Read will raise Constraint_Error.
Ramification: Thus, Stream_Element_Arrays
should start at 0 or 1, not Stream_Element_Offset'First.
Extensions to Ada 95
{
AI95-00161-01}
Amendment Correction: Added
pragma
Preelaborable_Initialization to type Root_Stream_Type.
Wording Changes from Ada 95
{
AI95-00227-01}
Fixed the wording for Read to properly define the result in Last when
no stream elements are transfered.
Extensions to Ada 2012
{
AI12-0293-1}
Package Ada.Streams.Storage and its children are
new.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe