File : adagio-buffered_stream.adb


with Ada.Unchecked_deallocation;

package body Adagio.Buffered_stream is

   procedure Initialize (this: in out Controlled_buffer_type) is
   begin
      this.Data:= new Buffer_type (1 .. this.Size);
   end Initialize;

   procedure Finalize(this: in out Controlled_buffer_type) is
      Procedure Delete is new Unchecked_deallocation
        (Buffer_type, Buffer_type_access);
   begin
      Delete(this.Data);
   end Finalize;

   -- Refill

   procedure Refill(BStream: in out Buffered_stream) is
   begin
      Read(BStream.Source.all, BStream.Buffer.Data.all, BStream.Last);
      BStream.Pos:= 1;
   end Refill;

   -- Overriden primitives:

   procedure Read(
      Stream : in out Buffered_stream;
      Item   : out Stream_Element_Array;
      Last   : out Stream_Element_Offset) is
      Remaining: Stream_element_count:= Item'length;
      Available: Stream_element_count;
   begin
      -- Get as many data as desired

      while Remaining > 0 loop
         Available:= Stream.Last - Stream.Pos + 1;
         if Available = 0 then
            Refill(Stream);
            Available:= Stream.Last - Stream.Pos + 1;
         elsif Available < 0 then
            Raise Program_error;
         end if;
         if Available >= Remaining then
            -- Enough in buffer:

            Item(Item'first..Item'first + Remaining - 1):=
               Stream.Buffer.Data(Stream.Pos..Stream.Pos + Remaining - 1);
            Stream.Pos:= Stream.Pos + Remaining;
            Remaining:= 0;
         else
            -- Not enough:

            Item(Item'first..Item'first + Available - 1):=
               Stream.Buffer.Data(Stream.Pos..Stream.Pos + Available - 1);
            Stream.Pos:= Stream.Pos + Available;
            Remaining:= Remaining - Available;
         end if;
      end loop;
      Last:= Item'last; 
      -- Note: never last will be less than 'last.

   end Read;

   -- Only reading is implemented. 

   -- Thus, any call to this raises Unimplemented_error.

        procedure Write(
      Stream : in out Buffered_stream;
      Item   : in Stream_Element_Array) is
   begin
      raise Unimplemented;
   end Write;

   -- Creation. It links a new buffered stream with any other stream:

   procedure Get_buffered_stream
     (BStream: in out Buffered_stream; 
      Stream:  Stream_access) is
   begin
      if Stream = null then
         raise Constraint_error;
      end if;
      BStream.Source:= Stream;
      BStream.Last:= BStream.Buffer.Data.all'first - 1;
      BStream.Pos:= Bstream.Buffer.Data.all'first;
   end Get_buffered_stream;

   -- Says if the internal buffer is depleted. Doesn't implies that the

   -- source stream is depleted. Thus, it can occur multiple times

   -- before the end of stream of the source.

   -- To check end of data, a reader MUST check both end of source and

   -- end of buffer.

   function End_of_buffer(BStream: in Buffered_stream) return boolean is
   begin
      return BStream.Pos > BStream.Last;
   end End_of_buffer;

end Adagio.Buffered_stream;