OSDN Git Service

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