From 729ef058830d3e45d2b2973a1bf8d9751982dfa4 Mon Sep 17 00:00:00 2001 From: Leo Germond Date: Thu, 16 Jan 2025 15:25:35 +0100 Subject: [PATCH] controlled types: idiom for refcounting --- .../10-idiom_refcounting.rst | 75 +++++++++++++++++++ ...rst => 700_expert_resource_management.rst} | 1 + 2 files changed, 76 insertions(+) create mode 100644 courses/fundamentals_of_ada/260_controlled_types/10-idiom_refcounting.rst rename courses/fundamentals_of_ada/{300_expert_resource_management.rst => 700_expert_resource_management.rst} (92%) diff --git a/courses/fundamentals_of_ada/260_controlled_types/10-idiom_refcounting.rst b/courses/fundamentals_of_ada/260_controlled_types/10-idiom_refcounting.rst new file mode 100644 index 000000000..bc24a0760 --- /dev/null +++ b/courses/fundamentals_of_ada/260_controlled_types/10-idiom_refcounting.rst @@ -0,0 +1,75 @@ +========================================= +Reference Counting Using Controlled Types +========================================= + +--------------- +Global Overview +--------------- + +* Idiom for counting object references + + - Safe deallocation + - No memory leak + - Efficient + - All :ada:`access` must then be using it + +* A refcounted type derives from :ada:`Refcounted` + + - Tagged + - Get a :ada:`Ref` through :ada:`Set` + - Turn a :ada:`Ref` into an :ada:`access` through :ada:`Get` + +.. code:: Ada + + package Ref_Counter is + type Refcounted is abstract tagged private; + procedure Free (Self : in out Refcounted) is null; + + type Refcounted_Access is access all Refcounted'Class; + type Ref is tagged private; + + procedure Set (Self : in out Ref; Data : Refcounted'Class); + function Get (Self : Ref) return Refcounted_Access; + procedure Finalize (P : in out Ref); + procedure Adjust (P : in out Ref); + private + type Refcounted is abstract tagged record + Refcount : Integer := 0; + end record; + + type Ref is new Ada.Finalization.Controlled with record + Data : Refcounted_Access; + end record; + +---------------------- +Implementation Details +---------------------- + +* :ada:`Set` is safe + + - :ada:`Ref` default value is :ada:`null` + - Clears up any previously used :ada:`Ref` + +.. code:: Ada + + procedure Set (Self : in out Ref; Data : Refcounted'Class) is + D : constant Refcounted_Access := new Refcounted'Class'(Data); + begin + if Self.Data /= null then + Finalize (Self); -- decrement old reference count + end if; + + Self.Data := D; + Adjust (Self); -- increment reference count (set to 1) + end Set; + +* :ada:`Adjust` called for all new references + +.. code:: Ada + + overriding procedure Adjust (P : in out Ref) is + begin + if P.Data /= null then + P.Data.Refcount := P.Data.Refcount + 1; + end if; + end Adjust; diff --git a/courses/fundamentals_of_ada/300_expert_resource_management.rst b/courses/fundamentals_of_ada/700_expert_resource_management.rst similarity index 92% rename from courses/fundamentals_of_ada/300_expert_resource_management.rst rename to courses/fundamentals_of_ada/700_expert_resource_management.rst index f29fcad31..0d92caf10 100644 --- a/courses/fundamentals_of_ada/300_expert_resource_management.rst +++ b/courses/fundamentals_of_ada/700_expert_resource_management.rst @@ -34,3 +34,4 @@ Expert Resource Management .. container:: PRELUDE END .. include:: 110_private_types/07-limited-private.rst +.. include:: 260_controlled_types/10-idiom_refcounting.rst