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
next prev 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