comp.lang.ada
 help / color / mirror / Atom feed
* Ada.Streams.Read Length Paramenter is not IN?
@ 2001-08-07  9:02 Lutz Donnerhacke
  2001-08-07 18:39 ` Ted Dennison
  2001-08-07 19:48 ` tmoran
  0 siblings, 2 replies; 5+ messages in thread
From: Lutz Donnerhacke @ 2001-08-07  9:02 UTC (permalink / raw)


Writing a very small 'Filedescriptor_Stream' package (to eliminate the libc,
dealing with sockets, and---of course---learning), I run into semantic
problems with 'Ada.Streams.Read':

procedure Read(
  Stream : in out XXX_Stream_Type;
  Item   :    out Stream_Element_Array;
  Last   :    out Stream_Element_Offset);

The RM says:
  The Read operation transfers Item'Length stream elements from the
  specified stream to fill the array Item. The index of the last stream
  element transferred is returned in Last. Last is less than Item'Last only
  if the end of the stream is reached.

I can not read an arbitary amount of data due to possible blocking or
confusing situation where the corresponding site has to close the transfer
in order to process the input. (Quite contrary to interactive)

I can not read each Storage_Element seperatly, due to massive system
performance decrease.

OTOH each T'Read or T'Input procedure exactly knows how many
Storage_Elements are needed to fullfill the request. Why is this information
not given to the Stream.Read procedure?

BTW: Do I understand the procedure semantics correctly, if I return Item and
     Last := Item'Last generally. But in the case of EOF returning Item
     larger than normally and set Item'Last to the last valid element.
     Would it be not simpler to have the following procedure?
       procedure Read(
         Stream : in out XXX_Stream_Type;
	 Data   :    out Stream_Element_Array;
	 Needed : in     Stream_Element_Offset;
	 EOT    :    out Boolean);

Please do not quote the source unless you really want to comment it.
\f
-------------------- filedescriptor_stream.ads --------------------
with Interfaces.C, Ada.Streams;

package Filedescriptor_Stream is
   type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class;   
   
   type Filedescriptor_Stream_Type is new Ada.Streams.Root_Stream_Type
     with private;
   
   function Stream(fd : Interfaces.C.int) return Stream_Access;
   
   Device_Error : exception;
   
   procedure Read(
     Stream : in out Filedescriptor_Stream_Type;
     Item   :    out Ada.Streams.Stream_Element_Array;
     Last   :    out Ada.Streams.Stream_Element_Offset);
      
   procedure Write(
     Stream : in out Filedescriptor_Stream_Type;
     Item   : in     Ada.Streams.Stream_Element_Array);
   
private
   type Filedescriptor_Stream_Type is new Ada.Streams.Root_Stream_Type
     with record fd : Interfaces.C.int; end record;
end Filedescriptor_Stream;
-------------------- filedescriptor_stream.ads --------------------
\f
-------------------- filedescriptor_stream.adb --------------------
with Interfaces.C, Ada.Streams;
use Interfaces.C, Ada.Streams;

