OSDN Git Service

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