OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-crbtgk.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT LIBRARY COMPONENTS                          --
4 --                                                                          --
5 --                ADA.CONTAINERS.RED_BLACK_TREES.GENERIC_KEYS               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2004-2008, 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 2,  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.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- This unit was originally developed by Matthew J Heaney.                  --
30 ------------------------------------------------------------------------------
31
32 package body Ada.Containers.Red_Black_Trees.Generic_Keys is
33
34    package Ops renames Tree_Operations;
35
36    -------------
37    -- Ceiling --
38    -------------
39
40    --  AKA Lower_Bound
41
42    function Ceiling (Tree : Tree_Type; Key : Key_Type) return Node_Access is
43       Y : Node_Access;
44       X : Node_Access;
45
46    begin
47       X := Tree.Root;
48       while X /= null loop
49          if Is_Greater_Key_Node (Key, X) then
50             X := Ops.Right (X);
51          else
52             Y := X;
53             X := Ops.Left (X);
54          end if;
55       end loop;
56
57       return Y;
58    end Ceiling;
59
60    ----------
61    -- Find --
62    ----------
63
64    function Find (Tree : Tree_Type; Key  : Key_Type) return Node_Access is
65       Y : Node_Access;
66       X : Node_Access;
67
68    begin
69       X := Tree.Root;
70       while X /= null loop
71          if Is_Greater_Key_Node (Key, X) then
72             X := Ops.Right (X);
73          else
74             Y := X;
75             X := Ops.Left (X);
76          end if;
77       end loop;
78
79       if Y = null then
80          return null;
81       end if;
82
83       if Is_Less_Key_Node (Key, Y) then
84          return null;
85       end if;
86
87       return Y;
88    end Find;
89
90    -----------
91    -- Floor --
92    -----------
93
94    function Floor (Tree : Tree_Type; Key  : Key_Type) return Node_Access is
95       Y : Node_Access;
96       X : Node_Access;
97
98    begin
99       X := Tree.Root;
100       while X /= null loop
101          if Is_Less_Key_Node (Key, X) then
102             X := Ops.Left (X);
103          else
104             Y := X;
105             X := Ops.Right (X);
106          end if;
107       end loop;
108
109       return Y;
110    end Floor;
111
112    --------------------------------
113    -- Generic_Conditional_Insert --
114    --------------------------------
115
116    procedure Generic_Conditional_Insert
117      (Tree     : in out Tree_Type;
118       Key      : Key_Type;
119       Node     : out Node_Access;
120       Inserted : out Boolean)
121    is
122       Y : Node_Access := null;
123       X : Node_Access := Tree.Root;
124
125    begin
126       Inserted := True;
127       while X /= null loop
128          Y := X;
129          Inserted := Is_Less_Key_Node (Key, X);
130
131          if Inserted then
132             X := Ops.Left (X);
133          else
134             X := Ops.Right (X);
135          end if;
136       end loop;
137
138       --  If Inserted is True, then this means either that Tree is
139       --  empty, or there was a least one node (strictly) greater than
140       --  Key. Otherwise, it means that Key is equal to or greater than
141       --  every node.
142
143       if Inserted then
144          if Y = Tree.First then
145             Insert_Post (Tree, Y, True, Node);
146             return;
147          end if;
148
149          Node := Ops.Previous (Y);
150
151       else
152          Node := Y;
153       end if;
154
155       --  Here Node has a value that is less than or equal to Key. We
156       --  now have to resolve whether Key is equal to or greater than
157       --  Node, which determines whether the insertion succeeds.
158
159       if Is_Greater_Key_Node (Key, Node) then
160          Insert_Post (Tree, Y, Inserted, Node);
161          Inserted := True;
162          return;
163       end if;
164
165       Inserted := False;
166    end Generic_Conditional_Insert;
167
168    ------------------------------------------
169    -- Generic_Conditional_Insert_With_Hint --
170    ------------------------------------------
171
172    procedure Generic_Conditional_Insert_With_Hint
173      (Tree      : in out Tree_Type;
174       Position  : Node_Access;
175       Key       : Key_Type;
176       Node      : out Node_Access;
177       Inserted  : out Boolean)
178    is
179    begin
180       --  The purpose of a hint is to avoid a search from the root of
181       --  tree. If we have it hint it means we only need to traverse the
182       --  subtree rooted at the hint to find the nearest neighbor. Note
183       --  that finding the neighbor means merely walking the tree; this
184       --  is not a search and the only comparisons that occur are with
185       --  the hint and its neighbor.
186
187       --  If Position is null, this is interpreted to mean that Key is
188       --  large relative to the nodes in the tree. If the tree is empty,
189       --  or Key is greater than the last node in the tree, then we're
190       --  done; otherwise the hint was "wrong" and we must search.
191
192       if Position = null then  -- largest
193          if Tree.Last = null
194            or else Is_Greater_Key_Node (Key, Tree.Last)
195          then
196             Insert_Post (Tree, Tree.Last, False, Node);
197             Inserted := True;
198          else
199             Conditional_Insert_Sans_Hint (Tree, Key, Node, Inserted);
200          end if;
201
202          return;
203       end if;
204
205       pragma Assert (Tree.Length > 0);
206
207       --  A hint can either name the node that immediately follows Key,
208       --  or immediately precedes Key. We first test whether Key is
209       --  less than the hint, and if so we compare Key to the node that
210       --  precedes the hint. If Key is both less than the hint and
211       --  greater than the hint's preceding neighbor, then we're done;
212       --  otherwise we must search.
213
214       --  Note also that a hint can either be an anterior node or a leaf
215       --  node. A new node is always inserted at the bottom of the tree
216       --  (at least prior to rebalancing), becoming the new left or
217       --  right child of leaf node (which prior to the insertion must
218       --  necessarily be null, since this is a leaf). If the hint names
219       --  an anterior node then its neighbor must be a leaf, and so
220       --  (here) we insert after the neighbor. If the hint names a leaf
221       --  then its neighbor must be anterior and so we insert before the
222       --  hint.
223
224       if Is_Less_Key_Node (Key, Position) then
225          declare
226             Before : constant Node_Access := Ops.Previous (Position);
227
228          begin
229             if Before = null then
230                Insert_Post (Tree, Tree.First, True, Node);
231                Inserted := True;
232
233             elsif Is_Greater_Key_Node (Key, Before) then
234                if Ops.Right (Before) = null then
235                   Insert_Post (Tree, Before, False, Node);
236                else
237                   Insert_Post (Tree, Position, True, Node);
238                end if;
239
240                Inserted := True;
241
242             else
243                Conditional_Insert_Sans_Hint (Tree, Key, Node, Inserted);
244             end if;
245          end;
246
247          return;
248       end if;
249
250       --  We know that Key isn't less than the hint so we try again,
251       --  this time to see if it's greater than the hint. If so we
252       --  compare Key to the node that follows the hint. If Key is both
253       --  greater than the hint and less than the hint's next neighbor,
254       --  then we're done; otherwise we must search.
255
256       if Is_Greater_Key_Node (Key, Position) then
257          declare
258             After : constant Node_Access := Ops.Next (Position);
259
260          begin
261             if After = null then
262                Insert_Post (Tree, Tree.Last, False, Node);
263                Inserted := True;
264
265             elsif Is_Less_Key_Node (Key, After) then
266                if Ops.Right (Position) = null then
267                   Insert_Post (Tree, Position, False, Node);
268                else
269                   Insert_Post (Tree, After, True, Node);
270                end if;
271
272                Inserted := True;
273
274             else
275                Conditional_Insert_Sans_Hint (Tree, Key, Node, Inserted);
276             end if;
277          end;
278
279          return;
280       end if;
281
282       --  We know that Key is neither less than the hint nor greater
283       --  than the hint, and that's the definition of equivalence.
284       --  There's nothing else we need to do, since a search would just
285       --  reach the same conclusion.
286
287       Node := Position;
288       Inserted := False;
289    end Generic_Conditional_Insert_With_Hint;
290
291    -------------------------
292    -- Generic_Insert_Post --
293    -------------------------
294
295    procedure Generic_Insert_Post
296      (Tree   : in out Tree_Type;
297       Y      : Node_Access;
298       Before : Boolean;
299       Z      : out Node_Access)
300    is
301    begin
302       if Tree.Length = Count_Type'Last then
303          raise Constraint_Error with "too many elements";
304       end if;
305
306       if Tree.Busy > 0 then
307          raise Program_Error with
308            "attempt to tamper with cursors (container is busy)";
309       end if;
310
311       Z := New_Node;
312       pragma Assert (Z /= null);
313       pragma Assert (Ops.Color (Z) = Red);
314
315       if Y = null then
316          pragma Assert (Tree.Length = 0);
317          pragma Assert (Tree.Root = null);
318          pragma Assert (Tree.First = null);
319          pragma Assert (Tree.Last = null);
320
321          Tree.Root := Z;
322          Tree.First := Z;
323          Tree.Last := Z;
324
325       elsif Before then
326          pragma Assert (Ops.Left (Y) = null);
327
328          Ops.Set_Left (Y, Z);
329
330          if Y = Tree.First then
331             Tree.First := Z;
332          end if;
333
334       else
335          pragma Assert (Ops.Right (Y) = null);
336
337          Ops.Set_Right (Y, Z);
338
339          if Y = Tree.Last then
340             Tree.Last := Z;
341          end if;
342       end if;
343
344       Ops.Set_Parent (Z, Y);
345       Ops.Rebalance_For_Insert (Tree, Z);
346       Tree.Length := Tree.Length + 1;
347    end Generic_Insert_Post;
348
349    -----------------------
350    -- Generic_Iteration --
351    -----------------------
352
353    procedure Generic_Iteration
354      (Tree : Tree_Type;
355       Key  : Key_Type)
356    is
357       procedure Iterate (Node : Node_Access);
358
359       -------------
360       -- Iterate --
361       -------------
362
363       procedure Iterate (Node : Node_Access) is
364          N : Node_Access;
365       begin
366          N := Node;
367          while N /= null loop
368             if Is_Less_Key_Node (Key, N) then
369                N := Ops.Left (N);
370             elsif Is_Greater_Key_Node (Key, N) then
371                N := Ops.Right (N);
372             else
373                Iterate (Ops.Left (N));
374                Process (N);
375                N := Ops.Right (N);
376             end if;
377          end loop;
378       end Iterate;
379
380    --  Start of processing for Generic_Iteration
381
382    begin
383       Iterate (Tree.Root);
384    end Generic_Iteration;
385
386    -------------------------------
387    -- Generic_Reverse_Iteration --
388    -------------------------------
389
390    procedure Generic_Reverse_Iteration
391      (Tree : Tree_Type;
392       Key  : Key_Type)
393    is
394       procedure Iterate (Node : Node_Access);
395
396       -------------
397       -- Iterate --
398       -------------
399
400       procedure Iterate (Node : Node_Access) is
401          N : Node_Access;
402       begin
403          N := Node;
404          while N /= null loop
405             if Is_Less_Key_Node (Key, N) then
406                N := Ops.Left (N);
407             elsif Is_Greater_Key_Node (Key, N) then
408                N := Ops.Right (N);
409             else
410                Iterate (Ops.Right (N));
411                Process (N);
412                N := Ops.Left (N);
413             end if;
414          end loop;
415       end Iterate;
416
417    --  Start of processing for Generic_Reverse_Iteration
418
419    begin
420       Iterate (Tree.Root);
421    end Generic_Reverse_Iteration;
422
423    ----------------------------------
424    -- Generic_Unconditional_Insert --
425    ----------------------------------
426
427    procedure Generic_Unconditional_Insert
428      (Tree : in out Tree_Type;
429       Key  : Key_Type;
430       Node : out Node_Access)
431    is
432       Y : Node_Access;
433       X : Node_Access;
434
435       Before : Boolean;
436
437    begin
438       Y := null;
439       Before := False;
440
441       X := Tree.Root;
442       while X /= null loop
443          Y := X;
444          Before := Is_Less_Key_Node (Key, X);
445
446          if Before then
447             X := Ops.Left (X);
448          else
449             X := Ops.Right (X);
450          end if;
451       end loop;
452
453       Insert_Post (Tree, Y, Before, Node);
454    end Generic_Unconditional_Insert;
455
456    --------------------------------------------
457    -- Generic_Unconditional_Insert_With_Hint --
458    --------------------------------------------
459
460    procedure Generic_Unconditional_Insert_With_Hint
461      (Tree : in out Tree_Type;
462       Hint : Node_Access;
463       Key  : Key_Type;
464       Node : out Node_Access)
465    is
466    begin
467       --  There are fewer constraints for an unconditional insertion
468       --  than for a conditional insertion, since we allow duplicate
469       --  keys. So instead of having to check (say) whether Key is
470       --  (strictly) greater than the hint's previous neighbor, here we
471       --  allow Key to be equal to or greater than the previous node.
472
473       --  There is the issue of what to do if Key is equivalent to the
474       --  hint. Does the new node get inserted before or after the hint?
475       --  We decide that it gets inserted after the hint, reasoning that
476       --  this is consistent with behavior for non-hint insertion, which
477       --  inserts a new node after existing nodes with equivalent keys.
478
479       --  First we check whether the hint is null, which is interpreted
480       --  to mean that Key is large relative to existing nodes.
481       --  Following our rule above, if Key is equal to or greater than
482       --  the last node, then we insert the new node immediately after
483       --  last. (We don't have an operation for testing whether a key is
484       --  "equal to or greater than" a node, so we must say instead "not
485       --  less than", which is equivalent.)
486
487       if Hint = null then  -- largest
488          if Tree.Last = null then
489             Insert_Post (Tree, null, False, Node);
490          elsif Is_Less_Key_Node (Key, Tree.Last) then
491             Unconditional_Insert_Sans_Hint (Tree, Key, Node);
492          else
493             Insert_Post (Tree, Tree.Last, False, Node);
494          end if;
495
496          return;
497       end if;
498
499       pragma Assert (Tree.Length > 0);
500
501       --  We decide here whether to insert the new node prior to the
502       --  hint. Key could be equivalent to the hint, so in theory we
503       --  could write the following test as "not greater than" (same as
504       --  "less than or equal to"). If Key were equivalent to the hint,
505       --  that would mean that the new node gets inserted before an
506       --  equivalent node. That wouldn't break any container invariants,
507       --  but our rule above says that new nodes always get inserted
508       --  after equivalent nodes. So here we test whether Key is both
509       --  less than the hint and equal to or greater than the hint's
510       --  previous neighbor, and if so insert it before the hint.
511
512       if Is_Less_Key_Node (Key, Hint) then
513          declare
514             Before : constant Node_Access := Ops.Previous (Hint);
515          begin
516             if Before = null then
517                Insert_Post (Tree, Hint, True, Node);
518             elsif Is_Less_Key_Node (Key, Before) then
519                Unconditional_Insert_Sans_Hint (Tree, Key, Node);
520             elsif Ops.Right (Before) = null then
521                Insert_Post (Tree, Before, False, Node);
522             else
523                Insert_Post (Tree, Hint, True, Node);
524             end if;
525          end;
526
527          return;
528       end if;
529
530       --  We know that Key isn't less than the hint, so it must be equal
531       --  or greater. So we just test whether Key is less than or equal
532       --  to (same as "not greater than") the hint's next neighbor, and
533       --  if so insert it after the hint.
534
535       declare
536          After : constant Node_Access := Ops.Next (Hint);
537       begin
538          if After = null then
539             Insert_Post (Tree, Hint, False, Node);
540          elsif Is_Greater_Key_Node (Key, After) then
541             Unconditional_Insert_Sans_Hint (Tree, Key, Node);
542          elsif Ops.Right (Hint) = null then
543             Insert_Post (Tree, Hint, False, Node);
544          else
545             Insert_Post (Tree, After, True, Node);
546          end if;
547       end;
548    end Generic_Unconditional_Insert_With_Hint;
549
550    -----------------
551    -- Upper_Bound --
552    -----------------
553
554    function Upper_Bound
555      (Tree : Tree_Type;
556       Key  : Key_Type) return Node_Access
557    is
558       Y : Node_Access;
559       X : Node_Access;
560
561    begin
562       X := Tree.Root;
563       while X /= null loop
564          if Is_Less_Key_Node (Key, X) then
565             Y := X;
566             X := Ops.Left (X);
567          else
568             X := Ops.Right (X);
569          end if;
570       end loop;
571
572       return Y;
573    end Upper_Bound;
574
575 end Ada.Containers.Red_Black_Trees.Generic_Keys;