with Ada.Finalization; with Ada.Unchecked_Deallocation; with Atomic.Signed; generic type T (<>) is private; type T_Access is access T; package SP.Memory with Preelaborate is -- Atomic reference counting pointer. type Arc is new Ada.Finalization.Controlled with private; type Reference_Type (Element : access T) is limited null record with Implicit_Dereference => Element; type Reference_Count is new Integer; package Atomic_Integer is new Atomic.Signed (Reference_Count); function Make (Allocated : T_Access) return Arc with Post => Is_Valid (Make'Result); function Make_Null return Arc with Post => not Is_Valid (Make_Null'Result); function Is_Valid (Self : Arc) return Boolean; function Get (Self : Arc) return Reference_Type with Pre => Is_Valid (Self); procedure Reset (Self : aliased in out Arc) with Post => not Is_Valid (Self); -- Debugging function to get number of reference counts. function Count (Self : aliased in out Arc) return Reference_Count; overriding procedure Initialize (Self : in out Arc); overriding procedure Adjust (Self : in out Arc); overriding procedure Finalize (Self : in out Arc) with Post => not Is_Valid (Self); private -- The backing type which actually tracks the reference count, as well as -- tracking the value being pointed to. type Control_Block is limited record Value : T_Access := null; Count : aliased Atomic_Integer.Instance := Atomic_Integer.Init (0); end record; type Control_Block_Access is access Control_Block; type Arc is new Ada.Finalization.Controlled with record Block : Control_Block_Access := null; end record; procedure Free is new Ada.Unchecked_Deallocation (T, T_Access); procedure Free is new Ada.Unchecked_Deallocation (Control_Block, Control_Block_Access); end SP.Memory;