package GNATCOLL.Refcount.Weakref is
pragma Obsolescent (Weakref, "Use GNATCOLL.Refcount.Shared_Pointers");
type Weak_Refcounted
is abstract new GNATCOLL.Refcount.Refcounted with private;
-- A special refcounted type, which can manipulate weak references
overriding procedure Free (Self : in out Weak_Refcounted);
-- If you need to override this procedure in your own code, you need to
-- make sure you correctly call this inherited procedure.
type Proxy is new GNATCOLL.Refcount.Refcounted with record
Proxied : Refcounted_Access;
end record;
package Proxy_Pointers is new Smart_Pointers (Proxy);
-- An internal, implementation type.
--
-- A weak ref acts as a smart pointed with two level of indirection:
-- type My_Type is new GNATCOLL.Refcount.Weakref.Refcounted with ...;
-- package P is new Weakref_Pointers (My_Type);
-- R : P.Ref;
-- WR : P.Weak_Ref;
-- R now takes care of the reference counting for R.Data.
-- R.Data is an access to My_Type, freed automatically.
--
-- WR now takes care of the reference counting for a Proxy, whose Proxied
-- is set to R.Data. This does not hold a reference to R.Data. However,
-- R.Data holds a reference to the proxy.
-- As a result, the proxy is never freed while R.Data exists. But the
-- latter can be destroyed even when the proxy exists.
generic
type Encapsulated is abstract new Weak_Refcounted with private;
package Weakref_Pointers is
package Pointers is new Smart_Pointers (Encapsulated);
subtype Encapsulated_Access is Pointers.Encapsulated_Access;
subtype Ref is Pointers.Ref;
Null_Ref : constant Ref := Pointers.Null_Ref;
procedure Set (Self : in out Ref; Data : Encapsulated'Class)
renames Pointers.Set;
procedure Set (Self : in out Ref; Data : access Encapsulated'Class)
renames Pointers.Set;
function Get (P : Ref) return Encapsulated_Access
renames Pointers.Get;
function "=" (P1, P2 : Ref) return Boolean
renames Pointers."=";
function "=" (P1, P2 : Pointers.Encapsulated_Access) return Boolean
renames Pointers."=";
-- The manipulation of the smart pointers
subtype Weak_Ref is Proxy_Pointers.Ref;
Null_Weak_Ref : constant Weak_Ref := Weak_Ref (Proxy_Pointers.Null_Ref);
function "=" (P1, P2 : Weak_Ref) return Boolean
renames Proxy_Pointers."=";
function Get_Weak_Ref (Self : Ref'Class) return Weak_Ref;
-- Return a weak reference to Self.
-- It does not hold a reference to Self, which means that Self could be
-- destroyed while the weak reference exists. However, this will not
-- result
-- in a Storage_Error when you access the reference.
function Was_Freed (Self : Weak_Ref'Class) return Boolean;
-- True if the weakly referenced element was freed (thus Get would
-- return Null_Ref). It is more efficient to use this function than
-- compare the result of Get with Null_Ref, since the latter will need
-- to play with refcounting.
function Get (Self : Weak_Ref'Class) return Ref;
procedure Get (Self : Weak_Ref'Class; R : out Ref'Class);
-- Return the weakly referenced object. This will return Null_Ref
-- if the object has already been destroyed.
-- The procedure version can be used if you have subclassed Ref.
-- The code should look like:
--
-- -- Create the smart pointer
-- Tmp : Refcounted_Access := new My_Refcounted_Type;
-- R : Ref := Allocate (Tmp); -- Hold a ref to Tmp
--
-- WRef := Get_Weak_Ref (R); -- Does not hold a ref to Tmp
--
-- R := Null_Ref; -- Releases ref to Tmp, and free Tmp
-- we now have Get (WRef) = null
--
-- In the case of a multitasking application, you must write your code
-- so that the referenced type is not freed while you are using it. For
-- instance:
-- declare
-- R : constant Ref := Get (WRef); -- hold a ref to Tmp
-- begin
-- if R /= Null_Ref then
-- ... manipulate R
-- Tmp cannot be freed while in the declare block, since we
-- own a reference to it
-- end if;
-- end;
end Weakref_Pointers;
end GNATCOLL.Refcount.Weakref;