comp.lang.ada
 help / color / mirror / Atom feed
From: "Matthew Heaney" <mheaney@on2.com>
Subject: Re: Impossible problem? A protected buffer to queue objects of a class-wide type
Date: 13 Apr 2007 10:02:57 -0700
Date: 2007-04-13T10:02:57-07:00	[thread overview]
Message-ID: <1176483777.264139.239360@p77g2000hsh.googlegroups.com> (raw)
In-Reply-To: <461cc46d$1_1@glkas0286.greenlnk.net>

On Apr 11, 6:34 am, "Phil Slater" <phil.sla...@baesystems.com> wrote:
> I've hit a brick wall. Every strategy I try doesn't work.

Won't the code below work?


> I need to write a generic package that exports a protected queue type that
> will act as a buffer for objects of a class-wide type.

That's fine.  You can declare the generic formal type as indefinite,
to make the package more general.

Note that I have used an Ada05 feature, extended return statement, to
return the class-wide object as the result of a function.  Is Ada05 is
not an option for you let me know and we'll figure something else out.


> My strategy is that
> when objects join the queue they are copied onto the heap,

Yes, that's what the solution below does.


> and an
> access-to-class-wide value is put onto the queue (could be array-based or
> linked-list-based - I don't mind).

I have created an internal buffer, implemented using the doubly-linked
list standard container, instantiated with an access type as the
generic actual.


> To retrieve an item from the queue, an
> access-to-class-wide value is removed from the queue, the heap object it
> designates is copied onto the stack, the heap object is deallocated, then
> the copy is returned.

Yes, the example below does that.


> The crux of the problem goes like this:
>
> (a) for the client code to retrieve an item, it needs to call a function; it
> can't be done through a procedure or entry "out" parameter since I can't
> declare an uninitialised variable of the class-wide type to pass as an
> actual parameter. So the client code needs to do something like this:
>     declare
>         Next_In_Line : Item'class := My_Buffer.Dequeue;  -- My_Buffer is the
> protected queue

The problem you're having is mixing layers of abstraction.  The queue
type below does indeed have a Deque function, and there is a
proctected object, but the protected object itself is an
implementation detail of the queue abstract data type.



> (b) To support this call, Dequeue must be written as a function. As such, it
> cannot change the protected queue. What I need is the "entry" functionality,
> since I want the Dequeue to wait if the queue is empty, and I want the item
> to be removed from the queue as well as retrieved.

Yes, you can do that, but you need two separate steps: the first step
is to use an entry (with a barrier) to remove the front item from the
queue's internal buffer (that's the protected object part), and then
return the value you removed from the internal buffer to the caller,
via a function (that's the abstract data type part).

In the example below I have used an extended return, since the return
type is indefinite.


> I cannot see a way through this problem, and am astounded that a language of
> this calibre seems to have rules that conspire together to make it appear
> impossible. What have I missed?

Use the Source, Luke!

--STX
private with Ada.Containers.Doubly_Linked_Lists;

generic
   type ET (<>) is private;

package Queues is

   type QT is limited private;

   function Deque (Q : not null access QT) return ET;

   procedure Enque (Q : in out QT; E : ET);

private

   type ET_Access is access ET;

   use Ada.Containers;
   package ET_Lists is new Doubly_Linked_Lists (ET_Access);

   protected type BT is
      entry Get (Obj : out ET_Access);
      procedure Put (Obj : ET_Access);
   private
      L : ET_Lists.List;
   end BT;

   type QT is limited record
     B : BT;
   end record;

end Queues;


with Ada.Unchecked_Deallocation;

package body Queues is

   procedure Free is new Ada.Unchecked_Deallocation (ET, ET_Access);

   protected body BT is

      entry Get (Obj : out ET_Access) when not L.Is_Empty is
      begin
         Obj := L.First_Element;
         L.Delete_First;
      end;

      procedure Put (Obj : ET_Access) is
      begin
         L.Append (Obj);
      end;

   end BT;

   function Deque (Q : not null access QT) return ET is
      Obj : ET_Access;

   begin
      Q.B.Get (Obj);

      return E : ET := Obj.all do
        Free (Obj);
      end return;
   end Deque;


   procedure Enque (Q : in out QT; E : ET) is
   begin
      Q.B.Put (ET_Access'(new ET'(E)));
   end;


end Queues;


Regards,
Matt




  parent reply	other threads:[~2007-04-13 17:02 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-04-11 11:34 Impossible problem? A protected buffer to queue objects of a class-wide type Phil Slater
2007-04-11 12:25 ` Rob Norris
2007-04-11 13:02   ` Phil Slater
2007-04-12  8:36     ` Stephen Leake
2007-04-11 13:14 ` Dmitry A. Kazakov
2007-04-11 14:01 ` Jean-Pierre Rosen
2007-04-11 17:18 ` tmoran
2007-04-13 17:02 ` Matthew Heaney [this message]
2007-04-13 17:26   ` Matthew Heaney
2007-04-13 17:36   ` Ed Falis
replies disabled

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