2015-09-28 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / ada / a-cbmutr.adb
blob2a075428071dfafe934b0641bac5328105fff6a6
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.BOUNDED_MULTIWAY_TREES --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2011-2014, 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 System; use type System.Address;
32 package body Ada.Containers.Bounded_Multiway_Trees is
34 pragma Annotate (CodePeer, Skip_Analysis);
36 --------------------
37 -- Root_Iterator --
38 --------------------
40 type Root_Iterator is abstract new Limited_Controlled and
41 Tree_Iterator_Interfaces.Forward_Iterator with
42 record
43 Container : Tree_Access;
44 Subtree : Count_Type;
45 end record;
47 overriding procedure Finalize (Object : in out Root_Iterator);
49 -----------------------
50 -- Subtree_Iterator --
51 -----------------------
53 type Subtree_Iterator is new Root_Iterator with null record;
55 overriding function First (Object : Subtree_Iterator) return Cursor;
57 overriding function Next
58 (Object : Subtree_Iterator;
59 Position : Cursor) return Cursor;
61 ---------------------
62 -- Child_Iterator --
63 ---------------------
65 type Child_Iterator is new Root_Iterator and
66 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
68 overriding function First (Object : Child_Iterator) return Cursor;
70 overriding function Next
71 (Object : Child_Iterator;
72 Position : Cursor) return Cursor;
74 overriding function Last (Object : Child_Iterator) return Cursor;
76 overriding function Previous
77 (Object : Child_Iterator;
78 Position : Cursor) return Cursor;
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
84 procedure Initialize_Node (Container : in out Tree; Index : Count_Type);
85 procedure Initialize_Root (Container : in out Tree);
87 procedure Allocate_Node
88 (Container : in out Tree;
89 Initialize_Element : not null access procedure (Index : Count_Type);
90 New_Node : out Count_Type);
92 procedure Allocate_Node
93 (Container : in out Tree;
94 New_Item : Element_Type;
95 New_Node : out Count_Type);
97 procedure Allocate_Node
98 (Container : in out Tree;
99 Stream : not null access Root_Stream_Type'Class;
100 New_Node : out Count_Type);
102 procedure Deallocate_Node
103 (Container : in out Tree;
104 X : Count_Type);
106 procedure Deallocate_Children
107 (Container : in out Tree;
108 Subtree : Count_Type;
109 Count : in out Count_Type);
111 procedure Deallocate_Subtree
112 (Container : in out Tree;
113 Subtree : Count_Type;
114 Count : in out Count_Type);
116 function Equal_Children
117 (Left_Tree : Tree;
118 Left_Subtree : Count_Type;
119 Right_Tree : Tree;
120 Right_Subtree : Count_Type) return Boolean;
122 function Equal_Subtree
123 (Left_Tree : Tree;
124 Left_Subtree : Count_Type;
125 Right_Tree : Tree;
126 Right_Subtree : Count_Type) return Boolean;
128 procedure Iterate_Children
129 (Container : Tree;
130 Subtree : Count_Type;
131 Process : not null access procedure (Position : Cursor));
133 procedure Iterate_Subtree
134 (Container : Tree;
135 Subtree : Count_Type;
136 Process : not null access procedure (Position : Cursor));
138 procedure Copy_Children
139 (Source : Tree;
140 Source_Parent : Count_Type;
141 Target : in out Tree;
142 Target_Parent : Count_Type;
143 Count : in out Count_Type);
145 procedure Copy_Subtree
146 (Source : Tree;
147 Source_Subtree : Count_Type;
148 Target : in out Tree;
149 Target_Parent : Count_Type;
150 Target_Subtree : out Count_Type;
151 Count : in out Count_Type);
153 function Find_In_Children
154 (Container : Tree;
155 Subtree : Count_Type;
156 Item : Element_Type) return Count_Type;
158 function Find_In_Subtree
159 (Container : Tree;
160 Subtree : Count_Type;
161 Item : Element_Type) return Count_Type;
163 function Child_Count
164 (Container : Tree;
165 Parent : Count_Type) return Count_Type;
167 function Subtree_Node_Count
168 (Container : Tree;
169 Subtree : Count_Type) return Count_Type;
171 function Is_Reachable
172 (Container : Tree;
173 From, To : Count_Type) return Boolean;
175 function Root_Node (Container : Tree) return Count_Type;
177 procedure Remove_Subtree
178 (Container : in out Tree;
179 Subtree : Count_Type);
181 procedure Insert_Subtree_Node
182 (Container : in out Tree;
183 Subtree : Count_Type'Base;
184 Parent : Count_Type;
185 Before : Count_Type'Base);
187 procedure Insert_Subtree_List
188 (Container : in out Tree;
189 First : Count_Type'Base;
190 Last : Count_Type'Base;
191 Parent : Count_Type;
192 Before : Count_Type'Base);
194 procedure Splice_Children
195 (Container : in out Tree;
196 Target_Parent : Count_Type;
197 Before : Count_Type'Base;
198 Source_Parent : Count_Type);
200 procedure Splice_Children
201 (Target : in out Tree;
202 Target_Parent : Count_Type;
203 Before : Count_Type'Base;
204 Source : in out Tree;
205 Source_Parent : Count_Type);
207 procedure Splice_Subtree
208 (Target : in out Tree;
209 Parent : Count_Type;
210 Before : Count_Type'Base;
211 Source : in out Tree;
212 Position : in out Count_Type); -- source on input, target on output
214 ---------
215 -- "=" --
216 ---------
218 function "=" (Left, Right : Tree) return Boolean is
219 begin
220 if Left'Address = Right'Address then
221 return True;
222 end if;
224 if Left.Count /= Right.Count then
225 return False;
226 end if;
228 if Left.Count = 0 then
229 return True;
230 end if;
232 return Equal_Children
233 (Left_Tree => Left,
234 Left_Subtree => Root_Node (Left),
235 Right_Tree => Right,
236 Right_Subtree => Root_Node (Right));
237 end "=";
239 ------------
240 -- Adjust --
241 ------------
243 procedure Adjust (Control : in out Reference_Control_Type) is
244 begin
245 if Control.Container /= null then
246 declare
247 C : Tree renames Control.Container.all;
248 B : Natural renames C.Busy;
249 L : Natural renames C.Lock;
250 begin
251 B := B + 1;
252 L := L + 1;
253 end;
254 end if;
255 end Adjust;
257 -------------------
258 -- Allocate_Node --
259 -------------------
261 procedure Allocate_Node
262 (Container : in out Tree;
263 Initialize_Element : not null access procedure (Index : Count_Type);
264 New_Node : out Count_Type)
266 begin
267 if Container.Free >= 0 then
268 New_Node := Container.Free;
269 pragma Assert (New_Node in Container.Elements'Range);
271 -- We always perform the assignment first, before we change container
272 -- state, in order to defend against exceptions duration assignment.
274 Initialize_Element (New_Node);
276 Container.Free := Container.Nodes (New_Node).Next;
278 else
279 -- A negative free store value means that the links of the nodes in
280 -- the free store have not been initialized. In this case, the nodes
281 -- are physically contiguous in the array, starting at the index that
282 -- is the absolute value of the Container.Free, and continuing until
283 -- the end of the array (Nodes'Last).
285 New_Node := abs Container.Free;
286 pragma Assert (New_Node in Container.Elements'Range);
288 -- As above, we perform this assignment first, before modifying any
289 -- container state.
291 Initialize_Element (New_Node);
293 Container.Free := Container.Free - 1;
295 if abs Container.Free > Container.Capacity then
296 Container.Free := 0;
297 end if;
298 end if;
300 Initialize_Node (Container, New_Node);
301 end Allocate_Node;
303 procedure Allocate_Node
304 (Container : in out Tree;
305 New_Item : Element_Type;
306 New_Node : out Count_Type)
308 procedure Initialize_Element (Index : Count_Type);
310 procedure Initialize_Element (Index : Count_Type) is
311 begin
312 Container.Elements (Index) := New_Item;
313 end Initialize_Element;
315 begin
316 Allocate_Node (Container, Initialize_Element'Access, New_Node);
317 end Allocate_Node;
319 procedure Allocate_Node
320 (Container : in out Tree;
321 Stream : not null access Root_Stream_Type'Class;
322 New_Node : out Count_Type)
324 procedure Initialize_Element (Index : Count_Type);
326 procedure Initialize_Element (Index : Count_Type) is
327 begin
328 Element_Type'Read (Stream, Container.Elements (Index));
329 end Initialize_Element;
331 begin
332 Allocate_Node (Container, Initialize_Element'Access, New_Node);
333 end Allocate_Node;
335 -------------------
336 -- Ancestor_Find --
337 -------------------
339 function Ancestor_Find
340 (Position : Cursor;
341 Item : Element_Type) return Cursor
343 R, N : Count_Type;
345 begin
346 if Position = No_Element then
347 raise Constraint_Error with "Position cursor has no element";
348 end if;
350 -- AI-0136 says to raise PE if Position equals the root node. This does
351 -- not seem correct, as this value is just the limiting condition of the
352 -- search. For now we omit this check, pending a ruling from the ARG.
353 -- ???
355 -- if Is_Root (Position) then
356 -- raise Program_Error with "Position cursor designates root";
357 -- end if;
359 R := Root_Node (Position.Container.all);
360 N := Position.Node;
361 while N /= R loop
362 if Position.Container.Elements (N) = Item then
363 return Cursor'(Position.Container, N);
364 end if;
366 N := Position.Container.Nodes (N).Parent;
367 end loop;
369 return No_Element;
370 end Ancestor_Find;
372 ------------------
373 -- Append_Child --
374 ------------------
376 procedure Append_Child
377 (Container : in out Tree;
378 Parent : Cursor;
379 New_Item : Element_Type;
380 Count : Count_Type := 1)
382 Nodes : Tree_Node_Array renames Container.Nodes;
383 First, Last : Count_Type;
385 begin
386 if Parent = No_Element then
387 raise Constraint_Error with "Parent cursor has no element";
388 end if;
390 if Parent.Container /= Container'Unrestricted_Access then
391 raise Program_Error with "Parent cursor not in container";
392 end if;
394 if Count = 0 then
395 return;
396 end if;
398 if Container.Count > Container.Capacity - Count then
399 raise Capacity_Error
400 with "requested count exceeds available storage";
401 end if;
403 if Container.Busy > 0 then
404 raise Program_Error
405 with "attempt to tamper with cursors (tree is busy)";
406 end if;
408 if Container.Count = 0 then
409 Initialize_Root (Container);
410 end if;
412 Allocate_Node (Container, New_Item, First);
413 Nodes (First).Parent := Parent.Node;
415 Last := First;
416 for J in Count_Type'(2) .. Count loop
417 Allocate_Node (Container, New_Item, Nodes (Last).Next);
418 Nodes (Nodes (Last).Next).Parent := Parent.Node;
419 Nodes (Nodes (Last).Next).Prev := Last;
421 Last := Nodes (Last).Next;
422 end loop;
424 Insert_Subtree_List
425 (Container => Container,
426 First => First,
427 Last => Last,
428 Parent => Parent.Node,
429 Before => No_Node); -- means "insert at end of list"
431 Container.Count := Container.Count + Count;
432 end Append_Child;
434 ------------
435 -- Assign --
436 ------------
438 procedure Assign (Target : in out Tree; Source : Tree) is
439 Target_Count : Count_Type;
441 begin
442 if Target'Address = Source'Address then
443 return;
444 end if;
446 if Target.Capacity < Source.Count then
447 raise Capacity_Error -- ???
448 with "Target capacity is less than Source count";
449 end if;
451 Target.Clear; -- Checks busy bit
453 if Source.Count = 0 then
454 return;
455 end if;
457 Initialize_Root (Target);
459 -- Copy_Children returns the number of nodes that it allocates, but it
460 -- does this by incrementing the count value passed in, so we must
461 -- initialize the count before calling Copy_Children.
463 Target_Count := 0;
465 Copy_Children
466 (Source => Source,
467 Source_Parent => Root_Node (Source),
468 Target => Target,
469 Target_Parent => Root_Node (Target),
470 Count => Target_Count);
472 pragma Assert (Target_Count = Source.Count);
473 Target.Count := Source.Count;
474 end Assign;
476 -----------------
477 -- Child_Count --
478 -----------------
480 function Child_Count (Parent : Cursor) return Count_Type is
481 begin
482 if Parent = No_Element then
483 return 0;
485 elsif Parent.Container.Count = 0 then
486 pragma Assert (Is_Root (Parent));
487 return 0;
489 else
490 return Child_Count (Parent.Container.all, Parent.Node);
491 end if;
492 end Child_Count;
494 function Child_Count
495 (Container : Tree;
496 Parent : Count_Type) return Count_Type
498 NN : Tree_Node_Array renames Container.Nodes;
499 CC : Children_Type renames NN (Parent).Children;
501 Result : Count_Type;
502 Node : Count_Type'Base;
504 begin
505 Result := 0;
506 Node := CC.First;
507 while Node > 0 loop
508 Result := Result + 1;
509 Node := NN (Node).Next;
510 end loop;
512 return Result;
513 end Child_Count;
515 -----------------
516 -- Child_Depth --
517 -----------------
519 function Child_Depth (Parent, Child : Cursor) return Count_Type is
520 Result : Count_Type;
521 N : Count_Type'Base;
523 begin
524 if Parent = No_Element then
525 raise Constraint_Error with "Parent cursor has no element";
526 end if;
528 if Child = No_Element then
529 raise Constraint_Error with "Child cursor has no element";
530 end if;
532 if Parent.Container /= Child.Container then
533 raise Program_Error with "Parent and Child in different containers";
534 end if;
536 if Parent.Container.Count = 0 then
537 pragma Assert (Is_Root (Parent));
538 pragma Assert (Child = Parent);
539 return 0;
540 end if;
542 Result := 0;
543 N := Child.Node;
544 while N /= Parent.Node loop
545 Result := Result + 1;
546 N := Parent.Container.Nodes (N).Parent;
548 if N < 0 then
549 raise Program_Error with "Parent is not ancestor of Child";
550 end if;
551 end loop;
553 return Result;
554 end Child_Depth;
556 -----------
557 -- Clear --
558 -----------
560 procedure Clear (Container : in out Tree) is
561 Container_Count : constant Count_Type := Container.Count;
562 Count : Count_Type;
564 begin
565 if Container.Busy > 0 then
566 raise Program_Error
567 with "attempt to tamper with cursors (tree is busy)";
568 end if;
570 if Container_Count = 0 then
571 return;
572 end if;
574 Container.Count := 0;
576 -- Deallocate_Children returns the number of nodes that it deallocates,
577 -- but it does this by incrementing the count value that is passed in,
578 -- so we must first initialize the count return value before calling it.
580 Count := 0;
582 Deallocate_Children
583 (Container => Container,
584 Subtree => Root_Node (Container),
585 Count => Count);
587 pragma Assert (Count = Container_Count);
588 end Clear;
590 ------------------------
591 -- Constant_Reference --
592 ------------------------
594 function Constant_Reference
595 (Container : aliased Tree;
596 Position : Cursor) return Constant_Reference_Type
598 begin
599 if Position.Container = null then
600 raise Constraint_Error with
601 "Position cursor has no element";
602 end if;
604 if Position.Container /= Container'Unrestricted_Access then
605 raise Program_Error with
606 "Position cursor designates wrong container";
607 end if;
609 if Position.Node = Root_Node (Container) then
610 raise Program_Error with "Position cursor designates root";
611 end if;
613 -- Implement Vet for multiway tree???
614 -- pragma Assert (Vet (Position),
615 -- "Position cursor in Constant_Reference is bad");
617 declare
618 C : Tree renames Position.Container.all;
619 B : Natural renames C.Busy;
620 L : Natural renames C.Lock;
622 begin
623 return R : constant Constant_Reference_Type :=
624 (Element => Container.Elements (Position.Node)'Access,
625 Control => (Controlled with Container'Unrestricted_Access))
627 B := B + 1;
628 L := L + 1;
629 end return;
630 end;
631 end Constant_Reference;
633 --------------
634 -- Contains --
635 --------------
637 function Contains
638 (Container : Tree;
639 Item : Element_Type) return Boolean
641 begin
642 return Find (Container, Item) /= No_Element;
643 end Contains;
645 ----------
646 -- Copy --
647 ----------
649 function Copy
650 (Source : Tree;
651 Capacity : Count_Type := 0) return Tree
653 C : Count_Type;
655 begin
656 if Capacity = 0 then
657 C := Source.Count;
658 elsif Capacity >= Source.Count then
659 C := Capacity;
660 else
661 raise Capacity_Error with "Capacity value too small";
662 end if;
664 return Target : Tree (Capacity => C) do
665 Initialize_Root (Target);
667 if Source.Count = 0 then
668 return;
669 end if;
671 Copy_Children
672 (Source => Source,
673 Source_Parent => Root_Node (Source),
674 Target => Target,
675 Target_Parent => Root_Node (Target),
676 Count => Target.Count);
678 pragma Assert (Target.Count = Source.Count);
679 end return;
680 end Copy;
682 -------------------
683 -- Copy_Children --
684 -------------------
686 procedure Copy_Children
687 (Source : Tree;
688 Source_Parent : Count_Type;
689 Target : in out Tree;
690 Target_Parent : Count_Type;
691 Count : in out Count_Type)
693 S_Nodes : Tree_Node_Array renames Source.Nodes;
694 S_Node : Tree_Node_Type renames S_Nodes (Source_Parent);
696 T_Nodes : Tree_Node_Array renames Target.Nodes;
697 T_Node : Tree_Node_Type renames T_Nodes (Target_Parent);
699 pragma Assert (T_Node.Children.First <= 0);
700 pragma Assert (T_Node.Children.Last <= 0);
702 T_CC : Children_Type;
703 C : Count_Type'Base;
705 begin
706 -- We special-case the first allocation, in order to establish the
707 -- representation invariants for type Children_Type.
709 C := S_Node.Children.First;
711 if C <= 0 then -- source parent has no children
712 return;
713 end if;
715 Copy_Subtree
716 (Source => Source,
717 Source_Subtree => C,
718 Target => Target,
719 Target_Parent => Target_Parent,
720 Target_Subtree => T_CC.First,
721 Count => Count);
723 T_CC.Last := T_CC.First;
725 -- The representation invariants for the Children_Type list have been
726 -- established, so we can now copy the remaining children of Source.
728 C := S_Nodes (C).Next;
729 while C > 0 loop
730 Copy_Subtree
731 (Source => Source,
732 Source_Subtree => C,
733 Target => Target,
734 Target_Parent => Target_Parent,
735 Target_Subtree => T_Nodes (T_CC.Last).Next,
736 Count => Count);
738 T_Nodes (T_Nodes (T_CC.Last).Next).Prev := T_CC.Last;
739 T_CC.Last := T_Nodes (T_CC.Last).Next;
741 C := S_Nodes (C).Next;
742 end loop;
744 -- We add the newly-allocated children to their parent list only after
745 -- the allocation has succeeded, in order to preserve invariants of the
746 -- parent.
748 T_Node.Children := T_CC;
749 end Copy_Children;
751 ------------------
752 -- Copy_Subtree --
753 ------------------
755 procedure Copy_Subtree
756 (Target : in out Tree;
757 Parent : Cursor;
758 Before : Cursor;
759 Source : Cursor)
761 Target_Subtree : Count_Type;
762 Target_Count : Count_Type;
764 begin
765 if Parent = No_Element then
766 raise Constraint_Error with "Parent cursor has no element";
767 end if;
769 if Parent.Container /= Target'Unrestricted_Access then
770 raise Program_Error with "Parent cursor not in container";
771 end if;
773 if Before /= No_Element then
774 if Before.Container /= Target'Unrestricted_Access then
775 raise Program_Error with "Before cursor not in container";
776 end if;
778 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
779 raise Constraint_Error with "Before cursor not child of Parent";
780 end if;
781 end if;
783 if Source = No_Element then
784 return;
785 end if;
787 if Is_Root (Source) then
788 raise Constraint_Error with "Source cursor designates root";
789 end if;
791 if Target.Count = 0 then
792 Initialize_Root (Target);
793 end if;
795 -- Copy_Subtree returns a count of the number of nodes that it
796 -- allocates, but it works by incrementing the value that is passed
797 -- in. We must therefore initialize the count value before calling
798 -- Copy_Subtree.
800 Target_Count := 0;
802 Copy_Subtree
803 (Source => Source.Container.all,
804 Source_Subtree => Source.Node,
805 Target => Target,
806 Target_Parent => Parent.Node,
807 Target_Subtree => Target_Subtree,
808 Count => Target_Count);
810 Insert_Subtree_Node
811 (Container => Target,
812 Subtree => Target_Subtree,
813 Parent => Parent.Node,
814 Before => Before.Node);
816 Target.Count := Target.Count + Target_Count;
817 end Copy_Subtree;
819 procedure Copy_Subtree
820 (Source : Tree;
821 Source_Subtree : Count_Type;
822 Target : in out Tree;
823 Target_Parent : Count_Type;
824 Target_Subtree : out Count_Type;
825 Count : in out Count_Type)
827 T_Nodes : Tree_Node_Array renames Target.Nodes;
829 begin
830 -- First we allocate the root of the target subtree.
832 Allocate_Node
833 (Container => Target,
834 New_Item => Source.Elements (Source_Subtree),
835 New_Node => Target_Subtree);
837 T_Nodes (Target_Subtree).Parent := Target_Parent;
838 Count := Count + 1;
840 -- We now have a new subtree (for the Target tree), containing only a
841 -- copy of the corresponding element in the Source subtree. Next we copy
842 -- the children of the Source subtree as children of the new Target
843 -- subtree.
845 Copy_Children
846 (Source => Source,
847 Source_Parent => Source_Subtree,
848 Target => Target,
849 Target_Parent => Target_Subtree,
850 Count => Count);
851 end Copy_Subtree;
853 -------------------------
854 -- Deallocate_Children --
855 -------------------------
857 procedure Deallocate_Children
858 (Container : in out Tree;
859 Subtree : Count_Type;
860 Count : in out Count_Type)
862 Nodes : Tree_Node_Array renames Container.Nodes;
863 Node : Tree_Node_Type renames Nodes (Subtree); -- parent
864 CC : Children_Type renames Node.Children;
865 C : Count_Type'Base;
867 begin
868 while CC.First > 0 loop
869 C := CC.First;
870 CC.First := Nodes (C).Next;
872 Deallocate_Subtree (Container, C, Count);
873 end loop;
875 CC.Last := 0;
876 end Deallocate_Children;
878 ---------------------
879 -- Deallocate_Node --
880 ---------------------
882 procedure Deallocate_Node
883 (Container : in out Tree;
884 X : Count_Type)
886 NN : Tree_Node_Array renames Container.Nodes;
887 pragma Assert (X > 0);
888 pragma Assert (X <= NN'Last);
890 N : Tree_Node_Type renames NN (X);
891 pragma Assert (N.Parent /= X); -- node is active
893 begin
894 -- The tree container actually contains two lists: one for the "active"
895 -- nodes that contain elements that have been inserted onto the tree,
896 -- and another for the "inactive" nodes of the free store, from which
897 -- nodes are allocated when a new child is inserted in the tree.
899 -- We desire that merely declaring a tree object should have only
900 -- minimal cost; specially, we want to avoid having to initialize the
901 -- free store (to fill in the links), especially if the capacity of the
902 -- tree object is large.
904 -- The head of the free list is indicated by Container.Free. If its
905 -- value is non-negative, then the free store has been initialized in
906 -- the "normal" way: Container.Free points to the head of the list of
907 -- free (inactive) nodes, and the value 0 means the free list is
908 -- empty. Each node on the free list has been initialized to point to
909 -- the next free node (via its Next component), and the value 0 means
910 -- that this is the last node of the free list.
912 -- If Container.Free is negative, then the links on the free store have
913 -- not been initialized. In this case the link values are implied: the
914 -- free store comprises the components of the node array started with
915 -- the absolute value of Container.Free, and continuing until the end of
916 -- the array (Nodes'Last).
918 -- We prefer to lazy-init the free store (in fact, we would prefer to
919 -- not initialize it at all, because such initialization is an O(n)
920 -- operation). The time when we need to actually initialize the nodes in
921 -- the free store is when the node that becomes inactive is not at the
922 -- end of the active list. The free store would then be discontigous and
923 -- so its nodes would need to be linked in the traditional way.
925 -- It might be possible to perform an optimization here. Suppose that
926 -- the free store can be represented as having two parts: one comprising
927 -- the non-contiguous inactive nodes linked together in the normal way,
928 -- and the other comprising the contiguous inactive nodes (that are not
929 -- linked together, at the end of the nodes array). This would allow us
930 -- to never have to initialize the free store, except in a lazy way as
931 -- nodes become inactive. ???
933 -- When an element is deleted from the list container, its node becomes
934 -- inactive, and so we set its Parent and Prev components to an
935 -- impossible value (the index of the node itself), to indicate that it
936 -- is now inactive. This provides a useful way to detect a dangling
937 -- cursor reference.
939 N.Parent := X; -- Node is deallocated (not on active list)
940 N.Prev := X;
942 if Container.Free >= 0 then
943 -- The free store has previously been initialized. All we need to do
944 -- here is link the newly-free'd node onto the free list.
946 N.Next := Container.Free;
947 Container.Free := X;
949 elsif X + 1 = abs Container.Free then
950 -- The free store has not been initialized, and the node becoming
951 -- inactive immediately precedes the start of the free store. All
952 -- we need to do is move the start of the free store back by one.
954 N.Next := X; -- Not strictly necessary, but marginally safer
955 Container.Free := Container.Free + 1;
957 else
958 -- The free store has not been initialized, and the node becoming
959 -- inactive does not immediately precede the free store. Here we
960 -- first initialize the free store (meaning the links are given
961 -- values in the traditional way), and then link the newly-free'd
962 -- node onto the head of the free store.
964 -- See the comments above for an optimization opportunity. If the
965 -- next link for a node on the free store is negative, then this
966 -- means the remaining nodes on the free store are physically
967 -- contiguous, starting at the absolute value of that index value.
968 -- ???
970 Container.Free := abs Container.Free;
972 if Container.Free > Container.Capacity then
973 Container.Free := 0;
975 else
976 for J in Container.Free .. Container.Capacity - 1 loop
977 NN (J).Next := J + 1;
978 end loop;
980 NN (Container.Capacity).Next := 0;
981 end if;
983 NN (X).Next := Container.Free;
984 Container.Free := X;
985 end if;
986 end Deallocate_Node;
988 ------------------------
989 -- Deallocate_Subtree --
990 ------------------------
992 procedure Deallocate_Subtree
993 (Container : in out Tree;
994 Subtree : Count_Type;
995 Count : in out Count_Type)
997 begin
998 Deallocate_Children (Container, Subtree, Count);
999 Deallocate_Node (Container, Subtree);
1000 Count := Count + 1;
1001 end Deallocate_Subtree;
1003 ---------------------
1004 -- Delete_Children --
1005 ---------------------
1007 procedure Delete_Children
1008 (Container : in out Tree;
1009 Parent : Cursor)
1011 Count : Count_Type;
1013 begin
1014 if Parent = No_Element then
1015 raise Constraint_Error with "Parent cursor has no element";
1016 end if;
1018 if Parent.Container /= Container'Unrestricted_Access then
1019 raise Program_Error with "Parent cursor not in container";
1020 end if;
1022 if Container.Busy > 0 then
1023 raise Program_Error
1024 with "attempt to tamper with cursors (tree is busy)";
1025 end if;
1027 if Container.Count = 0 then
1028 pragma Assert (Is_Root (Parent));
1029 return;
1030 end if;
1032 -- Deallocate_Children returns a count of the number of nodes that it
1033 -- deallocates, but it works by incrementing the value that is passed
1034 -- in. We must therefore initialize the count value before calling
1035 -- Deallocate_Children.
1037 Count := 0;
1039 Deallocate_Children (Container, Parent.Node, Count);
1040 pragma Assert (Count <= Container.Count);
1042 Container.Count := Container.Count - Count;
1043 end Delete_Children;
1045 -----------------
1046 -- Delete_Leaf --
1047 -----------------
1049 procedure Delete_Leaf
1050 (Container : in out Tree;
1051 Position : in out Cursor)
1053 X : Count_Type;
1055 begin
1056 if Position = No_Element then
1057 raise Constraint_Error with "Position cursor has no element";
1058 end if;
1060 if Position.Container /= Container'Unrestricted_Access then
1061 raise Program_Error with "Position cursor not in container";
1062 end if;
1064 if Is_Root (Position) then
1065 raise Program_Error with "Position cursor designates root";
1066 end if;
1068 if not Is_Leaf (Position) then
1069 raise Constraint_Error with "Position cursor does not designate leaf";
1070 end if;
1072 if Container.Busy > 0 then
1073 raise Program_Error
1074 with "attempt to tamper with cursors (tree is busy)";
1075 end if;
1077 X := Position.Node;
1078 Position := No_Element;
1080 Remove_Subtree (Container, X);
1081 Container.Count := Container.Count - 1;
1083 Deallocate_Node (Container, X);
1084 end Delete_Leaf;
1086 --------------------
1087 -- Delete_Subtree --
1088 --------------------
1090 procedure Delete_Subtree
1091 (Container : in out Tree;
1092 Position : in out Cursor)
1094 X : Count_Type;
1095 Count : Count_Type;
1097 begin
1098 if Position = No_Element then
1099 raise Constraint_Error with "Position cursor has no element";
1100 end if;
1102 if Position.Container /= Container'Unrestricted_Access then
1103 raise Program_Error with "Position cursor not in container";
1104 end if;
1106 if Is_Root (Position) then
1107 raise Program_Error with "Position cursor designates root";
1108 end if;
1110 if Container.Busy > 0 then
1111 raise Program_Error
1112 with "attempt to tamper with cursors (tree is busy)";
1113 end if;
1115 X := Position.Node;
1116 Position := No_Element;
1118 Remove_Subtree (Container, X);
1120 -- Deallocate_Subtree returns a count of the number of nodes that it
1121 -- deallocates, but it works by incrementing the value that is passed
1122 -- in. We must therefore initialize the count value before calling
1123 -- Deallocate_Subtree.
1125 Count := 0;
1127 Deallocate_Subtree (Container, X, Count);
1128 pragma Assert (Count <= Container.Count);
1130 Container.Count := Container.Count - Count;
1131 end Delete_Subtree;
1133 -----------
1134 -- Depth --
1135 -----------
1137 function Depth (Position : Cursor) return Count_Type is
1138 Result : Count_Type;
1139 N : Count_Type'Base;
1141 begin
1142 if Position = No_Element then
1143 return 0;
1144 end if;
1146 if Is_Root (Position) then
1147 return 1;
1148 end if;
1150 Result := 0;
1151 N := Position.Node;
1152 while N >= 0 loop
1153 N := Position.Container.Nodes (N).Parent;
1154 Result := Result + 1;
1155 end loop;
1157 return Result;
1158 end Depth;
1160 -------------
1161 -- Element --
1162 -------------
1164 function Element (Position : Cursor) return Element_Type is
1165 begin
1166 if Position.Container = null then
1167 raise Constraint_Error with "Position cursor has no element";
1168 end if;
1170 if Position.Node = Root_Node (Position.Container.all) then
1171 raise Program_Error with "Position cursor designates root";
1172 end if;
1174 return Position.Container.Elements (Position.Node);
1175 end Element;
1177 --------------------
1178 -- Equal_Children --
1179 --------------------
1181 function Equal_Children
1182 (Left_Tree : Tree;
1183 Left_Subtree : Count_Type;
1184 Right_Tree : Tree;
1185 Right_Subtree : Count_Type) return Boolean
1187 L_NN : Tree_Node_Array renames Left_Tree.Nodes;
1188 R_NN : Tree_Node_Array renames Right_Tree.Nodes;
1190 Left_Children : Children_Type renames L_NN (Left_Subtree).Children;
1191 Right_Children : Children_Type renames R_NN (Right_Subtree).Children;
1193 L, R : Count_Type'Base;
1195 begin
1196 if Child_Count (Left_Tree, Left_Subtree)
1197 /= Child_Count (Right_Tree, Right_Subtree)
1198 then
1199 return False;
1200 end if;
1202 L := Left_Children.First;
1203 R := Right_Children.First;
1204 while L > 0 loop
1205 if not Equal_Subtree (Left_Tree, L, Right_Tree, R) then
1206 return False;
1207 end if;
1209 L := L_NN (L).Next;
1210 R := R_NN (R).Next;
1211 end loop;
1213 return True;
1214 end Equal_Children;
1216 -------------------
1217 -- Equal_Subtree --
1218 -------------------
1220 function Equal_Subtree
1221 (Left_Position : Cursor;
1222 Right_Position : Cursor) return Boolean
1224 begin
1225 if Left_Position = No_Element then
1226 raise Constraint_Error with "Left cursor has no element";
1227 end if;
1229 if Right_Position = No_Element then
1230 raise Constraint_Error with "Right cursor has no element";
1231 end if;
1233 if Left_Position = Right_Position then
1234 return True;
1235 end if;
1237 if Is_Root (Left_Position) then
1238 if not Is_Root (Right_Position) then
1239 return False;
1240 end if;
1242 if Left_Position.Container.Count = 0 then
1243 return Right_Position.Container.Count = 0;
1244 end if;
1246 if Right_Position.Container.Count = 0 then
1247 return False;
1248 end if;
1250 return Equal_Children
1251 (Left_Tree => Left_Position.Container.all,
1252 Left_Subtree => Left_Position.Node,
1253 Right_Tree => Right_Position.Container.all,
1254 Right_Subtree => Right_Position.Node);
1255 end if;
1257 if Is_Root (Right_Position) then
1258 return False;
1259 end if;
1261 return Equal_Subtree
1262 (Left_Tree => Left_Position.Container.all,
1263 Left_Subtree => Left_Position.Node,
1264 Right_Tree => Right_Position.Container.all,
1265 Right_Subtree => Right_Position.Node);
1266 end Equal_Subtree;
1268 function Equal_Subtree
1269 (Left_Tree : Tree;
1270 Left_Subtree : Count_Type;
1271 Right_Tree : Tree;
1272 Right_Subtree : Count_Type) return Boolean
1274 begin
1275 if Left_Tree.Elements (Left_Subtree) /=
1276 Right_Tree.Elements (Right_Subtree)
1277 then
1278 return False;
1279 end if;
1281 return Equal_Children
1282 (Left_Tree => Left_Tree,
1283 Left_Subtree => Left_Subtree,
1284 Right_Tree => Right_Tree,
1285 Right_Subtree => Right_Subtree);
1286 end Equal_Subtree;
1288 --------------
1289 -- Finalize --
1290 --------------
1292 procedure Finalize (Object : in out Root_Iterator) is
1293 B : Natural renames Object.Container.Busy;
1294 begin
1295 B := B - 1;
1296 end Finalize;
1298 procedure Finalize (Control : in out Reference_Control_Type) is
1299 begin
1300 if Control.Container /= null then
1301 declare
1302 C : Tree renames Control.Container.all;
1303 B : Natural renames C.Busy;
1304 L : Natural renames C.Lock;
1305 begin
1306 B := B - 1;
1307 L := L - 1;
1308 end;
1310 Control.Container := null;
1311 end if;
1312 end Finalize;
1314 ----------
1315 -- Find --
1316 ----------
1318 function Find
1319 (Container : Tree;
1320 Item : Element_Type) return Cursor
1322 Node : Count_Type;
1324 begin
1325 if Container.Count = 0 then
1326 return No_Element;
1327 end if;
1329 Node := Find_In_Children (Container, Root_Node (Container), Item);
1331 if Node = 0 then
1332 return No_Element;
1333 end if;
1335 return Cursor'(Container'Unrestricted_Access, Node);
1336 end Find;
1338 -----------
1339 -- First --
1340 -----------
1342 overriding function First (Object : Subtree_Iterator) return Cursor is
1343 begin
1344 if Object.Subtree = Root_Node (Object.Container.all) then
1345 return First_Child (Root (Object.Container.all));
1346 else
1347 return Cursor'(Object.Container, Object.Subtree);
1348 end if;
1349 end First;
1351 overriding function First (Object : Child_Iterator) return Cursor is
1352 begin
1353 return First_Child (Cursor'(Object.Container, Object.Subtree));
1354 end First;
1356 -----------------
1357 -- First_Child --
1358 -----------------
1360 function First_Child (Parent : Cursor) return Cursor is
1361 Node : Count_Type'Base;
1363 begin
1364 if Parent = No_Element then
1365 raise Constraint_Error with "Parent cursor has no element";
1366 end if;
1368 if Parent.Container.Count = 0 then
1369 pragma Assert (Is_Root (Parent));
1370 return No_Element;
1371 end if;
1373 Node := Parent.Container.Nodes (Parent.Node).Children.First;
1375 if Node <= 0 then
1376 return No_Element;
1377 end if;
1379 return Cursor'(Parent.Container, Node);
1380 end First_Child;
1382 -------------------------
1383 -- First_Child_Element --
1384 -------------------------
1386 function First_Child_Element (Parent : Cursor) return Element_Type is
1387 begin
1388 return Element (First_Child (Parent));
1389 end First_Child_Element;
1391 ----------------------
1392 -- Find_In_Children --
1393 ----------------------
1395 function Find_In_Children
1396 (Container : Tree;
1397 Subtree : Count_Type;
1398 Item : Element_Type) return Count_Type
1400 N : Count_Type'Base;
1401 Result : Count_Type;
1403 begin
1404 N := Container.Nodes (Subtree).Children.First;
1405 while N > 0 loop
1406 Result := Find_In_Subtree (Container, N, Item);
1408 if Result > 0 then
1409 return Result;
1410 end if;
1412 N := Container.Nodes (N).Next;
1413 end loop;
1415 return 0;
1416 end Find_In_Children;
1418 ---------------------
1419 -- Find_In_Subtree --
1420 ---------------------
1422 function Find_In_Subtree
1423 (Position : Cursor;
1424 Item : Element_Type) return Cursor
1426 Result : Count_Type;
1428 begin
1429 if Position = No_Element then
1430 raise Constraint_Error with "Position cursor has no element";
1431 end if;
1433 -- Commented-out pending ruling by ARG. ???
1435 -- if Position.Container /= Container'Unrestricted_Access then
1436 -- raise Program_Error with "Position cursor not in container";
1437 -- end if;
1439 if Position.Container.Count = 0 then
1440 pragma Assert (Is_Root (Position));
1441 return No_Element;
1442 end if;
1444 if Is_Root (Position) then
1445 Result := Find_In_Children
1446 (Container => Position.Container.all,
1447 Subtree => Position.Node,
1448 Item => Item);
1450 else
1451 Result := Find_In_Subtree
1452 (Container => Position.Container.all,
1453 Subtree => Position.Node,
1454 Item => Item);
1455 end if;
1457 if Result = 0 then
1458 return No_Element;
1459 end if;
1461 return Cursor'(Position.Container, Result);
1462 end Find_In_Subtree;
1464 function Find_In_Subtree
1465 (Container : Tree;
1466 Subtree : Count_Type;
1467 Item : Element_Type) return Count_Type
1469 begin
1470 if Container.Elements (Subtree) = Item then
1471 return Subtree;
1472 end if;
1474 return Find_In_Children (Container, Subtree, Item);
1475 end Find_In_Subtree;
1477 -----------------
1478 -- Has_Element --
1479 -----------------
1481 function Has_Element (Position : Cursor) return Boolean is
1482 begin
1483 if Position = No_Element then
1484 return False;
1485 end if;
1487 return Position.Node /= Root_Node (Position.Container.all);
1488 end Has_Element;
1490 ---------------------
1491 -- Initialize_Node --
1492 ---------------------
1494 procedure Initialize_Node
1495 (Container : in out Tree;
1496 Index : Count_Type)
1498 begin
1499 Container.Nodes (Index) :=
1500 (Parent => No_Node,
1501 Prev => 0,
1502 Next => 0,
1503 Children => (others => 0));
1504 end Initialize_Node;
1506 ---------------------
1507 -- Initialize_Root --
1508 ---------------------
1510 procedure Initialize_Root (Container : in out Tree) is
1511 begin
1512 Initialize_Node (Container, Root_Node (Container));
1513 end Initialize_Root;
1515 ------------------
1516 -- Insert_Child --
1517 ------------------
1519 procedure Insert_Child
1520 (Container : in out Tree;
1521 Parent : Cursor;
1522 Before : Cursor;
1523 New_Item : Element_Type;
1524 Count : Count_Type := 1)
1526 Position : Cursor;
1527 pragma Unreferenced (Position);
1529 begin
1530 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1531 end Insert_Child;
1533 procedure Insert_Child
1534 (Container : in out Tree;
1535 Parent : Cursor;
1536 Before : Cursor;
1537 New_Item : Element_Type;
1538 Position : out Cursor;
1539 Count : Count_Type := 1)
1541 Nodes : Tree_Node_Array renames Container.Nodes;
1542 First : Count_Type;
1543 Last : Count_Type;
1545 begin
1546 if Parent = No_Element then
1547 raise Constraint_Error with "Parent cursor has no element";
1548 end if;
1550 if Parent.Container /= Container'Unrestricted_Access then
1551 raise Program_Error with "Parent cursor not in container";
1552 end if;
1554 if Before /= No_Element then
1555 if Before.Container /= Container'Unrestricted_Access then
1556 raise Program_Error with "Before cursor not in container";
1557 end if;
1559 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1560 raise Constraint_Error with "Parent cursor not parent of Before";
1561 end if;
1562 end if;
1564 if Count = 0 then
1565 Position := No_Element; -- Need ruling from ARG ???
1566 return;
1567 end if;
1569 if Container.Count > Container.Capacity - Count then
1570 raise Capacity_Error
1571 with "requested count exceeds available storage";
1572 end if;
1574 if Container.Busy > 0 then
1575 raise Program_Error
1576 with "attempt to tamper with cursors (tree is busy)";
1577 end if;
1579 if Container.Count = 0 then
1580 Initialize_Root (Container);
1581 end if;
1583 Allocate_Node (Container, New_Item, First);
1584 Nodes (First).Parent := Parent.Node;
1586 Last := First;
1587 for J in Count_Type'(2) .. Count loop
1588 Allocate_Node (Container, New_Item, Nodes (Last).Next);
1589 Nodes (Nodes (Last).Next).Parent := Parent.Node;
1590 Nodes (Nodes (Last).Next).Prev := Last;
1592 Last := Nodes (Last).Next;
1593 end loop;
1595 Insert_Subtree_List
1596 (Container => Container,
1597 First => First,
1598 Last => Last,
1599 Parent => Parent.Node,
1600 Before => Before.Node);
1602 Container.Count := Container.Count + Count;
1604 Position := Cursor'(Parent.Container, First);
1605 end Insert_Child;
1607 procedure Insert_Child
1608 (Container : in out Tree;
1609 Parent : Cursor;
1610 Before : Cursor;
1611 Position : out Cursor;
1612 Count : Count_Type := 1)
1614 Nodes : Tree_Node_Array renames Container.Nodes;
1615 First : Count_Type;
1616 Last : Count_Type;
1618 New_Item : Element_Type;
1619 pragma Unmodified (New_Item);
1620 -- OK to reference, see below
1622 begin
1623 if Parent = No_Element then
1624 raise Constraint_Error with "Parent cursor has no element";
1625 end if;
1627 if Parent.Container /= Container'Unrestricted_Access then
1628 raise Program_Error with "Parent cursor not in container";
1629 end if;
1631 if Before /= No_Element then
1632 if Before.Container /= Container'Unrestricted_Access then
1633 raise Program_Error with "Before cursor not in container";
1634 end if;
1636 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1637 raise Constraint_Error with "Parent cursor not parent of Before";
1638 end if;
1639 end if;
1641 if Count = 0 then
1642 Position := No_Element; -- Need ruling from ARG ???
1643 return;
1644 end if;
1646 if Container.Count > Container.Capacity - Count then
1647 raise Capacity_Error
1648 with "requested count exceeds available storage";
1649 end if;
1651 if Container.Busy > 0 then
1652 raise Program_Error
1653 with "attempt to tamper with cursors (tree is busy)";
1654 end if;
1656 if Container.Count = 0 then
1657 Initialize_Root (Container);
1658 end if;
1660 -- There is no explicit element provided, but in an instance the element
1661 -- type may be a scalar with a Default_Value aspect, or a composite
1662 -- type with such a scalar component, or components with default
1663 -- initialization, so insert the specified number of possibly
1664 -- initialized elements at the given position.
1666 Allocate_Node (Container, New_Item, First);
1667 Nodes (First).Parent := Parent.Node;
1669 Last := First;
1670 for J in Count_Type'(2) .. Count loop
1671 Allocate_Node (Container, New_Item, Nodes (Last).Next);
1672 Nodes (Nodes (Last).Next).Parent := Parent.Node;
1673 Nodes (Nodes (Last).Next).Prev := Last;
1675 Last := Nodes (Last).Next;
1676 end loop;
1678 Insert_Subtree_List
1679 (Container => Container,
1680 First => First,
1681 Last => Last,
1682 Parent => Parent.Node,
1683 Before => Before.Node);
1685 Container.Count := Container.Count + Count;
1687 Position := Cursor'(Parent.Container, First);
1688 end Insert_Child;
1690 -------------------------
1691 -- Insert_Subtree_List --
1692 -------------------------
1694 procedure Insert_Subtree_List
1695 (Container : in out Tree;
1696 First : Count_Type'Base;
1697 Last : Count_Type'Base;
1698 Parent : Count_Type;
1699 Before : Count_Type'Base)
1701 NN : Tree_Node_Array renames Container.Nodes;
1702 N : Tree_Node_Type renames NN (Parent);
1703 CC : Children_Type renames N.Children;
1705 begin
1706 -- This is a simple utility operation to insert a list of nodes
1707 -- (First..Last) as children of Parent. The Before node specifies where
1708 -- the new children should be inserted relative to existing children.
1710 if First <= 0 then
1711 pragma Assert (Last <= 0);
1712 return;
1713 end if;
1715 pragma Assert (Last > 0);
1716 pragma Assert (Before <= 0 or else NN (Before).Parent = Parent);
1718 if CC.First <= 0 then -- no existing children
1719 CC.First := First;
1720 NN (CC.First).Prev := 0;
1721 CC.Last := Last;
1722 NN (CC.Last).Next := 0;
1724 elsif Before <= 0 then -- means "insert after existing nodes"
1725 NN (CC.Last).Next := First;
1726 NN (First).Prev := CC.Last;
1727 CC.Last := Last;
1728 NN (CC.Last).Next := 0;
1730 elsif Before = CC.First then
1731 NN (Last).Next := CC.First;
1732 NN (CC.First).Prev := Last;
1733 CC.First := First;
1734 NN (CC.First).Prev := 0;
1736 else
1737 NN (NN (Before).Prev).Next := First;
1738 NN (First).Prev := NN (Before).Prev;
1739 NN (Last).Next := Before;
1740 NN (Before).Prev := Last;
1741 end if;
1742 end Insert_Subtree_List;
1744 -------------------------
1745 -- Insert_Subtree_Node --
1746 -------------------------
1748 procedure Insert_Subtree_Node
1749 (Container : in out Tree;
1750 Subtree : Count_Type'Base;
1751 Parent : Count_Type;
1752 Before : Count_Type'Base)
1754 begin
1755 -- This is a simple wrapper operation to insert a single child into the
1756 -- Parent's children list.
1758 Insert_Subtree_List
1759 (Container => Container,
1760 First => Subtree,
1761 Last => Subtree,
1762 Parent => Parent,
1763 Before => Before);
1764 end Insert_Subtree_Node;
1766 --------------
1767 -- Is_Empty --
1768 --------------
1770 function Is_Empty (Container : Tree) return Boolean is
1771 begin
1772 return Container.Count = 0;
1773 end Is_Empty;
1775 -------------
1776 -- Is_Leaf --
1777 -------------
1779 function Is_Leaf (Position : Cursor) return Boolean is
1780 begin
1781 if Position = No_Element then
1782 return False;
1783 end if;
1785 if Position.Container.Count = 0 then
1786 pragma Assert (Is_Root (Position));
1787 return True;
1788 end if;
1790 return Position.Container.Nodes (Position.Node).Children.First <= 0;
1791 end Is_Leaf;
1793 ------------------
1794 -- Is_Reachable --
1795 ------------------
1797 function Is_Reachable
1798 (Container : Tree;
1799 From, To : Count_Type) return Boolean
1801 Idx : Count_Type;
1803 begin
1804 Idx := From;
1805 while Idx >= 0 loop
1806 if Idx = To then
1807 return True;
1808 end if;
1810 Idx := Container.Nodes (Idx).Parent;
1811 end loop;
1813 return False;
1814 end Is_Reachable;
1816 -------------
1817 -- Is_Root --
1818 -------------
1820 function Is_Root (Position : Cursor) return Boolean is
1821 begin
1822 return
1823 (if Position.Container = null then False
1824 else Position.Node = Root_Node (Position.Container.all));
1825 end Is_Root;
1827 -------------
1828 -- Iterate --
1829 -------------
1831 procedure Iterate
1832 (Container : Tree;
1833 Process : not null access procedure (Position : Cursor))
1835 B : Natural renames Container'Unrestricted_Access.all.Busy;
1837 begin
1838 if Container.Count = 0 then
1839 return;
1840 end if;
1842 B := B + 1;
1844 Iterate_Children
1845 (Container => Container,
1846 Subtree => Root_Node (Container),
1847 Process => Process);
1849 B := B - 1;
1851 exception
1852 when others =>
1853 B := B - 1;
1854 raise;
1855 end Iterate;
1857 function Iterate (Container : Tree)
1858 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1860 begin
1861 return Iterate_Subtree (Root (Container));
1862 end Iterate;
1864 ----------------------
1865 -- Iterate_Children --
1866 ----------------------
1868 procedure Iterate_Children
1869 (Parent : Cursor;
1870 Process : not null access procedure (Position : Cursor))
1872 begin
1873 if Parent = No_Element then
1874 raise Constraint_Error with "Parent cursor has no element";
1875 end if;
1877 if Parent.Container.Count = 0 then
1878 pragma Assert (Is_Root (Parent));
1879 return;
1880 end if;
1882 declare
1883 B : Natural renames Parent.Container.Busy;
1884 C : Count_Type;
1885 NN : Tree_Node_Array renames Parent.Container.Nodes;
1887 begin
1888 B := B + 1;
1890 C := NN (Parent.Node).Children.First;
1891 while C > 0 loop
1892 Process (Cursor'(Parent.Container, Node => C));
1893 C := NN (C).Next;
1894 end loop;
1896 B := B - 1;
1898 exception
1899 when others =>
1900 B := B - 1;
1901 raise;
1902 end;
1903 end Iterate_Children;
1905 procedure Iterate_Children
1906 (Container : Tree;
1907 Subtree : Count_Type;
1908 Process : not null access procedure (Position : Cursor))
1910 NN : Tree_Node_Array renames Container.Nodes;
1911 N : Tree_Node_Type renames NN (Subtree);
1912 C : Count_Type;
1914 begin
1915 -- This is a helper function to recursively iterate over all the nodes
1916 -- in a subtree, in depth-first fashion. This particular helper just
1917 -- visits the children of this subtree, not the root of the subtree
1918 -- itself. This is useful when starting from the ultimate root of the
1919 -- entire tree (see Iterate), as that root does not have an element.
1921 C := N.Children.First;
1922 while C > 0 loop
1923 Iterate_Subtree (Container, C, Process);
1924 C := NN (C).Next;
1925 end loop;
1926 end Iterate_Children;
1928 function Iterate_Children
1929 (Container : Tree;
1930 Parent : Cursor)
1931 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1933 C : constant Tree_Access := Container'Unrestricted_Access;
1934 B : Natural renames C.Busy;
1936 begin
1937 if Parent = No_Element then
1938 raise Constraint_Error with "Parent cursor has no element";
1939 end if;
1941 if Parent.Container /= C then
1942 raise Program_Error with "Parent cursor not in container";
1943 end if;
1945 return It : constant Child_Iterator :=
1946 Child_Iterator'(Limited_Controlled with
1947 Container => C,
1948 Subtree => Parent.Node)
1950 B := B + 1;
1951 end return;
1952 end Iterate_Children;
1954 ---------------------
1955 -- Iterate_Subtree --
1956 ---------------------
1958 function Iterate_Subtree
1959 (Position : Cursor)
1960 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1962 begin
1963 if Position = No_Element then
1964 raise Constraint_Error with "Position cursor has no element";
1965 end if;
1967 -- Implement Vet for multiway trees???
1968 -- pragma Assert (Vet (Position), "bad subtree cursor");
1970 declare
1971 B : Natural renames Position.Container.Busy;
1972 begin
1973 return It : constant Subtree_Iterator :=
1974 (Limited_Controlled with
1975 Container => Position.Container,
1976 Subtree => Position.Node)
1978 B := B + 1;
1979 end return;
1980 end;
1981 end Iterate_Subtree;
1983 procedure Iterate_Subtree
1984 (Position : Cursor;
1985 Process : not null access procedure (Position : Cursor))
1987 begin
1988 if Position = No_Element then
1989 raise Constraint_Error with "Position cursor has no element";
1990 end if;
1992 if Position.Container.Count = 0 then
1993 pragma Assert (Is_Root (Position));
1994 return;
1995 end if;
1997 declare
1998 T : Tree renames Position.Container.all;
1999 B : Natural renames T.Busy;
2001 begin
2002 B := B + 1;
2004 if Is_Root (Position) then
2005 Iterate_Children (T, Position.Node, Process);
2006 else
2007 Iterate_Subtree (T, Position.Node, Process);
2008 end if;
2010 B := B - 1;
2012 exception
2013 when others =>
2014 B := B - 1;
2015 raise;
2016 end;
2017 end Iterate_Subtree;
2019 procedure Iterate_Subtree
2020 (Container : Tree;
2021 Subtree : Count_Type;
2022 Process : not null access procedure (Position : Cursor))
2024 begin
2025 -- This is a helper function to recursively iterate over all the nodes
2026 -- in a subtree, in depth-first fashion. It first visits the root of the
2027 -- subtree, then visits its children.
2029 Process (Cursor'(Container'Unrestricted_Access, Subtree));
2030 Iterate_Children (Container, Subtree, Process);
2031 end Iterate_Subtree;
2033 ----------
2034 -- Last --
2035 ----------
2037 overriding function Last (Object : Child_Iterator) return Cursor is
2038 begin
2039 return Last_Child (Cursor'(Object.Container, Object.Subtree));
2040 end Last;
2042 ----------------
2043 -- Last_Child --
2044 ----------------
2046 function Last_Child (Parent : Cursor) return Cursor is
2047 Node : Count_Type'Base;
2049 begin
2050 if Parent = No_Element then
2051 raise Constraint_Error with "Parent cursor has no element";
2052 end if;
2054 if Parent.Container.Count = 0 then
2055 pragma Assert (Is_Root (Parent));
2056 return No_Element;
2057 end if;
2059 Node := Parent.Container.Nodes (Parent.Node).Children.Last;
2061 if Node <= 0 then
2062 return No_Element;
2063 end if;
2065 return Cursor'(Parent.Container, Node);
2066 end Last_Child;
2068 ------------------------
2069 -- Last_Child_Element --
2070 ------------------------
2072 function Last_Child_Element (Parent : Cursor) return Element_Type is
2073 begin
2074 return Element (Last_Child (Parent));
2075 end Last_Child_Element;
2077 ----------
2078 -- Move --
2079 ----------
2081 procedure Move (Target : in out Tree; Source : in out Tree) is
2082 begin
2083 if Target'Address = Source'Address then
2084 return;
2085 end if;
2087 if Source.Busy > 0 then
2088 raise Program_Error
2089 with "attempt to tamper with cursors of Source (tree is busy)";
2090 end if;
2092 Target.Assign (Source);
2093 Source.Clear;
2094 end Move;
2096 ----------
2097 -- Next --
2098 ----------
2100 overriding function Next
2101 (Object : Subtree_Iterator;
2102 Position : Cursor) return Cursor
2104 begin
2105 if Position.Container = null then
2106 return No_Element;
2107 end if;
2109 if Position.Container /= Object.Container then
2110 raise Program_Error with
2111 "Position cursor of Next designates wrong tree";
2112 end if;
2114 pragma Assert (Object.Container.Count > 0);
2115 pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2117 declare
2118 Nodes : Tree_Node_Array renames Object.Container.Nodes;
2119 Node : Count_Type;
2121 begin
2122 Node := Position.Node;
2124 if Nodes (Node).Children.First > 0 then
2125 return Cursor'(Object.Container, Nodes (Node).Children.First);
2126 end if;
2128 while Node /= Object.Subtree loop
2129 if Nodes (Node).Next > 0 then
2130 return Cursor'(Object.Container, Nodes (Node).Next);
2131 end if;
2133 Node := Nodes (Node).Parent;
2134 end loop;
2136 return No_Element;
2137 end;
2138 end Next;
2140 overriding function Next
2141 (Object : Child_Iterator;
2142 Position : Cursor) return Cursor
2144 begin
2145 if Position.Container = null then
2146 return No_Element;
2147 end if;
2149 if Position.Container /= Object.Container then
2150 raise Program_Error with
2151 "Position cursor of Next designates wrong tree";
2152 end if;
2154 pragma Assert (Object.Container.Count > 0);
2155 pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2157 return Next_Sibling (Position);
2158 end Next;
2160 ------------------
2161 -- Next_Sibling --
2162 ------------------
2164 function Next_Sibling (Position : Cursor) return Cursor is
2165 begin
2166 if Position = No_Element then
2167 return No_Element;
2168 end if;
2170 if Position.Container.Count = 0 then
2171 pragma Assert (Is_Root (Position));
2172 return No_Element;
2173 end if;
2175 declare
2176 T : Tree renames Position.Container.all;
2177 NN : Tree_Node_Array renames T.Nodes;
2178 N : Tree_Node_Type renames NN (Position.Node);
2180 begin
2181 if N.Next <= 0 then
2182 return No_Element;
2183 end if;
2185 return Cursor'(Position.Container, N.Next);
2186 end;
2187 end Next_Sibling;
2189 procedure Next_Sibling (Position : in out Cursor) is
2190 begin
2191 Position := Next_Sibling (Position);
2192 end Next_Sibling;
2194 ----------------
2195 -- Node_Count --
2196 ----------------
2198 function Node_Count (Container : Tree) return Count_Type is
2199 begin
2200 -- Container.Count is the number of nodes we have actually allocated. We
2201 -- cache the value specifically so this Node_Count operation can execute
2202 -- in O(1) time, which makes it behave similarly to how the Length
2203 -- selector function behaves for other containers.
2205 -- The cached node count value only describes the nodes we have
2206 -- allocated; the root node itself is not included in that count. The
2207 -- Node_Count operation returns a value that includes the root node
2208 -- (because the RM says so), so we must add 1 to our cached value.
2210 return 1 + Container.Count;
2211 end Node_Count;
2213 ------------
2214 -- Parent --
2215 ------------
2217 function Parent (Position : Cursor) return Cursor is
2218 begin
2219 if Position = No_Element then
2220 return No_Element;
2221 end if;
2223 if Position.Container.Count = 0 then
2224 pragma Assert (Is_Root (Position));
2225 return No_Element;
2226 end if;
2228 declare
2229 T : Tree renames Position.Container.all;
2230 NN : Tree_Node_Array renames T.Nodes;
2231 N : Tree_Node_Type renames NN (Position.Node);
2233 begin
2234 if N.Parent < 0 then
2235 pragma Assert (Position.Node = Root_Node (T));
2236 return No_Element;
2237 end if;
2239 return Cursor'(Position.Container, N.Parent);
2240 end;
2241 end Parent;
2243 -------------------
2244 -- Prepend_Child --
2245 -------------------
2247 procedure Prepend_Child
2248 (Container : in out Tree;
2249 Parent : Cursor;
2250 New_Item : Element_Type;
2251 Count : Count_Type := 1)
2253 Nodes : Tree_Node_Array renames Container.Nodes;
2254 First, Last : Count_Type;
2256 begin
2257 if Parent = No_Element then
2258 raise Constraint_Error with "Parent cursor has no element";
2259 end if;
2261 if Parent.Container /= Container'Unrestricted_Access then
2262 raise Program_Error with "Parent cursor not in container";
2263 end if;
2265 if Count = 0 then
2266 return;
2267 end if;
2269 if Container.Count > Container.Capacity - Count then
2270 raise Capacity_Error
2271 with "requested count exceeds available storage";
2272 end if;
2274 if Container.Busy > 0 then
2275 raise Program_Error
2276 with "attempt to tamper with cursors (tree is busy)";
2277 end if;
2279 if Container.Count = 0 then
2280 Initialize_Root (Container);
2281 end if;
2283 Allocate_Node (Container, New_Item, First);
2284 Nodes (First).Parent := Parent.Node;
2286 Last := First;
2287 for J in Count_Type'(2) .. Count loop
2288 Allocate_Node (Container, New_Item, Nodes (Last).Next);
2289 Nodes (Nodes (Last).Next).Parent := Parent.Node;
2290 Nodes (Nodes (Last).Next).Prev := Last;
2292 Last := Nodes (Last).Next;
2293 end loop;
2295 Insert_Subtree_List
2296 (Container => Container,
2297 First => First,
2298 Last => Last,
2299 Parent => Parent.Node,
2300 Before => Nodes (Parent.Node).Children.First);
2302 Container.Count := Container.Count + Count;
2303 end Prepend_Child;
2305 --------------
2306 -- Previous --
2307 --------------
2309 overriding function Previous
2310 (Object : Child_Iterator;
2311 Position : Cursor) return Cursor
2313 begin
2314 if Position.Container = null then
2315 return No_Element;
2316 end if;
2318 if Position.Container /= Object.Container then
2319 raise Program_Error with
2320 "Position cursor of Previous designates wrong tree";
2321 end if;
2323 return Previous_Sibling (Position);
2324 end Previous;
2326 ----------------------
2327 -- Previous_Sibling --
2328 ----------------------
2330 function Previous_Sibling (Position : Cursor) return Cursor is
2331 begin
2332 if Position = No_Element then
2333 return No_Element;
2334 end if;
2336 if Position.Container.Count = 0 then
2337 pragma Assert (Is_Root (Position));
2338 return No_Element;
2339 end if;
2341 declare
2342 T : Tree renames Position.Container.all;
2343 NN : Tree_Node_Array renames T.Nodes;
2344 N : Tree_Node_Type renames NN (Position.Node);
2346 begin
2347 if N.Prev <= 0 then
2348 return No_Element;
2349 end if;
2351 return Cursor'(Position.Container, N.Prev);
2352 end;
2353 end Previous_Sibling;
2355 procedure Previous_Sibling (Position : in out Cursor) is
2356 begin
2357 Position := Previous_Sibling (Position);
2358 end Previous_Sibling;
2360 -------------------
2361 -- Query_Element --
2362 -------------------
2364 procedure Query_Element
2365 (Position : Cursor;
2366 Process : not null access procedure (Element : Element_Type))
2368 begin
2369 if Position = No_Element then
2370 raise Constraint_Error with "Position cursor has no element";
2371 end if;
2373 if Is_Root (Position) then
2374 raise Program_Error with "Position cursor designates root";
2375 end if;
2377 declare
2378 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2379 B : Natural renames T.Busy;
2380 L : Natural renames T.Lock;
2382 begin
2383 B := B + 1;
2384 L := L + 1;
2386 Process (Element => T.Elements (Position.Node));
2388 L := L - 1;
2389 B := B - 1;
2391 exception
2392 when others =>
2393 L := L - 1;
2394 B := B - 1;
2395 raise;
2396 end;
2397 end Query_Element;
2399 ----------
2400 -- Read --
2401 ----------
2403 procedure Read
2404 (Stream : not null access Root_Stream_Type'Class;
2405 Container : out Tree)
2407 procedure Read_Children (Subtree : Count_Type);
2409 function Read_Subtree
2410 (Parent : Count_Type) return Count_Type;
2412 NN : Tree_Node_Array renames Container.Nodes;
2414 Total_Count : Count_Type'Base;
2415 -- Value read from the stream that says how many elements follow
2417 Read_Count : Count_Type'Base;
2418 -- Actual number of elements read from the stream
2420 -------------------
2421 -- Read_Children --
2422 -------------------
2424 procedure Read_Children (Subtree : Count_Type) is
2425 Count : Count_Type'Base;
2426 -- number of child subtrees
2428 CC : Children_Type;
2430 begin
2431 Count_Type'Read (Stream, Count);
2433 if Count < 0 then
2434 raise Program_Error with "attempt to read from corrupt stream";
2435 end if;
2437 if Count = 0 then
2438 return;
2439 end if;
2441 CC.First := Read_Subtree (Parent => Subtree);
2442 CC.Last := CC.First;
2444 for J in Count_Type'(2) .. Count loop
2445 NN (CC.Last).Next := Read_Subtree (Parent => Subtree);
2446 NN (NN (CC.Last).Next).Prev := CC.Last;
2447 CC.Last := NN (CC.Last).Next;
2448 end loop;
2450 -- Now that the allocation and reads have completed successfully, it
2451 -- is safe to link the children to their parent.
2453 NN (Subtree).Children := CC;
2454 end Read_Children;
2456 ------------------
2457 -- Read_Subtree --
2458 ------------------
2460 function Read_Subtree
2461 (Parent : Count_Type) return Count_Type
2463 Subtree : Count_Type;
2465 begin
2466 Allocate_Node (Container, Stream, Subtree);
2467 Container.Nodes (Subtree).Parent := Parent;
2469 Read_Count := Read_Count + 1;
2471 Read_Children (Subtree);
2473 return Subtree;
2474 end Read_Subtree;
2476 -- Start of processing for Read
2478 begin
2479 Container.Clear; -- checks busy bit
2481 Count_Type'Read (Stream, Total_Count);
2483 if Total_Count < 0 then
2484 raise Program_Error with "attempt to read from corrupt stream";
2485 end if;
2487 if Total_Count = 0 then
2488 return;
2489 end if;
2491 if Total_Count > Container.Capacity then
2492 raise Capacity_Error -- ???
2493 with "node count in stream exceeds container capacity";
2494 end if;
2496 Initialize_Root (Container);
2498 Read_Count := 0;
2500 Read_Children (Root_Node (Container));
2502 if Read_Count /= Total_Count then
2503 raise Program_Error with "attempt to read from corrupt stream";
2504 end if;
2506 Container.Count := Total_Count;
2507 end Read;
2509 procedure Read
2510 (Stream : not null access Root_Stream_Type'Class;
2511 Position : out Cursor)
2513 begin
2514 raise Program_Error with "attempt to read tree cursor from stream";
2515 end Read;
2517 procedure Read
2518 (Stream : not null access Root_Stream_Type'Class;
2519 Item : out Reference_Type)
2521 begin
2522 raise Program_Error with "attempt to stream reference";
2523 end Read;
2525 procedure Read
2526 (Stream : not null access Root_Stream_Type'Class;
2527 Item : out Constant_Reference_Type)
2529 begin
2530 raise Program_Error with "attempt to stream reference";
2531 end Read;
2533 ---------------
2534 -- Reference --
2535 ---------------
2537 function Reference
2538 (Container : aliased in out Tree;
2539 Position : Cursor) return Reference_Type
2541 begin
2542 if Position.Container = null then
2543 raise Constraint_Error with
2544 "Position cursor has no element";
2545 end if;
2547 if Position.Container /= Container'Unrestricted_Access then
2548 raise Program_Error with
2549 "Position cursor designates wrong container";
2550 end if;
2552 if Position.Node = Root_Node (Container) then
2553 raise Program_Error with "Position cursor designates root";
2554 end if;
2556 -- Implement Vet for multiway tree???
2557 -- pragma Assert (Vet (Position),
2558 -- "Position cursor in Constant_Reference is bad");
2560 declare
2561 C : Tree renames Position.Container.all;
2562 B : Natural renames C.Busy;
2563 L : Natural renames C.Lock;
2564 begin
2565 return R : constant Reference_Type :=
2566 (Element => Container.Elements (Position.Node)'Access,
2567 Control => (Controlled with Position.Container))
2569 B := B + 1;
2570 L := L + 1;
2571 end return;
2572 end;
2574 end Reference;
2576 --------------------
2577 -- Remove_Subtree --
2578 --------------------
2580 procedure Remove_Subtree
2581 (Container : in out Tree;
2582 Subtree : Count_Type)
2584 NN : Tree_Node_Array renames Container.Nodes;
2585 N : Tree_Node_Type renames NN (Subtree);
2586 CC : Children_Type renames NN (N.Parent).Children;
2588 begin
2589 -- This is a utility operation to remove a subtree node from its
2590 -- parent's list of children.
2592 if CC.First = Subtree then
2593 pragma Assert (N.Prev <= 0);
2595 if CC.Last = Subtree then
2596 pragma Assert (N.Next <= 0);
2597 CC.First := 0;
2598 CC.Last := 0;
2600 else
2601 CC.First := N.Next;
2602 NN (CC.First).Prev := 0;
2603 end if;
2605 elsif CC.Last = Subtree then
2606 pragma Assert (N.Next <= 0);
2607 CC.Last := N.Prev;
2608 NN (CC.Last).Next := 0;
2610 else
2611 NN (N.Prev).Next := N.Next;
2612 NN (N.Next).Prev := N.Prev;
2613 end if;
2614 end Remove_Subtree;
2616 ----------------------
2617 -- Replace_Element --
2618 ----------------------
2620 procedure Replace_Element
2621 (Container : in out Tree;
2622 Position : Cursor;
2623 New_Item : Element_Type)
2625 begin
2626 if Position = No_Element then
2627 raise Constraint_Error with "Position cursor has no element";
2628 end if;
2630 if Position.Container /= Container'Unrestricted_Access then
2631 raise Program_Error with "Position cursor not in container";
2632 end if;
2634 if Is_Root (Position) then
2635 raise Program_Error with "Position cursor designates root";
2636 end if;
2638 if Container.Lock > 0 then
2639 raise Program_Error
2640 with "attempt to tamper with elements (tree is locked)";
2641 end if;
2643 Container.Elements (Position.Node) := New_Item;
2644 end Replace_Element;
2646 ------------------------------
2647 -- Reverse_Iterate_Children --
2648 ------------------------------
2650 procedure Reverse_Iterate_Children
2651 (Parent : Cursor;
2652 Process : not null access procedure (Position : Cursor))
2654 begin
2655 if Parent = No_Element then
2656 raise Constraint_Error with "Parent cursor has no element";
2657 end if;
2659 if Parent.Container.Count = 0 then
2660 pragma Assert (Is_Root (Parent));
2661 return;
2662 end if;
2664 declare
2665 NN : Tree_Node_Array renames Parent.Container.Nodes;
2666 B : Natural renames Parent.Container.Busy;
2667 C : Count_Type;
2669 begin
2670 B := B + 1;
2672 C := NN (Parent.Node).Children.Last;
2673 while C > 0 loop
2674 Process (Cursor'(Parent.Container, Node => C));
2675 C := NN (C).Prev;
2676 end loop;
2678 B := B - 1;
2680 exception
2681 when others =>
2682 B := B - 1;
2683 raise;
2684 end;
2685 end Reverse_Iterate_Children;
2687 ----------
2688 -- Root --
2689 ----------
2691 function Root (Container : Tree) return Cursor is
2692 begin
2693 return (Container'Unrestricted_Access, Root_Node (Container));
2694 end Root;
2696 ---------------
2697 -- Root_Node --
2698 ---------------
2700 function Root_Node (Container : Tree) return Count_Type is
2701 pragma Unreferenced (Container);
2703 begin
2704 return 0;
2705 end Root_Node;
2707 ---------------------
2708 -- Splice_Children --
2709 ---------------------
2711 procedure Splice_Children
2712 (Target : in out Tree;
2713 Target_Parent : Cursor;
2714 Before : Cursor;
2715 Source : in out Tree;
2716 Source_Parent : Cursor)
2718 begin
2719 if Target_Parent = No_Element then
2720 raise Constraint_Error with "Target_Parent cursor has no element";
2721 end if;
2723 if Target_Parent.Container /= Target'Unrestricted_Access then
2724 raise Program_Error
2725 with "Target_Parent cursor not in Target container";
2726 end if;
2728 if Before /= No_Element then
2729 if Before.Container /= Target'Unrestricted_Access then
2730 raise Program_Error
2731 with "Before cursor not in Target container";
2732 end if;
2734 if Target.Nodes (Before.Node).Parent /= Target_Parent.Node then
2735 raise Constraint_Error
2736 with "Before cursor not child of Target_Parent";
2737 end if;
2738 end if;
2740 if Source_Parent = No_Element then
2741 raise Constraint_Error with "Source_Parent cursor has no element";
2742 end if;
2744 if Source_Parent.Container /= Source'Unrestricted_Access then
2745 raise Program_Error
2746 with "Source_Parent cursor not in Source container";
2747 end if;
2749 if Source.Count = 0 then
2750 pragma Assert (Is_Root (Source_Parent));
2751 return;
2752 end if;
2754 if Target'Address = Source'Address then
2755 if Target_Parent = Source_Parent then
2756 return;
2757 end if;
2759 if Target.Busy > 0 then
2760 raise Program_Error
2761 with "attempt to tamper with cursors (Target tree is busy)";
2762 end if;
2764 if Is_Reachable (Container => Target,
2765 From => Target_Parent.Node,
2766 To => Source_Parent.Node)
2767 then
2768 raise Constraint_Error
2769 with "Source_Parent is ancestor of Target_Parent";
2770 end if;
2772 Splice_Children
2773 (Container => Target,
2774 Target_Parent => Target_Parent.Node,
2775 Before => Before.Node,
2776 Source_Parent => Source_Parent.Node);
2778 return;
2779 end if;
2781 if Target.Busy > 0 then
2782 raise Program_Error
2783 with "attempt to tamper with cursors (Target tree is busy)";
2784 end if;
2786 if Source.Busy > 0 then
2787 raise Program_Error
2788 with "attempt to tamper with cursors (Source tree is busy)";
2789 end if;
2791 if Target.Count = 0 then
2792 Initialize_Root (Target);
2793 end if;
2795 Splice_Children
2796 (Target => Target,
2797 Target_Parent => Target_Parent.Node,
2798 Before => Before.Node,
2799 Source => Source,
2800 Source_Parent => Source_Parent.Node);
2801 end Splice_Children;
2803 procedure Splice_Children
2804 (Container : in out Tree;
2805 Target_Parent : Cursor;
2806 Before : Cursor;
2807 Source_Parent : Cursor)
2809 begin
2810 if Target_Parent = No_Element then
2811 raise Constraint_Error with "Target_Parent cursor has no element";
2812 end if;
2814 if Target_Parent.Container /= Container'Unrestricted_Access then
2815 raise Program_Error
2816 with "Target_Parent cursor not in container";
2817 end if;
2819 if Before /= No_Element then
2820 if Before.Container /= Container'Unrestricted_Access then
2821 raise Program_Error
2822 with "Before cursor not in container";
2823 end if;
2825 if Container.Nodes (Before.Node).Parent /= Target_Parent.Node then
2826 raise Constraint_Error
2827 with "Before cursor not child of Target_Parent";
2828 end if;
2829 end if;
2831 if Source_Parent = No_Element then
2832 raise Constraint_Error with "Source_Parent cursor has no element";
2833 end if;
2835 if Source_Parent.Container /= Container'Unrestricted_Access then
2836 raise Program_Error
2837 with "Source_Parent cursor not in container";
2838 end if;
2840 if Target_Parent = Source_Parent then
2841 return;
2842 end if;
2844 pragma Assert (Container.Count > 0);
2846 if Container.Busy > 0 then
2847 raise Program_Error
2848 with "attempt to tamper with cursors (tree is busy)";
2849 end if;
2851 if Is_Reachable (Container => Container,
2852 From => Target_Parent.Node,
2853 To => Source_Parent.Node)
2854 then
2855 raise Constraint_Error
2856 with "Source_Parent is ancestor of Target_Parent";
2857 end if;
2859 Splice_Children
2860 (Container => Container,
2861 Target_Parent => Target_Parent.Node,
2862 Before => Before.Node,
2863 Source_Parent => Source_Parent.Node);
2864 end Splice_Children;
2866 procedure Splice_Children
2867 (Container : in out Tree;
2868 Target_Parent : Count_Type;
2869 Before : Count_Type'Base;
2870 Source_Parent : Count_Type)
2872 NN : Tree_Node_Array renames Container.Nodes;
2873 CC : constant Children_Type := NN (Source_Parent).Children;
2874 C : Count_Type'Base;
2876 begin
2877 -- This is a utility operation to remove the children from Source parent
2878 -- and insert them into Target parent.
2880 NN (Source_Parent).Children := Children_Type'(others => 0);
2882 -- Fix up the Parent pointers of each child to designate its new Target
2883 -- parent.
2885 C := CC.First;
2886 while C > 0 loop
2887 NN (C).Parent := Target_Parent;
2888 C := NN (C).Next;
2889 end loop;
2891 Insert_Subtree_List
2892 (Container => Container,
2893 First => CC.First,
2894 Last => CC.Last,
2895 Parent => Target_Parent,
2896 Before => Before);
2897 end Splice_Children;
2899 procedure Splice_Children
2900 (Target : in out Tree;
2901 Target_Parent : Count_Type;
2902 Before : Count_Type'Base;
2903 Source : in out Tree;
2904 Source_Parent : Count_Type)
2906 S_NN : Tree_Node_Array renames Source.Nodes;
2907 S_CC : Children_Type renames S_NN (Source_Parent).Children;
2909 Target_Count, Source_Count : Count_Type;
2910 T, S : Count_Type'Base;
2912 begin
2913 -- This is a utility operation to copy the children from the Source
2914 -- parent and insert them as children of the Target parent, and then
2915 -- delete them from the Source. (This is not a true splice operation,
2916 -- but it is the best we can do in a bounded form.) The Before position
2917 -- specifies where among the Target parent's exising children the new
2918 -- children are inserted.
2920 -- Before we attempt the insertion, we must count the sources nodes in
2921 -- order to determine whether the target have enough storage
2922 -- available. Note that calculating this value is an O(n) operation.
2924 -- Here is an optimization opportunity: iterate of each children the
2925 -- source explicitly, and keep a running count of the total number of
2926 -- nodes. Compare the running total to the capacity of the target each
2927 -- pass through the loop. This is more efficient than summing the counts
2928 -- of child subtree (which is what Subtree_Node_Count does) and then
2929 -- comparing that total sum to the target's capacity. ???
2931 -- Here is another possibility. We currently treat the splice as an
2932 -- all-or-nothing proposition: either we can insert all of children of
2933 -- the source, or we raise exception with modifying the target. The
2934 -- price for not causing side-effect is an O(n) determination of the
2935 -- source count. If we are willing to tolerate side-effect, then we
2936 -- could loop over the children of the source, counting that subtree and
2937 -- then immediately inserting it in the target. The issue here is that
2938 -- the test for available storage could fail during some later pass,
2939 -- after children have already been inserted into target. ???
2941 Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1;
2943 if Source_Count = 0 then
2944 return;
2945 end if;
2947 if Target.Count > Target.Capacity - Source_Count then
2948 raise Capacity_Error -- ???
2949 with "Source count exceeds available storage on Target";
2950 end if;
2952 -- Copy_Subtree returns a count of the number of nodes it inserts, but
2953 -- it does this by incrementing the value passed in. Therefore we must
2954 -- initialize the count before calling Copy_Subtree.
2956 Target_Count := 0;
2958 S := S_CC.First;
2959 while S > 0 loop
2960 Copy_Subtree
2961 (Source => Source,
2962 Source_Subtree => S,
2963 Target => Target,
2964 Target_Parent => Target_Parent,
2965 Target_Subtree => T,
2966 Count => Target_Count);
2968 Insert_Subtree_Node
2969 (Container => Target,
2970 Subtree => T,
2971 Parent => Target_Parent,
2972 Before => Before);
2974 S := S_NN (S).Next;
2975 end loop;
2977 pragma Assert (Target_Count = Source_Count);
2978 Target.Count := Target.Count + Target_Count;
2980 -- As with Copy_Subtree, operation Deallocate_Children returns a count
2981 -- of the number of nodes it deallocates, but it works by incrementing
2982 -- the value passed in. We must therefore initialize the count before
2983 -- calling it.
2985 Source_Count := 0;
2987 Deallocate_Children (Source, Source_Parent, Source_Count);
2988 pragma Assert (Source_Count = Target_Count);
2990 Source.Count := Source.Count - Source_Count;
2991 end Splice_Children;
2993 --------------------
2994 -- Splice_Subtree --
2995 --------------------
2997 procedure Splice_Subtree
2998 (Target : in out Tree;
2999 Parent : Cursor;
3000 Before : Cursor;
3001 Source : in out Tree;
3002 Position : in out Cursor)
3004 begin
3005 if Parent = No_Element then
3006 raise Constraint_Error with "Parent cursor has no element";
3007 end if;
3009 if Parent.Container /= Target'Unrestricted_Access then
3010 raise Program_Error with "Parent cursor not in Target container";
3011 end if;
3013 if Before /= No_Element then
3014 if Before.Container /= Target'Unrestricted_Access then
3015 raise Program_Error with "Before cursor not in Target container";
3016 end if;
3018 if Target.Nodes (Before.Node).Parent /= Parent.Node then
3019 raise Constraint_Error with "Before cursor not child of Parent";
3020 end if;
3021 end if;
3023 if Position = No_Element then
3024 raise Constraint_Error with "Position cursor has no element";
3025 end if;
3027 if Position.Container /= Source'Unrestricted_Access then
3028 raise Program_Error with "Position cursor not in Source container";
3029 end if;
3031 if Is_Root (Position) then
3032 raise Program_Error with "Position cursor designates root";
3033 end if;
3035 if Target'Address = Source'Address then
3036 if Target.Nodes (Position.Node).Parent = Parent.Node then
3037 if Before = No_Element then
3038 if Target.Nodes (Position.Node).Next <= 0 then -- last child
3039 return;
3040 end if;
3042 elsif Position.Node = Before.Node then
3043 return;
3045 elsif Target.Nodes (Position.Node).Next = Before.Node then
3046 return;
3047 end if;
3048 end if;
3050 if Target.Busy > 0 then
3051 raise Program_Error
3052 with "attempt to tamper with cursors (Target tree is busy)";
3053 end if;
3055 if Is_Reachable (Container => Target,
3056 From => Parent.Node,
3057 To => Position.Node)
3058 then
3059 raise Constraint_Error with "Position is ancestor of Parent";
3060 end if;
3062 Remove_Subtree (Target, Position.Node);
3064 Target.Nodes (Position.Node).Parent := Parent.Node;
3065 Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node);
3067 return;
3068 end if;
3070 if Target.Busy > 0 then
3071 raise Program_Error
3072 with "attempt to tamper with cursors (Target tree is busy)";
3073 end if;
3075 if Source.Busy > 0 then
3076 raise Program_Error
3077 with "attempt to tamper with cursors (Source tree is busy)";
3078 end if;
3080 if Target.Count = 0 then
3081 Initialize_Root (Target);
3082 end if;
3084 Splice_Subtree
3085 (Target => Target,
3086 Parent => Parent.Node,
3087 Before => Before.Node,
3088 Source => Source,
3089 Position => Position.Node); -- modified during call
3091 Position.Container := Target'Unrestricted_Access;
3092 end Splice_Subtree;
3094 procedure Splice_Subtree
3095 (Container : in out Tree;
3096 Parent : Cursor;
3097 Before : Cursor;
3098 Position : Cursor)
3100 begin
3101 if Parent = No_Element then
3102 raise Constraint_Error with "Parent cursor has no element";
3103 end if;
3105 if Parent.Container /= Container'Unrestricted_Access then
3106 raise Program_Error with "Parent cursor not in container";
3107 end if;
3109 if Before /= No_Element then
3110 if Before.Container /= Container'Unrestricted_Access then
3111 raise Program_Error with "Before cursor not in container";
3112 end if;
3114 if Container.Nodes (Before.Node).Parent /= Parent.Node then
3115 raise Constraint_Error with "Before cursor not child of Parent";
3116 end if;
3117 end if;
3119 if Position = No_Element then
3120 raise Constraint_Error with "Position cursor has no element";
3121 end if;
3123 if Position.Container /= Container'Unrestricted_Access then
3124 raise Program_Error with "Position cursor not in container";
3125 end if;
3127 if Is_Root (Position) then
3129 -- Should this be PE instead? Need ARG confirmation. ???
3131 raise Constraint_Error with "Position cursor designates root";
3132 end if;
3134 if Container.Nodes (Position.Node).Parent = Parent.Node then
3135 if Before = No_Element then
3136 if Container.Nodes (Position.Node).Next <= 0 then -- last child
3137 return;
3138 end if;
3140 elsif Position.Node = Before.Node then
3141 return;
3143 elsif Container.Nodes (Position.Node).Next = Before.Node then
3144 return;
3145 end if;
3146 end if;
3148 if Container.Busy > 0 then
3149 raise Program_Error
3150 with "attempt to tamper with cursors (tree is busy)";
3151 end if;
3153 if Is_Reachable (Container => Container,
3154 From => Parent.Node,
3155 To => Position.Node)
3156 then
3157 raise Constraint_Error with "Position is ancestor of Parent";
3158 end if;
3160 Remove_Subtree (Container, Position.Node);
3161 Container.Nodes (Position.Node).Parent := Parent.Node;
3162 Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node);
3163 end Splice_Subtree;
3165 procedure Splice_Subtree
3166 (Target : in out Tree;
3167 Parent : Count_Type;
3168 Before : Count_Type'Base;
3169 Source : in out Tree;
3170 Position : in out Count_Type) -- Source on input, Target on output
3172 Source_Count : Count_Type := Subtree_Node_Count (Source, Position);
3173 pragma Assert (Source_Count >= 1);
3175 Target_Subtree : Count_Type;
3176 Target_Count : Count_Type;
3178 begin
3179 -- This is a utility operation to do the heavy lifting associated with
3180 -- splicing a subtree from one tree to another. Note that "splicing"
3181 -- is a bit of a misnomer here in the case of a bounded tree, because
3182 -- the elements must be copied from the source to the target.
3184 if Target.Count > Target.Capacity - Source_Count then
3185 raise Capacity_Error -- ???
3186 with "Source count exceeds available storage on Target";
3187 end if;
3189 -- Copy_Subtree returns a count of the number of nodes it inserts, but
3190 -- it does this by incrementing the value passed in. Therefore we must
3191 -- initialize the count before calling Copy_Subtree.
3193 Target_Count := 0;
3195 Copy_Subtree
3196 (Source => Source,
3197 Source_Subtree => Position,
3198 Target => Target,
3199 Target_Parent => Parent,
3200 Target_Subtree => Target_Subtree,
3201 Count => Target_Count);
3203 pragma Assert (Target_Count = Source_Count);
3205 -- Now link the newly-allocated subtree into the target.
3207 Insert_Subtree_Node
3208 (Container => Target,
3209 Subtree => Target_Subtree,
3210 Parent => Parent,
3211 Before => Before);
3213 Target.Count := Target.Count + Target_Count;
3215 -- The manipulation of the Target container is complete. Now we remove
3216 -- the subtree from the Source container.
3218 Remove_Subtree (Source, Position); -- unlink the subtree
3220 -- As with Copy_Subtree, operation Deallocate_Subtree returns a count of
3221 -- the number of nodes it deallocates, but it works by incrementing the
3222 -- value passed in. We must therefore initialize the count before
3223 -- calling it.
3225 Source_Count := 0;
3227 Deallocate_Subtree (Source, Position, Source_Count);
3228 pragma Assert (Source_Count = Target_Count);
3230 Source.Count := Source.Count - Source_Count;
3232 Position := Target_Subtree;
3233 end Splice_Subtree;
3235 ------------------------
3236 -- Subtree_Node_Count --
3237 ------------------------
3239 function Subtree_Node_Count (Position : Cursor) return Count_Type is
3240 begin
3241 if Position = No_Element then
3242 return 0;
3243 end if;
3245 if Position.Container.Count = 0 then
3246 pragma Assert (Is_Root (Position));
3247 return 1;
3248 end if;
3250 return Subtree_Node_Count (Position.Container.all, Position.Node);
3251 end Subtree_Node_Count;
3253 function Subtree_Node_Count
3254 (Container : Tree;
3255 Subtree : Count_Type) return Count_Type
3257 Result : Count_Type;
3258 Node : Count_Type'Base;
3260 begin
3261 Result := 1;
3262 Node := Container.Nodes (Subtree).Children.First;
3263 while Node > 0 loop
3264 Result := Result + Subtree_Node_Count (Container, Node);
3265 Node := Container.Nodes (Node).Next;
3266 end loop;
3267 return Result;
3268 end Subtree_Node_Count;
3270 ----------
3271 -- Swap --
3272 ----------
3274 procedure Swap
3275 (Container : in out Tree;
3276 I, J : Cursor)
3278 begin
3279 if I = No_Element then
3280 raise Constraint_Error with "I cursor has no element";
3281 end if;
3283 if I.Container /= Container'Unrestricted_Access then
3284 raise Program_Error with "I cursor not in container";
3285 end if;
3287 if Is_Root (I) then
3288 raise Program_Error with "I cursor designates root";
3289 end if;
3291 if I = J then -- make this test sooner???
3292 return;
3293 end if;
3295 if J = No_Element then
3296 raise Constraint_Error with "J cursor has no element";
3297 end if;
3299 if J.Container /= Container'Unrestricted_Access then
3300 raise Program_Error with "J cursor not in container";
3301 end if;
3303 if Is_Root (J) then
3304 raise Program_Error with "J cursor designates root";
3305 end if;
3307 if Container.Lock > 0 then
3308 raise Program_Error
3309 with "attempt to tamper with elements (tree is locked)";
3310 end if;
3312 declare
3313 EE : Element_Array renames Container.Elements;
3314 EI : constant Element_Type := EE (I.Node);
3316 begin
3317 EE (I.Node) := EE (J.Node);
3318 EE (J.Node) := EI;
3319 end;
3320 end Swap;
3322 --------------------
3323 -- Update_Element --
3324 --------------------
3326 procedure Update_Element
3327 (Container : in out Tree;
3328 Position : Cursor;
3329 Process : not null access procedure (Element : in out Element_Type))
3331 begin
3332 if Position = No_Element then
3333 raise Constraint_Error with "Position cursor has no element";
3334 end if;
3336 if Position.Container /= Container'Unrestricted_Access then
3337 raise Program_Error with "Position cursor not in container";
3338 end if;
3340 if Is_Root (Position) then
3341 raise Program_Error with "Position cursor designates root";
3342 end if;
3344 declare
3345 T : Tree renames Position.Container.all'Unrestricted_Access.all;
3346 B : Natural renames T.Busy;
3347 L : Natural renames T.Lock;
3349 begin
3350 B := B + 1;
3351 L := L + 1;
3353 Process (Element => T.Elements (Position.Node));
3355 L := L - 1;
3356 B := B - 1;
3358 exception
3359 when others =>
3360 L := L - 1;
3361 B := B - 1;
3362 raise;
3363 end;
3364 end Update_Element;
3366 -----------
3367 -- Write --
3368 -----------
3370 procedure Write
3371 (Stream : not null access Root_Stream_Type'Class;
3372 Container : Tree)
3374 procedure Write_Children (Subtree : Count_Type);
3375 procedure Write_Subtree (Subtree : Count_Type);
3377 --------------------
3378 -- Write_Children --
3379 --------------------
3381 procedure Write_Children (Subtree : Count_Type) is
3382 CC : Children_Type renames Container.Nodes (Subtree).Children;
3383 C : Count_Type'Base;
3385 begin
3386 Count_Type'Write (Stream, Child_Count (Container, Subtree));
3388 C := CC.First;
3389 while C > 0 loop
3390 Write_Subtree (C);
3391 C := Container.Nodes (C).Next;
3392 end loop;
3393 end Write_Children;
3395 -------------------
3396 -- Write_Subtree --
3397 -------------------
3399 procedure Write_Subtree (Subtree : Count_Type) is
3400 begin
3401 Element_Type'Write (Stream, Container.Elements (Subtree));
3402 Write_Children (Subtree);
3403 end Write_Subtree;
3405 -- Start of processing for Write
3407 begin
3408 Count_Type'Write (Stream, Container.Count);
3410 if Container.Count = 0 then
3411 return;
3412 end if;
3414 Write_Children (Root_Node (Container));
3415 end Write;
3417 procedure Write
3418 (Stream : not null access Root_Stream_Type'Class;
3419 Position : Cursor)
3421 begin
3422 raise Program_Error with "attempt to write tree cursor to stream";
3423 end Write;
3425 procedure Write
3426 (Stream : not null access Root_Stream_Type'Class;
3427 Item : Reference_Type)
3429 begin
3430 raise Program_Error with "attempt to stream reference";
3431 end Write;
3433 procedure Write
3434 (Stream : not null access Root_Stream_Type'Class;
3435 Item : Constant_Reference_Type)
3437 begin
3438 raise Program_Error with "attempt to stream reference";
3439 end Write;
3441 end Ada.Containers.Bounded_Multiway_Trees;