1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . I N D E F I N I T E _ H O L D E R S --
9 -- Copyright (C) 2013-2014, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 ------------------------------------------------------------------------------
28 with Ada.Unchecked_Deallocation;
30 package body Ada.Containers.Indefinite_Holders is
33 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
39 function "=" (Left, Right : Holder) return Boolean is
41 if Left.Reference = Right.Reference then
42 -- Covers both null and not null but the same shared object cases.
46 elsif Left.Reference /= null and Right.Reference /= null then
47 return Left.Reference.Element.all = Right.Reference.Element.all;
57 overriding procedure Adjust (Container : in out Holder) is
59 if Container.Reference /= null then
60 Reference (Container.Reference);
66 overriding procedure Adjust (Control : in out Reference_Control_Type) is
68 if Control.Container /= null then
69 Reference (Control.Container.Reference);
72 B : Natural renames Control.Container.Busy;
83 procedure Assign (Target : in out Holder; Source : Holder) is
85 if Target.Busy /= 0 then
86 raise Program_Error with "attempt to tamper with elements";
89 if Target.Reference /= Source.Reference then
90 if Target.Reference /= null then
91 Unreference (Target.Reference);
94 Target.Reference := Source.Reference;
96 if Source.Reference /= null then
97 Reference (Target.Reference);
106 procedure Clear (Container : in out Holder) is
108 if Container.Busy /= 0 then
109 raise Program_Error with "attempt to tamper with elements";
112 Unreference (Container.Reference);
113 Container.Reference := null;
116 ------------------------
117 -- Constant_Reference --
118 ------------------------
120 function Constant_Reference
121 (Container : aliased Holder) return Constant_Reference_Type
123 Ref : constant Constant_Reference_Type :=
124 (Element => Container.Reference.Element.all'Access,
125 Control => (Controlled with Container'Unrestricted_Access));
126 B : Natural renames Ref.Control.Container.Busy;
128 Reference (Ref.Control.Container.Reference);
131 end Constant_Reference;
137 function Copy (Source : Holder) return Holder is
139 if Source.Reference = null then
140 return (Controlled with null, 0);
142 Reference (Source.Reference);
144 return (Controlled with Source.Reference, 0);
152 function Element (Container : Holder) return Element_Type is
154 if Container.Reference = null then
155 raise Constraint_Error with "container is empty";
157 return Container.Reference.Element.all;
165 overriding procedure Finalize (Container : in out Holder) is
167 if Container.Busy /= 0 then
168 raise Program_Error with "attempt to tamper with elements";
171 if Container.Reference /= null then
172 Unreference (Container.Reference);
173 Container.Reference := null;
177 overriding procedure Finalize (Control : in out Reference_Control_Type) is
179 if Control.Container /= null then
180 Unreference (Control.Container.Reference);
181 Control.Container.Busy := Control.Container.Busy - 1;
184 Control.Container := null;
191 function Is_Empty (Container : Holder) return Boolean is
193 return Container.Reference = null;
200 procedure Move (Target : in out Holder; Source : in out Holder) is
202 if Target.Busy /= 0 then
203 raise Program_Error with "attempt to tamper with elements";
206 if Source.Busy /= 0 then
207 raise Program_Error with "attempt to tamper with elements";
210 if Target.Reference /= Source.Reference then
211 if Target.Reference /= null then
212 Unreference (Target.Reference);
215 Target.Reference := Source.Reference;
216 Source.Reference := null;
224 procedure Query_Element
226 Process : not null access procedure (Element : Element_Type))
228 B : Natural renames Container'Unrestricted_Access.Busy;
231 if Container.Reference = null then
232 raise Constraint_Error with "container is empty";
238 Process (Container.Reference.Element.all);
253 (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
254 Container : out Holder)
259 if not Boolean'Input (Stream) then
260 Container.Reference :=
263 Element => new Element_Type'(Element_Type'Input (Stream)));
268 (Stream : not null access Root_Stream_Type'Class;
269 Item : out Constant_Reference_Type)
272 raise Program_Error with "attempt to stream reference";
276 (Stream : not null access Root_Stream_Type'Class;
277 Item : out Reference_Type)
280 raise Program_Error with "attempt to stream reference";
287 procedure Reference (Item : not null Shared_Holder_Access) is
289 System.Atomic_Counters.Increment (Item.Counter);
293 (Container : aliased in out Holder) return Reference_Type
295 Ref : constant Reference_Type :=
296 (Element => Container.Reference.Element.all'Access,
297 Control => (Controlled with Container'Unrestricted_Access));
299 Reference (Ref.Control.Container.Reference);
300 Container.Busy := Container.Busy + 1;
304 ---------------------
305 -- Replace_Element --
306 ---------------------
308 procedure Replace_Element
309 (Container : in out Holder;
310 New_Item : Element_Type)
312 -- Element allocator may need an accessibility check in case actual type
313 -- is class-wide or has access discriminants (RM 4.8(10.1) and
316 pragma Unsuppress (Accessibility_Check);
319 if Container.Busy /= 0 then
320 raise Program_Error with "attempt to tamper with elements";
323 if Container.Reference = null then
324 -- Holder is empty, allocate new Shared_Holder.
326 Container.Reference :=
329 Element => new Element_Type'(New_Item));
331 elsif System.Atomic_Counters.Is_One (Container.Reference.Counter) then
332 -- Shared_Holder can be reused.
334 Free (Container.Reference.Element);
335 Container.Reference.Element := new Element_Type'(New_Item);
338 Unreference (Container.Reference);
339 Container.Reference :=
342 Element => new Element_Type'(New_Item));
350 function To_Holder (New_Item : Element_Type) return Holder is
351 -- The element allocator may need an accessibility check in the case the
352 -- actual type is class-wide or has access discriminants (RM 4.8(10.1)
355 pragma Unsuppress (Accessibility_Check);
362 Element => new Element_Type'(New_Item)), 0);
369 procedure Unreference (Item : not null Shared_Holder_Access) is
372 new Ada.Unchecked_Deallocation (Shared_Holder, Shared_Holder_Access);
374 Aux : Shared_Holder_Access := Item;
377 if System.Atomic_Counters.Decrement (Aux.Counter) then
387 procedure Update_Element
389 Process : not null access procedure (Element : in out Element_Type))
391 B : Natural renames Container'Unrestricted_Access.Busy;
394 if Container.Reference = null then
395 raise Constraint_Error with "container is empty";
401 Process (Container.Reference.Element.all);
416 (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
420 Boolean'Output (Stream, Container.Reference = null);
422 if Container.Reference /= null then
423 Element_Type'Output (Stream, Container.Reference.Element.all);
428 (Stream : not null access Root_Stream_Type'Class;
429 Item : Reference_Type)
432 raise Program_Error with "attempt to stream reference";
436 (Stream : not null access Root_Stream_Type'Class;
437 Item : Constant_Reference_Type)
440 raise Program_Error with "attempt to stream reference";
443 end Ada.Containers.Indefinite_Holders;