OSDN Git Service

PR c++/60046
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-btgbso.adb
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-2011, 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 ------------------------------------------------------------------------------
29
30 with System; use type System.Address;
31
32 package body Ada.Containers.Red_Black_Trees.Generic_Bounded_Set_Operations is
33
34    -----------------------
35    -- Local Subprograms --
36    -----------------------
37
38    function Copy (Source : Set_Type) return Set_Type;
39
40    ----------
41    -- Copy --
42    ----------
43
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;
50
51    ----------------
52    -- Difference --
53    ----------------
54
55    procedure Set_Difference (Target : in out Set_Type; Source : Set_Type) is
56       Tgt, Src : Count_Type;
57
58       TN : Nodes_Type renames Target.Nodes;
59       SN : Nodes_Type renames Source.Nodes;
60
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;
67
68          Tree_Operations.Clear_Tree (Target);
69          return;
70       end if;
71
72       if Source.Length = 0 then
73          return;
74       end if;
75
76       if Target.Busy > 0 then
77          raise Program_Error with
78            "attempt to tamper with cursors (container is busy)";
79       end if;
80
81       Tgt := Target.First;
82       Src := Source.First;
83       loop
84          if Tgt = 0 then
85             return;
86          end if;
87
88          if Src = 0 then
89             return;
90          end if;
91
92          if Is_Less (TN (Tgt), SN (Src)) then
93             Tgt := Tree_Operations.Next (Target, Tgt);
94
95          elsif Is_Less (SN (Src), TN (Tgt)) then
96             Src := Tree_Operations.Next (Source, Src);
97
98          else
99             declare
100                X : constant Count_Type := Tgt;
101             begin
102                Tgt := Tree_Operations.Next (Target, Tgt);
103
104                Tree_Operations.Delete_Node_Sans_Free (Target, X);
105                Tree_Operations.Free (Target, X);
106             end;
107
108             Src := Tree_Operations.Next (Source, Src);
109          end if;
110       end loop;
111    end Set_Difference;
112
113    function Set_Difference (Left, Right : Set_Type) return Set_Type is
114       L_Node : Count_Type;
115       R_Node : Count_Type;
116
117       Dst_Node : Count_Type;
118       pragma Warnings (Off, Dst_Node);
119
120    begin
121       if Left'Address = Right'Address then
122          return S : Set_Type (0);  -- Empty set
123       end if;
124
125       if Left.Length = 0 then
126          return S : Set_Type (0);  -- Empty set
127       end if;
128
129       if Right.Length = 0 then
130          return Copy (Left);
131       end if;
132
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;
140
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);
148
149                   L_Node := Tree_Operations.Next (Left, L_Node);
150                end loop;
151
152                return;
153             end if;
154
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);
161
162                L_Node := Tree_Operations.Next (Left, L_Node);
163
164             elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then
165                R_Node := Tree_Operations.Next (Right, R_Node);
166
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;
174
175    ------------------
176    -- Intersection --
177    ------------------
178
179    procedure Set_Intersection
180      (Target : in out Set_Type;
181       Source : Set_Type)
182    is
183       Tgt : Count_Type;
184       Src : Count_Type;
185
186    begin
187       if Target'Address = Source'Address then
188          return;
189       end if;
190
191       if Target.Busy > 0 then
192          raise Program_Error with
193            "attempt to tamper with cursors (container is busy)";
194       end if;
195
196       if Source.Length = 0 then
197          Tree_Operations.Clear_Tree (Target);
198          return;
199       end if;
200
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);
211
212                Tree_Operations.Delete_Node_Sans_Free (Target, X);
213                Tree_Operations.Free (Target, X);
214             end;
215
216          elsif Is_Less (Source.Nodes (Src), Target.Nodes (Tgt)) then
217             Src := Tree_Operations.Next (Source, Src);
218
219          else
220             Tgt := Tree_Operations.Next (Target, Tgt);
221             Src := Tree_Operations.Next (Source, Src);
222          end if;
223       end loop;
224
225       while Tgt /= 0 loop
226          declare
227             X : constant Count_Type := Tgt;
228          begin
229             Tgt := Tree_Operations.Next (Target, Tgt);
230
231             Tree_Operations.Delete_Node_Sans_Free (Target, X);
232             Tree_Operations.Free (Target, X);
233          end;
234       end loop;
235    end Set_Intersection;
236
237    function Set_Intersection (Left, Right : Set_Type) return Set_Type is
238       L_Node : Count_Type;
239       R_Node : Count_Type;
240
241       Dst_Node : Count_Type;
242       pragma Warnings (Off, Dst_Node);
243
244    begin
245       if Left'Address = Right'Address then
246          return Copy (Left);
247       end if;
248
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;
256
257             if R_Node = 0 then
258                return;
259             end if;
260
261             if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then
262                L_Node := Tree_Operations.Next (Left, L_Node);
263
264             elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then
265                R_Node := Tree_Operations.Next (Right, R_Node);
266
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);
273
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;
280
281    ---------------
282    -- Is_Subset --
283    ---------------
284
285    function Set_Subset
286      (Subset : Set_Type;
287       Of_Set : Set_Type) return Boolean
288    is
289       Subset_Node : Count_Type;
290       Set_Node    : Count_Type;
291
292    begin
293       if Subset'Address = Of_Set'Address then
294          return True;
295       end if;
296
297       if Subset.Length > Of_Set.Length then
298          return False;
299       end if;
300
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;
307
308          if Subset_Node = 0 then
309             return True;
310          end if;
311
312          if Is_Less (Subset.Nodes (Subset_Node), Of_Set.Nodes (Set_Node)) then
313             return False;
314          end if;
315
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;
324
325    -------------
326    -- Overlap --
327    -------------
328
329    function Set_Overlap (Left, Right : Set_Type) return Boolean is
330       L_Node : Count_Type;
331       R_Node : Count_Type;
332
333    begin
334       if Left'Address = Right'Address then
335          return Left.Length /= 0;
336       end if;
337
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;
346
347          if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then
348             L_Node := Tree_Operations.Next (Left, L_Node);
349
350          elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then
351             R_Node := Tree_Operations.Next (Right, R_Node);
352
353          else
354             return True;
355          end if;
356       end loop;
357    end Set_Overlap;
358
359    --------------------------
360    -- Symmetric_Difference --
361    --------------------------
362
363    procedure Set_Symmetric_Difference
364      (Target : in out Set_Type;
365       Source : Set_Type)
366    is
367       Tgt : Count_Type;
368       Src : Count_Type;
369
370       New_Tgt_Node : Count_Type;
371       pragma Warnings (Off, New_Tgt_Node);
372
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;
378
379       if Target'Address = Source'Address then
380          Tree_Operations.Clear_Tree (Target);
381          return;
382       end if;
383
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);
394
395                Src := Tree_Operations.Next (Source, Src);
396             end loop;
397
398             return;
399          end if;
400
401          if Src = 0 then
402             return;
403          end if;
404
405          if Is_Less (Target.Nodes (Tgt), Source.Nodes (Src)) then
406             Tgt := Tree_Operations.Next (Target, Tgt);
407
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);
414
415             Src := Tree_Operations.Next (Source, Src);
416
417          else
418             declare
419                X : constant Count_Type := Tgt;
420             begin
421                Tgt := Tree_Operations.Next (Target, Tgt);
422
423                Tree_Operations.Delete_Node_Sans_Free (Target, X);
424                Tree_Operations.Free (Target, X);
425             end;
426
427             Src := Tree_Operations.Next (Source, Src);
428          end if;
429       end loop;
430    end Set_Symmetric_Difference;
431
432    function Set_Symmetric_Difference
433      (Left, Right : Set_Type) return Set_Type
434    is
435       L_Node : Count_Type;
436       R_Node : Count_Type;
437
438       Dst_Node : Count_Type;
439       pragma Warnings (Off, Dst_Node);
440
441    begin
442       if Left'Address = Right'Address then
443          return S : Set_Type (0);  -- Empty set
444       end if;
445
446       if Right.Length = 0 then
447          return Copy (Left);
448       end if;
449
450       if Left.Length = 0 then
451          return Copy (Right);
452       end if;
453
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);
465
466                   R_Node := Tree_Operations.Next (Right, R_Node);
467                end loop;
468
469                return;
470             end if;
471
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);
479
480                   L_Node := Tree_Operations.Next (Left, L_Node);
481                end loop;
482
483                return;
484             end if;
485
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);
492
493                L_Node := Tree_Operations.Next (Left, L_Node);
494
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);
501
502                R_Node := Tree_Operations.Next (Right, R_Node);
503
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;
511
512    -----------
513    -- Union --
514    -----------
515
516    procedure Set_Union (Target : in out Set_Type; Source : Set_Type) is
517       Hint : Count_Type := 0;
518
519       procedure Process (Node : Count_Type);
520       pragma Inline (Process);
521
522       procedure Iterate is new Tree_Operations.Generic_Iteration (Process);
523
524       -------------
525       -- Process --
526       -------------
527
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;
536
537    --  Start of processing for Union
538
539    begin
540       if Target'Address = Source'Address then
541          return;
542       end if;
543
544       if Target.Busy > 0 then
545          raise Program_Error with
546            "attempt to tamper with cursors (container is busy)";
547       end if;
548
549       --  Note that there's no way to decide a priori whether the target has
550       --  enough capacity for the union with source. We cannot simply compare
551       --  the sum of the existing lengths to the capacity of the target,
552       --  because equivalent items from source are not included in the union.
553
554       Iterate (Source);
555    end Set_Union;
556
557    function Set_Union (Left, Right : Set_Type) return Set_Type is
558    begin
559       if Left'Address = Right'Address then
560          return Copy (Left);
561       end if;
562
563       if Left.Length = 0 then
564          return Copy (Right);
565       end if;
566
567       if Right.Length = 0 then
568          return Copy (Left);
569       end if;
570
571       return Result : Set_Type (Left.Length + Right.Length) do
572          Assign (Target => Result, Source => Left);
573
574          Insert_Right : declare
575             Hint : Count_Type := 0;
576
577             procedure Process (Node : Count_Type);
578             pragma Inline (Process);
579
580             procedure Iterate is
581               new Tree_Operations.Generic_Iteration (Process);
582
583             -------------
584             -- Process --
585             -------------
586
587             procedure Process (Node : Count_Type) is
588             begin
589                Insert_With_Hint
590                  (Dst_Set  => Result,
591                   Dst_Hint => Hint,
592                   Src_Node => Right.Nodes (Node),
593                   Dst_Node => Hint);
594             end Process;
595
596          --  Start of processing for Insert_Right
597
598          begin
599             Iterate (Right);
600          end Insert_Right;
601       end return;
602    end Set_Union;
603
604 end Ada.Containers.Red_Black_Trees.Generic_Bounded_Set_Operations;