-- -- -- package Object.Archived Copyright (c) Dmitry A. Kazakov -- -- Implementation Luebeck -- -- Summer, 2003 -- -- -- -- Last revision : 20:41 21 Jul 2017 -- -- -- -- This library is free software; you can redistribute it and/or -- -- modify it under the terms of the GNU General Public License as -- -- published by the Free Software Foundation; either version 2 of -- -- the License, 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 -- -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- -- General Public License for more details. You should have -- -- received a copy of the GNU General Public License along with -- -- this library; if not, write to the Free Software Foundation, -- -- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- --____________________________________________________________________-- with Ada.IO_Exceptions; use Ada.IO_Exceptions; with Object.Archived.Sets; use Object.Archived.Sets; with System; use System; package body Object.Archived is use Dispatch_Tables; package Link_Handles is new Object.Handle (Backward_Link, Backward_Link_Ptr); use Link_Handles; -- procedure Dump_List (Object : Deposit'Class) is -- use Ada.Text_IO, Ada.Tags, System.Storage_Elements; -- function "+" (Value : Address) return Integer_Address -- renames To_Integer; -- function Status (Link : Boolean) return String is -- begin -- if Link then -- return ""; -- else -- return "broken"; -- end if; -- end Status; -- This : Backward_Link_Ptr; -- begin -- Put_Line -- ( "Object: " -- & Expanded_Name (Object'Tag) -- & " at" -- & Integer_Address'Image (+Object'Address) -- ); -- if Object.Delivery = null then -- Put_Line (" no backward links"); -- else -- This := Object.Delivery; -- loop -- Put_Line -- ( " " -- & Expanded_Name (This.all'Tag) -- & Integer_Address'Image (+This.Prev.all'Address) -- & " <-" -- & Status (This.Prev.Next = This) -- & Integer_Address'Image (+This.all'Address) -- & " ->" -- & Status (This.Next.Prev = This) -- & Integer_Address'Image (+This.Next.all'Address) -- ); -- This := This.Next; -- exit when This = Object.Delivery; -- end loop; -- end if; -- end Dump_List; procedure Attach ( Link : Backward_Link_Ptr; Object : Deposit_Ptr ) is begin Detach (Link.all); if Object /= null then Link.Object := Object; if Object.Delivery = null then Object.Delivery := Link; Link.Next := Link; Link.Prev := Link; else Link.Next := Object.Delivery; -- This -> List head Link.Prev := Link.Next.Prev; -- List tail <- This Link.Prev.Next := Link; Link.Next.Prev := Link; end if; end if; end Attach; procedure Close (Object : in out Deposit'Class) is This : Backward_Link_Ptr := Object.Delivery; Lock : Link_Handles.Handle; begin while This /= null loop Set (Lock, This); Destroyed (This.all); Detach (This.all); This := Object.Delivery; end loop; end Close; procedure Create ( Source : String; Pointer : in out Integer; Class : String; List : Deposit_Container'Class; Object : out Deposit_Ptr ) is Constructor : Restore; begin begin Constructor := Find (Dispatch_Table, Class); exception when End_Error => raise Name_Error; end; Constructor (Source, Pointer, Class, List, Object); end Create; procedure Delete (Object : in out Deposit'Class) is procedure Free is new Ada.Unchecked_Deallocation ( Backward_Link'Class, Backward_Link_Ptr ); begin if Object.Delivery /= null then declare Set : Deposit_Set; Handle : Link_Handles.Handle; This : Backward_Link_Ptr := new Walker_Stub; Next : Backward_Link_Ptr; begin -- -- The list of backward links can be modified while we are -- walking down it. A stub backward link object is inserted -- in the list. The object is pointed by This. This.Prev is -- notified. Then This is moved forward in the list until it -- becomes next the list head. This prevents list corruption -- when some list elements are removed from or inserted into -- the list upon notification. -- This.Prev := Object.Delivery; This.Next := Object.Delivery.Next; This.Next.Prev := This; This.Prev.Next := This; This.Object := Object.Delivery.Object; loop Link_Handles.Set (Handle, This.Prev); Deleted (Ptr (Handle).all, Set); Next := This.Next; exit when Next = Object.Delivery; -- -- Moving This forward in the list -- .______. .______. .______. .______. -- |This. |-->| |-->| |-->|Next. | -- | Prev| | This | | Next | | Next| -- |______|<--|______|<--|______|<--|______| -- -- .______. .______. .______. .______. -- | |-->| |-->| |-->| | -- | | | Next | | This | | | -- |______|<--|______|<--|______|<--|______| -- Next.Prev := This.Prev; This.Prev.Next := Next; This.Prev := Next; This.Next := Next.Next; Next.Next.Prev := This; Next.Next := This; end loop; Free (This); end; end if; end Delete; procedure Deleted ( Link : in out Walker_Stub; Temps : in out Deposit_Container'Class ) is begin null; end Deleted; procedure Destroyed (Link : in out Walker_Stub) is begin null; end Destroyed; procedure Detach (Link : in out Backward_Link) is begin if Link.Object /= null then if Link.Next = Link.Next.Next then Link.Object.Delivery := null; -- The only item else if Link.Next.Prev = Link.Object.Delivery then Link.Object.Delivery := Link.Next; -- The first item end if; Link.Next.Prev := Link.Prev; Link.Prev.Next := Link.Next; end if; Link.Object := null; end if; end Detach; procedure Finalize (Object : in out Deposit) is begin Close (Object); Finalize (Entity (Object)); end Finalize; procedure Finalize (Link : in out Backward_Link) is begin Detach (Link); Finalize (Entity (Link)); end Finalize; procedure Get_Referents ( Object : Deposit; Container : in out Deposit_Container'Class ) is begin null; end Get_Referents; function Is_Empty (Container : Deposit_Container'Class) return Boolean is begin return Get_Size (Container) = 0; end Is_Empty; function Is_Registered (Class : String) return Boolean is begin return IsIn (Dispatch_Table, Class); end Is_Registered; procedure Register_Class ( Class : String; Constructor : Restore ) is begin Add (Dispatch_Table, Class, Constructor); exception when Name_Error => if Find (Dispatch_Table, Class) /= Constructor then raise; end if; end Register_Class; function Self (Link : Backward_Link) return Backward_Link_Ptr is begin if Link.Object = null then raise Constraint_Error; else return Link.Next.Prev; end if; end Self; function This (Link : Backward_Link) return Deposit_Ptr is begin if Link.Object = null then raise Constraint_Error; else return Link.Object; end if; end This; function To_Object_Ptr (Link : Backward_Link_Ptr) return Backward_Link_Ptr is begin return Link; end To_Object_Ptr; function "<" (Left, Right : Backward_Link_Ptr) return Boolean is begin return ( Right /= null and then ( Left = null or else Left.all'Address < Right.all'Address ) ); end "<"; end Object.Archived;