PR rtl-optimization/79386
[official-gcc.git] / gcc / ada / a-comutr.adb
blob7804b0f574f4fee4461706b5599bd502e9689e08
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . M U L T I W A Y _ T R E E S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2016, 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 with Ada.Unchecked_Conversion;
31 with Ada.Unchecked_Deallocation;
33 with System; use type System.Address;
35 package body Ada.Containers.Multiway_Trees is
37 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
38 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
39 -- See comment in Ada.Containers.Helpers
41 --------------------
42 -- Root_Iterator --
43 --------------------
45 type Root_Iterator is abstract new Limited_Controlled and
46 Tree_Iterator_Interfaces.Forward_Iterator with
47 record
48 Container : Tree_Access;
49 Subtree : Tree_Node_Access;
50 end record
51 with Disable_Controlled => not T_Check;
53 overriding procedure Finalize (Object : in out Root_Iterator);
55 -----------------------
56 -- Subtree_Iterator --
57 -----------------------
59 -- ??? these headers are a bit odd, but for sure they do not substitute
60 -- for documenting things, what *is* a Subtree_Iterator?
62 type Subtree_Iterator is new Root_Iterator with null record;
64 overriding function First (Object : Subtree_Iterator) return Cursor;
66 overriding function Next
67 (Object : Subtree_Iterator;
68 Position : Cursor) return Cursor;
70 ---------------------
71 -- Child_Iterator --
72 ---------------------
74 type Child_Iterator is new Root_Iterator and
75 Tree_Iterator_Interfaces.Reversible_Iterator with null record
76 with Disable_Controlled => not T_Check;
78 overriding function First (Object : Child_Iterator) return Cursor;
80 overriding function Next
81 (Object : Child_Iterator;
82 Position : Cursor) return Cursor;
84 overriding function Last (Object : Child_Iterator) return Cursor;
86 overriding function Previous
87 (Object : Child_Iterator;
88 Position : Cursor) return Cursor;
90 -----------------------
91 -- Local Subprograms --
92 -----------------------
94 function Root_Node (Container : Tree) return Tree_Node_Access;
96 procedure Deallocate_Node is
97 new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
99 procedure Deallocate_Children
100 (Subtree : Tree_Node_Access;
101 Count : in out Count_Type);
103 procedure Deallocate_Subtree
104 (Subtree : in out Tree_Node_Access;
105 Count : in out Count_Type);
107 function Equal_Children
108 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
110 function Equal_Subtree
111 (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
113 procedure Iterate_Children
114 (Container : Tree_Access;
115 Subtree : Tree_Node_Access;
116 Process : not null access procedure (Position : Cursor));
118 procedure Iterate_Subtree
119 (Container : Tree_Access;
120 Subtree : Tree_Node_Access;
121 Process : not null access procedure (Position : Cursor));
123 procedure Copy_Children
124 (Source : Children_Type;
125 Parent : Tree_Node_Access;
126 Count : in out Count_Type);
128 procedure Copy_Subtree
129 (Source : Tree_Node_Access;
130 Parent : Tree_Node_Access;
131 Target : out Tree_Node_Access;
132 Count : in out Count_Type);
134 function Find_In_Children
135 (Subtree : Tree_Node_Access;
136 Item : Element_Type) return Tree_Node_Access;
138 function Find_In_Subtree
139 (Subtree : Tree_Node_Access;
140 Item : Element_Type) return Tree_Node_Access;
142 function Child_Count (Children : Children_Type) return Count_Type;
144 function Subtree_Node_Count
145 (Subtree : Tree_Node_Access) return Count_Type;
147 function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
149 procedure Remove_Subtree (Subtree : Tree_Node_Access);
151 procedure Insert_Subtree_Node
152 (Subtree : Tree_Node_Access;
153 Parent : Tree_Node_Access;
154 Before : Tree_Node_Access);
156 procedure Insert_Subtree_List
157 (First : Tree_Node_Access;
158 Last : Tree_Node_Access;
159 Parent : Tree_Node_Access;
160 Before : Tree_Node_Access);
162 procedure Splice_Children
163 (Target_Parent : Tree_Node_Access;
164 Before : Tree_Node_Access;
165 Source_Parent : Tree_Node_Access);
167 ---------
168 -- "=" --
169 ---------
171 function "=" (Left, Right : Tree) return Boolean is
172 begin
173 return Equal_Children (Root_Node (Left), Root_Node (Right));
174 end "=";
176 ------------
177 -- Adjust --
178 ------------
180 procedure Adjust (Container : in out Tree) is
181 Source : constant Children_Type := Container.Root.Children;
182 Source_Count : constant Count_Type := Container.Count;
183 Target_Count : Count_Type;
185 begin
186 -- We first restore the target container to its default-initialized
187 -- state, before we attempt any allocation, to ensure that invariants
188 -- are preserved in the event that the allocation fails.
190 Container.Root.Children := Children_Type'(others => null);
191 Zero_Counts (Container.TC);
192 Container.Count := 0;
194 -- Copy_Children returns a count of the number of nodes that it
195 -- allocates, but it works by incrementing the value that is passed
196 -- in. We must therefore initialize the count value before calling
197 -- Copy_Children.
199 Target_Count := 0;
201 -- Now we attempt the allocation of subtrees. The invariants are
202 -- satisfied even if the allocation fails.
204 Copy_Children (Source, Root_Node (Container), Target_Count);
205 pragma Assert (Target_Count = Source_Count);
207 Container.Count := Source_Count;
208 end Adjust;
210 -------------------
211 -- Ancestor_Find --
212 -------------------
214 function Ancestor_Find
215 (Position : Cursor;
216 Item : Element_Type) return Cursor
218 R, N : Tree_Node_Access;
220 begin
221 if Checks and then Position = No_Element then
222 raise Constraint_Error with "Position cursor has no element";
223 end if;
225 -- Commented-out pending official ruling from ARG. ???
227 -- if Position.Container /= Container'Unrestricted_Access then
228 -- raise Program_Error with "Position cursor not in container";
229 -- end if;
231 -- AI-0136 says to raise PE if Position equals the root node. This does
232 -- not seem correct, as this value is just the limiting condition of the
233 -- search. For now we omit this check, pending a ruling from the ARG.???
235 -- if Checks and then Is_Root (Position) then
236 -- raise Program_Error with "Position cursor designates root";
237 -- end if;
239 R := Root_Node (Position.Container.all);
240 N := Position.Node;
241 while N /= R loop
242 if N.Element = Item then
243 return Cursor'(Position.Container, N);
244 end if;
246 N := N.Parent;
247 end loop;
249 return No_Element;
250 end Ancestor_Find;
252 ------------------
253 -- Append_Child --
254 ------------------
256 procedure Append_Child
257 (Container : in out Tree;
258 Parent : Cursor;
259 New_Item : Element_Type;
260 Count : Count_Type := 1)
262 First : Tree_Node_Access;
263 Last : Tree_Node_Access;
265 begin
266 if Checks and then Parent = No_Element then
267 raise Constraint_Error with "Parent cursor has no element";
268 end if;
270 if Checks and then Parent.Container /= Container'Unrestricted_Access then
271 raise Program_Error with "Parent cursor not in container";
272 end if;
274 if Count = 0 then
275 return;
276 end if;
278 TC_Check (Container.TC);
280 First := new Tree_Node_Type'(Parent => Parent.Node,
281 Element => New_Item,
282 others => <>);
284 Last := First;
285 for J in Count_Type'(2) .. Count loop
287 -- Reclaim other nodes if Storage_Error. ???
289 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
290 Prev => Last,
291 Element => New_Item,
292 others => <>);
294 Last := Last.Next;
295 end loop;
297 Insert_Subtree_List
298 (First => First,
299 Last => Last,
300 Parent => Parent.Node,
301 Before => null); -- null means "insert at end of list"
303 -- In order for operation Node_Count to complete in O(1) time, we cache
304 -- the count value. Here we increment the total count by the number of
305 -- nodes we just inserted.
307 Container.Count := Container.Count + Count;
308 end Append_Child;
310 ------------
311 -- Assign --
312 ------------
314 procedure Assign (Target : in out Tree; Source : Tree) is
315 Source_Count : constant Count_Type := Source.Count;
316 Target_Count : Count_Type;
318 begin
319 if Target'Address = Source'Address then
320 return;
321 end if;
323 Target.Clear; -- checks busy bit
325 -- Copy_Children returns the number of nodes that it allocates, but it
326 -- does this by incrementing the count value passed in, so we must
327 -- initialize the count before calling Copy_Children.
329 Target_Count := 0;
331 -- Note that Copy_Children inserts the newly-allocated children into
332 -- their parent list only after the allocation of all the children has
333 -- succeeded. This preserves invariants even if the allocation fails.
335 Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
336 pragma Assert (Target_Count = Source_Count);
338 Target.Count := Source_Count;
339 end Assign;
341 -----------------
342 -- Child_Count --
343 -----------------
345 function Child_Count (Parent : Cursor) return Count_Type is
346 begin
347 return (if Parent = No_Element
348 then 0 else Child_Count (Parent.Node.Children));
349 end Child_Count;
351 function Child_Count (Children : Children_Type) return Count_Type is
352 Result : Count_Type;
353 Node : Tree_Node_Access;
355 begin
356 Result := 0;
357 Node := Children.First;
358 while Node /= null loop
359 Result := Result + 1;
360 Node := Node.Next;
361 end loop;
363 return Result;
364 end Child_Count;
366 -----------------
367 -- Child_Depth --
368 -----------------
370 function Child_Depth (Parent, Child : Cursor) return Count_Type is
371 Result : Count_Type;
372 N : Tree_Node_Access;
374 begin
375 if Checks and then Parent = No_Element then
376 raise Constraint_Error with "Parent cursor has no element";
377 end if;
379 if Checks and then Child = No_Element then
380 raise Constraint_Error with "Child cursor has no element";
381 end if;
383 if Checks and then Parent.Container /= Child.Container then
384 raise Program_Error with "Parent and Child in different containers";
385 end if;
387 Result := 0;
388 N := Child.Node;
389 while N /= Parent.Node loop
390 Result := Result + 1;
391 N := N.Parent;
393 if Checks and then N = null then
394 raise Program_Error with "Parent is not ancestor of Child";
395 end if;
396 end loop;
398 return Result;
399 end Child_Depth;
401 -----------
402 -- Clear --
403 -----------
405 procedure Clear (Container : in out Tree) is
406 Container_Count, Children_Count : Count_Type;
408 begin
409 TC_Check (Container.TC);
411 -- We first set the container count to 0, in order to preserve
412 -- invariants in case the deallocation fails. (This works because
413 -- Deallocate_Children immediately removes the children from their
414 -- parent, and then does the actual deallocation.)
416 Container_Count := Container.Count;
417 Container.Count := 0;
419 -- Deallocate_Children returns the number of nodes that it deallocates,
420 -- but it does this by incrementing the count value that is passed in,
421 -- so we must first initialize the count return value before calling it.
423 Children_Count := 0;
425 -- See comment above. Deallocate_Children immediately removes the
426 -- children list from their parent node (here, the root of the tree),
427 -- and only after that does it attempt the actual deallocation. So even
428 -- if the deallocation fails, the representation invariants for the tree
429 -- are preserved.
431 Deallocate_Children (Root_Node (Container), Children_Count);
432 pragma Assert (Children_Count = Container_Count);
433 end Clear;
435 ------------------------
436 -- Constant_Reference --
437 ------------------------
439 function Constant_Reference
440 (Container : aliased Tree;
441 Position : Cursor) return Constant_Reference_Type
443 begin
444 if Checks and then Position.Container = null then
445 raise Constraint_Error with
446 "Position cursor has no element";
447 end if;
449 if Checks and then Position.Container /= Container'Unrestricted_Access
450 then
451 raise Program_Error with
452 "Position cursor designates wrong container";
453 end if;
455 if Checks and then Position.Node = Root_Node (Container) then
456 raise Program_Error with "Position cursor designates root";
457 end if;
459 -- Implement Vet for multiway tree???
460 -- pragma Assert (Vet (Position),
461 -- "Position cursor in Constant_Reference is bad");
463 declare
464 C : Tree renames Position.Container.all;
465 TC : constant Tamper_Counts_Access :=
466 C.TC'Unrestricted_Access;
467 begin
468 return R : constant Constant_Reference_Type :=
469 (Element => Position.Node.Element'Access,
470 Control => (Controlled with TC))
472 Lock (TC.all);
473 end return;
474 end;
475 end Constant_Reference;
477 --------------
478 -- Contains --
479 --------------
481 function Contains
482 (Container : Tree;
483 Item : Element_Type) return Boolean
485 begin
486 return Find (Container, Item) /= No_Element;
487 end Contains;
489 ----------
490 -- Copy --
491 ----------
493 function Copy (Source : Tree) return Tree is
494 begin
495 return Target : Tree do
496 Copy_Children
497 (Source => Source.Root.Children,
498 Parent => Root_Node (Target),
499 Count => Target.Count);
501 pragma Assert (Target.Count = Source.Count);
502 end return;
503 end Copy;
505 -------------------
506 -- Copy_Children --
507 -------------------
509 procedure Copy_Children
510 (Source : Children_Type;
511 Parent : Tree_Node_Access;
512 Count : in out Count_Type)
514 pragma Assert (Parent /= null);
515 pragma Assert (Parent.Children.First = null);
516 pragma Assert (Parent.Children.Last = null);
518 CC : Children_Type;
519 C : Tree_Node_Access;
521 begin
522 -- We special-case the first allocation, in order to establish the
523 -- representation invariants for type Children_Type.
525 C := Source.First;
527 if C = null then
528 return;
529 end if;
531 Copy_Subtree
532 (Source => C,
533 Parent => Parent,
534 Target => CC.First,
535 Count => Count);
537 CC.Last := CC.First;
539 -- The representation invariants for the Children_Type list have been
540 -- established, so we can now copy the remaining children of Source.
542 C := C.Next;
543 while C /= null loop
544 Copy_Subtree
545 (Source => C,
546 Parent => Parent,
547 Target => CC.Last.Next,
548 Count => Count);
550 CC.Last.Next.Prev := CC.Last;
551 CC.Last := CC.Last.Next;
553 C := C.Next;
554 end loop;
556 -- Add the newly-allocated children to their parent list only after the
557 -- allocation has succeeded, so as to preserve invariants of the parent.
559 Parent.Children := CC;
560 end Copy_Children;
562 ------------------
563 -- Copy_Subtree --
564 ------------------
566 procedure Copy_Subtree
567 (Target : in out Tree;
568 Parent : Cursor;
569 Before : Cursor;
570 Source : Cursor)
572 Target_Subtree : Tree_Node_Access;
573 Target_Count : Count_Type;
575 begin
576 if Checks and then Parent = No_Element then
577 raise Constraint_Error with "Parent cursor has no element";
578 end if;
580 if Checks and then Parent.Container /= Target'Unrestricted_Access then
581 raise Program_Error with "Parent cursor not in container";
582 end if;
584 if Before /= No_Element then
585 if Checks and then Before.Container /= Target'Unrestricted_Access then
586 raise Program_Error with "Before cursor not in container";
587 end if;
589 if Checks and then Before.Node.Parent /= Parent.Node then
590 raise Constraint_Error with "Before cursor not child of Parent";
591 end if;
592 end if;
594 if Source = No_Element then
595 return;
596 end if;
598 if Checks and then Is_Root (Source) then
599 raise Constraint_Error with "Source cursor designates root";
600 end if;
602 -- Copy_Subtree returns a count of the number of nodes that it
603 -- allocates, but it works by incrementing the value that is passed
604 -- in. We must therefore initialize the count value before calling
605 -- Copy_Subtree.
607 Target_Count := 0;
609 Copy_Subtree
610 (Source => Source.Node,
611 Parent => Parent.Node,
612 Target => Target_Subtree,
613 Count => Target_Count);
615 pragma Assert (Target_Subtree /= null);
616 pragma Assert (Target_Subtree.Parent = Parent.Node);
617 pragma Assert (Target_Count >= 1);
619 Insert_Subtree_Node
620 (Subtree => Target_Subtree,
621 Parent => Parent.Node,
622 Before => Before.Node);
624 -- In order for operation Node_Count to complete in O(1) time, we cache
625 -- the count value. Here we increment the total count by the number of
626 -- nodes we just inserted.
628 Target.Count := Target.Count + Target_Count;
629 end Copy_Subtree;
631 procedure Copy_Subtree
632 (Source : Tree_Node_Access;
633 Parent : Tree_Node_Access;
634 Target : out Tree_Node_Access;
635 Count : in out Count_Type)
637 begin
638 Target := new Tree_Node_Type'(Element => Source.Element,
639 Parent => Parent,
640 others => <>);
642 Count := Count + 1;
644 Copy_Children
645 (Source => Source.Children,
646 Parent => Target,
647 Count => Count);
648 end Copy_Subtree;
650 -------------------------
651 -- Deallocate_Children --
652 -------------------------
654 procedure Deallocate_Children
655 (Subtree : Tree_Node_Access;
656 Count : in out Count_Type)
658 pragma Assert (Subtree /= null);
660 CC : Children_Type := Subtree.Children;
661 C : Tree_Node_Access;
663 begin
664 -- We immediately remove the children from their parent, in order to
665 -- preserve invariants in case the deallocation fails.
667 Subtree.Children := Children_Type'(others => null);
669 while CC.First /= null loop
670 C := CC.First;
671 CC.First := C.Next;
673 Deallocate_Subtree (C, Count);
674 end loop;
675 end Deallocate_Children;
677 ------------------------
678 -- Deallocate_Subtree --
679 ------------------------
681 procedure Deallocate_Subtree
682 (Subtree : in out Tree_Node_Access;
683 Count : in out Count_Type)
685 begin
686 Deallocate_Children (Subtree, Count);
687 Deallocate_Node (Subtree);
688 Count := Count + 1;
689 end Deallocate_Subtree;
691 ---------------------
692 -- Delete_Children --
693 ---------------------
695 procedure Delete_Children
696 (Container : in out Tree;
697 Parent : Cursor)
699 Count : Count_Type;
701 begin
702 if Checks and then Parent = No_Element then
703 raise Constraint_Error with "Parent cursor has no element";
704 end if;
706 if Checks and then Parent.Container /= Container'Unrestricted_Access then
707 raise Program_Error with "Parent cursor not in container";
708 end if;
710 TC_Check (Container.TC);
712 -- Deallocate_Children returns a count of the number of nodes that it
713 -- deallocates, but it works by incrementing the value that is passed
714 -- in. We must therefore initialize the count value before calling
715 -- Deallocate_Children.
717 Count := 0;
719 Deallocate_Children (Parent.Node, Count);
720 pragma Assert (Count <= Container.Count);
722 Container.Count := Container.Count - Count;
723 end Delete_Children;
725 -----------------
726 -- Delete_Leaf --
727 -----------------
729 procedure Delete_Leaf
730 (Container : in out Tree;
731 Position : in out Cursor)
733 X : Tree_Node_Access;
735 begin
736 if Checks and then Position = No_Element then
737 raise Constraint_Error with "Position cursor has no element";
738 end if;
740 if Checks and then Position.Container /= Container'Unrestricted_Access
741 then
742 raise Program_Error with "Position cursor not in container";
743 end if;
745 if Checks and then Is_Root (Position) then
746 raise Program_Error with "Position cursor designates root";
747 end if;
749 if Checks and then not Is_Leaf (Position) then
750 raise Constraint_Error with "Position cursor does not designate leaf";
751 end if;
753 TC_Check (Container.TC);
755 X := Position.Node;
756 Position := No_Element;
758 -- Restore represention invariants before attempting the actual
759 -- deallocation.
761 Remove_Subtree (X);
762 Container.Count := Container.Count - 1;
764 -- It is now safe to attempt the deallocation. This leaf node has been
765 -- disassociated from the tree, so even if the deallocation fails,
766 -- representation invariants will remain satisfied.
768 Deallocate_Node (X);
769 end Delete_Leaf;
771 --------------------
772 -- Delete_Subtree --
773 --------------------
775 procedure Delete_Subtree
776 (Container : in out Tree;
777 Position : in out Cursor)
779 X : Tree_Node_Access;
780 Count : Count_Type;
782 begin
783 if Checks and then Position = No_Element then
784 raise Constraint_Error with "Position cursor has no element";
785 end if;
787 if Checks and then Position.Container /= Container'Unrestricted_Access
788 then
789 raise Program_Error with "Position cursor not in container";
790 end if;
792 if Checks and then Is_Root (Position) then
793 raise Program_Error with "Position cursor designates root";
794 end if;
796 TC_Check (Container.TC);
798 X := Position.Node;
799 Position := No_Element;
801 -- Here is one case where a deallocation failure can result in the
802 -- violation of a representation invariant. We disassociate the subtree
803 -- from the tree now, but we only decrement the total node count after
804 -- we attempt the deallocation. However, if the deallocation fails, the
805 -- total node count will not get decremented.
807 -- One way around this dilemma is to count the nodes in the subtree
808 -- before attempt to delete the subtree, but that is an O(n) operation,
809 -- so it does not seem worth it.
811 -- Perhaps this is much ado about nothing, since the only way
812 -- deallocation can fail is if Controlled Finalization fails: this
813 -- propagates Program_Error so all bets are off anyway. ???
815 Remove_Subtree (X);
817 -- Deallocate_Subtree returns a count of the number of nodes that it
818 -- deallocates, but it works by incrementing the value that is passed
819 -- in. We must therefore initialize the count value before calling
820 -- Deallocate_Subtree.
822 Count := 0;
824 Deallocate_Subtree (X, Count);
825 pragma Assert (Count <= Container.Count);
827 -- See comments above. We would prefer to do this sooner, but there's no
828 -- way to satisfy that goal without a potentially severe execution
829 -- penalty.
831 Container.Count := Container.Count - Count;
832 end Delete_Subtree;
834 -----------
835 -- Depth --
836 -----------
838 function Depth (Position : Cursor) return Count_Type is
839 Result : Count_Type;
840 N : Tree_Node_Access;
842 begin
843 Result := 0;
844 N := Position.Node;
845 while N /= null loop
846 N := N.Parent;
847 Result := Result + 1;
848 end loop;
850 return Result;
851 end Depth;
853 -------------
854 -- Element --
855 -------------
857 function Element (Position : Cursor) return Element_Type is
858 begin
859 if Checks and then Position.Container = null then
860 raise Constraint_Error with "Position cursor has no element";
861 end if;
863 if Checks and then Position.Node = Root_Node (Position.Container.all)
864 then
865 raise Program_Error with "Position cursor designates root";
866 end if;
868 return Position.Node.Element;
869 end Element;
871 --------------------
872 -- Equal_Children --
873 --------------------
875 function Equal_Children
876 (Left_Subtree : Tree_Node_Access;
877 Right_Subtree : Tree_Node_Access) return Boolean
879 Left_Children : Children_Type renames Left_Subtree.Children;
880 Right_Children : Children_Type renames Right_Subtree.Children;
882 L, R : Tree_Node_Access;
884 begin
885 if Child_Count (Left_Children) /= Child_Count (Right_Children) then
886 return False;
887 end if;
889 L := Left_Children.First;
890 R := Right_Children.First;
891 while L /= null loop
892 if not Equal_Subtree (L, R) then
893 return False;
894 end if;
896 L := L.Next;
897 R := R.Next;
898 end loop;
900 return True;
901 end Equal_Children;
903 -------------------
904 -- Equal_Subtree --
905 -------------------
907 function Equal_Subtree
908 (Left_Position : Cursor;
909 Right_Position : Cursor) return Boolean
911 begin
912 if Checks and then Left_Position = No_Element then
913 raise Constraint_Error with "Left cursor has no element";
914 end if;
916 if Checks and then Right_Position = No_Element then
917 raise Constraint_Error with "Right cursor has no element";
918 end if;
920 if Left_Position = Right_Position then
921 return True;
922 end if;
924 if Is_Root (Left_Position) then
925 if not Is_Root (Right_Position) then
926 return False;
927 end if;
929 return Equal_Children (Left_Position.Node, Right_Position.Node);
930 end if;
932 if Is_Root (Right_Position) then
933 return False;
934 end if;
936 return Equal_Subtree (Left_Position.Node, Right_Position.Node);
937 end Equal_Subtree;
939 function Equal_Subtree
940 (Left_Subtree : Tree_Node_Access;
941 Right_Subtree : Tree_Node_Access) return Boolean
943 begin
944 if Left_Subtree.Element /= Right_Subtree.Element then
945 return False;
946 end if;
948 return Equal_Children (Left_Subtree, Right_Subtree);
949 end Equal_Subtree;
951 --------------
952 -- Finalize --
953 --------------
955 procedure Finalize (Object : in out Root_Iterator) is
956 begin
957 Unbusy (Object.Container.TC);
958 end Finalize;
960 ----------
961 -- Find --
962 ----------
964 function Find
965 (Container : Tree;
966 Item : Element_Type) return Cursor
968 N : constant Tree_Node_Access :=
969 Find_In_Children (Root_Node (Container), Item);
970 begin
971 if N = null then
972 return No_Element;
973 else
974 return Cursor'(Container'Unrestricted_Access, N);
975 end if;
976 end Find;
978 -----------
979 -- First --
980 -----------
982 overriding function First (Object : Subtree_Iterator) return Cursor is
983 begin
984 if Object.Subtree = Root_Node (Object.Container.all) then
985 return First_Child (Root (Object.Container.all));
986 else
987 return Cursor'(Object.Container, Object.Subtree);
988 end if;
989 end First;
991 overriding function First (Object : Child_Iterator) return Cursor is
992 begin
993 return First_Child (Cursor'(Object.Container, Object.Subtree));
994 end First;
996 -----------------
997 -- First_Child --
998 -----------------
1000 function First_Child (Parent : Cursor) return Cursor is
1001 Node : Tree_Node_Access;
1003 begin
1004 if Checks and then Parent = No_Element then
1005 raise Constraint_Error with "Parent cursor has no element";
1006 end if;
1008 Node := Parent.Node.Children.First;
1010 if Node = null then
1011 return No_Element;
1012 end if;
1014 return Cursor'(Parent.Container, Node);
1015 end First_Child;
1017 -------------------------
1018 -- First_Child_Element --
1019 -------------------------
1021 function First_Child_Element (Parent : Cursor) return Element_Type is
1022 begin
1023 return Element (First_Child (Parent));
1024 end First_Child_Element;
1026 ----------------------
1027 -- Find_In_Children --
1028 ----------------------
1030 function Find_In_Children
1031 (Subtree : Tree_Node_Access;
1032 Item : Element_Type) return Tree_Node_Access
1034 N, Result : Tree_Node_Access;
1036 begin
1037 N := Subtree.Children.First;
1038 while N /= null loop
1039 Result := Find_In_Subtree (N, Item);
1041 if Result /= null then
1042 return Result;
1043 end if;
1045 N := N.Next;
1046 end loop;
1048 return null;
1049 end Find_In_Children;
1051 ---------------------
1052 -- Find_In_Subtree --
1053 ---------------------
1055 function Find_In_Subtree
1056 (Position : Cursor;
1057 Item : Element_Type) return Cursor
1059 Result : Tree_Node_Access;
1061 begin
1062 if Checks and then Position = No_Element then
1063 raise Constraint_Error with "Position cursor has no element";
1064 end if;
1066 -- Commented out pending official ruling by ARG. ???
1068 -- if Checks and then
1069 -- Position.Container /= Container'Unrestricted_Access
1070 -- then
1071 -- raise Program_Error with "Position cursor not in container";
1072 -- end if;
1074 Result :=
1075 (if Is_Root (Position)
1076 then Find_In_Children (Position.Node, Item)
1077 else Find_In_Subtree (Position.Node, Item));
1079 if Result = null then
1080 return No_Element;
1081 end if;
1083 return Cursor'(Position.Container, Result);
1084 end Find_In_Subtree;
1086 function Find_In_Subtree
1087 (Subtree : Tree_Node_Access;
1088 Item : Element_Type) return Tree_Node_Access
1090 begin
1091 if Subtree.Element = Item then
1092 return Subtree;
1093 end if;
1095 return Find_In_Children (Subtree, Item);
1096 end Find_In_Subtree;
1098 ------------------------
1099 -- Get_Element_Access --
1100 ------------------------
1102 function Get_Element_Access
1103 (Position : Cursor) return not null Element_Access is
1104 begin
1105 return Position.Node.Element'Access;
1106 end Get_Element_Access;
1108 -----------------
1109 -- Has_Element --
1110 -----------------
1112 function Has_Element (Position : Cursor) return Boolean is
1113 begin
1114 return (if Position = No_Element then False
1115 else Position.Node.Parent /= null);
1116 end Has_Element;
1118 ------------------
1119 -- Insert_Child --
1120 ------------------
1122 procedure Insert_Child
1123 (Container : in out Tree;
1124 Parent : Cursor;
1125 Before : Cursor;
1126 New_Item : Element_Type;
1127 Count : Count_Type := 1)
1129 Position : Cursor;
1130 pragma Unreferenced (Position);
1132 begin
1133 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1134 end Insert_Child;
1136 procedure Insert_Child
1137 (Container : in out Tree;
1138 Parent : Cursor;
1139 Before : Cursor;
1140 New_Item : Element_Type;
1141 Position : out Cursor;
1142 Count : Count_Type := 1)
1144 First : Tree_Node_Access;
1145 Last : Tree_Node_Access;
1147 begin
1148 if Checks and then Parent = No_Element then
1149 raise Constraint_Error with "Parent cursor has no element";
1150 end if;
1152 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1153 raise Program_Error with "Parent cursor not in container";
1154 end if;
1156 if Before /= No_Element then
1157 if Checks and then Before.Container /= Container'Unrestricted_Access
1158 then
1159 raise Program_Error with "Before cursor not in container";
1160 end if;
1162 if Checks and then Before.Node.Parent /= Parent.Node then
1163 raise Constraint_Error with "Parent cursor not parent of Before";
1164 end if;
1165 end if;
1167 if Count = 0 then
1168 Position := No_Element; -- Need ruling from ARG ???
1169 return;
1170 end if;
1172 TC_Check (Container.TC);
1174 First := new Tree_Node_Type'(Parent => Parent.Node,
1175 Element => New_Item,
1176 others => <>);
1178 Last := First;
1179 for J in Count_Type'(2) .. Count loop
1181 -- Reclaim other nodes if Storage_Error. ???
1183 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1184 Prev => Last,
1185 Element => New_Item,
1186 others => <>);
1188 Last := Last.Next;
1189 end loop;
1191 Insert_Subtree_List
1192 (First => First,
1193 Last => Last,
1194 Parent => Parent.Node,
1195 Before => Before.Node);
1197 -- In order for operation Node_Count to complete in O(1) time, we cache
1198 -- the count value. Here we increment the total count by the number of
1199 -- nodes we just inserted.
1201 Container.Count := Container.Count + Count;
1203 Position := Cursor'(Parent.Container, First);
1204 end Insert_Child;
1206 procedure Insert_Child
1207 (Container : in out Tree;
1208 Parent : Cursor;
1209 Before : Cursor;
1210 Position : out Cursor;
1211 Count : Count_Type := 1)
1213 First : Tree_Node_Access;
1214 Last : Tree_Node_Access;
1216 begin
1217 if Checks and then Parent = No_Element then
1218 raise Constraint_Error with "Parent cursor has no element";
1219 end if;
1221 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1222 raise Program_Error with "Parent cursor not in container";
1223 end if;
1225 if Before /= No_Element then
1226 if Checks and then Before.Container /= Container'Unrestricted_Access
1227 then
1228 raise Program_Error with "Before cursor not in container";
1229 end if;
1231 if Checks and then Before.Node.Parent /= Parent.Node then
1232 raise Constraint_Error with "Parent cursor not parent of Before";
1233 end if;
1234 end if;
1236 if Count = 0 then
1237 Position := No_Element; -- Need ruling from ARG ???
1238 return;
1239 end if;
1241 TC_Check (Container.TC);
1243 First := new Tree_Node_Type'(Parent => Parent.Node,
1244 Element => <>,
1245 others => <>);
1247 Last := First;
1248 for J in Count_Type'(2) .. Count loop
1250 -- Reclaim other nodes if Storage_Error. ???
1252 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1253 Prev => Last,
1254 Element => <>,
1255 others => <>);
1257 Last := Last.Next;
1258 end loop;
1260 Insert_Subtree_List
1261 (First => First,
1262 Last => Last,
1263 Parent => Parent.Node,
1264 Before => Before.Node);
1266 -- In order for operation Node_Count to complete in O(1) time, we cache
1267 -- the count value. Here we increment the total count by the number of
1268 -- nodes we just inserted.
1270 Container.Count := Container.Count + Count;
1272 Position := Cursor'(Parent.Container, First);
1273 end Insert_Child;
1275 -------------------------
1276 -- Insert_Subtree_List --
1277 -------------------------
1279 procedure Insert_Subtree_List
1280 (First : Tree_Node_Access;
1281 Last : Tree_Node_Access;
1282 Parent : Tree_Node_Access;
1283 Before : Tree_Node_Access)
1285 pragma Assert (Parent /= null);
1286 C : Children_Type renames Parent.Children;
1288 begin
1289 -- This is a simple utility operation to insert a list of nodes (from
1290 -- First..Last) as children of Parent. The Before node specifies where
1291 -- the new children should be inserted relative to the existing
1292 -- children.
1294 if First = null then
1295 pragma Assert (Last = null);
1296 return;
1297 end if;
1299 pragma Assert (Last /= null);
1300 pragma Assert (Before = null or else Before.Parent = Parent);
1302 if C.First = null then
1303 C.First := First;
1304 C.First.Prev := null;
1305 C.Last := Last;
1306 C.Last.Next := null;
1308 elsif Before = null then -- means "insert after existing nodes"
1309 C.Last.Next := First;
1310 First.Prev := C.Last;
1311 C.Last := Last;
1312 C.Last.Next := null;
1314 elsif Before = C.First then
1315 Last.Next := C.First;
1316 C.First.Prev := Last;
1317 C.First := First;
1318 C.First.Prev := null;
1320 else
1321 Before.Prev.Next := First;
1322 First.Prev := Before.Prev;
1323 Last.Next := Before;
1324 Before.Prev := Last;
1325 end if;
1326 end Insert_Subtree_List;
1328 -------------------------
1329 -- Insert_Subtree_Node --
1330 -------------------------
1332 procedure Insert_Subtree_Node
1333 (Subtree : Tree_Node_Access;
1334 Parent : Tree_Node_Access;
1335 Before : Tree_Node_Access)
1337 begin
1338 -- This is a simple wrapper operation to insert a single child into the
1339 -- Parent's children list.
1341 Insert_Subtree_List
1342 (First => Subtree,
1343 Last => Subtree,
1344 Parent => Parent,
1345 Before => Before);
1346 end Insert_Subtree_Node;
1348 --------------
1349 -- Is_Empty --
1350 --------------
1352 function Is_Empty (Container : Tree) return Boolean is
1353 begin
1354 return Container.Root.Children.First = null;
1355 end Is_Empty;
1357 -------------
1358 -- Is_Leaf --
1359 -------------
1361 function Is_Leaf (Position : Cursor) return Boolean is
1362 begin
1363 return (if Position = No_Element then False
1364 else Position.Node.Children.First = null);
1365 end Is_Leaf;
1367 ------------------
1368 -- Is_Reachable --
1369 ------------------
1371 function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1372 pragma Assert (From /= null);
1373 pragma Assert (To /= null);
1375 N : Tree_Node_Access;
1377 begin
1378 N := From;
1379 while N /= null loop
1380 if N = To then
1381 return True;
1382 end if;
1384 N := N.Parent;
1385 end loop;
1387 return False;
1388 end Is_Reachable;
1390 -------------
1391 -- Is_Root --
1392 -------------
1394 function Is_Root (Position : Cursor) return Boolean is
1395 begin
1396 return (if Position.Container = null then False
1397 else Position = Root (Position.Container.all));
1398 end Is_Root;
1400 -------------
1401 -- Iterate --
1402 -------------
1404 procedure Iterate
1405 (Container : Tree;
1406 Process : not null access procedure (Position : Cursor))
1408 Busy : With_Busy (Container.TC'Unrestricted_Access);
1409 begin
1410 Iterate_Children
1411 (Container => Container'Unrestricted_Access,
1412 Subtree => Root_Node (Container),
1413 Process => Process);
1414 end Iterate;
1416 function Iterate (Container : Tree)
1417 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1419 begin
1420 return Iterate_Subtree (Root (Container));
1421 end Iterate;
1423 ----------------------
1424 -- Iterate_Children --
1425 ----------------------
1427 procedure Iterate_Children
1428 (Parent : Cursor;
1429 Process : not null access procedure (Position : Cursor))
1431 C : Tree_Node_Access;
1432 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
1433 begin
1434 if Checks and then Parent = No_Element then
1435 raise Constraint_Error with "Parent cursor has no element";
1436 end if;
1438 C := Parent.Node.Children.First;
1439 while C /= null loop
1440 Process (Position => Cursor'(Parent.Container, Node => C));
1441 C := C.Next;
1442 end loop;
1443 end Iterate_Children;
1445 procedure Iterate_Children
1446 (Container : Tree_Access;
1447 Subtree : Tree_Node_Access;
1448 Process : not null access procedure (Position : Cursor))
1450 Node : Tree_Node_Access;
1452 begin
1453 -- This is a helper function to recursively iterate over all the nodes
1454 -- in a subtree, in depth-first fashion. This particular helper just
1455 -- visits the children of this subtree, not the root of the subtree node
1456 -- itself. This is useful when starting from the ultimate root of the
1457 -- entire tree (see Iterate), as that root does not have an element.
1459 Node := Subtree.Children.First;
1460 while Node /= null loop
1461 Iterate_Subtree (Container, Node, Process);
1462 Node := Node.Next;
1463 end loop;
1464 end Iterate_Children;
1466 function Iterate_Children
1467 (Container : Tree;
1468 Parent : Cursor)
1469 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1471 C : constant Tree_Access := Container'Unrestricted_Access;
1472 begin
1473 if Checks and then Parent = No_Element then
1474 raise Constraint_Error with "Parent cursor has no element";
1475 end if;
1477 if Checks and then Parent.Container /= C then
1478 raise Program_Error with "Parent cursor not in container";
1479 end if;
1481 return It : constant Child_Iterator :=
1482 (Limited_Controlled with
1483 Container => C,
1484 Subtree => Parent.Node)
1486 Busy (C.TC);
1487 end return;
1488 end Iterate_Children;
1490 ---------------------
1491 -- Iterate_Subtree --
1492 ---------------------
1494 function Iterate_Subtree
1495 (Position : Cursor)
1496 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1498 C : constant Tree_Access := Position.Container;
1499 begin
1500 if Checks and then Position = No_Element then
1501 raise Constraint_Error with "Position cursor has no element";
1502 end if;
1504 -- Implement Vet for multiway trees???
1505 -- pragma Assert (Vet (Position), "bad subtree cursor");
1507 return It : constant Subtree_Iterator :=
1508 (Limited_Controlled with
1509 Container => C,
1510 Subtree => Position.Node)
1512 Busy (C.TC);
1513 end return;
1514 end Iterate_Subtree;
1516 procedure Iterate_Subtree
1517 (Position : Cursor;
1518 Process : not null access procedure (Position : Cursor))
1520 Busy : With_Busy (Position.Container.TC'Unrestricted_Access);
1521 begin
1522 if Checks and then Position = No_Element then
1523 raise Constraint_Error with "Position cursor has no element";
1524 end if;
1526 if Is_Root (Position) then
1527 Iterate_Children (Position.Container, Position.Node, Process);
1528 else
1529 Iterate_Subtree (Position.Container, Position.Node, Process);
1530 end if;
1531 end Iterate_Subtree;
1533 procedure Iterate_Subtree
1534 (Container : Tree_Access;
1535 Subtree : Tree_Node_Access;
1536 Process : not null access procedure (Position : Cursor))
1538 begin
1539 -- This is a helper function to recursively iterate over all the nodes
1540 -- in a subtree, in depth-first fashion. It first visits the root of the
1541 -- subtree, then visits its children.
1543 Process (Cursor'(Container, Subtree));
1544 Iterate_Children (Container, Subtree, Process);
1545 end Iterate_Subtree;
1547 ----------
1548 -- Last --
1549 ----------
1551 overriding function Last (Object : Child_Iterator) return Cursor is
1552 begin
1553 return Last_Child (Cursor'(Object.Container, Object.Subtree));
1554 end Last;
1556 ----------------
1557 -- Last_Child --
1558 ----------------
1560 function Last_Child (Parent : Cursor) return Cursor is
1561 Node : Tree_Node_Access;
1563 begin
1564 if Checks and then Parent = No_Element then
1565 raise Constraint_Error with "Parent cursor has no element";
1566 end if;
1568 Node := Parent.Node.Children.Last;
1570 if Node = null then
1571 return No_Element;
1572 end if;
1574 return (Parent.Container, Node);
1575 end Last_Child;
1577 ------------------------
1578 -- Last_Child_Element --
1579 ------------------------
1581 function Last_Child_Element (Parent : Cursor) return Element_Type is
1582 begin
1583 return Element (Last_Child (Parent));
1584 end Last_Child_Element;
1586 ----------
1587 -- Move --
1588 ----------
1590 procedure Move (Target : in out Tree; Source : in out Tree) is
1591 Node : Tree_Node_Access;
1593 begin
1594 if Target'Address = Source'Address then
1595 return;
1596 end if;
1598 TC_Check (Source.TC);
1600 Target.Clear; -- checks busy bit
1602 Target.Root.Children := Source.Root.Children;
1603 Source.Root.Children := Children_Type'(others => null);
1605 Node := Target.Root.Children.First;
1606 while Node /= null loop
1607 Node.Parent := Root_Node (Target);
1608 Node := Node.Next;
1609 end loop;
1611 Target.Count := Source.Count;
1612 Source.Count := 0;
1613 end Move;
1615 ----------
1616 -- Next --
1617 ----------
1619 function Next
1620 (Object : Subtree_Iterator;
1621 Position : Cursor) return Cursor
1623 Node : Tree_Node_Access;
1625 begin
1626 if Position.Container = null then
1627 return No_Element;
1628 end if;
1630 if Checks and then Position.Container /= Object.Container then
1631 raise Program_Error with
1632 "Position cursor of Next designates wrong tree";
1633 end if;
1635 Node := Position.Node;
1637 if Node.Children.First /= null then
1638 return Cursor'(Object.Container, Node.Children.First);
1639 end if;
1641 while Node /= Object.Subtree loop
1642 if Node.Next /= null then
1643 return Cursor'(Object.Container, Node.Next);
1644 end if;
1646 Node := Node.Parent;
1647 end loop;
1649 return No_Element;
1650 end Next;
1652 function Next
1653 (Object : Child_Iterator;
1654 Position : Cursor) return Cursor
1656 begin
1657 if Position.Container = null then
1658 return No_Element;
1659 end if;
1661 if Checks and then Position.Container /= Object.Container then
1662 raise Program_Error with
1663 "Position cursor of Next designates wrong tree";
1664 end if;
1666 return Next_Sibling (Position);
1667 end Next;
1669 ------------------
1670 -- Next_Sibling --
1671 ------------------
1673 function Next_Sibling (Position : Cursor) return Cursor is
1674 begin
1675 if Position = No_Element then
1676 return No_Element;
1677 end if;
1679 if Position.Node.Next = null then
1680 return No_Element;
1681 end if;
1683 return Cursor'(Position.Container, Position.Node.Next);
1684 end Next_Sibling;
1686 procedure Next_Sibling (Position : in out Cursor) is
1687 begin
1688 Position := Next_Sibling (Position);
1689 end Next_Sibling;
1691 ----------------
1692 -- Node_Count --
1693 ----------------
1695 function Node_Count (Container : Tree) return Count_Type is
1696 begin
1697 -- Container.Count is the number of nodes we have actually allocated. We
1698 -- cache the value specifically so this Node_Count operation can execute
1699 -- in O(1) time, which makes it behave similarly to how the Length
1700 -- selector function behaves for other containers.
1702 -- The cached node count value only describes the nodes we have
1703 -- allocated; the root node itself is not included in that count. The
1704 -- Node_Count operation returns a value that includes the root node
1705 -- (because the RM says so), so we must add 1 to our cached value.
1707 return 1 + Container.Count;
1708 end Node_Count;
1710 ------------
1711 -- Parent --
1712 ------------
1714 function Parent (Position : Cursor) return Cursor is
1715 begin
1716 if Position = No_Element then
1717 return No_Element;
1718 end if;
1720 if Position.Node.Parent = null then
1721 return No_Element;
1722 end if;
1724 return Cursor'(Position.Container, Position.Node.Parent);
1725 end Parent;
1727 -------------------
1728 -- Prepent_Child --
1729 -------------------
1731 procedure Prepend_Child
1732 (Container : in out Tree;
1733 Parent : Cursor;
1734 New_Item : Element_Type;
1735 Count : Count_Type := 1)
1737 First, Last : Tree_Node_Access;
1739 begin
1740 if Checks and then Parent = No_Element then
1741 raise Constraint_Error with "Parent cursor has no element";
1742 end if;
1744 if Checks and then Parent.Container /= Container'Unrestricted_Access then
1745 raise Program_Error with "Parent cursor not in container";
1746 end if;
1748 if Count = 0 then
1749 return;
1750 end if;
1752 TC_Check (Container.TC);
1754 First := new Tree_Node_Type'(Parent => Parent.Node,
1755 Element => New_Item,
1756 others => <>);
1758 Last := First;
1760 for J in Count_Type'(2) .. Count loop
1762 -- Reclaim other nodes if Storage_Error???
1764 Last.Next := new Tree_Node_Type'(Parent => Parent.Node,
1765 Prev => Last,
1766 Element => New_Item,
1767 others => <>);
1769 Last := Last.Next;
1770 end loop;
1772 Insert_Subtree_List
1773 (First => First,
1774 Last => Last,
1775 Parent => Parent.Node,
1776 Before => Parent.Node.Children.First);
1778 -- In order for operation Node_Count to complete in O(1) time, we cache
1779 -- the count value. Here we increment the total count by the number of
1780 -- nodes we just inserted.
1782 Container.Count := Container.Count + Count;
1783 end Prepend_Child;
1785 --------------
1786 -- Previous --
1787 --------------
1789 overriding function Previous
1790 (Object : Child_Iterator;
1791 Position : Cursor) return Cursor
1793 begin
1794 if Position.Container = null then
1795 return No_Element;
1796 end if;
1798 if Checks and then Position.Container /= Object.Container then
1799 raise Program_Error with
1800 "Position cursor of Previous designates wrong tree";
1801 end if;
1803 return Previous_Sibling (Position);
1804 end Previous;
1806 ----------------------
1807 -- Previous_Sibling --
1808 ----------------------
1810 function Previous_Sibling (Position : Cursor) return Cursor is
1811 begin
1812 return
1813 (if Position = No_Element then No_Element
1814 elsif Position.Node.Prev = null then No_Element
1815 else Cursor'(Position.Container, Position.Node.Prev));
1816 end Previous_Sibling;
1818 procedure Previous_Sibling (Position : in out Cursor) is
1819 begin
1820 Position := Previous_Sibling (Position);
1821 end Previous_Sibling;
1823 ----------------------
1824 -- Pseudo_Reference --
1825 ----------------------
1827 function Pseudo_Reference
1828 (Container : aliased Tree'Class) return Reference_Control_Type
1830 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
1831 begin
1832 return R : constant Reference_Control_Type := (Controlled with TC) do
1833 Lock (TC.all);
1834 end return;
1835 end Pseudo_Reference;
1837 -------------------
1838 -- Query_Element --
1839 -------------------
1841 procedure Query_Element
1842 (Position : Cursor;
1843 Process : not null access procedure (Element : Element_Type))
1845 T : Tree renames Position.Container.all'Unrestricted_Access.all;
1846 Lock : With_Lock (T.TC'Unrestricted_Access);
1847 begin
1848 if Checks and then Position = No_Element then
1849 raise Constraint_Error with "Position cursor has no element";
1850 end if;
1852 if Checks and then Is_Root (Position) then
1853 raise Program_Error with "Position cursor designates root";
1854 end if;
1856 Process (Position.Node.Element);
1857 end Query_Element;
1859 ----------
1860 -- Read --
1861 ----------
1863 procedure Read
1864 (Stream : not null access Root_Stream_Type'Class;
1865 Container : out Tree)
1867 procedure Read_Children (Subtree : Tree_Node_Access);
1869 function Read_Subtree
1870 (Parent : Tree_Node_Access) return Tree_Node_Access;
1872 Total_Count : Count_Type'Base;
1873 -- Value read from the stream that says how many elements follow
1875 Read_Count : Count_Type'Base;
1876 -- Actual number of elements read from the stream
1878 -------------------
1879 -- Read_Children --
1880 -------------------
1882 procedure Read_Children (Subtree : Tree_Node_Access) is
1883 pragma Assert (Subtree /= null);
1884 pragma Assert (Subtree.Children.First = null);
1885 pragma Assert (Subtree.Children.Last = null);
1887 Count : Count_Type'Base;
1888 -- Number of child subtrees
1890 C : Children_Type;
1892 begin
1893 Count_Type'Read (Stream, Count);
1895 if Checks and then Count < 0 then
1896 raise Program_Error with "attempt to read from corrupt stream";
1897 end if;
1899 if Count = 0 then
1900 return;
1901 end if;
1903 C.First := Read_Subtree (Parent => Subtree);
1904 C.Last := C.First;
1906 for J in Count_Type'(2) .. Count loop
1907 C.Last.Next := Read_Subtree (Parent => Subtree);
1908 C.Last.Next.Prev := C.Last;
1909 C.Last := C.Last.Next;
1910 end loop;
1912 -- Now that the allocation and reads have completed successfully, it
1913 -- is safe to link the children to their parent.
1915 Subtree.Children := C;
1916 end Read_Children;
1918 ------------------
1919 -- Read_Subtree --
1920 ------------------
1922 function Read_Subtree
1923 (Parent : Tree_Node_Access) return Tree_Node_Access
1925 Subtree : constant Tree_Node_Access :=
1926 new Tree_Node_Type'
1927 (Parent => Parent,
1928 Element => Element_Type'Input (Stream),
1929 others => <>);
1931 begin
1932 Read_Count := Read_Count + 1;
1934 Read_Children (Subtree);
1936 return Subtree;
1937 end Read_Subtree;
1939 -- Start of processing for Read
1941 begin
1942 Container.Clear; -- checks busy bit
1944 Count_Type'Read (Stream, Total_Count);
1946 if Checks and then Total_Count < 0 then
1947 raise Program_Error with "attempt to read from corrupt stream";
1948 end if;
1950 if Total_Count = 0 then
1951 return;
1952 end if;
1954 Read_Count := 0;
1956 Read_Children (Root_Node (Container));
1958 if Checks and then Read_Count /= Total_Count then
1959 raise Program_Error with "attempt to read from corrupt stream";
1960 end if;
1962 Container.Count := Total_Count;
1963 end Read;
1965 procedure Read
1966 (Stream : not null access Root_Stream_Type'Class;
1967 Position : out Cursor)
1969 begin
1970 raise Program_Error with "attempt to read tree cursor from stream";
1971 end Read;
1973 procedure Read
1974 (Stream : not null access Root_Stream_Type'Class;
1975 Item : out Reference_Type)
1977 begin
1978 raise Program_Error with "attempt to stream reference";
1979 end Read;
1981 procedure Read
1982 (Stream : not null access Root_Stream_Type'Class;
1983 Item : out Constant_Reference_Type)
1985 begin
1986 raise Program_Error with "attempt to stream reference";
1987 end Read;
1989 ---------------
1990 -- Reference --
1991 ---------------
1993 function Reference
1994 (Container : aliased in out Tree;
1995 Position : Cursor) return Reference_Type
1997 begin
1998 if Checks and then Position.Container = null then
1999 raise Constraint_Error with
2000 "Position cursor has no element";
2001 end if;
2003 if Checks and then Position.Container /= Container'Unrestricted_Access
2004 then
2005 raise Program_Error with
2006 "Position cursor designates wrong container";
2007 end if;
2009 if Checks and then Position.Node = Root_Node (Container) then
2010 raise Program_Error with "Position cursor designates root";
2011 end if;
2013 -- Implement Vet for multiway tree???
2014 -- pragma Assert (Vet (Position),
2015 -- "Position cursor in Constant_Reference is bad");
2017 declare
2018 C : Tree renames Position.Container.all;
2019 TC : constant Tamper_Counts_Access :=
2020 C.TC'Unrestricted_Access;
2021 begin
2022 return R : constant Reference_Type :=
2023 (Element => Position.Node.Element'Access,
2024 Control => (Controlled with TC))
2026 Lock (TC.all);
2027 end return;
2028 end;
2029 end Reference;
2031 --------------------
2032 -- Remove_Subtree --
2033 --------------------
2035 procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2036 C : Children_Type renames Subtree.Parent.Children;
2038 begin
2039 -- This is a utility operation to remove a subtree node from its
2040 -- parent's list of children.
2042 if C.First = Subtree then
2043 pragma Assert (Subtree.Prev = null);
2045 if C.Last = Subtree then
2046 pragma Assert (Subtree.Next = null);
2047 C.First := null;
2048 C.Last := null;
2050 else
2051 C.First := Subtree.Next;
2052 C.First.Prev := null;
2053 end if;
2055 elsif C.Last = Subtree then
2056 pragma Assert (Subtree.Next = null);
2057 C.Last := Subtree.Prev;
2058 C.Last.Next := null;
2060 else
2061 Subtree.Prev.Next := Subtree.Next;
2062 Subtree.Next.Prev := Subtree.Prev;
2063 end if;
2064 end Remove_Subtree;
2066 ----------------------
2067 -- Replace_Element --
2068 ----------------------
2070 procedure Replace_Element
2071 (Container : in out Tree;
2072 Position : Cursor;
2073 New_Item : Element_Type)
2075 begin
2076 if Checks and then Position = No_Element then
2077 raise Constraint_Error with "Position cursor has no element";
2078 end if;
2080 if Checks and then Position.Container /= Container'Unrestricted_Access
2081 then
2082 raise Program_Error with "Position cursor not in container";
2083 end if;
2085 if Checks and then Is_Root (Position) then
2086 raise Program_Error with "Position cursor designates root";
2087 end if;
2089 TE_Check (Container.TC);
2091 Position.Node.Element := New_Item;
2092 end Replace_Element;
2094 ------------------------------
2095 -- Reverse_Iterate_Children --
2096 ------------------------------
2098 procedure Reverse_Iterate_Children
2099 (Parent : Cursor;
2100 Process : not null access procedure (Position : Cursor))
2102 C : Tree_Node_Access;
2103 Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
2104 begin
2105 if Checks and then Parent = No_Element then
2106 raise Constraint_Error with "Parent cursor has no element";
2107 end if;
2109 C := Parent.Node.Children.Last;
2110 while C /= null loop
2111 Process (Position => Cursor'(Parent.Container, Node => C));
2112 C := C.Prev;
2113 end loop;
2114 end Reverse_Iterate_Children;
2116 ----------
2117 -- Root --
2118 ----------
2120 function Root (Container : Tree) return Cursor is
2121 begin
2122 return (Container'Unrestricted_Access, Root_Node (Container));
2123 end Root;
2125 ---------------
2126 -- Root_Node --
2127 ---------------
2129 function Root_Node (Container : Tree) return Tree_Node_Access is
2130 type Root_Node_Access is access all Root_Node_Type;
2131 for Root_Node_Access'Storage_Size use 0;
2132 pragma Convention (C, Root_Node_Access);
2134 function To_Tree_Node_Access is
2135 new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2137 -- Start of processing for Root_Node
2139 begin
2140 -- This is a utility function for converting from an access type that
2141 -- designates the distinguished root node to an access type designating
2142 -- a non-root node. The representation of a root node does not have an
2143 -- element, but is otherwise identical to a non-root node, so the
2144 -- conversion itself is safe.
2146 return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2147 end Root_Node;
2149 ---------------------
2150 -- Splice_Children --
2151 ---------------------
2153 procedure Splice_Children
2154 (Target : in out Tree;
2155 Target_Parent : Cursor;
2156 Before : Cursor;
2157 Source : in out Tree;
2158 Source_Parent : Cursor)
2160 Count : Count_Type;
2162 begin
2163 if Checks and then Target_Parent = No_Element then
2164 raise Constraint_Error with "Target_Parent cursor has no element";
2165 end if;
2167 if Checks and then Target_Parent.Container /= Target'Unrestricted_Access
2168 then
2169 raise Program_Error
2170 with "Target_Parent cursor not in Target container";
2171 end if;
2173 if Before /= No_Element then
2174 if Checks and then Before.Container /= Target'Unrestricted_Access then
2175 raise Program_Error
2176 with "Before cursor not in Target container";
2177 end if;
2179 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2180 raise Constraint_Error
2181 with "Before cursor not child of Target_Parent";
2182 end if;
2183 end if;
2185 if Checks and then Source_Parent = No_Element then
2186 raise Constraint_Error with "Source_Parent cursor has no element";
2187 end if;
2189 if Checks and then Source_Parent.Container /= Source'Unrestricted_Access
2190 then
2191 raise Program_Error
2192 with "Source_Parent cursor not in Source container";
2193 end if;
2195 if Target'Address = Source'Address then
2196 if Target_Parent = Source_Parent then
2197 return;
2198 end if;
2200 TC_Check (Target.TC);
2202 if Checks and then Is_Reachable (From => Target_Parent.Node,
2203 To => Source_Parent.Node)
2204 then
2205 raise Constraint_Error
2206 with "Source_Parent is ancestor of Target_Parent";
2207 end if;
2209 Splice_Children
2210 (Target_Parent => Target_Parent.Node,
2211 Before => Before.Node,
2212 Source_Parent => Source_Parent.Node);
2214 return;
2215 end if;
2217 TC_Check (Target.TC);
2218 TC_Check (Source.TC);
2220 -- We cache the count of the nodes we have allocated, so that operation
2221 -- Node_Count can execute in O(1) time. But that means we must count the
2222 -- nodes in the subtree we remove from Source and insert into Target, in
2223 -- order to keep the count accurate.
2225 Count := Subtree_Node_Count (Source_Parent.Node);
2226 pragma Assert (Count >= 1);
2228 Count := Count - 1; -- because Source_Parent node does not move
2230 Splice_Children
2231 (Target_Parent => Target_Parent.Node,
2232 Before => Before.Node,
2233 Source_Parent => Source_Parent.Node);
2235 Source.Count := Source.Count - Count;
2236 Target.Count := Target.Count + Count;
2237 end Splice_Children;
2239 procedure Splice_Children
2240 (Container : in out Tree;
2241 Target_Parent : Cursor;
2242 Before : Cursor;
2243 Source_Parent : Cursor)
2245 begin
2246 if Checks and then Target_Parent = No_Element then
2247 raise Constraint_Error with "Target_Parent cursor has no element";
2248 end if;
2250 if Checks and then
2251 Target_Parent.Container /= Container'Unrestricted_Access
2252 then
2253 raise Program_Error
2254 with "Target_Parent cursor not in container";
2255 end if;
2257 if Before /= No_Element then
2258 if Checks and then Before.Container /= Container'Unrestricted_Access
2259 then
2260 raise Program_Error
2261 with "Before cursor not in container";
2262 end if;
2264 if Checks and then Before.Node.Parent /= Target_Parent.Node then
2265 raise Constraint_Error
2266 with "Before cursor not child of Target_Parent";
2267 end if;
2268 end if;
2270 if Checks and then Source_Parent = No_Element then
2271 raise Constraint_Error with "Source_Parent cursor has no element";
2272 end if;
2274 if Checks and then
2275 Source_Parent.Container /= Container'Unrestricted_Access
2276 then
2277 raise Program_Error
2278 with "Source_Parent cursor not in container";
2279 end if;
2281 if Target_Parent = Source_Parent then
2282 return;
2283 end if;
2285 TC_Check (Container.TC);
2287 if Checks and then Is_Reachable (From => Target_Parent.Node,
2288 To => Source_Parent.Node)
2289 then
2290 raise Constraint_Error
2291 with "Source_Parent is ancestor of Target_Parent";
2292 end if;
2294 Splice_Children
2295 (Target_Parent => Target_Parent.Node,
2296 Before => Before.Node,
2297 Source_Parent => Source_Parent.Node);
2298 end Splice_Children;
2300 procedure Splice_Children
2301 (Target_Parent : Tree_Node_Access;
2302 Before : Tree_Node_Access;
2303 Source_Parent : Tree_Node_Access)
2305 CC : constant Children_Type := Source_Parent.Children;
2306 C : Tree_Node_Access;
2308 begin
2309 -- This is a utility operation to remove the children from
2310 -- Source parent and insert them into Target parent.
2312 Source_Parent.Children := Children_Type'(others => null);
2314 -- Fix up the Parent pointers of each child to designate
2315 -- its new Target parent.
2317 C := CC.First;
2318 while C /= null loop
2319 C.Parent := Target_Parent;
2320 C := C.Next;
2321 end loop;
2323 Insert_Subtree_List
2324 (First => CC.First,
2325 Last => CC.Last,
2326 Parent => Target_Parent,
2327 Before => Before);
2328 end Splice_Children;
2330 --------------------
2331 -- Splice_Subtree --
2332 --------------------
2334 procedure Splice_Subtree
2335 (Target : in out Tree;
2336 Parent : Cursor;
2337 Before : Cursor;
2338 Source : in out Tree;
2339 Position : in out Cursor)
2341 Subtree_Count : Count_Type;
2343 begin
2344 if Checks and then Parent = No_Element then
2345 raise Constraint_Error with "Parent cursor has no element";
2346 end if;
2348 if Checks and then Parent.Container /= Target'Unrestricted_Access then
2349 raise Program_Error with "Parent cursor not in Target container";
2350 end if;
2352 if Before /= No_Element then
2353 if Checks and then Before.Container /= Target'Unrestricted_Access then
2354 raise Program_Error with "Before cursor not in Target container";
2355 end if;
2357 if Checks and then Before.Node.Parent /= Parent.Node then
2358 raise Constraint_Error with "Before cursor not child of Parent";
2359 end if;
2360 end if;
2362 if Checks and then Position = No_Element then
2363 raise Constraint_Error with "Position cursor has no element";
2364 end if;
2366 if Checks and then Position.Container /= Source'Unrestricted_Access then
2367 raise Program_Error with "Position cursor not in Source container";
2368 end if;
2370 if Checks and then Is_Root (Position) then
2371 raise Program_Error with "Position cursor designates root";
2372 end if;
2374 if Target'Address = Source'Address then
2375 if Position.Node.Parent = Parent.Node then
2376 if Position.Node = Before.Node then
2377 return;
2378 end if;
2380 if Position.Node.Next = Before.Node then
2381 return;
2382 end if;
2383 end if;
2385 TC_Check (Target.TC);
2387 if Checks and then
2388 Is_Reachable (From => Parent.Node, To => Position.Node)
2389 then
2390 raise Constraint_Error with "Position is ancestor of Parent";
2391 end if;
2393 Remove_Subtree (Position.Node);
2395 Position.Node.Parent := Parent.Node;
2396 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2398 return;
2399 end if;
2401 TC_Check (Target.TC);
2402 TC_Check (Source.TC);
2404 -- This is an unfortunate feature of this API: we must count the nodes
2405 -- in the subtree that we remove from the source tree, which is an O(n)
2406 -- operation. It would have been better if the Tree container did not
2407 -- have a Node_Count selector; a user that wants the number of nodes in
2408 -- the tree could simply call Subtree_Node_Count, with the understanding
2409 -- that such an operation is O(n).
2411 -- Of course, we could choose to implement the Node_Count selector as an
2412 -- O(n) operation, which would turn this splice operation into an O(1)
2413 -- operation. ???
2415 Subtree_Count := Subtree_Node_Count (Position.Node);
2416 pragma Assert (Subtree_Count <= Source.Count);
2418 Remove_Subtree (Position.Node);
2419 Source.Count := Source.Count - Subtree_Count;
2421 Position.Node.Parent := Parent.Node;
2422 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2424 Target.Count := Target.Count + Subtree_Count;
2426 Position.Container := Target'Unrestricted_Access;
2427 end Splice_Subtree;
2429 procedure Splice_Subtree
2430 (Container : in out Tree;
2431 Parent : Cursor;
2432 Before : Cursor;
2433 Position : Cursor)
2435 begin
2436 if Checks and then Parent = No_Element then
2437 raise Constraint_Error with "Parent cursor has no element";
2438 end if;
2440 if Checks and then Parent.Container /= Container'Unrestricted_Access then
2441 raise Program_Error with "Parent cursor not in container";
2442 end if;
2444 if Before /= No_Element then
2445 if Checks and then Before.Container /= Container'Unrestricted_Access
2446 then
2447 raise Program_Error with "Before cursor not in container";
2448 end if;
2450 if Checks and then Before.Node.Parent /= Parent.Node then
2451 raise Constraint_Error with "Before cursor not child of Parent";
2452 end if;
2453 end if;
2455 if Checks and then Position = No_Element then
2456 raise Constraint_Error with "Position cursor has no element";
2457 end if;
2459 if Checks and then Position.Container /= Container'Unrestricted_Access
2460 then
2461 raise Program_Error with "Position cursor not in container";
2462 end if;
2464 if Checks and then Is_Root (Position) then
2466 -- Should this be PE instead? Need ARG confirmation. ???
2468 raise Constraint_Error with "Position cursor designates root";
2469 end if;
2471 if Position.Node.Parent = Parent.Node then
2472 if Position.Node = Before.Node then
2473 return;
2474 end if;
2476 if Position.Node.Next = Before.Node then
2477 return;
2478 end if;
2479 end if;
2481 TC_Check (Container.TC);
2483 if Checks and then
2484 Is_Reachable (From => Parent.Node, To => Position.Node)
2485 then
2486 raise Constraint_Error with "Position is ancestor of Parent";
2487 end if;
2489 Remove_Subtree (Position.Node);
2491 Position.Node.Parent := Parent.Node;
2492 Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2493 end Splice_Subtree;
2495 ------------------------
2496 -- Subtree_Node_Count --
2497 ------------------------
2499 function Subtree_Node_Count (Position : Cursor) return Count_Type is
2500 begin
2501 if Position = No_Element then
2502 return 0;
2503 end if;
2505 return Subtree_Node_Count (Position.Node);
2506 end Subtree_Node_Count;
2508 function Subtree_Node_Count
2509 (Subtree : Tree_Node_Access) return Count_Type
2511 Result : Count_Type;
2512 Node : Tree_Node_Access;
2514 begin
2515 Result := 1;
2516 Node := Subtree.Children.First;
2517 while Node /= null loop
2518 Result := Result + Subtree_Node_Count (Node);
2519 Node := Node.Next;
2520 end loop;
2522 return Result;
2523 end Subtree_Node_Count;
2525 ----------
2526 -- Swap --
2527 ----------
2529 procedure Swap
2530 (Container : in out Tree;
2531 I, J : Cursor)
2533 begin
2534 if Checks and then I = No_Element then
2535 raise Constraint_Error with "I cursor has no element";
2536 end if;
2538 if Checks and then I.Container /= Container'Unrestricted_Access then
2539 raise Program_Error with "I cursor not in container";
2540 end if;
2542 if Checks and then Is_Root (I) then
2543 raise Program_Error with "I cursor designates root";
2544 end if;
2546 if I = J then -- make this test sooner???
2547 return;
2548 end if;
2550 if Checks and then J = No_Element then
2551 raise Constraint_Error with "J cursor has no element";
2552 end if;
2554 if Checks and then J.Container /= Container'Unrestricted_Access then
2555 raise Program_Error with "J cursor not in container";
2556 end if;
2558 if Checks and then Is_Root (J) then
2559 raise Program_Error with "J cursor designates root";
2560 end if;
2562 TE_Check (Container.TC);
2564 declare
2565 EI : constant Element_Type := I.Node.Element;
2567 begin
2568 I.Node.Element := J.Node.Element;
2569 J.Node.Element := EI;
2570 end;
2571 end Swap;
2573 --------------------
2574 -- Update_Element --
2575 --------------------
2577 procedure Update_Element
2578 (Container : in out Tree;
2579 Position : Cursor;
2580 Process : not null access procedure (Element : in out Element_Type))
2582 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2583 Lock : With_Lock (T.TC'Unrestricted_Access);
2584 begin
2585 if Checks and then Position = No_Element then
2586 raise Constraint_Error with "Position cursor has no element";
2587 end if;
2589 if Checks and then Position.Container /= Container'Unrestricted_Access
2590 then
2591 raise Program_Error with "Position cursor not in container";
2592 end if;
2594 if Checks and then Is_Root (Position) then
2595 raise Program_Error with "Position cursor designates root";
2596 end if;
2598 Process (Position.Node.Element);
2599 end Update_Element;
2601 -----------
2602 -- Write --
2603 -----------
2605 procedure Write
2606 (Stream : not null access Root_Stream_Type'Class;
2607 Container : Tree)
2609 procedure Write_Children (Subtree : Tree_Node_Access);
2610 procedure Write_Subtree (Subtree : Tree_Node_Access);
2612 --------------------
2613 -- Write_Children --
2614 --------------------
2616 procedure Write_Children (Subtree : Tree_Node_Access) is
2617 CC : Children_Type renames Subtree.Children;
2618 C : Tree_Node_Access;
2620 begin
2621 Count_Type'Write (Stream, Child_Count (CC));
2623 C := CC.First;
2624 while C /= null loop
2625 Write_Subtree (C);
2626 C := C.Next;
2627 end loop;
2628 end Write_Children;
2630 -------------------
2631 -- Write_Subtree --
2632 -------------------
2634 procedure Write_Subtree (Subtree : Tree_Node_Access) is
2635 begin
2636 Element_Type'Output (Stream, Subtree.Element);
2637 Write_Children (Subtree);
2638 end Write_Subtree;
2640 -- Start of processing for Write
2642 begin
2643 Count_Type'Write (Stream, Container.Count);
2645 if Container.Count = 0 then
2646 return;
2647 end if;
2649 Write_Children (Root_Node (Container));
2650 end Write;
2652 procedure Write
2653 (Stream : not null access Root_Stream_Type'Class;
2654 Position : Cursor)
2656 begin
2657 raise Program_Error with "attempt to write tree cursor to stream";
2658 end Write;
2660 procedure Write
2661 (Stream : not null access Root_Stream_Type'Class;
2662 Item : Reference_Type)
2664 begin
2665 raise Program_Error with "attempt to stream reference";
2666 end Write;
2668 procedure Write
2669 (Stream : not null access Root_Stream_Type'Class;
2670 Item : Constant_Reference_Type)
2672 begin
2673 raise Program_Error with "attempt to stream reference";
2674 end Write;
2676 end Ada.Containers.Multiway_Trees;