4.1.15. GNATCOLL.Refcount.Weakref

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;