Merge -r 127928:132243 from trunk
[official-gcc.git] / gcc / ada / a-rbtgso.adb
blobad4f76f5df6cc521461f136192fbc925889bdb5f
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . R E D _ B L A C K _ T R E E S . --
6 -- G E N E R I C _ S E T _ O P E R A T I O N S --
7 -- --
8 -- B o d y --
9 -- --
10 -- Copyright (C) 2004-2007, Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
21 -- Boston, MA 02110-1301, USA. --
22 -- --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
29 -- --
30 -- This unit was originally developed by Matthew J Heaney. --
31 ------------------------------------------------------------------------------
33 with System; use type System.Address;
35 package body Ada.Containers.Red_Black_Trees.Generic_Set_Operations is
37 -----------------------
38 -- Local Subprograms --
39 -----------------------
41 procedure Clear (Tree : in out Tree_Type);
43 function Copy (Source : Tree_Type) return Tree_Type;
45 -----------
46 -- Clear --
47 -----------
49 procedure Clear (Tree : in out Tree_Type) is
50 pragma Assert (Tree.Busy = 0);
51 pragma Assert (Tree.Lock = 0);
53 Root : Node_Access := Tree.Root;
54 pragma Warnings (Off, Root);
56 begin
57 Tree.Root := null;
58 Tree.First := null;
59 Tree.Last := null;
60 Tree.Length := 0;
62 Delete_Tree (Root);
63 end Clear;
65 ----------
66 -- Copy --
67 ----------
69 function Copy (Source : Tree_Type) return Tree_Type is
70 Target : Tree_Type;
72 begin
73 if Source.Length = 0 then
74 return Target;
75 end if;
77 Target.Root := Copy_Tree (Source.Root);
78 Target.First := Tree_Operations.Min (Target.Root);
79 Target.Last := Tree_Operations.Max (Target.Root);
80 Target.Length := Source.Length;
82 return Target;
83 end Copy;
85 ----------------
86 -- Difference --
87 ----------------
89 procedure Difference (Target : in out Tree_Type; Source : Tree_Type) is
90 Tgt : Node_Access := Target.First;
91 Src : Node_Access := Source.First;
93 begin
94 if Target'Address = Source'Address then
95 if Target.Busy > 0 then
96 raise Program_Error with
97 "attempt to tamper with cursors (container is busy)";
98 end if;
100 Clear (Target);
101 return;
102 end if;
104 if Source.Length = 0 then
105 return;
106 end if;
108 if Target.Busy > 0 then
109 raise Program_Error with
110 "attempt to tamper with cursors (container is busy)";
111 end if;
113 loop
114 if Tgt = null then
115 return;
116 end if;
118 if Src = null then
119 return;
120 end if;
122 if Is_Less (Tgt, Src) then
123 Tgt := Tree_Operations.Next (Tgt);
125 elsif Is_Less (Src, Tgt) then
126 Src := Tree_Operations.Next (Src);
128 else
129 declare
130 X : Node_Access := Tgt;
131 begin
132 Tgt := Tree_Operations.Next (Tgt);
133 Tree_Operations.Delete_Node_Sans_Free (Target, X);
134 Free (X);
135 end;
137 Src := Tree_Operations.Next (Src);
138 end if;
139 end loop;
140 end Difference;
142 function Difference (Left, Right : Tree_Type) return Tree_Type is
143 Tree : Tree_Type;
145 L_Node : Node_Access := Left.First;
146 R_Node : Node_Access := Right.First;
148 Dst_Node : Node_Access;
149 pragma Warnings (Off, Dst_Node);
151 begin
152 if Left'Address = Right'Address then
153 return Tree; -- Empty set
154 end if;
156 if Left.Length = 0 then
157 return Tree; -- Empty set
158 end if;
160 if Right.Length = 0 then
161 return Copy (Left);
162 end if;
164 loop
165 if L_Node = null then
166 return Tree;
167 end if;
169 if R_Node = null then
170 while L_Node /= null loop
171 Insert_With_Hint
172 (Dst_Tree => Tree,
173 Dst_Hint => null,
174 Src_Node => L_Node,
175 Dst_Node => Dst_Node);
177 L_Node := Tree_Operations.Next (L_Node);
179 end loop;
181 return Tree;
182 end if;
184 if Is_Less (L_Node, R_Node) then
185 Insert_With_Hint
186 (Dst_Tree => Tree,
187 Dst_Hint => null,
188 Src_Node => L_Node,
189 Dst_Node => Dst_Node);
191 L_Node := Tree_Operations.Next (L_Node);
193 elsif Is_Less (R_Node, L_Node) then
194 R_Node := Tree_Operations.Next (R_Node);
196 else
197 L_Node := Tree_Operations.Next (L_Node);
198 R_Node := Tree_Operations.Next (R_Node);
199 end if;
200 end loop;
202 exception
203 when others =>
204 Delete_Tree (Tree.Root);
205 raise;
206 end Difference;
208 ------------------
209 -- Intersection --
210 ------------------
212 procedure Intersection
213 (Target : in out Tree_Type;
214 Source : Tree_Type)
216 Tgt : Node_Access := Target.First;
217 Src : Node_Access := Source.First;
219 begin
220 if Target'Address = Source'Address then
221 return;
222 end if;
224 if Target.Busy > 0 then
225 raise Program_Error with
226 "attempt to tamper with cursors (container is busy)";
227 end if;
229 if Source.Length = 0 then
230 Clear (Target);
231 return;
232 end if;
234 while Tgt /= null
235 and then Src /= null
236 loop
237 if Is_Less (Tgt, Src) then
238 declare
239 X : Node_Access := Tgt;
240 begin
241 Tgt := Tree_Operations.Next (Tgt);
242 Tree_Operations.Delete_Node_Sans_Free (Target, X);
243 Free (X);
244 end;
246 elsif Is_Less (Src, Tgt) then
247 Src := Tree_Operations.Next (Src);
249 else
250 Tgt := Tree_Operations.Next (Tgt);
251 Src := Tree_Operations.Next (Src);
252 end if;
253 end loop;
255 while Tgt /= null loop
256 declare
257 X : Node_Access := Tgt;
258 begin
259 Tgt := Tree_Operations.Next (Tgt);
260 Tree_Operations.Delete_Node_Sans_Free (Target, X);
261 Free (X);
262 end;
263 end loop;
264 end Intersection;
266 function Intersection (Left, Right : Tree_Type) return Tree_Type is
267 Tree : Tree_Type;
269 L_Node : Node_Access := Left.First;
270 R_Node : Node_Access := Right.First;
272 Dst_Node : Node_Access;
273 pragma Warnings (Off, Dst_Node);
275 begin
276 if Left'Address = Right'Address then
277 return Copy (Left);
278 end if;
280 loop
281 if L_Node = null then
282 return Tree;
283 end if;
285 if R_Node = null then
286 return Tree;
287 end if;
289 if Is_Less (L_Node, R_Node) then
290 L_Node := Tree_Operations.Next (L_Node);
292 elsif Is_Less (R_Node, L_Node) then
293 R_Node := Tree_Operations.Next (R_Node);
295 else
296 Insert_With_Hint
297 (Dst_Tree => Tree,
298 Dst_Hint => null,
299 Src_Node => L_Node,
300 Dst_Node => Dst_Node);
302 L_Node := Tree_Operations.Next (L_Node);
303 R_Node := Tree_Operations.Next (R_Node);
304 end if;
305 end loop;
307 exception
308 when others =>
309 Delete_Tree (Tree.Root);
310 raise;
311 end Intersection;
313 ---------------
314 -- Is_Subset --
315 ---------------
317 function Is_Subset
318 (Subset : Tree_Type;
319 Of_Set : Tree_Type) return Boolean
321 begin
322 if Subset'Address = Of_Set'Address then
323 return True;
324 end if;
326 if Subset.Length > Of_Set.Length then
327 return False;
328 end if;
330 declare
331 Subset_Node : Node_Access := Subset.First;
332 Set_Node : Node_Access := Of_Set.First;
334 begin
335 loop
336 if Set_Node = null then
337 return Subset_Node = null;
338 end if;
340 if Subset_Node = null then
341 return True;
342 end if;
344 if Is_Less (Subset_Node, Set_Node) then
345 return False;
346 end if;
348 if Is_Less (Set_Node, Subset_Node) then
349 Set_Node := Tree_Operations.Next (Set_Node);
350 else
351 Set_Node := Tree_Operations.Next (Set_Node);
352 Subset_Node := Tree_Operations.Next (Subset_Node);
353 end if;
354 end loop;
355 end;
356 end Is_Subset;
358 -------------
359 -- Overlap --
360 -------------
362 function Overlap (Left, Right : Tree_Type) return Boolean is
363 L_Node : Node_Access := Left.First;
364 R_Node : Node_Access := Right.First;
366 begin
367 if Left'Address = Right'Address then
368 return Left.Length /= 0;
369 end if;
371 loop
372 if L_Node = null
373 or else R_Node = null
374 then
375 return False;
376 end if;
378 if Is_Less (L_Node, R_Node) then
379 L_Node := Tree_Operations.Next (L_Node);
381 elsif Is_Less (R_Node, L_Node) then
382 R_Node := Tree_Operations.Next (R_Node);
384 else
385 return True;
386 end if;
387 end loop;
388 end Overlap;
390 --------------------------
391 -- Symmetric_Difference --
392 --------------------------
394 procedure Symmetric_Difference
395 (Target : in out Tree_Type;
396 Source : Tree_Type)
398 Tgt : Node_Access := Target.First;
399 Src : Node_Access := Source.First;
401 New_Tgt_Node : Node_Access;
402 pragma Warnings (Off, New_Tgt_Node);
404 begin
405 if Target.Busy > 0 then
406 raise Program_Error with
407 "attempt to tamper with cursors (container is busy)";
408 end if;
410 if Target'Address = Source'Address then
411 Clear (Target);
412 return;
413 end if;
415 loop
416 if Tgt = null then
417 while Src /= null loop
418 Insert_With_Hint
419 (Dst_Tree => Target,
420 Dst_Hint => null,
421 Src_Node => Src,
422 Dst_Node => New_Tgt_Node);
424 Src := Tree_Operations.Next (Src);
425 end loop;
427 return;
428 end if;
430 if Src = null then
431 return;
432 end if;
434 if Is_Less (Tgt, Src) then
435 Tgt := Tree_Operations.Next (Tgt);
437 elsif Is_Less (Src, Tgt) then
438 Insert_With_Hint
439 (Dst_Tree => Target,
440 Dst_Hint => Tgt,
441 Src_Node => Src,
442 Dst_Node => New_Tgt_Node);
444 Src := Tree_Operations.Next (Src);
446 else
447 declare
448 X : Node_Access := Tgt;
449 begin
450 Tgt := Tree_Operations.Next (Tgt);
451 Tree_Operations.Delete_Node_Sans_Free (Target, X);
452 Free (X);
453 end;
455 Src := Tree_Operations.Next (Src);
456 end if;
457 end loop;
458 end Symmetric_Difference;
460 function Symmetric_Difference (Left, Right : Tree_Type) return Tree_Type is
461 Tree : Tree_Type;
463 L_Node : Node_Access := Left.First;
464 R_Node : Node_Access := Right.First;
466 Dst_Node : Node_Access;
467 pragma Warnings (Off, Dst_Node);
469 begin
470 if Left'Address = Right'Address then
471 return Tree; -- Empty set
472 end if;
474 if Right.Length = 0 then
475 return Copy (Left);
476 end if;
478 if Left.Length = 0 then
479 return Copy (Right);
480 end if;
482 loop
483 if L_Node = null then
484 while R_Node /= null loop
485 Insert_With_Hint
486 (Dst_Tree => Tree,
487 Dst_Hint => null,
488 Src_Node => R_Node,
489 Dst_Node => Dst_Node);
490 R_Node := Tree_Operations.Next (R_Node);
491 end loop;
493 return Tree;
494 end if;
496 if R_Node = null then
497 while L_Node /= null loop
498 Insert_With_Hint
499 (Dst_Tree => Tree,
500 Dst_Hint => null,
501 Src_Node => L_Node,
502 Dst_Node => Dst_Node);
504 L_Node := Tree_Operations.Next (L_Node);
505 end loop;
507 return Tree;
508 end if;
510 if Is_Less (L_Node, R_Node) then
511 Insert_With_Hint
512 (Dst_Tree => Tree,
513 Dst_Hint => null,
514 Src_Node => L_Node,
515 Dst_Node => Dst_Node);
517 L_Node := Tree_Operations.Next (L_Node);
519 elsif Is_Less (R_Node, L_Node) then
520 Insert_With_Hint
521 (Dst_Tree => Tree,
522 Dst_Hint => null,
523 Src_Node => R_Node,
524 Dst_Node => Dst_Node);
526 R_Node := Tree_Operations.Next (R_Node);
528 else
529 L_Node := Tree_Operations.Next (L_Node);
530 R_Node := Tree_Operations.Next (R_Node);
531 end if;
532 end loop;
534 exception
535 when others =>
536 Delete_Tree (Tree.Root);
537 raise;
538 end Symmetric_Difference;
540 -----------
541 -- Union --
542 -----------
544 procedure Union (Target : in out Tree_Type; Source : Tree_Type)
546 Hint : Node_Access;
548 procedure Process (Node : Node_Access);
549 pragma Inline (Process);
551 procedure Iterate is new Tree_Operations.Generic_Iteration (Process);
553 -------------
554 -- Process --
555 -------------
557 procedure Process (Node : Node_Access) is
558 begin
559 Insert_With_Hint
560 (Dst_Tree => Target,
561 Dst_Hint => Hint,
562 Src_Node => Node,
563 Dst_Node => Hint);
564 end Process;
566 -- Start of processing for Union
568 begin
569 if Target'Address = Source'Address then
570 return;
571 end if;
573 if Target.Busy > 0 then
574 raise Program_Error with
575 "attempt to tamper with cursors (container is busy)";
576 end if;
578 Iterate (Source);
579 end Union;
581 function Union (Left, Right : Tree_Type) return Tree_Type is
582 begin
583 if Left'Address = Right'Address then
584 return Copy (Left);
585 end if;
587 if Left.Length = 0 then
588 return Copy (Right);
589 end if;
591 if Right.Length = 0 then
592 return Copy (Left);
593 end if;
595 declare
596 Tree : Tree_Type := Copy (Left);
598 Hint : Node_Access;
600 procedure Process (Node : Node_Access);
601 pragma Inline (Process);
603 procedure Iterate is
604 new Tree_Operations.Generic_Iteration (Process);
606 -------------
607 -- Process --
608 -------------
610 procedure Process (Node : Node_Access) is
611 begin
612 Insert_With_Hint
613 (Dst_Tree => Tree,
614 Dst_Hint => Hint,
615 Src_Node => Node,
616 Dst_Node => Hint);
617 end Process;
619 -- Start of processing for Union
621 begin
622 Iterate (Right);
623 return Tree;
625 exception
626 when others =>
627 Delete_Tree (Tree.Root);
628 raise;
629 end;
631 end Union;
633 end Ada.Containers.Red_Black_Trees.Generic_Set_Operations;