* g++.dg/template/using30.C: Move ...
[official-gcc.git] / gcc / ada / a-coinho-shared.adb
blob783121c6b9d6be0e54e4ec1cef7ca8abff092038
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
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 --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2013-2014, Free Software Foundation, Inc. --
10 -- --
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. --
17 -- --
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. --
21 -- --
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 -- Note: special attention must be paid to the case of simultaneous access
29 -- to internal shared objects and elements by different tasks. The Reference
30 -- counter of internal shared object is the only component protected using
31 -- atomic operations; other components and elements can be modified only when
32 -- reference counter is equal to one (so there are no other references to this
33 -- internal shared object and element).
35 with Ada.Unchecked_Deallocation;
37 package body Ada.Containers.Indefinite_Holders is
39 pragma Annotate (CodePeer, Skip_Analysis);
41 procedure Free is
42 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
44 ---------
45 -- "=" --
46 ---------
48 function "=" (Left, Right : Holder) return Boolean is
49 begin
50 if Left.Reference = Right.Reference then
52 -- Covers both null and not null but the same shared object cases
54 return True;
56 elsif Left.Reference /= null and Right.Reference /= null then
57 return Left.Reference.Element.all = Right.Reference.Element.all;
59 else
60 return False;
61 end if;
62 end "=";
64 ------------
65 -- Adjust --
66 ------------
68 overriding procedure Adjust (Container : in out Holder) is
69 begin
70 if Container.Reference /= null then
71 if Container.Busy = 0 then
73 -- Container is not locked, reuse existing internal shared object
75 Reference (Container.Reference);
76 else
77 -- Otherwise, create copy of both internal shared object and
78 -- element.
80 Container.Reference :=
81 new Shared_Holder'
82 (Counter => <>,
83 Element =>
84 new Element_Type'(Container.Reference.Element.all));
85 end if;
86 end if;
88 Container.Busy := 0;
89 end Adjust;
91 overriding procedure Adjust (Control : in out Reference_Control_Type) is
92 begin
93 if Control.Container /= null then
94 Reference (Control.Container.Reference);
95 Control.Container.Busy := Control.Container.Busy + 1;
96 end if;
97 end Adjust;
99 ------------
100 -- Assign --
101 ------------
103 procedure Assign (Target : in out Holder; Source : Holder) is
104 begin
105 if Target.Busy /= 0 then
106 raise Program_Error with "attempt to tamper with elements";
107 end if;
109 if Target.Reference /= Source.Reference then
110 if Target.Reference /= null then
111 Unreference (Target.Reference);
112 end if;
114 Target.Reference := Source.Reference;
116 if Source.Reference /= null then
117 Reference (Target.Reference);
118 end if;
119 end if;
120 end Assign;
122 -----------
123 -- Clear --
124 -----------
126 procedure Clear (Container : in out Holder) is
127 begin
128 if Container.Busy /= 0 then
129 raise Program_Error with "attempt to tamper with elements";
130 end if;
132 Unreference (Container.Reference);
133 Container.Reference := null;
134 end Clear;
136 ------------------------
137 -- Constant_Reference --
138 ------------------------
140 function Constant_Reference
141 (Container : aliased Holder) return Constant_Reference_Type is
142 begin
143 if Container.Reference = null then
144 raise Constraint_Error with "container is empty";
146 elsif Container.Busy = 0
147 and then not System.Atomic_Counters.Is_One
148 (Container.Reference.Counter)
149 then
150 -- Container is not locked and internal shared object is used by
151 -- other container, create copy of both internal shared object and
152 -- element.
154 Container'Unrestricted_Access.Reference :=
155 new Shared_Holder'
156 (Counter => <>,
157 Element => new Element_Type'(Container.Reference.Element.all));
158 end if;
160 declare
161 Ref : constant Constant_Reference_Type :=
162 (Element => Container.Reference.Element.all'Access,
163 Control => (Controlled with Container'Unrestricted_Access));
164 begin
165 Reference (Ref.Control.Container.Reference);
166 Ref.Control.Container.Busy := Ref.Control.Container.Busy + 1;
167 return Ref;
168 end;
169 end Constant_Reference;
171 ----------
172 -- Copy --
173 ----------
175 function Copy (Source : Holder) return Holder is
176 begin
177 if Source.Reference = null then
178 return (Controlled with null, 0);
180 elsif Source.Busy = 0 then
182 -- Container is not locked, reuse internal shared object
184 Reference (Source.Reference);
186 return (Controlled with Source.Reference, 0);
188 else
189 -- Otherwise, create copy of both internal shared object and element
191 return
192 (Controlled with
193 new Shared_Holder'
194 (Counter => <>,
195 Element => new Element_Type'(Source.Reference.Element.all)),
197 end if;
198 end Copy;
200 -------------
201 -- Element --
202 -------------
204 function Element (Container : Holder) return Element_Type is
205 begin
206 if Container.Reference = null then
207 raise Constraint_Error with "container is empty";
208 else
209 return Container.Reference.Element.all;
210 end if;
211 end Element;
213 --------------
214 -- Finalize --
215 --------------
217 overriding procedure Finalize (Container : in out Holder) is
218 begin
219 if Container.Busy /= 0 then
220 raise Program_Error with "attempt to tamper with elements";
221 end if;
223 if Container.Reference /= null then
224 Unreference (Container.Reference);
225 Container.Reference := null;
226 end if;
227 end Finalize;
229 overriding procedure Finalize (Control : in out Reference_Control_Type) is
230 begin
231 if Control.Container /= null then
232 Unreference (Control.Container.Reference);
233 Control.Container.Busy := Control.Container.Busy - 1;
234 Control.Container := null;
235 end if;
236 end Finalize;
238 --------------
239 -- Is_Empty --
240 --------------
242 function Is_Empty (Container : Holder) return Boolean is
243 begin
244 return Container.Reference = null;
245 end Is_Empty;
247 ----------
248 -- Move --
249 ----------
251 procedure Move (Target : in out Holder; Source : in out Holder) is
252 begin
253 if Target.Busy /= 0 then
254 raise Program_Error with "attempt to tamper with elements";
255 end if;
257 if Source.Busy /= 0 then
258 raise Program_Error with "attempt to tamper with elements";
259 end if;
261 if Target.Reference /= Source.Reference then
262 if Target.Reference /= null then
263 Unreference (Target.Reference);
264 end if;
266 Target.Reference := Source.Reference;
267 Source.Reference := null;
268 end if;
269 end Move;
271 -------------------
272 -- Query_Element --
273 -------------------
275 procedure Query_Element
276 (Container : Holder;
277 Process : not null access procedure (Element : Element_Type))
279 B : Natural renames Container'Unrestricted_Access.Busy;
281 begin
282 if Container.Reference = null then
283 raise Constraint_Error with "container is empty";
285 elsif Container.Busy = 0
286 and then
287 not System.Atomic_Counters.Is_One (Container.Reference.Counter)
288 then
289 -- Container is not locked and internal shared object is used by
290 -- other container, create copy of both internal shared object and
291 -- element.
293 Container'Unrestricted_Access.Reference :=
294 new Shared_Holder'
295 (Counter => <>,
296 Element => new Element_Type'(Container.Reference.Element.all));
297 end if;
299 B := B + 1;
301 begin
302 Process (Container.Reference.Element.all);
303 exception
304 when others =>
305 B := B - 1;
306 raise;
307 end;
309 B := B - 1;
310 end Query_Element;
312 ----------
313 -- Read --
314 ----------
316 procedure Read
317 (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
318 Container : out Holder)
320 begin
321 Clear (Container);
323 if not Boolean'Input (Stream) then
324 Container.Reference :=
325 new Shared_Holder'
326 (Counter => <>,
327 Element => new Element_Type'(Element_Type'Input (Stream)));
328 end if;
329 end Read;
331 procedure Read
332 (Stream : not null access Root_Stream_Type'Class;
333 Item : out Constant_Reference_Type)
335 begin
336 raise Program_Error with "attempt to stream reference";
337 end Read;
339 procedure Read
340 (Stream : not null access Root_Stream_Type'Class;
341 Item : out Reference_Type)
343 begin
344 raise Program_Error with "attempt to stream reference";
345 end Read;
347 ---------------
348 -- Reference --
349 ---------------
351 procedure Reference (Item : not null Shared_Holder_Access) is
352 begin
353 System.Atomic_Counters.Increment (Item.Counter);
354 end Reference;
356 function Reference
357 (Container : aliased in out Holder) return Reference_Type
359 begin
360 if Container.Reference = null then
361 raise Constraint_Error with "container is empty";
363 elsif Container.Busy = 0
364 and then
365 not System.Atomic_Counters.Is_One (Container.Reference.Counter)
366 then
367 -- Container is not locked and internal shared object is used by
368 -- other container, create copy of both internal shared object and
369 -- element.
371 Container.Reference :=
372 new Shared_Holder'
373 (Counter => <>,
374 Element => new Element_Type'(Container.Reference.Element.all));
375 end if;
377 declare
378 Ref : constant Reference_Type :=
379 (Element => Container.Reference.Element.all'Access,
380 Control => (Controlled with Container'Unrestricted_Access));
381 begin
382 Reference (Ref.Control.Container.Reference);
383 Ref.Control.Container.Busy := Ref.Control.Container.Busy + 1;
384 return Ref;
385 end;
386 end Reference;
388 ---------------------
389 -- Replace_Element --
390 ---------------------
392 procedure Replace_Element
393 (Container : in out Holder;
394 New_Item : Element_Type)
396 -- Element allocator may need an accessibility check in case actual type
397 -- is class-wide or has access discriminants (RM 4.8(10.1) and
398 -- AI12-0035).
400 pragma Unsuppress (Accessibility_Check);
402 begin
403 if Container.Busy /= 0 then
404 raise Program_Error with "attempt to tamper with elements";
405 end if;
407 if Container.Reference = null then
408 -- Holder is empty, allocate new Shared_Holder.
410 Container.Reference :=
411 new Shared_Holder'
412 (Counter => <>,
413 Element => new Element_Type'(New_Item));
415 elsif System.Atomic_Counters.Is_One (Container.Reference.Counter) then
416 -- Shared_Holder can be reused.
418 Free (Container.Reference.Element);
419 Container.Reference.Element := new Element_Type'(New_Item);
421 else
422 Unreference (Container.Reference);
423 Container.Reference :=
424 new Shared_Holder'
425 (Counter => <>,
426 Element => new Element_Type'(New_Item));
427 end if;
428 end Replace_Element;
430 ---------------
431 -- To_Holder --
432 ---------------
434 function To_Holder (New_Item : Element_Type) return Holder is
435 -- The element allocator may need an accessibility check in the case the
436 -- actual type is class-wide or has access discriminants (RM 4.8(10.1)
437 -- and AI12-0035).
439 pragma Unsuppress (Accessibility_Check);
441 begin
442 return
443 (Controlled with
444 new Shared_Holder'
445 (Counter => <>,
446 Element => new Element_Type'(New_Item)), 0);
447 end To_Holder;
449 -----------------
450 -- Unreference --
451 -----------------
453 procedure Unreference (Item : not null Shared_Holder_Access) is
455 procedure Free is
456 new Ada.Unchecked_Deallocation (Shared_Holder, Shared_Holder_Access);
458 Aux : Shared_Holder_Access := Item;
460 begin
461 if System.Atomic_Counters.Decrement (Aux.Counter) then
462 Free (Aux.Element);
463 Free (Aux);
464 end if;
465 end Unreference;
467 --------------------
468 -- Update_Element --
469 --------------------
471 procedure Update_Element
472 (Container : in out Holder;
473 Process : not null access procedure (Element : in out Element_Type))
475 B : Natural renames Container.Busy;
477 begin
478 if Container.Reference = null then
479 raise Constraint_Error with "container is empty";
481 elsif Container.Busy = 0
482 and then
483 not System.Atomic_Counters.Is_One (Container.Reference.Counter)
484 then
485 -- Container is not locked and internal shared object is used by
486 -- other container, create copy of both internal shared object and
487 -- element.
489 Container'Unrestricted_Access.Reference :=
490 new Shared_Holder'
491 (Counter => <>,
492 Element => new Element_Type'(Container.Reference.Element.all));
493 end if;
495 B := B + 1;
497 begin
498 Process (Container.Reference.Element.all);
499 exception
500 when others =>
501 B := B - 1;
502 raise;
503 end;
505 B := B - 1;
506 end Update_Element;
508 -----------
509 -- Write --
510 -----------
512 procedure Write
513 (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
514 Container : Holder)
516 begin
517 Boolean'Output (Stream, Container.Reference = null);
519 if Container.Reference /= null then
520 Element_Type'Output (Stream, Container.Reference.Element.all);
521 end if;
522 end Write;
524 procedure Write
525 (Stream : not null access Root_Stream_Type'Class;
526 Item : Reference_Type)
528 begin
529 raise Program_Error with "attempt to stream reference";
530 end Write;
532 procedure Write
533 (Stream : not null access Root_Stream_Type'Class;
534 Item : Constant_Reference_Type)
536 begin
537 raise Program_Error with "attempt to stream reference";
538 end Write;
540 end Ada.Containers.Indefinite_Holders;