generic
    type Object_Type is limited private;
    pragma Must_Be_Constrained (Object_Type);

    -- The user may supply algorithms to be executed whenever
    -- an Object_Type variable is allocated, opened, or closed:

    with procedure On_Allocate (Object : in out Object_Type) is <>;
    with procedure On_Open (Object : in out Object_Type) is <>;
    with procedure On_Close (Object : in out Object_Type) is <>;

    -- These procedures are called strictly sequentially,
    -- by a synchronizing task inside the pool manager.
    -- They must NOT call the operations below:

package Managed_Pool_Generic is

    type Object_Id is private;
    Null_Object_Id : constant Object_Id;

    procedure Open (Object : out Object_Id);

    procedure Close (Object : Object_Id);

    function Is_Open (Object : Object_Id) return Boolean;

    type Hidden_Type is limited private; -- secret stuff

    type Object_Record is
        record
            Hidden : Hidden_Type;
            Object : Object_Type;
        end record;

    type Object_Pointer is access Object_Record;

    function Value (Object : Object_Id) return Object_Pointer;

    Not_Open : exception; -- may be raised by Value

    type Iterator is limited private;
    -- Used to scan all open (or all closed) objects.
    procedure Init_Open (Iter : in out Iterator);   -- scan open objects
    procedure Init_Closed (Iter : in out Iterator); -- scan closed objects
    procedure Next (Iter : in out Iterator);
    function Value (Iter : Iterator) return Object_Pointer;
    function Done (Iter : Iterator) return Boolean;

    type Unique_Id is new Long_Integer range 0 .. Long_Integer'Last;
    Null_Unique_Id : constant Unique_Id := Unique_Id'First;

    function Unique (Object : Object_Id) return Unique_Id;
    -- Each object_id has an associated unique_id.
    -- Two object_ids are equal if and only their unique_ids are.
    -- An uninitialized Object_Id has the Null_Unique_Id.

private

    type Object_Id is
        record
            Unique : Unique_Id := Null_Unique_Id;
            Value : Object_Pointer := null;
        end record;

    Null_Object_Id : constant Object_Id := (Null_Unique_Id, null);

    type Hidden_Type is
        record
            Unique : Unique_Id := Null_Unique_Id;
            Next : Object_Pointer := null;
        end record;

    type Iterator is new Object_Pointer;

end Managed_Pool_Generic;