2010-12-20 Tobias Burnus <burnus@net-b.de>
[official-gcc.git] / gcc / ada / a-btgbso.adb
blobbd4dad4b86d6fa6c00f2517153ee405332b94cf0
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.RED_BLACK_TREES.GENERIC_BOUNDED_SET_OPERATIONS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2010, 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 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with System; use type System.Address;
32 package body Ada.Containers.Red_Black_Trees.Generic_Bounded_Set_Operations is
34 -----------------------
35 -- Local Subprograms --
36 -----------------------
38 function Copy (Source : Set_Type) return Set_Type;
40 ----------
41 -- Copy --
42 ----------
44 function Copy (Source : Set_Type) return Set_Type is
45 begin
46 return Target : Set_Type (Source.Length) do
47 Assign (Target => Target, Source => Source);
48 end return;
49 end Copy;
51 ----------------
52 -- Difference --
53 ----------------
55 procedure Set_Difference (Target : in out Set_Type; Source : Set_Type) is
56 Tgt, Src : Count_Type;
58 TN : Nodes_Type renames Target.Nodes;
59 SN : Nodes_Type renames Source.Nodes;
61 begin
62 if Target'Address = Source'Address then
63 if Target.Busy > 0 then
64 raise Program_Error with
65 "attempt to tamper with cursors (container is busy)";
66 end if;
68 Tree_Operations.Clear_Tree (Target);
69 return;
70 end if;
72 if Source.Length = 0 then
73 return;
74 end if;
76 if Target.Busy > 0 then
77 raise Program_Error with
78 "attempt to tamper with cursors (container is busy)";
79 end if;
81 Tgt := Target.First;
82 Src := Source.First;
83 loop
84 if Tgt = 0 then
85 return;
86 end if;
88 if Src = 0 then
89 return;
90 end if;
92 if Is_Less (TN (Tgt), SN (Src)) then
93 Tgt := Tree_Operations.Next (Target, Tgt);
95 elsif Is_Less (SN (Src), TN (Tgt)) then
96 Src := Tree_Operations.Next (Source, Src);
98 else
99 declare
100 X : constant Count_Type := Tgt;
101 begin
102 Tgt := Tree_Operations.Next (Target, Tgt);
104 Tree_Operations.Delete_Node_Sans_Free (Target, X);
105 Tree_Operations.Free (Target, X);
106 end;
108 Src := Tree_Operations.Next (Source, Src);
109 end if;
110 end loop;
111 end Set_Difference;
113 function Set_Difference (Left, Right : Set_Type) return Set_Type is
114 L_Node : Count_Type;
115 R_Node : Count_Type;
117 Dst_Node : Count_Type;
118 pragma Warnings (Off, Dst_Node);
120 begin
121 if Left'Address = Right'Address then
122 return S : Set_Type (0); -- Empty set
123 end if;
125 if Left.Length = 0 then
126 return S : Set_Type (0); -- Empty set
127 end if;
129 if Right.Length = 0 then
130 return Copy (Left);
131 end if;
133 return Result : Set_Type (Left.Length) do
134 L_Node := Left.First;
135 R_Node := Right.First;
136 loop
137 if L_Node = 0 then
138 return;
139 end if;
141 if R_Node = 0 then
142 while L_Node /= 0 loop
143 Insert_With_Hint
144 (Dst_Set => Result,
145 Dst_Hint => 0,
146 Src_Node => Left.Nodes (L_Node),
147 Dst_Node => Dst_Node);
149 L_Node := Tree_Operations.Next (Left, L_Node);
150 end loop;
152 return;
153 end if;
155 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then
156 Insert_With_Hint
157 (Dst_Set => Result,
158 Dst_Hint => 0,
159 Src_Node => Left.Nodes (L_Node),
160 Dst_Node => Dst_Node);
162 L_Node := Tree_Operations.Next (Left, L_Node);
164 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then
165 R_Node := Tree_Operations.Next (Right, R_Node);
167 else
168 L_Node := Tree_Operations.Next (Left, L_Node);
169 R_Node := Tree_Operations.Next (Right, R_Node);
170 end if;
171 end loop;
172 end return;
173 end Set_Difference;
175 ------------------
176 -- Intersection --
177 ------------------
179 procedure Set_Intersection
180 (Target : in out Set_Type;
181 Source : Set_Type)
183 Tgt : Count_Type;
184 Src : Count_Type;
186 begin
187 if Target'Address = Source'Address then
188 return;
189 end if;
191 if Target.Busy > 0 then
192 raise Program_Error with
193 "attempt to tamper with cursors (container is busy)";
194 end if;
196 if Source.Length = 0 then
197 Tree_Operations.Clear_Tree (Target);
198 return;
199 end if;
201 Tgt := Target.First;
202 Src := Source.First;
203 while Tgt /= 0
204 and then Src /= 0
205 loop
206 if Is_Less (Target.Nodes (Tgt), Source.Nodes (Src)) then
207 declare
208 X : constant Count_Type := Tgt;
209 begin
210 Tgt := Tree_Operations.Next (Target, Tgt);
212 Tree_Operations.Delete_Node_Sans_Free (Target, X);
213 Tree_Operations.Free (Target, X);
214 end;
216 elsif Is_Less (Source.Nodes (Src), Target.Nodes (Tgt)) then
217 Src := Tree_Operations.Next (Source, Src);
219 else
220 Tgt := Tree_Operations.Next (Target, Tgt);
221 Src := Tree_Operations.Next (Source, Src);
222 end if;
223 end loop;
225 while Tgt /= 0 loop
226 declare
227 X : constant Count_Type := Tgt;
228 begin
229 Tgt := Tree_Operations.Next (Target, Tgt);
231 Tree_Operations.Delete_Node_Sans_Free (Target, X);
232 Tree_Operations.Free (Target, X);
233 end;
234 end loop;
235 end Set_Intersection;
237 function Set_Intersection (Left, Right : Set_Type) return Set_Type is
238 L_Node : Count_Type;
239 R_Node : Count_Type;
241 Dst_Node : Count_Type;
242 pragma Warnings (Off, Dst_Node);
244 begin
245 if Left'Address = Right'Address then
246 return Copy (Left);
247 end if;
249 return Result : Set_Type (Count_Type'Min (Left.Length, Right.Length)) do
250 L_Node := Left.First;
251 R_Node := Right.First;
252 loop
253 if L_Node = 0 then
254 return;
255 end if;
257 if R_Node = 0 then
258 return;
259 end if;
261 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then
262 L_Node := Tree_Operations.Next (Left, L_Node);
264 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then
265 R_Node := Tree_Operations.Next (Right, R_Node);
267 else
268 Insert_With_Hint
269 (Dst_Set => Result,
270 Dst_Hint => 0,
271 Src_Node => Left.Nodes (L_Node),
272 Dst_Node => Dst_Node);
274 L_Node := Tree_Operations.Next (Left, L_Node);
275 R_Node := Tree_Operations.Next (Right, R_Node);
276 end if;
277 end loop;
278 end return;
279 end Set_Intersection;
281 ---------------
282 -- Is_Subset --
283 ---------------
285 function Set_Subset
286 (Subset : Set_Type;
287 Of_Set : Set_Type) return Boolean
289 Subset_Node : Count_Type;
290 Set_Node : Count_Type;
292 begin
293 if Subset'Address = Of_Set'Address then
294 return True;
295 end if;
297 if Subset.Length > Of_Set.Length then
298 return False;
299 end if;
301 Subset_Node := Subset.First;
302 Set_Node := Of_Set.First;
303 loop
304 if Set_Node = 0 then
305 return Subset_Node = 0;
306 end if;
308 if Subset_Node = 0 then
309 return True;
310 end if;
312 if Is_Less (Subset.Nodes (Subset_Node), Of_Set.Nodes (Set_Node)) then
313 return False;
314 end if;
316 if Is_Less (Of_Set.Nodes (Set_Node), Subset.Nodes (Subset_Node)) then
317 Set_Node := Tree_Operations.Next (Of_Set, Set_Node);
318 else
319 Set_Node := Tree_Operations.Next (Of_Set, Set_Node);
320 Subset_Node := Tree_Operations.Next (Subset, Subset_Node);
321 end if;
322 end loop;
323 end Set_Subset;
325 -------------
326 -- Overlap --
327 -------------
329 function Set_Overlap (Left, Right : Set_Type) return Boolean is
330 L_Node : Count_Type;
331 R_Node : Count_Type;
333 begin
334 if Left'Address = Right'Address then
335 return Left.Length /= 0;
336 end if;
338 L_Node := Left.First;
339 R_Node := Right.First;
340 loop
341 if L_Node = 0
342 or else R_Node = 0
343 then
344 return False;
345 end if;
347 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then
348 L_Node := Tree_Operations.Next (Left, L_Node);
350 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then
351 R_Node := Tree_Operations.Next (Right, R_Node);
353 else
354 return True;
355 end if;
356 end loop;
357 end Set_Overlap;
359 --------------------------
360 -- Symmetric_Difference --
361 --------------------------
363 procedure Set_Symmetric_Difference
364 (Target : in out Set_Type;
365 Source : Set_Type)
367 Tgt : Count_Type;
368 Src : Count_Type;
370 New_Tgt_Node : Count_Type;
371 pragma Warnings (Off, New_Tgt_Node);
373 begin
374 if Target.Busy > 0 then
375 raise Program_Error with
376 "attempt to tamper with cursors (container is busy)";
377 end if;
379 if Target'Address = Source'Address then
380 Tree_Operations.Clear_Tree (Target);
381 return;
382 end if;
384 Tgt := Target.First;
385 Src := Source.First;
386 loop
387 if Tgt = 0 then
388 while Src /= 0 loop
389 Insert_With_Hint
390 (Dst_Set => Target,
391 Dst_Hint => 0,
392 Src_Node => Source.Nodes (Src),
393 Dst_Node => New_Tgt_Node);
395 Src := Tree_Operations.Next (Source, Src);
396 end loop;
398 return;
399 end if;
401 if Src = 0 then
402 return;
403 end if;
405 if Is_Less (Target.Nodes (Tgt), Source.Nodes (Src)) then
406 Tgt := Tree_Operations.Next (Target, Tgt);
408 elsif Is_Less (Source.Nodes (Src), Target.Nodes (Tgt)) then
409 Insert_With_Hint
410 (Dst_Set => Target,
411 Dst_Hint => Tgt,
412 Src_Node => Source.Nodes (Src),
413 Dst_Node => New_Tgt_Node);
415 Src := Tree_Operations.Next (Source, Src);
417 else
418 declare
419 X : constant Count_Type := Tgt;
420 begin
421 Tgt := Tree_Operations.Next (Target, Tgt);
423 Tree_Operations.Delete_Node_Sans_Free (Target, X);
424 Tree_Operations.Free (Target, X);
425 end;
427 Src := Tree_Operations.Next (Source, Src);
428 end if;
429 end loop;
430 end Set_Symmetric_Difference;
432 function Set_Symmetric_Difference
433 (Left, Right : Set_Type) return Set_Type
435 L_Node : Count_Type;
436 R_Node : Count_Type;
438 Dst_Node : Count_Type;
439 pragma Warnings (Off, Dst_Node);
441 begin
442 if Left'Address = Right'Address then
443 return S : Set_Type (0); -- Empty set
444 end if;
446 if Right.Length = 0 then
447 return Copy (Left);
448 end if;
450 if Left.Length = 0 then
451 return Copy (Right);
452 end if;
454 return Result : Set_Type (Left.Length + Right.Length) do
455 L_Node := Left.First;
456 R_Node := Right.First;
457 loop
458 if L_Node = 0 then
459 while R_Node /= 0 loop
460 Insert_With_Hint
461 (Dst_Set => Result,
462 Dst_Hint => 0,
463 Src_Node => Right.Nodes (R_Node),
464 Dst_Node => Dst_Node);
466 R_Node := Tree_Operations.Next (Right, R_Node);
467 end loop;
469 return;
470 end if;
472 if R_Node = 0 then
473 while L_Node /= 0 loop
474 Insert_With_Hint
475 (Dst_Set => Result,
476 Dst_Hint => 0,
477 Src_Node => Left.Nodes (L_Node),
478 Dst_Node => Dst_Node);
480 L_Node := Tree_Operations.Next (Left, L_Node);
481 end loop;
483 return;
484 end if;
486 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then
487 Insert_With_Hint
488 (Dst_Set => Result,
489 Dst_Hint => 0,
490 Src_Node => Left.Nodes (L_Node),
491 Dst_Node => Dst_Node);
493 L_Node := Tree_Operations.Next (Left, L_Node);
495 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then
496 Insert_With_Hint
497 (Dst_Set => Result,
498 Dst_Hint => 0,
499 Src_Node => Right.Nodes (R_Node),
500 Dst_Node => Dst_Node);
502 R_Node := Tree_Operations.Next (Right, R_Node);
504 else
505 L_Node := Tree_Operations.Next (Left, L_Node);
506 R_Node := Tree_Operations.Next (Right, R_Node);
507 end if;
508 end loop;
509 end return;
510 end Set_Symmetric_Difference;
512 -----------
513 -- Union --
514 -----------
516 procedure Set_Union (Target : in out Set_Type; Source : Set_Type) is
517 Hint : Count_Type := 0;
519 procedure Process (Node : Count_Type);
520 pragma Inline (Process);
522 procedure Iterate is new Tree_Operations.Generic_Iteration (Process);
524 -------------
525 -- Process --
526 -------------
528 procedure Process (Node : Count_Type) is
529 begin
530 Insert_With_Hint
531 (Dst_Set => Target,
532 Dst_Hint => Hint,
533 Src_Node => Source.Nodes (Node),
534 Dst_Node => Hint);
535 end Process;
537 -- Start of processing for Union
539 begin
540 if Target'Address = Source'Address then
541 return;
542 end if;
544 if Target.Busy > 0 then
545 raise Program_Error with
546 "attempt to tamper with cursors (container is busy)";
547 end if;
549 -- Note that there's no way to decide a priori whether the
550 -- target has enough capacity for the union with source.
551 -- We cannot simply compare the sum of the existing lengths
552 -- to the capacity of the target, because equivalent items
553 -- from source are not included in the union.
555 Iterate (Source);
556 end Set_Union;
558 function Set_Union (Left, Right : Set_Type) return Set_Type is
559 begin
560 if Left'Address = Right'Address then
561 return Copy (Left);
562 end if;
564 if Left.Length = 0 then
565 return Copy (Right);
566 end if;
568 if Right.Length = 0 then
569 return Copy (Left);
570 end if;
572 return Result : Set_Type (Left.Length + Right.Length) do
573 Assign (Target => Result, Source => Left);
575 Insert_Right : declare
576 Hint : Count_Type := 0;
578 procedure Process (Node : Count_Type);
579 pragma Inline (Process);
581 procedure Iterate is
582 new Tree_Operations.Generic_Iteration (Process);
584 -------------
585 -- Process --
586 -------------
588 procedure Process (Node : Count_Type) is
589 begin
590 Insert_With_Hint
591 (Dst_Set => Result,
592 Dst_Hint => Hint,
593 Src_Node => Right.Nodes (Node),
594 Dst_Node => Hint);
595 end Process;
597 -- Start of processing for Insert_Right
599 begin
600 Iterate (Right);
601 end Insert_Right;
602 end return;
603 end Set_Union;
605 end Ada.Containers.Red_Black_Trees.Generic_Bounded_Set_Operations;