|
| 1 | +========================================= |
| 2 | +Reference Counting Using Controlled Types |
| 3 | +========================================= |
| 4 | + |
| 5 | +--------------- |
| 6 | +Global Overview |
| 7 | +--------------- |
| 8 | + |
| 9 | +* Idiom for counting object references |
| 10 | + |
| 11 | + - Safe deallocation |
| 12 | + - No memory leak |
| 13 | + - Efficient |
| 14 | + - All :ada:`access` must then be using it |
| 15 | + |
| 16 | +* A refcounted type derives from :ada:`Refcounted` |
| 17 | + |
| 18 | + - Tagged |
| 19 | + - Get a :ada:`Ref` through :ada:`Set` |
| 20 | + - Turn a :ada:`Ref` into an :ada:`access` through :ada:`Get` |
| 21 | + |
| 22 | +.. code:: Ada |
| 23 | + |
| 24 | + package Ref_Counter is |
| 25 | + type Refcounted is abstract tagged private; |
| 26 | + procedure Free (Self : in out Refcounted) is null; |
| 27 | +
|
| 28 | + type Refcounted_Access is access all Refcounted'Class; |
| 29 | + type Ref is tagged private; |
| 30 | +
|
| 31 | + procedure Set (Self : in out Ref; Data : Refcounted'Class); |
| 32 | + function Get (Self : Ref) return Refcounted_Access; |
| 33 | + procedure Finalize (P : in out Ref); |
| 34 | + procedure Adjust (P : in out Ref); |
| 35 | + private |
| 36 | + type Refcounted is abstract tagged record |
| 37 | + Refcount : Integer := 0; |
| 38 | + end record; |
| 39 | +
|
| 40 | + type Ref is new Ada.Finalization.Controlled with record |
| 41 | + Data : Refcounted_Access; |
| 42 | + end record; |
| 43 | +
|
| 44 | +---------------------- |
| 45 | +Implementation Details |
| 46 | +---------------------- |
| 47 | + |
| 48 | +* :ada:`Set` is safe |
| 49 | + |
| 50 | + - :ada:`Ref` default value is :ada:`null` |
| 51 | + - Clears up any previously used :ada:`Ref` |
| 52 | + |
| 53 | +.. code:: Ada |
| 54 | +
|
| 55 | + procedure Set (Self : in out Ref; Data : Refcounted'Class) is |
| 56 | + D : constant Refcounted_Access := new Refcounted'Class'(Data); |
| 57 | + begin |
| 58 | + if Self.Data /= null then |
| 59 | + Finalize (Self); -- decrement old reference count |
| 60 | + end if; |
| 61 | +
|
| 62 | + Self.Data := D; |
| 63 | + Adjust (Self); -- increment reference count (set to 1) |
| 64 | + end Set; |
| 65 | +
|
| 66 | +* :ada:`Adjust` called for all new references |
| 67 | + |
| 68 | +.. code:: Ada |
| 69 | +
|
| 70 | + overriding procedure Adjust (P : in out Ref) is |
| 71 | + begin |
| 72 | + if P.Data /= null then |
| 73 | + P.Data.Refcount := P.Data.Refcount + 1; |
| 74 | + end if; |
| 75 | + end Adjust; |
0 commit comments