package body Filedescriptor_Stream is
   function Stream(fd : int) return Stream_Access is
      res : Stream_Access := new Filedescriptor_Stream_Type;
   begin
      Filedescriptor_Stream_Type(res.all).fd := fd;
      return res;
   end Stream;
   
   function Read(Stream : in Filedescriptor_Stream_Type)
     return Stream_Element_Array;
   type void_p is access all Stream_Element;
   for void_p'Size use 32;
   

   function c_write(fd : int; buff : void_p; len : size_t) return int;
   function c_read(fd : int; buff : void_p; len : size_t) return int;
   pragma Import(C, c_write, "write");
   pragma Import(C, c_read, "read");
   
   function Read(Stream : in Filedescriptor_Stream_Type)
     return Stream_Element_Array is
      data : aliased Stream_Element_Array (0 .. 0);
   begin
      if 1 = c_read (Stream.fd, data(0)'Unrestricted_Access, 1) then
         return data; --  & Read (Stream);
      else
         return data;
      end if;      
   end Read;
   
   procedure Read(
     Stream : in out Filedescriptor_Stream_Type;
     Item   :    out Stream_Element_Array;
     Last   :    out Stream_Element_Offset) is
   begin
      Item := Read (Stream);
      Last := Item'Last;
   end Read;
      
   procedure Write(
     Stream : in out Filedescriptor_Stream_Type;
     Item   : in     Stream_Element_Array) is
      pos : Stream_Element_Offset := Item'First;
      len : size_t := Item'Length;
      res : int;
   begin
      while len > 0 loop
         res := c_write(Stream.fd, Item(pos)'Unrestricted_Access, len);
         if res = -1 then raise Device_Error; end if;
         len := len - size_t(res);
         pos := pos + Stream_Element_Offset(res);
      end loop;
   end Write;
   
end Filedescriptor_Stream;
-------------------- filedescriptor_stream.adb --------------------
\f
----------------------- test_fd_stream.adb ------------------------
with Filedescriptor_Stream;
use Filedescriptor_Stream;

procedure Test_Fd_Stream is
   sout : Stream_Access := Stream (1);
begin
   String'Write(sout, "a =" & Integer'Image(a) & ASCII.LF);
   String'Write(sout, "b =" & Integer'Image(b) & ASCII.LF);
   String'Write(sout, "c =" & Integer'Image(c) & ASCII.LF);
end Test_Fd_Stream;
----------------------- test_fd_stream.adb ------------------------



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Ada.Streams.Read Length Paramenter is not IN?
  2001-08-07  9:02 Ada.Streams.Read Length Paramenter is not IN? Lutz Donnerhacke
@ 2001-08-07 18:39 ` Ted Dennison
  2001-08-07 20:18   ` Lutz Donnerhacke
  2001-08-07 19:48 ` tmoran
  1 sibling, 1 reply; 5+ messages in thread
From: Ted Dennison @ 2001-08-07 18:39 UTC (permalink / raw)


In article <slrn9mvbej.hs.lutz@taranis.iks-jena.de>, Lutz Donnerhacke says...
>procedure Read(
>  Stream : in out XXX_Stream_Type;
>  Item   :    out Stream_Element_Array;
>  Last   :    out Stream_Element_Offset);
..
>OTOH each T'Read or T'Input procedure exactly knows how many
>Storage_Elements are needed to fullfill the request. Why is this information
>not given to the Stream.Read procedure?

It is. That information is Item'length. One of the nifty things about Ada is
that we don't need a separate parameter to specify how large a passed-in buffer
is.

You may protest that there's no guarantee that they won't give you a bigger
buffer than they need, but the guarantee is implied. Think about it. If you gave
back more data than they needed, what could they do with the extra? How would
they get it back in the stream so it could go to the rightful owner? There's no
way. So they will call you with the exact sized buffer for the data they want to
read.

>BTW: Do I understand the procedure semantics correctly, if I return Item and
>     Last := Item'Last generally. But in the case of EOF returning Item
>     larger than normally and set Item'Last to the last valid element.
>     Would it be not simpler to have the following procedure?

The data returned couldn't be *larger*, (the buffer is only Item'Last long). It
could be smaller due to EOF, in which case I'd expect either you to return Last
< Item'Last, or you to raise an exception. I think Streams.Stream_IO raises
END_ERROR.

---
T.E.D.    homepage   - http://www.telepath.com/dennison/Ted/TED.html
          home email - mailto:dennison@telepath.com



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Ada.Streams.Read Length Paramenter is not IN?
  2001-08-07  9:02 Ada.Streams.Read Length Paramenter is not IN? Lutz Donnerhacke
  2001-08-07 18:39 ` Ted Dennison
@ 2001-08-07 19:48 ` tmoran
  2001-08-07 20:21   ` Lutz Donnerhacke
  1 sibling, 1 reply; 5+ messages in thread
