File: gnatcoll-refcount-weakref.ads

package info (click to toggle)
libgnatcoll 18-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 5,068 kB
  • sloc: ada: 40,393; python: 354; ansic: 310; makefile: 245; sh: 31
file content (146 lines) | stat: -rw-r--r-- 7,231 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
------------------------------------------------------------------------------
--                             G N A T C O L L                              --
--                                                                          --
--                     Copyright (C) 2010-2017, AdaCore                     --
--                                                                          --
-- This library is free software;  you can redistribute it and/or modify it --
-- under terms of the  GNU General Public License  as published by the Free --
-- Software  Foundation;  either version 3,  or (at your  option) any later --
-- version. This library is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN- --
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE.                            --
--                                                                          --
--                                                                          --
--                                                                          --
--                                                                          --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
------------------------------------------------------------------------------

--  By definition, an object can never be freed while there are references
--  to it.
--  However, this simple scheme fails in some cases. For instance, imagine
--  you want to cache some refcounted type into a map. The map would then
--  own a reference to the object, which is thus never freed while the map
--  exists (presumably for the life of your application).
--  A solution to this problem is the notion of "weak reference": these act
--  as containers that point to the element, without owning a reference to
--  them. When the element is destroyed (because its refcount can now reach
--  0), the container is set to a special state that indicates the element
--  no longer exists.
--  With this scheme, the cache will still contain entries for the elements,
--  but those entries will return a Null_Ref when accessed.

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;

private

   type Weak_Refcounted
     is abstract new GNATCOLL.Refcount.Refcounted
   with record
      Proxy : Proxy_Pointers.Ref;  --  Hold a reference to a proxy
   end record;

end GNATCOLL.Refcount.Weakref;