fixing pr42337
[official-gcc.git] / gcc / ada / a-crbtgk.adb
blob59d25be4557139f2fa1233ad3bf63f3ae6351f71
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 ------------------------------------------------------------------------------
30 package body Ada.Containers.Red_Black_Trees.Generic_Keys is
32 package Ops renames Tree_Operations;
34 -------------
35 -- Ceiling --
36 -------------
38 -- AKA Lower_Bound
40 function Ceiling (Tree : Tree_Type; Key : Key_Type) return Node_Access is
41 Y : Node_Access;
42 X : Node_Access;
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;
55 return Y;
56 end Ceiling;
58 ----------
59 -- Find --
60 ----------
62 function Find (Tree : Tree_Type; Key : Key_Type) return Node_Access is
63 Y : Node_Access;
64 X : Node_Access;
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;
77 if Y = null then
78 return null;
79 end if;
81 if Is_Less_Key_Node (Key, Y) then
82 return null;
83 end if;
85 return Y;
86 end Find;
88 -----------
89 -- Floor --
90 -----------
92 function Floor (Tree : Tree_Type; Key : Key_Type) return Node_Access is
93 Y : Node_Access;
94 X : Node_Access;
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;
107 return Y;
108 end Floor;
110 --------------------------------
111 -- Generic_Conditional_Insert --
112 --------------------------------
114 procedure Generic_Conditional_Insert
115 (Tree : in out Tree_Type;
116 Key : Key_Type;
117 Node : out Node_Access;
118 Inserted : out Boolean)
120 Y : Node_Access := null;
121 X : Node_Access := Tree.Root;
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;
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.
136 if Inserted then
137 if Y = Tree.First then
138 Insert_Post (Tree, Y, True, Node);
139 return;
140 end if;
142 Node := Ops.Previous (Y);
144 else
145 Node := Y;
146 end if;
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.
152 if Is_Greater_Key_Node (Key, Node) then
153 Insert_Post (Tree, Y, Inserted, Node);
154 Inserted := True;
155 return;
156 end if;
158 Inserted := False;
159 end Generic_Conditional_Insert;
161 ------------------------------------------
162 -- Generic_Conditional_Insert_With_Hint --
163 ------------------------------------------
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)
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.
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.
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;
195 return;
196 end if;
198 pragma Assert (Tree.Length > 0);
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.
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.
217 if Is_Less_Key_Node (Key, Position) then
218 declare
219 Before : constant Node_Access := Ops.Previous (Position);
221 begin
222 if Before = null then
223 Insert_Post (Tree, Tree.First, True, Node);
224 Inserted := True;
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;
233 Inserted := True;
235 else
236 Conditional_Insert_Sans_Hint (Tree, Key, Node, Inserted);
237 end if;
238 end;
240 return;
241 end if;
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.
249 if Is_Greater_Key_Node (Key, Position) then
250 declare
251 After : constant Node_Access := Ops.Next (Position);
253 begin
254 if After = null then
255 Insert_Post (Tree, Tree.Last, False, Node);
256 Inserted := True;
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;
265 Inserted := True;
267 else
268 Conditional_Insert_Sans_Hint (Tree, Key, Node, Inserted);
269 end if;
270 end;
272 return;
273 end if;
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.
280 Node := Position;
281 Inserted := False;
282 end Generic_Conditional_Insert_With_Hint;
284 -------------------------
285 -- Generic_Insert_Post --
286 -------------------------
288 procedure Generic_Insert_Post
289 (Tree : in out Tree_Type;
290 Y : Node_Access;
291 Before : Boolean;
292 Z : out Node_Access)
294 begin
295 if Tree.Length = Count_Type'Last then
296 raise Constraint_Error with "too many elements";
297 end if;
299 if Tree.Busy > 0 then
300 raise Program_Error with
301 "attempt to tamper with cursors (container is busy)";
302 end if;
304 Z := New_Node;
305 pragma Assert (Z /= null);
306 pragma Assert (Ops.Color (Z) = Red);
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);
314 Tree.Root := Z;
315 Tree.First := Z;
316 Tree.Last := Z;
318 elsif Before then
319 pragma Assert (Ops.Left (Y) = null);
321 Ops.Set_Left (Y, Z);
323 if Y = Tree.First then
324 Tree.First := Z;
325 end if;
327 else
328 pragma Assert (Ops.Right (Y) = null);
330 Ops.Set_Right (Y, Z);
332 if Y = Tree.Last then
333 Tree.Last := Z;
334 end if;
335 end if;
337 Ops.Set_Parent (Z, Y);
338 Ops.Rebalance_For_Insert (Tree, Z);
339 Tree.Length := Tree.Length + 1;
340 end Generic_Insert_Post;
342 -----------------------
343 -- Generic_Iteration --
344 -----------------------
346 procedure Generic_Iteration
347 (Tree : Tree_Type;
348 Key : Key_Type)
350 procedure Iterate (Node : Node_Access);
352 -------------
353 -- Iterate --
354 -------------
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;
373 -- Start of processing for Generic_Iteration
375 begin
376 Iterate (Tree.Root);
377 end Generic_Iteration;
379 -------------------------------
380 -- Generic_Reverse_Iteration --
381 -------------------------------
383 procedure Generic_Reverse_Iteration
384 (Tree : Tree_Type;
385 Key : Key_Type)
387 procedure Iterate (Node : Node_Access);
389 -------------
390 -- Iterate --
391 -------------
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;
410 -- Start of processing for Generic_Reverse_Iteration
412 begin
413 Iterate (Tree.Root);
414 end Generic_Reverse_Iteration;
416 ----------------------------------
417 -- Generic_Unconditional_Insert --
418 ----------------------------------
420 procedure Generic_Unconditional_Insert
421 (Tree : in out Tree_Type;
422 Key : Key_Type;
423 Node : out Node_Access)
425 Y : Node_Access;
426 X : Node_Access;
428 Before : Boolean;
430 begin
431 Y := null;
432 Before := False;
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;
441 Insert_Post (Tree, Y, Before, Node);
442 end Generic_Unconditional_Insert;
444 --------------------------------------------
445 -- Generic_Unconditional_Insert_With_Hint --
446 --------------------------------------------
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)
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.
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.
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.)
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;
484 return;
485 end if;
487 pragma Assert (Tree.Length > 0);
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.
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;
515 return;
516 end if;
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.
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;
538 -----------------
539 -- Upper_Bound --
540 -----------------
542 function Upper_Bound
543 (Tree : Tree_Type;
544 Key : Key_Type) return Node_Access
546 Y : Node_Access;
547 X : Node_Access;
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;
560 return Y;
561 end Upper_Bound;
563 end Ada.Containers.Red_Black_Trees.Generic_Keys;