From: tmoran @ 2001-08-07 19:48 UTC (permalink / raw)


> Ada.Streams.Read Length Parameter is not IN?
  Because Item'length tells how much data is wanted.  Last tells you,
as output, how much you actually got.  If you have a situation where
Last < Item'last does *not* mean EOF, but just means "that's all for
now", then you can use a loop to keep trying until it's all there.
  Next : Stream_Element_Offset := Item'first;
 ...
  while Next <= Item'last loop
    Read(F, Item(Next .. Item'last), Last);
    Next := Last+1;
  end loop;

> OTOH each T'Read or T'Input procedure exactly knows how many
> Storage_Elements are needed to fulfill the request. Why is this information
> not given to the Stream.Read procedure?
   It is.  Any time you pass as array as a parameter you implicitly
are also passing its 'first, 'last, 'length.

>  procedure Read(
>    Stream : in out Filedescriptor_Stream_Type;
>    Item   :    out Stream_Element_Array;
>    Last   :    out Stream_Element_Offset) is
>  begin
>     Item := Read (Stream);
>     Last := Item'Last;
>  end Read;
  This is unlikely to work.  Since your Read (Stream) always returns
an array of one element, assigning that to Item will only work if
Item is an array of one element.  The length of a particular
Stream_Element_Array is not dynamic.  That's why Last is there -
so you can see the length of the actual useful data portion of Item.



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Ada.Streams.Read Length Paramenter is not IN?
  2001-08-07 18:39 ` Ted Dennison
@ 2001-08-07 20:18   ` Lutz Donnerhacke
  0 siblings, 0 replies; 5+ messages in thread
From: Lutz Donnerhacke @ 2001-08-07 20:18 UTC (permalink / raw)


* Ted Dennison wrote:
>In article <slrn9mvbej.hs.lutz@taranis.iks-jena.de>, Lutz Donnerhacke says...
>>OTOH each T'Read or T'Input procedure exactly knows how many
>>Storage_Elements are needed to fullfill the request. Why is this
>>information not given to the Stream.Read procedure?
>
>It is. That information is Item'length.

Yep. I got this idea a few hours ago. But now it's too late to cancel my
proof of stupity.

>One of the nifty things about Ada is that we don't need a separate
>parameter to specify how large a passed-in buffer is.

I was confused by functions returning arrays. I didn't get at once, that an
OUT parameter implicitly provides the discriminants as IN parameters.

>You may protest that there's no guarantee that they won't give you a
>bigger buffer than they need, but the guarantee is implied.

Don't worry. I got it.




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Ada.Streams.Read Length Paramenter is not IN?
  2001-08-07 19:48 ` tmoran
@ 2001-08-07 20:21   ` Lutz Donnerhacke
  0 siblings, 0 replies; 5+ messages in thread
From: Lutz Donnerhacke @ 2001-08-07 20:21 UTC (permalink / raw)


* tmoran@acm.org wrote:
>>  procedure Read(
>>    Stream : in out Filedescriptor_Stream_Type;
>>    Item   :    out Stream_Element_Array;
>>    Last   :    out Stream_Element_Offset) is
>>  begin
>>     Item := Read (Stream);
>>     Last := Item'Last;
>>  end Read;
>
>his is unlikely to work.

I got a hard to find CONTRAINT_ERROR. But debugging it I learned the
direction of discriminats of unconstraint out parameters.

>dynamic.  That's why Last is there - so you can see the length of the
>actual useful data portion of Item.

Very sensefull indeed. Thanx to all.



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2001-08-07 20:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-08-07  9:02 Ada.Streams.Read Length Paramenter is not IN? Lutz Donnerhacke
2001-08-07 18:39 ` Ted Dennison
2001-08-07 20:18   ` Lutz Donnerhacke
2001-08-07 19:48 ` tmoran
2001-08-07 20:21   ` Lutz Donnerhacke

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox