Merge from trunk:
[official-gcc.git] / main / gcc / ada / a-cbmutr.adb
blob26b0085b648625ae3e956d6bacc2c5933528d45d
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 --------------------
35 -- Root_Iterator --
36 --------------------
38 type Root_Iterator is abstract new Limited_Controlled and
39 Tree_Iterator_Interfaces.Forward_Iterator with
40 record
41 Container : Tree_Access;
42 Subtree : Count_Type;
43 end record;
45 overriding procedure Finalize (Object : in out Root_Iterator);
47 -----------------------
48 -- Subtree_Iterator --
49 -----------------------
51 type Subtree_Iterator is new Root_Iterator with null record;
53 overriding function First (Object : Subtree_Iterator) return Cursor;
55 overriding function Next
56 (Object : Subtree_Iterator;
57 Position : Cursor) return Cursor;
59 ---------------------
60 -- Child_Iterator --
61 ---------------------
63 type Child_Iterator is new Root_Iterator and
64 Tree_Iterator_Interfaces.Reversible_Iterator with null record;
66 overriding function First (Object : Child_Iterator) return Cursor;
68 overriding function Next
69 (Object : Child_Iterator;
70 Position : Cursor) return Cursor;
72 overriding function Last (Object : Child_Iterator) return Cursor;
74 overriding function Previous
75 (Object : Child_Iterator;
76 Position : Cursor) return Cursor;
78 -----------------------
79 -- Local Subprograms --
80 -----------------------
82 procedure Initialize_Node (Container : in out Tree; Index : Count_Type);
83 procedure Initialize_Root (Container : in out Tree);
85 procedure Allocate_Node
86 (Container : in out Tree;
87 Initialize_Element : not null access procedure (Index : Count_Type);
88 New_Node : out Count_Type);
90 procedure Allocate_Node
91 (Container : in out Tree;
92 New_Item : Element_Type;
93 New_Node : out Count_Type);
95 procedure Allocate_Node
96 (Container : in out Tree;
97 Stream : not null access Root_Stream_Type'Class;
98 New_Node : out Count_Type);
100 procedure Deallocate_Node
101 (Container : in out Tree;
102 X : Count_Type);
104 procedure Deallocate_Children
105 (Container : in out Tree;
106 Subtree : Count_Type;
107 Count : in out Count_Type);
109 procedure Deallocate_Subtree
110 (Container : in out Tree;
111 Subtree : Count_Type;
112 Count : in out Count_Type);
114 function Equal_Children
115 (Left_Tree : Tree;
116 Left_Subtree : Count_Type;
117 Right_Tree : Tree;
118 Right_Subtree : Count_Type) return Boolean;
120 function Equal_Subtree
121 (Left_Tree : Tree;
122 Left_Subtree : Count_Type;
123 Right_Tree : Tree;
124 Right_Subtree : Count_Type) return Boolean;
126 procedure Iterate_Children
127 (Container : Tree;
128 Subtree : Count_Type;
129 Process : not null access procedure (Position : Cursor));
131 procedure Iterate_Subtree
132 (Container : Tree;
133 Subtree : Count_Type;
134 Process : not null access procedure (Position : Cursor));
136 procedure Copy_Children
137 (Source : Tree;
138 Source_Parent : Count_Type;
139 Target : in out Tree;
140 Target_Parent : Count_Type;
141 Count : in out Count_Type);
143 procedure Copy_Subtree
144 (Source : Tree;
145 Source_Subtree : Count_Type;
146 Target : in out Tree;
147 Target_Parent : Count_Type;
148 Target_Subtree : out Count_Type;
149 Count : in out Count_Type);
151 function Find_In_Children
152 (Container : Tree;
153 Subtree : Count_Type;
154 Item : Element_Type) return Count_Type;
156 function Find_In_Subtree
157 (Container : Tree;
158 Subtree : Count_Type;
159 Item : Element_Type) return Count_Type;
161 function Child_Count
162 (Container : Tree;
163 Parent : Count_Type) return Count_Type;
165 function Subtree_Node_Count
166 (Container : Tree;
167 Subtree : Count_Type) return Count_Type;
169 function Is_Reachable
170 (Container : Tree;
171 From, To : Count_Type) return Boolean;
173 function Root_Node (Container : Tree) return Count_Type;
175 procedure Remove_Subtree
176 (Container : in out Tree;
177 Subtree : Count_Type);
179 procedure Insert_Subtree_Node
180 (Container : in out Tree;
181 Subtree : Count_Type'Base;
182 Parent : Count_Type;
183 Before : Count_Type'Base);
185 procedure Insert_Subtree_List
186 (Container : in out Tree;
187 First : Count_Type'Base;
188 Last : Count_Type'Base;
189 Parent : Count_Type;
190 Before : Count_Type'Base);
192 procedure Splice_Children
193 (Container : in out Tree;
194 Target_Parent : Count_Type;
195 Before : Count_Type'Base;
196 Source_Parent : Count_Type);
198 procedure Splice_Children
199 (Target : in out Tree;
200 Target_Parent : Count_Type;
201 Before : Count_Type'Base;
202 Source : in out Tree;
203 Source_Parent : Count_Type);
205 procedure Splice_Subtree
206 (Target : in out Tree;
207 Parent : Count_Type;
208 Before : Count_Type'Base;
209 Source : in out Tree;
210 Position : in out Count_Type); -- source on input, target on output
212 ---------
213 -- "=" --
214 ---------
216 function "=" (Left, Right : Tree) return Boolean is
217 begin
218 if Left'Address = Right'Address then
219 return True;
220 end if;
222 if Left.Count /= Right.Count then
223 return False;
224 end if;
226 if Left.Count = 0 then
227 return True;
228 end if;
230 return Equal_Children
231 (Left_Tree => Left,
232 Left_Subtree => Root_Node (Left),
233 Right_Tree => Right,
234 Right_Subtree => Root_Node (Right));
235 end "=";
237 ------------
238 -- Adjust --
239 ------------
241 procedure Adjust (Control : in out Reference_Control_Type) is
242 begin
243 if Control.Container /= null then
244 declare
245 C : Tree renames Control.Container.all;
246 B : Natural renames C.Busy;
247 L : Natural renames C.Lock;
248 begin
249 B := B + 1;
250 L := L + 1;
251 end;
252 end if;
253 end Adjust;
255 -------------------
256 -- Allocate_Node --
257 -------------------
259 procedure Allocate_Node
260 (Container : in out Tree;
261 Initialize_Element : not null access procedure (Index : Count_Type);
262 New_Node : out Count_Type)
264 begin
265 if Container.Free >= 0 then
266 New_Node := Container.Free;
267 pragma Assert (New_Node in Container.Elements'Range);
269 -- We always perform the assignment first, before we change container
270 -- state, in order to defend against exceptions duration assignment.
272 Initialize_Element (New_Node);
274 Container.Free := Container.Nodes (New_Node).Next;
276 else
277 -- A negative free store value means that the links of the nodes in
278 -- the free store have not been initialized. In this case, the nodes
279 -- are physically contiguous in the array, starting at the index that
280 -- is the absolute value of the Container.Free, and continuing until
281 -- the end of the array (Nodes'Last).
283 New_Node := abs Container.Free;
284 pragma Assert (New_Node in Container.Elements'Range);
286 -- As above, we perform this assignment first, before modifying any
287 -- container state.
289 Initialize_Element (New_Node);
291 Container.Free := Container.Free - 1;
293 if abs Container.Free > Container.Capacity then
294 Container.Free := 0;
295 end if;
296 end if;
298 Initialize_Node (Container, New_Node);
299 end Allocate_Node;
301 procedure Allocate_Node
302 (Container : in out Tree;
303 New_Item : Element_Type;
304 New_Node : out Count_Type)
306 procedure Initialize_Element (Index : Count_Type);
308 procedure Initialize_Element (Index : Count_Type) is
309 begin
310 Container.Elements (Index) := New_Item;
311 end Initialize_Element;
313 begin
314 Allocate_Node (Container, Initialize_Element'Access, New_Node);
315 end Allocate_Node;
317 procedure Allocate_Node
318 (Container : in out Tree;
319 Stream : not null access Root_Stream_Type'Class;
320 New_Node : out Count_Type)
322 procedure Initialize_Element (Index : Count_Type);
324 procedure Initialize_Element (Index : Count_Type) is
325 begin
326 Element_Type'Read (Stream, Container.Elements (Index));
327 end Initialize_Element;
329 begin
330 Allocate_Node (Container, Initialize_Element'Access, New_Node);
331 end Allocate_Node;
333 -------------------
334 -- Ancestor_Find --
335 -------------------
337 function Ancestor_Find
338 (Position : Cursor;
339 Item : Element_Type) return Cursor
341 R, N : Count_Type;
343 begin
344 if Position = No_Element then
345 raise Constraint_Error with "Position cursor has no element";
346 end if;
348 -- AI-0136 says to raise PE if Position equals the root node. This does
349 -- not seem correct, as this value is just the limiting condition of the
350 -- search. For now we omit this check, pending a ruling from the ARG.
351 -- ???
353 -- if Is_Root (Position) then
354 -- raise Program_Error with "Position cursor designates root";
355 -- end if;
357 R := Root_Node (Position.Container.all);
358 N := Position.Node;
359 while N /= R loop
360 if Position.Container.Elements (N) = Item then
361 return Cursor'(Position.Container, N);
362 end if;
364 N := Position.Container.Nodes (N).Parent;
365 end loop;
367 return No_Element;
368 end Ancestor_Find;
370 ------------------
371 -- Append_Child --
372 ------------------
374 procedure Append_Child
375 (Container : in out Tree;
376 Parent : Cursor;
377 New_Item : Element_Type;
378 Count : Count_Type := 1)
380 Nodes : Tree_Node_Array renames Container.Nodes;
381 First, Last : Count_Type;
383 begin
384 if Parent = No_Element then
385 raise Constraint_Error with "Parent cursor has no element";
386 end if;
388 if Parent.Container /= Container'Unrestricted_Access then
389 raise Program_Error with "Parent cursor not in container";
390 end if;
392 if Count = 0 then
393 return;
394 end if;
396 if Container.Count > Container.Capacity - Count then
397 raise Capacity_Error
398 with "requested count exceeds available storage";
399 end if;
401 if Container.Busy > 0 then
402 raise Program_Error
403 with "attempt to tamper with cursors (tree is busy)";
404 end if;
406 if Container.Count = 0 then
407 Initialize_Root (Container);
408 end if;
410 Allocate_Node (Container, New_Item, First);
411 Nodes (First).Parent := Parent.Node;
413 Last := First;
414 for J in Count_Type'(2) .. Count loop
415 Allocate_Node (Container, New_Item, Nodes (Last).Next);
416 Nodes (Nodes (Last).Next).Parent := Parent.Node;
417 Nodes (Nodes (Last).Next).Prev := Last;
419 Last := Nodes (Last).Next;
420 end loop;
422 Insert_Subtree_List
423 (Container => Container,
424 First => First,
425 Last => Last,
426 Parent => Parent.Node,
427 Before => No_Node); -- means "insert at end of list"
429 Container.Count := Container.Count + Count;
430 end Append_Child;
432 ------------
433 -- Assign --
434 ------------
436 procedure Assign (Target : in out Tree; Source : Tree) is
437 Target_Count : Count_Type;
439 begin
440 if Target'Address = Source'Address then
441 return;
442 end if;
444 if Target.Capacity < Source.Count then
445 raise Capacity_Error -- ???
446 with "Target capacity is less than Source count";
447 end if;
449 Target.Clear; -- Checks busy bit
451 if Source.Count = 0 then
452 return;
453 end if;
455 Initialize_Root (Target);
457 -- Copy_Children returns the number of nodes that it allocates, but it
458 -- does this by incrementing the count value passed in, so we must
459 -- initialize the count before calling Copy_Children.
461 Target_Count := 0;
463 Copy_Children
464 (Source => Source,
465 Source_Parent => Root_Node (Source),
466 Target => Target,
467 Target_Parent => Root_Node (Target),
468 Count => Target_Count);
470 pragma Assert (Target_Count = Source.Count);
471 Target.Count := Source.Count;
472 end Assign;
474 -----------------
475 -- Child_Count --
476 -----------------
478 function Child_Count (Parent : Cursor) return Count_Type is
479 begin
480 if Parent = No_Element then
481 return 0;
483 elsif Parent.Container.Count = 0 then
484 pragma Assert (Is_Root (Parent));
485 return 0;
487 else
488 return Child_Count (Parent.Container.all, Parent.Node);
489 end if;
490 end Child_Count;
492 function Child_Count
493 (Container : Tree;
494 Parent : Count_Type) return Count_Type
496 NN : Tree_Node_Array renames Container.Nodes;
497 CC : Children_Type renames NN (Parent).Children;
499 Result : Count_Type;
500 Node : Count_Type'Base;
502 begin
503 Result := 0;
504 Node := CC.First;
505 while Node > 0 loop
506 Result := Result + 1;
507 Node := NN (Node).Next;
508 end loop;
510 return Result;
511 end Child_Count;
513 -----------------
514 -- Child_Depth --
515 -----------------
517 function Child_Depth (Parent, Child : Cursor) return Count_Type is
518 Result : Count_Type;
519 N : Count_Type'Base;
521 begin
522 if Parent = No_Element then
523 raise Constraint_Error with "Parent cursor has no element";
524 end if;
526 if Child = No_Element then
527 raise Constraint_Error with "Child cursor has no element";
528 end if;
530 if Parent.Container /= Child.Container then
531 raise Program_Error with "Parent and Child in different containers";
532 end if;
534 if Parent.Container.Count = 0 then
535 pragma Assert (Is_Root (Parent));
536 pragma Assert (Child = Parent);
537 return 0;
538 end if;
540 Result := 0;
541 N := Child.Node;
542 while N /= Parent.Node loop
543 Result := Result + 1;
544 N := Parent.Container.Nodes (N).Parent;
546 if N < 0 then
547 raise Program_Error with "Parent is not ancestor of Child";
548 end if;
549 end loop;
551 return Result;
552 end Child_Depth;
554 -----------
555 -- Clear --
556 -----------
558 procedure Clear (Container : in out Tree) is
559 Container_Count : constant Count_Type := Container.Count;
560 Count : Count_Type;
562 begin
563 if Container.Busy > 0 then
564 raise Program_Error
565 with "attempt to tamper with cursors (tree is busy)";
566 end if;
568 if Container_Count = 0 then
569 return;
570 end if;
572 Container.Count := 0;
574 -- Deallocate_Children returns the number of nodes that it deallocates,
575 -- but it does this by incrementing the count value that is passed in,
576 -- so we must first initialize the count return value before calling it.
578 Count := 0;
580 Deallocate_Children
581 (Container => Container,
582 Subtree => Root_Node (Container),
583 Count => Count);
585 pragma Assert (Count = Container_Count);
586 end Clear;
588 ------------------------
589 -- Constant_Reference --
590 ------------------------
592 function Constant_Reference
593 (Container : aliased Tree;
594 Position : Cursor) return Constant_Reference_Type
596 begin
597 if Position.Container = null then
598 raise Constraint_Error with
599 "Position cursor has no element";
600 end if;
602 if Position.Container /= Container'Unrestricted_Access then
603 raise Program_Error with
604 "Position cursor designates wrong container";
605 end if;
607 if Position.Node = Root_Node (Container) then
608 raise Program_Error with "Position cursor designates root";
609 end if;
611 -- Implement Vet for multiway tree???
612 -- pragma Assert (Vet (Position),
613 -- "Position cursor in Constant_Reference is bad");
615 declare
616 C : Tree renames Position.Container.all;
617 B : Natural renames C.Busy;
618 L : Natural renames C.Lock;
620 begin
621 return R : constant Constant_Reference_Type :=
622 (Element => Container.Elements (Position.Node)'Access,
623 Control => (Controlled with Container'Unrestricted_Access))
625 B := B + 1;
626 L := L + 1;
627 end return;
628 end;
629 end Constant_Reference;
631 --------------
632 -- Contains --
633 --------------
635 function Contains
636 (Container : Tree;
637 Item : Element_Type) return Boolean
639 begin
640 return Find (Container, Item) /= No_Element;
641 end Contains;
643 ----------
644 -- Copy --
645 ----------
647 function Copy
648 (Source : Tree;
649 Capacity : Count_Type := 0) return Tree
651 C : Count_Type;
653 begin
654 if Capacity = 0 then
655 C := Source.Count;
656 elsif Capacity >= Source.Count then
657 C := Capacity;
658 else
659 raise Capacity_Error with "Capacity value too small";
660 end if;
662 return Target : Tree (Capacity => C) do
663 Initialize_Root (Target);
665 if Source.Count = 0 then
666 return;
667 end if;
669 Copy_Children
670 (Source => Source,
671 Source_Parent => Root_Node (Source),
672 Target => Target,
673 Target_Parent => Root_Node (Target),
674 Count => Target.Count);
676 pragma Assert (Target.Count = Source.Count);
677 end return;
678 end Copy;
680 -------------------
681 -- Copy_Children --
682 -------------------
684 procedure Copy_Children
685 (Source : Tree;
686 Source_Parent : Count_Type;
687 Target : in out Tree;
688 Target_Parent : Count_Type;
689 Count : in out Count_Type)
691 S_Nodes : Tree_Node_Array renames Source.Nodes;
692 S_Node : Tree_Node_Type renames S_Nodes (Source_Parent);
694 T_Nodes : Tree_Node_Array renames Target.Nodes;
695 T_Node : Tree_Node_Type renames T_Nodes (Target_Parent);
697 pragma Assert (T_Node.Children.First <= 0);
698 pragma Assert (T_Node.Children.Last <= 0);
700 T_CC : Children_Type;
701 C : Count_Type'Base;
703 begin
704 -- We special-case the first allocation, in order to establish the
705 -- representation invariants for type Children_Type.
707 C := S_Node.Children.First;
709 if C <= 0 then -- source parent has no children
710 return;
711 end if;
713 Copy_Subtree
714 (Source => Source,
715 Source_Subtree => C,
716 Target => Target,
717 Target_Parent => Target_Parent,
718 Target_Subtree => T_CC.First,
719 Count => Count);
721 T_CC.Last := T_CC.First;
723 -- The representation invariants for the Children_Type list have been
724 -- established, so we can now copy the remaining children of Source.
726 C := S_Nodes (C).Next;
727 while C > 0 loop
728 Copy_Subtree
729 (Source => Source,
730 Source_Subtree => C,
731 Target => Target,
732 Target_Parent => Target_Parent,
733 Target_Subtree => T_Nodes (T_CC.Last).Next,
734 Count => Count);
736 T_Nodes (T_Nodes (T_CC.Last).Next).Prev := T_CC.Last;
737 T_CC.Last := T_Nodes (T_CC.Last).Next;
739 C := S_Nodes (C).Next;
740 end loop;
742 -- We add the newly-allocated children to their parent list only after
743 -- the allocation has succeeded, in order to preserve invariants of the
744 -- parent.
746 T_Node.Children := T_CC;
747 end Copy_Children;
749 ------------------
750 -- Copy_Subtree --
751 ------------------
753 procedure Copy_Subtree
754 (Target : in out Tree;
755 Parent : Cursor;
756 Before : Cursor;
757 Source : Cursor)
759 Target_Subtree : Count_Type;
760 Target_Count : Count_Type;
762 begin
763 if Parent = No_Element then
764 raise Constraint_Error with "Parent cursor has no element";
765 end if;
767 if Parent.Container /= Target'Unrestricted_Access then
768 raise Program_Error with "Parent cursor not in container";
769 end if;
771 if Before /= No_Element then
772 if Before.Container /= Target'Unrestricted_Access then
773 raise Program_Error with "Before cursor not in container";
774 end if;
776 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
777 raise Constraint_Error with "Before cursor not child of Parent";
778 end if;
779 end if;
781 if Source = No_Element then
782 return;
783 end if;
785 if Is_Root (Source) then
786 raise Constraint_Error with "Source cursor designates root";
787 end if;
789 if Target.Count = 0 then
790 Initialize_Root (Target);
791 end if;
793 -- Copy_Subtree returns a count of the number of nodes that it
794 -- allocates, but it works by incrementing the value that is passed
795 -- in. We must therefore initialize the count value before calling
796 -- Copy_Subtree.
798 Target_Count := 0;
800 Copy_Subtree
801 (Source => Source.Container.all,
802 Source_Subtree => Source.Node,
803 Target => Target,
804 Target_Parent => Parent.Node,
805 Target_Subtree => Target_Subtree,
806 Count => Target_Count);
808 Insert_Subtree_Node
809 (Container => Target,
810 Subtree => Target_Subtree,
811 Parent => Parent.Node,
812 Before => Before.Node);
814 Target.Count := Target.Count + Target_Count;
815 end Copy_Subtree;
817 procedure Copy_Subtree
818 (Source : Tree;
819 Source_Subtree : Count_Type;
820 Target : in out Tree;
821 Target_Parent : Count_Type;
822 Target_Subtree : out Count_Type;
823 Count : in out Count_Type)
825 T_Nodes : Tree_Node_Array renames Target.Nodes;
827 begin
828 -- First we allocate the root of the target subtree.
830 Allocate_Node
831 (Container => Target,
832 New_Item => Source.Elements (Source_Subtree),
833 New_Node => Target_Subtree);
835 T_Nodes (Target_Subtree).Parent := Target_Parent;
836 Count := Count + 1;
838 -- We now have a new subtree (for the Target tree), containing only a
839 -- copy of the corresponding element in the Source subtree. Next we copy
840 -- the children of the Source subtree as children of the new Target
841 -- subtree.
843 Copy_Children
844 (Source => Source,
845 Source_Parent => Source_Subtree,
846 Target => Target,
847 Target_Parent => Target_Subtree,
848 Count => Count);
849 end Copy_Subtree;
851 -------------------------
852 -- Deallocate_Children --
853 -------------------------
855 procedure Deallocate_Children
856 (Container : in out Tree;
857 Subtree : Count_Type;
858 Count : in out Count_Type)
860 Nodes : Tree_Node_Array renames Container.Nodes;
861 Node : Tree_Node_Type renames Nodes (Subtree); -- parent
862 CC : Children_Type renames Node.Children;
863 C : Count_Type'Base;
865 begin
866 while CC.First > 0 loop
867 C := CC.First;
868 CC.First := Nodes (C).Next;
870 Deallocate_Subtree (Container, C, Count);
871 end loop;
873 CC.Last := 0;
874 end Deallocate_Children;
876 ---------------------
877 -- Deallocate_Node --
878 ---------------------
880 procedure Deallocate_Node
881 (Container : in out Tree;
882 X : Count_Type)
884 NN : Tree_Node_Array renames Container.Nodes;
885 pragma Assert (X > 0);
886 pragma Assert (X <= NN'Last);
888 N : Tree_Node_Type renames NN (X);
889 pragma Assert (N.Parent /= X); -- node is active
891 begin
892 -- The tree container actually contains two lists: one for the "active"
893 -- nodes that contain elements that have been inserted onto the tree,
894 -- and another for the "inactive" nodes of the free store, from which
895 -- nodes are allocated when a new child is inserted in the tree.
897 -- We desire that merely declaring a tree object should have only
898 -- minimal cost; specially, we want to avoid having to initialize the
899 -- free store (to fill in the links), especially if the capacity of the
900 -- tree object is large.
902 -- The head of the free list is indicated by Container.Free. If its
903 -- value is non-negative, then the free store has been initialized in
904 -- the "normal" way: Container.Free points to the head of the list of
905 -- free (inactive) nodes, and the value 0 means the free list is
906 -- empty. Each node on the free list has been initialized to point to
907 -- the next free node (via its Next component), and the value 0 means
908 -- that this is the last node of the free list.
910 -- If Container.Free is negative, then the links on the free store have
911 -- not been initialized. In this case the link values are implied: the
912 -- free store comprises the components of the node array started with
913 -- the absolute value of Container.Free, and continuing until the end of
914 -- the array (Nodes'Last).
916 -- We prefer to lazy-init the free store (in fact, we would prefer to
917 -- not initialize it at all, because such initialization is an O(n)
918 -- operation). The time when we need to actually initialize the nodes in
919 -- the free store is when the node that becomes inactive is not at the
920 -- end of the active list. The free store would then be discontigous and
921 -- so its nodes would need to be linked in the traditional way.
923 -- It might be possible to perform an optimization here. Suppose that
924 -- the free store can be represented as having two parts: one comprising
925 -- the non-contiguous inactive nodes linked together in the normal way,
926 -- and the other comprising the contiguous inactive nodes (that are not
927 -- linked together, at the end of the nodes array). This would allow us
928 -- to never have to initialize the free store, except in a lazy way as
929 -- nodes become inactive. ???
931 -- When an element is deleted from the list container, its node becomes
932 -- inactive, and so we set its Parent and Prev components to an
933 -- impossible value (the index of the node itself), to indicate that it
934 -- is now inactive. This provides a useful way to detect a dangling
935 -- cursor reference.
937 N.Parent := X; -- Node is deallocated (not on active list)
938 N.Prev := X;
940 if Container.Free >= 0 then
941 -- The free store has previously been initialized. All we need to do
942 -- here is link the newly-free'd node onto the free list.
944 N.Next := Container.Free;
945 Container.Free := X;
947 elsif X + 1 = abs Container.Free then
948 -- The free store has not been initialized, and the node becoming
949 -- inactive immediately precedes the start of the free store. All
950 -- we need to do is move the start of the free store back by one.
952 N.Next := X; -- Not strictly necessary, but marginally safer
953 Container.Free := Container.Free + 1;
955 else
956 -- The free store has not been initialized, and the node becoming
957 -- inactive does not immediately precede the free store. Here we
958 -- first initialize the free store (meaning the links are given
959 -- values in the traditional way), and then link the newly-free'd
960 -- node onto the head of the free store.
962 -- See the comments above for an optimization opportunity. If the
963 -- next link for a node on the free store is negative, then this
964 -- means the remaining nodes on the free store are physically
965 -- contiguous, starting at the absolute value of that index value.
966 -- ???
968 Container.Free := abs Container.Free;
970 if Container.Free > Container.Capacity then
971 Container.Free := 0;
973 else
974 for J in Container.Free .. Container.Capacity - 1 loop
975 NN (J).Next := J + 1;
976 end loop;
978 NN (Container.Capacity).Next := 0;
979 end if;
981 NN (X).Next := Container.Free;
982 Container.Free := X;
983 end if;
984 end Deallocate_Node;
986 ------------------------
987 -- Deallocate_Subtree --
988 ------------------------
990 procedure Deallocate_Subtree
991 (Container : in out Tree;
992 Subtree : Count_Type;
993 Count : in out Count_Type)
995 begin
996 Deallocate_Children (Container, Subtree, Count);
997 Deallocate_Node (Container, Subtree);
998 Count := Count + 1;
999 end Deallocate_Subtree;
1001 ---------------------
1002 -- Delete_Children --
1003 ---------------------
1005 procedure Delete_Children
1006 (Container : in out Tree;
1007 Parent : Cursor)
1009 Count : Count_Type;
1011 begin
1012 if Parent = No_Element then
1013 raise Constraint_Error with "Parent cursor has no element";
1014 end if;
1016 if Parent.Container /= Container'Unrestricted_Access then
1017 raise Program_Error with "Parent cursor not in container";
1018 end if;
1020 if Container.Busy > 0 then
1021 raise Program_Error
1022 with "attempt to tamper with cursors (tree is busy)";
1023 end if;
1025 if Container.Count = 0 then
1026 pragma Assert (Is_Root (Parent));
1027 return;
1028 end if;
1030 -- Deallocate_Children returns a count of the number of nodes that it
1031 -- deallocates, but it works by incrementing the value that is passed
1032 -- in. We must therefore initialize the count value before calling
1033 -- Deallocate_Children.
1035 Count := 0;
1037 Deallocate_Children (Container, Parent.Node, Count);
1038 pragma Assert (Count <= Container.Count);
1040 Container.Count := Container.Count - Count;
1041 end Delete_Children;
1043 -----------------
1044 -- Delete_Leaf --
1045 -----------------
1047 procedure Delete_Leaf
1048 (Container : in out Tree;
1049 Position : in out Cursor)
1051 X : Count_Type;
1053 begin
1054 if Position = No_Element then
1055 raise Constraint_Error with "Position cursor has no element";
1056 end if;
1058 if Position.Container /= Container'Unrestricted_Access then
1059 raise Program_Error with "Position cursor not in container";
1060 end if;
1062 if Is_Root (Position) then
1063 raise Program_Error with "Position cursor designates root";
1064 end if;
1066 if not Is_Leaf (Position) then
1067 raise Constraint_Error with "Position cursor does not designate leaf";
1068 end if;
1070 if Container.Busy > 0 then
1071 raise Program_Error
1072 with "attempt to tamper with cursors (tree is busy)";
1073 end if;
1075 X := Position.Node;
1076 Position := No_Element;
1078 Remove_Subtree (Container, X);
1079 Container.Count := Container.Count - 1;
1081 Deallocate_Node (Container, X);
1082 end Delete_Leaf;
1084 --------------------
1085 -- Delete_Subtree --
1086 --------------------
1088 procedure Delete_Subtree
1089 (Container : in out Tree;
1090 Position : in out Cursor)
1092 X : Count_Type;
1093 Count : Count_Type;
1095 begin
1096 if Position = No_Element then
1097 raise Constraint_Error with "Position cursor has no element";
1098 end if;
1100 if Position.Container /= Container'Unrestricted_Access then
1101 raise Program_Error with "Position cursor not in container";
1102 end if;
1104 if Is_Root (Position) then
1105 raise Program_Error with "Position cursor designates root";
1106 end if;
1108 if Container.Busy > 0 then
1109 raise Program_Error
1110 with "attempt to tamper with cursors (tree is busy)";
1111 end if;
1113 X := Position.Node;
1114 Position := No_Element;
1116 Remove_Subtree (Container, X);
1118 -- Deallocate_Subtree returns a count of the number of nodes that it
1119 -- deallocates, but it works by incrementing the value that is passed
1120 -- in. We must therefore initialize the count value before calling
1121 -- Deallocate_Subtree.
1123 Count := 0;
1125 Deallocate_Subtree (Container, X, Count);
1126 pragma Assert (Count <= Container.Count);
1128 Container.Count := Container.Count - Count;
1129 end Delete_Subtree;
1131 -----------
1132 -- Depth --
1133 -----------
1135 function Depth (Position : Cursor) return Count_Type is
1136 Result : Count_Type;
1137 N : Count_Type'Base;
1139 begin
1140 if Position = No_Element then
1141 return 0;
1142 end if;
1144 if Is_Root (Position) then
1145 return 1;
1146 end if;
1148 Result := 0;
1149 N := Position.Node;
1150 while N >= 0 loop
1151 N := Position.Container.Nodes (N).Parent;
1152 Result := Result + 1;
1153 end loop;
1155 return Result;
1156 end Depth;
1158 -------------
1159 -- Element --
1160 -------------
1162 function Element (Position : Cursor) return Element_Type is
1163 begin
1164 if Position.Container = null then
1165 raise Constraint_Error with "Position cursor has no element";
1166 end if;
1168 if Position.Node = Root_Node (Position.Container.all) then
1169 raise Program_Error with "Position cursor designates root";
1170 end if;
1172 return Position.Container.Elements (Position.Node);
1173 end Element;
1175 --------------------
1176 -- Equal_Children --
1177 --------------------
1179 function Equal_Children
1180 (Left_Tree : Tree;
1181 Left_Subtree : Count_Type;
1182 Right_Tree : Tree;
1183 Right_Subtree : Count_Type) return Boolean
1185 L_NN : Tree_Node_Array renames Left_Tree.Nodes;
1186 R_NN : Tree_Node_Array renames Right_Tree.Nodes;
1188 Left_Children : Children_Type renames L_NN (Left_Subtree).Children;
1189 Right_Children : Children_Type renames R_NN (Right_Subtree).Children;
1191 L, R : Count_Type'Base;
1193 begin
1194 if Child_Count (Left_Tree, Left_Subtree)
1195 /= Child_Count (Right_Tree, Right_Subtree)
1196 then
1197 return False;
1198 end if;
1200 L := Left_Children.First;
1201 R := Right_Children.First;
1202 while L > 0 loop
1203 if not Equal_Subtree (Left_Tree, L, Right_Tree, R) then
1204 return False;
1205 end if;
1207 L := L_NN (L).Next;
1208 R := R_NN (R).Next;
1209 end loop;
1211 return True;
1212 end Equal_Children;
1214 -------------------
1215 -- Equal_Subtree --
1216 -------------------
1218 function Equal_Subtree
1219 (Left_Position : Cursor;
1220 Right_Position : Cursor) return Boolean
1222 begin
1223 if Left_Position = No_Element then
1224 raise Constraint_Error with "Left cursor has no element";
1225 end if;
1227 if Right_Position = No_Element then
1228 raise Constraint_Error with "Right cursor has no element";
1229 end if;
1231 if Left_Position = Right_Position then
1232 return True;
1233 end if;
1235 if Is_Root (Left_Position) then
1236 if not Is_Root (Right_Position) then
1237 return False;
1238 end if;
1240 if Left_Position.Container.Count = 0 then
1241 return Right_Position.Container.Count = 0;
1242 end if;
1244 if Right_Position.Container.Count = 0 then
1245 return False;
1246 end if;
1248 return Equal_Children
1249 (Left_Tree => Left_Position.Container.all,
1250 Left_Subtree => Left_Position.Node,
1251 Right_Tree => Right_Position.Container.all,
1252 Right_Subtree => Right_Position.Node);
1253 end if;
1255 if Is_Root (Right_Position) then
1256 return False;
1257 end if;
1259 return Equal_Subtree
1260 (Left_Tree => Left_Position.Container.all,
1261 Left_Subtree => Left_Position.Node,
1262 Right_Tree => Right_Position.Container.all,
1263 Right_Subtree => Right_Position.Node);
1264 end Equal_Subtree;
1266 function Equal_Subtree
1267 (Left_Tree : Tree;
1268 Left_Subtree : Count_Type;
1269 Right_Tree : Tree;
1270 Right_Subtree : Count_Type) return Boolean
1272 begin
1273 if Left_Tree.Elements (Left_Subtree) /=
1274 Right_Tree.Elements (Right_Subtree)
1275 then
1276 return False;
1277 end if;
1279 return Equal_Children
1280 (Left_Tree => Left_Tree,
1281 Left_Subtree => Left_Subtree,
1282 Right_Tree => Right_Tree,
1283 Right_Subtree => Right_Subtree);
1284 end Equal_Subtree;
1286 --------------
1287 -- Finalize --
1288 --------------
1290 procedure Finalize (Object : in out Root_Iterator) is
1291 B : Natural renames Object.Container.Busy;
1292 begin
1293 B := B - 1;
1294 end Finalize;
1296 procedure Finalize (Control : in out Reference_Control_Type) is
1297 begin
1298 if Control.Container /= null then
1299 declare
1300 C : Tree renames Control.Container.all;
1301 B : Natural renames C.Busy;
1302 L : Natural renames C.Lock;
1303 begin
1304 B := B - 1;
1305 L := L - 1;
1306 end;
1308 Control.Container := null;
1309 end if;
1310 end Finalize;
1312 ----------
1313 -- Find --
1314 ----------
1316 function Find
1317 (Container : Tree;
1318 Item : Element_Type) return Cursor
1320 Node : Count_Type;
1322 begin
1323 if Container.Count = 0 then
1324 return No_Element;
1325 end if;
1327 Node := Find_In_Children (Container, Root_Node (Container), Item);
1329 if Node = 0 then
1330 return No_Element;
1331 end if;
1333 return Cursor'(Container'Unrestricted_Access, Node);
1334 end Find;
1336 -----------
1337 -- First --
1338 -----------
1340 overriding function First (Object : Subtree_Iterator) return Cursor is
1341 begin
1342 if Object.Subtree = Root_Node (Object.Container.all) then
1343 return First_Child (Root (Object.Container.all));
1344 else
1345 return Cursor'(Object.Container, Object.Subtree);
1346 end if;
1347 end First;
1349 overriding function First (Object : Child_Iterator) return Cursor is
1350 begin
1351 return First_Child (Cursor'(Object.Container, Object.Subtree));
1352 end First;
1354 -----------------
1355 -- First_Child --
1356 -----------------
1358 function First_Child (Parent : Cursor) return Cursor is
1359 Node : Count_Type'Base;
1361 begin
1362 if Parent = No_Element then
1363 raise Constraint_Error with "Parent cursor has no element";
1364 end if;
1366 if Parent.Container.Count = 0 then
1367 pragma Assert (Is_Root (Parent));
1368 return No_Element;
1369 end if;
1371 Node := Parent.Container.Nodes (Parent.Node).Children.First;
1373 if Node <= 0 then
1374 return No_Element;
1375 end if;
1377 return Cursor'(Parent.Container, Node);
1378 end First_Child;
1380 -------------------------
1381 -- First_Child_Element --
1382 -------------------------
1384 function First_Child_Element (Parent : Cursor) return Element_Type is
1385 begin
1386 return Element (First_Child (Parent));
1387 end First_Child_Element;
1389 ----------------------
1390 -- Find_In_Children --
1391 ----------------------
1393 function Find_In_Children
1394 (Container : Tree;
1395 Subtree : Count_Type;
1396 Item : Element_Type) return Count_Type
1398 N : Count_Type'Base;
1399 Result : Count_Type;
1401 begin
1402 N := Container.Nodes (Subtree).Children.First;
1403 while N > 0 loop
1404 Result := Find_In_Subtree (Container, N, Item);
1406 if Result > 0 then
1407 return Result;
1408 end if;
1410 N := Container.Nodes (N).Next;
1411 end loop;
1413 return 0;
1414 end Find_In_Children;
1416 ---------------------
1417 -- Find_In_Subtree --
1418 ---------------------
1420 function Find_In_Subtree
1421 (Position : Cursor;
1422 Item : Element_Type) return Cursor
1424 Result : Count_Type;
1426 begin
1427 if Position = No_Element then
1428 raise Constraint_Error with "Position cursor has no element";
1429 end if;
1431 -- Commented-out pending ruling by ARG. ???
1433 -- if Position.Container /= Container'Unrestricted_Access then
1434 -- raise Program_Error with "Position cursor not in container";
1435 -- end if;
1437 if Position.Container.Count = 0 then
1438 pragma Assert (Is_Root (Position));
1439 return No_Element;
1440 end if;
1442 if Is_Root (Position) then
1443 Result := Find_In_Children
1444 (Container => Position.Container.all,
1445 Subtree => Position.Node,
1446 Item => Item);
1448 else
1449 Result := Find_In_Subtree
1450 (Container => Position.Container.all,
1451 Subtree => Position.Node,
1452 Item => Item);
1453 end if;
1455 if Result = 0 then
1456 return No_Element;
1457 end if;
1459 return Cursor'(Position.Container, Result);
1460 end Find_In_Subtree;
1462 function Find_In_Subtree
1463 (Container : Tree;
1464 Subtree : Count_Type;
1465 Item : Element_Type) return Count_Type
1467 begin
1468 if Container.Elements (Subtree) = Item then
1469 return Subtree;
1470 end if;
1472 return Find_In_Children (Container, Subtree, Item);
1473 end Find_In_Subtree;
1475 -----------------
1476 -- Has_Element --
1477 -----------------
1479 function Has_Element (Position : Cursor) return Boolean is
1480 begin
1481 if Position = No_Element then
1482 return False;
1483 end if;
1485 return Position.Node /= Root_Node (Position.Container.all);
1486 end Has_Element;
1488 ---------------------
1489 -- Initialize_Node --
1490 ---------------------
1492 procedure Initialize_Node
1493 (Container : in out Tree;
1494 Index : Count_Type)
1496 begin
1497 Container.Nodes (Index) :=
1498 (Parent => No_Node,
1499 Prev => 0,
1500 Next => 0,
1501 Children => (others => 0));
1502 end Initialize_Node;
1504 ---------------------
1505 -- Initialize_Root --
1506 ---------------------
1508 procedure Initialize_Root (Container : in out Tree) is
1509 begin
1510 Initialize_Node (Container, Root_Node (Container));
1511 end Initialize_Root;
1513 ------------------
1514 -- Insert_Child --
1515 ------------------
1517 procedure Insert_Child
1518 (Container : in out Tree;
1519 Parent : Cursor;
1520 Before : Cursor;
1521 New_Item : Element_Type;
1522 Count : Count_Type := 1)
1524 Position : Cursor;
1525 pragma Unreferenced (Position);
1527 begin
1528 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1529 end Insert_Child;
1531 procedure Insert_Child
1532 (Container : in out Tree;
1533 Parent : Cursor;
1534 Before : Cursor;
1535 New_Item : Element_Type;
1536 Position : out Cursor;
1537 Count : Count_Type := 1)
1539 Nodes : Tree_Node_Array renames Container.Nodes;
1540 First : Count_Type;
1541 Last : Count_Type;
1543 begin
1544 if Parent = No_Element then
1545 raise Constraint_Error with "Parent cursor has no element";
1546 end if;
1548 if Parent.Container /= Container'Unrestricted_Access then
1549 raise Program_Error with "Parent cursor not in container";
1550 end if;
1552 if Before /= No_Element then
1553 if Before.Container /= Container'Unrestricted_Access then
1554 raise Program_Error with "Before cursor not in container";
1555 end if;
1557 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1558 raise Constraint_Error with "Parent cursor not parent of Before";
1559 end if;
1560 end if;
1562 if Count = 0 then
1563 Position := No_Element; -- Need ruling from ARG ???
1564 return;
1565 end if;
1567 if Container.Count > Container.Capacity - Count then
1568 raise Capacity_Error
1569 with "requested count exceeds available storage";
1570 end if;
1572 if Container.Busy > 0 then
1573 raise Program_Error
1574 with "attempt to tamper with cursors (tree is busy)";
1575 end if;
1577 if Container.Count = 0 then
1578 Initialize_Root (Container);
1579 end if;
1581 Allocate_Node (Container, New_Item, First);
1582 Nodes (First).Parent := Parent.Node;
1584 Last := First;
1585 for J in Count_Type'(2) .. Count loop
1586 Allocate_Node (Container, New_Item, Nodes (Last).Next);
1587 Nodes (Nodes (Last).Next).Parent := Parent.Node;
1588 Nodes (Nodes (Last).Next).Prev := Last;
1590 Last := Nodes (Last).Next;
1591 end loop;
1593 Insert_Subtree_List
1594 (Container => Container,
1595 First => First,
1596 Last => Last,
1597 Parent => Parent.Node,
1598 Before => Before.Node);
1600 Container.Count := Container.Count + Count;
1602 Position := Cursor'(Parent.Container, First);
1603 end Insert_Child;
1605 procedure Insert_Child
1606 (Container : in out Tree;
1607 Parent : Cursor;
1608 Before : Cursor;
1609 Position : out Cursor;
1610 Count : Count_Type := 1)
1612 Nodes : Tree_Node_Array renames Container.Nodes;
1613 First : Count_Type;
1614 Last : Count_Type;
1616 New_Item : Element_Type;
1617 pragma Unmodified (New_Item);
1618 -- OK to reference, see below
1620 begin
1621 if Parent = No_Element then
1622 raise Constraint_Error with "Parent cursor has no element";
1623 end if;
1625 if Parent.Container /= Container'Unrestricted_Access then
1626 raise Program_Error with "Parent cursor not in container";
1627 end if;
1629 if Before /= No_Element then
1630 if Before.Container /= Container'Unrestricted_Access then
1631 raise Program_Error with "Before cursor not in container";
1632 end if;
1634 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1635 raise Constraint_Error with "Parent cursor not parent of Before";
1636 end if;
1637 end if;
1639 if Count = 0 then
1640 Position := No_Element; -- Need ruling from ARG ???
1641 return;
1642 end if;
1644 if Container.Count > Container.Capacity - Count then
1645 raise Capacity_Error
1646 with "requested count exceeds available storage";
1647 end if;
1649 if Container.Busy > 0 then
1650 raise Program_Error
1651 with "attempt to tamper with cursors (tree is busy)";
1652 end if;
1654 if Container.Count = 0 then
1655 Initialize_Root (Container);
1656 end if;
1658 -- There is no explicit element provided, but in an instance the element
1659 -- type may be a scalar with a Default_Value aspect, or a composite
1660 -- type with such a scalar component, or components with default
1661 -- initialization, so insert the specified number of possibly
1662 -- initialized elements at the given position.
1664 Allocate_Node (Container, New_Item, First);
1665 Nodes (First).Parent := Parent.Node;
1667 Last := First;
1668 for J in Count_Type'(2) .. Count loop
1669 Allocate_Node (Container, New_Item, Nodes (Last).Next);
1670 Nodes (Nodes (Last).Next).Parent := Parent.Node;
1671 Nodes (Nodes (Last).Next).Prev := Last;
1673 Last := Nodes (Last).Next;
1674 end loop;
1676 Insert_Subtree_List
1677 (Container => Container,
1678 First => First,
1679 Last => Last,
1680 Parent => Parent.Node,
1681 Before => Before.Node);
1683 Container.Count := Container.Count + Count;
1685 Position := Cursor'(Parent.Container, First);
1686 end Insert_Child;
1688 -------------------------
1689 -- Insert_Subtree_List --
1690 -------------------------
1692 procedure Insert_Subtree_List
1693 (Container : in out Tree;
1694 First : Count_Type'Base;
1695 Last : Count_Type'Base;
1696 Parent : Count_Type;
1697 Before : Count_Type'Base)
1699 NN : Tree_Node_Array renames Container.Nodes;
1700 N : Tree_Node_Type renames NN (Parent);
1701 CC : Children_Type renames N.Children;
1703 begin
1704 -- This is a simple utility operation to insert a list of nodes
1705 -- (First..Last) as children of Parent. The Before node specifies where
1706 -- the new children should be inserted relative to existing children.
1708 if First <= 0 then
1709 pragma Assert (Last <= 0);
1710 return;
1711 end if;
1713 pragma Assert (Last > 0);
1714 pragma Assert (Before <= 0 or else NN (Before).Parent = Parent);
1716 if CC.First <= 0 then -- no existing children
1717 CC.First := First;
1718 NN (CC.First).Prev := 0;
1719 CC.Last := Last;
1720 NN (CC.Last).Next := 0;
1722 elsif Before <= 0 then -- means "insert after existing nodes"
1723 NN (CC.Last).Next := First;
1724 NN (First).Prev := CC.Last;
1725 CC.Last := Last;
1726 NN (CC.Last).Next := 0;
1728 elsif Before = CC.First then
1729 NN (Last).Next := CC.First;
1730 NN (CC.First).Prev := Last;
1731 CC.First := First;
1732 NN (CC.First).Prev := 0;
1734 else
1735 NN (NN (Before).Prev).Next := First;
1736 NN (First).Prev := NN (Before).Prev;
1737 NN (Last).Next := Before;
1738 NN (Before).Prev := Last;
1739 end if;
1740 end Insert_Subtree_List;
1742 -------------------------
1743 -- Insert_Subtree_Node --
1744 -------------------------
1746 procedure Insert_Subtree_Node
1747 (Container : in out Tree;
1748 Subtree : Count_Type'Base;
1749 Parent : Count_Type;
1750 Before : Count_Type'Base)
1752 begin
1753 -- This is a simple wrapper operation to insert a single child into the
1754 -- Parent's children list.
1756 Insert_Subtree_List
1757 (Container => Container,
1758 First => Subtree,
1759 Last => Subtree,
1760 Parent => Parent,
1761 Before => Before);
1762 end Insert_Subtree_Node;
1764 --------------
1765 -- Is_Empty --
1766 --------------
1768 function Is_Empty (Container : Tree) return Boolean is
1769 begin
1770 return Container.Count = 0;
1771 end Is_Empty;
1773 -------------
1774 -- Is_Leaf --
1775 -------------
1777 function Is_Leaf (Position : Cursor) return Boolean is
1778 begin
1779 if Position = No_Element then
1780 return False;
1781 end if;
1783 if Position.Container.Count = 0 then
1784 pragma Assert (Is_Root (Position));
1785 return True;
1786 end if;
1788 return Position.Container.Nodes (Position.Node).Children.First <= 0;
1789 end Is_Leaf;
1791 ------------------
1792 -- Is_Reachable --
1793 ------------------
1795 function Is_Reachable
1796 (Container : Tree;
1797 From, To : Count_Type) return Boolean
1799 Idx : Count_Type;
1801 begin
1802 Idx := From;
1803 while Idx >= 0 loop
1804 if Idx = To then
1805 return True;
1806 end if;
1808 Idx := Container.Nodes (Idx).Parent;
1809 end loop;
1811 return False;
1812 end Is_Reachable;
1814 -------------
1815 -- Is_Root --
1816 -------------
1818 function Is_Root (Position : Cursor) return Boolean is
1819 begin
1820 return
1821 (if Position.Container = null then False
1822 else Position.Node = Root_Node (Position.Container.all));
1823 end Is_Root;
1825 -------------
1826 -- Iterate --
1827 -------------
1829 procedure Iterate
1830 (Container : Tree;
1831 Process : not null access procedure (Position : Cursor))
1833 B : Natural renames Container'Unrestricted_Access.all.Busy;
1835 begin
1836 if Container.Count = 0 then
1837 return;
1838 end if;
1840 B := B + 1;
1842 Iterate_Children
1843 (Container => Container,
1844 Subtree => Root_Node (Container),
1845 Process => Process);
1847 B := B - 1;
1849 exception
1850 when others =>
1851 B := B - 1;
1852 raise;
1853 end Iterate;
1855 function Iterate (Container : Tree)
1856 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1858 begin
1859 return Iterate_Subtree (Root (Container));
1860 end Iterate;
1862 ----------------------
1863 -- Iterate_Children --
1864 ----------------------
1866 procedure Iterate_Children
1867 (Parent : Cursor;
1868 Process : not null access procedure (Position : Cursor))
1870 begin
1871 if Parent = No_Element then
1872 raise Constraint_Error with "Parent cursor has no element";
1873 end if;
1875 if Parent.Container.Count = 0 then
1876 pragma Assert (Is_Root (Parent));
1877 return;
1878 end if;
1880 declare
1881 B : Natural renames Parent.Container.Busy;
1882 C : Count_Type;
1883 NN : Tree_Node_Array renames Parent.Container.Nodes;
1885 begin
1886 B := B + 1;
1888 C := NN (Parent.Node).Children.First;
1889 while C > 0 loop
1890 Process (Cursor'(Parent.Container, Node => C));
1891 C := NN (C).Next;
1892 end loop;
1894 B := B - 1;
1896 exception
1897 when others =>
1898 B := B - 1;
1899 raise;
1900 end;
1901 end Iterate_Children;
1903 procedure Iterate_Children
1904 (Container : Tree;
1905 Subtree : Count_Type;
1906 Process : not null access procedure (Position : Cursor))
1908 NN : Tree_Node_Array renames Container.Nodes;
1909 N : Tree_Node_Type renames NN (Subtree);
1910 C : Count_Type;
1912 begin
1913 -- This is a helper function to recursively iterate over all the nodes
1914 -- in a subtree, in depth-first fashion. This particular helper just
1915 -- visits the children of this subtree, not the root of the subtree
1916 -- itself. This is useful when starting from the ultimate root of the
1917 -- entire tree (see Iterate), as that root does not have an element.
1919 C := N.Children.First;
1920 while C > 0 loop
1921 Iterate_Subtree (Container, C, Process);
1922 C := NN (C).Next;
1923 end loop;
1924 end Iterate_Children;
1926 function Iterate_Children
1927 (Container : Tree;
1928 Parent : Cursor)
1929 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1931 C : constant Tree_Access := Container'Unrestricted_Access;
1932 B : Natural renames C.Busy;
1934 begin
1935 if Parent = No_Element then
1936 raise Constraint_Error with "Parent cursor has no element";
1937 end if;
1939 if Parent.Container /= C then
1940 raise Program_Error with "Parent cursor not in container";
1941 end if;
1943 return It : constant Child_Iterator :=
1944 Child_Iterator'(Limited_Controlled with
1945 Container => C,
1946 Subtree => Parent.Node)
1948 B := B + 1;
1949 end return;
1950 end Iterate_Children;
1952 ---------------------
1953 -- Iterate_Subtree --
1954 ---------------------
1956 function Iterate_Subtree
1957 (Position : Cursor)
1958 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1960 begin
1961 if Position = No_Element then
1962 raise Constraint_Error with "Position cursor has no element";
1963 end if;
1965 -- Implement Vet for multiway trees???
1966 -- pragma Assert (Vet (Position), "bad subtree cursor");
1968 declare
1969 B : Natural renames Position.Container.Busy;
1970 begin
1971 return It : constant Subtree_Iterator :=
1972 (Limited_Controlled with
1973 Container => Position.Container,
1974 Subtree => Position.Node)
1976 B := B + 1;
1977 end return;
1978 end;
1979 end Iterate_Subtree;
1981 procedure Iterate_Subtree
1982 (Position : Cursor;
1983 Process : not null access procedure (Position : Cursor))
1985 begin
1986 if Position = No_Element then
1987 raise Constraint_Error with "Position cursor has no element";
1988 end if;
1990 if Position.Container.Count = 0 then
1991 pragma Assert (Is_Root (Position));
1992 return;
1993 end if;
1995 declare
1996 T : Tree renames Position.Container.all;
1997 B : Natural renames T.Busy;
1999 begin
2000 B := B + 1;
2002 if Is_Root (Position) then
2003 Iterate_Children (T, Position.Node, Process);
2004 else
2005 Iterate_Subtree (T, Position.Node, Process);
2006 end if;
2008 B := B - 1;
2010 exception
2011 when others =>
2012 B := B - 1;
2013 raise;
2014 end;
2015 end Iterate_Subtree;
2017 procedure Iterate_Subtree
2018 (Container : Tree;
2019 Subtree : Count_Type;
2020 Process : not null access procedure (Position : Cursor))
2022 begin
2023 -- This is a helper function to recursively iterate over all the nodes
2024 -- in a subtree, in depth-first fashion. It first visits the root of the
2025 -- subtree, then visits its children.
2027 Process (Cursor'(Container'Unrestricted_Access, Subtree));
2028 Iterate_Children (Container, Subtree, Process);
2029 end Iterate_Subtree;
2031 ----------
2032 -- Last --
2033 ----------
2035 overriding function Last (Object : Child_Iterator) return Cursor is
2036 begin
2037 return Last_Child (Cursor'(Object.Container, Object.Subtree));
2038 end Last;
2040 ----------------
2041 -- Last_Child --
2042 ----------------
2044 function Last_Child (Parent : Cursor) return Cursor is
2045 Node : Count_Type'Base;
2047 begin
2048 if Parent = No_Element then
2049 raise Constraint_Error with "Parent cursor has no element";
2050 end if;
2052 if Parent.Container.Count = 0 then
2053 pragma Assert (Is_Root (Parent));
2054 return No_Element;
2055 end if;
2057 Node := Parent.Container.Nodes (Parent.Node).Children.Last;
2059 if Node <= 0 then
2060 return No_Element;
2061 end if;
2063 return Cursor'(Parent.Container, Node);
2064 end Last_Child;
2066 ------------------------
2067 -- Last_Child_Element --
2068 ------------------------
2070 function Last_Child_Element (Parent : Cursor) return Element_Type is
2071 begin
2072 return Element (Last_Child (Parent));
2073 end Last_Child_Element;
2075 ----------
2076 -- Move --
2077 ----------
2079 procedure Move (Target : in out Tree; Source : in out Tree) is
2080 begin
2081 if Target'Address = Source'Address then
2082 return;
2083 end if;
2085 if Source.Busy > 0 then
2086 raise Program_Error
2087 with "attempt to tamper with cursors of Source (tree is busy)";
2088 end if;
2090 Target.Assign (Source);
2091 Source.Clear;
2092 end Move;
2094 ----------
2095 -- Next --
2096 ----------
2098 overriding function Next
2099 (Object : Subtree_Iterator;
2100 Position : Cursor) return Cursor
2102 begin
2103 if Position.Container = null then
2104 return No_Element;
2105 end if;
2107 if Position.Container /= Object.Container then
2108 raise Program_Error with
2109 "Position cursor of Next designates wrong tree";
2110 end if;
2112 pragma Assert (Object.Container.Count > 0);
2113 pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2115 declare
2116 Nodes : Tree_Node_Array renames Object.Container.Nodes;
2117 Node : Count_Type;
2119 begin
2120 Node := Position.Node;
2122 if Nodes (Node).Children.First > 0 then
2123 return Cursor'(Object.Container, Nodes (Node).Children.First);
2124 end if;
2126 while Node /= Object.Subtree loop
2127 if Nodes (Node).Next > 0 then
2128 return Cursor'(Object.Container, Nodes (Node).Next);
2129 end if;
2131 Node := Nodes (Node).Parent;
2132 end loop;
2134 return No_Element;
2135 end;
2136 end Next;
2138 overriding function Next
2139 (Object : Child_Iterator;
2140 Position : Cursor) return Cursor
2142 begin
2143 if Position.Container = null then
2144 return No_Element;
2145 end if;
2147 if Position.Container /= Object.Container then
2148 raise Program_Error with
2149 "Position cursor of Next designates wrong tree";
2150 end if;
2152 pragma Assert (Object.Container.Count > 0);
2153 pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2155 return Next_Sibling (Position);
2156 end Next;
2158 ------------------
2159 -- Next_Sibling --
2160 ------------------
2162 function Next_Sibling (Position : Cursor) return Cursor is
2163 begin
2164 if Position = No_Element then
2165 return No_Element;
2166 end if;
2168 if Position.Container.Count = 0 then
2169 pragma Assert (Is_Root (Position));
2170 return No_Element;
2171 end if;
2173 declare
2174 T : Tree renames Position.Container.all;
2175 NN : Tree_Node_Array renames T.Nodes;
2176 N : Tree_Node_Type renames NN (Position.Node);
2178 begin
2179 if N.Next <= 0 then
2180 return No_Element;
2181 end if;
2183 return Cursor'(Position.Container, N.Next);
2184 end;
2185 end Next_Sibling;
2187 procedure Next_Sibling (Position : in out Cursor) is
2188 begin
2189 Position := Next_Sibling (Position);
2190 end Next_Sibling;
2192 ----------------
2193 -- Node_Count --
2194 ----------------
2196 function Node_Count (Container : Tree) return Count_Type is
2197 begin
2198 -- Container.Count is the number of nodes we have actually allocated. We
2199 -- cache the value specifically so this Node_Count operation can execute
2200 -- in O(1) time, which makes it behave similarly to how the Length
2201 -- selector function behaves for other containers.
2203 -- The cached node count value only describes the nodes we have
2204 -- allocated; the root node itself is not included in that count. The
2205 -- Node_Count operation returns a value that includes the root node
2206 -- (because the RM says so), so we must add 1 to our cached value.
2208 return 1 + Container.Count;
2209 end Node_Count;
2211 ------------
2212 -- Parent --
2213 ------------
2215 function Parent (Position : Cursor) return Cursor is
2216 begin
2217 if Position = No_Element then
2218 return No_Element;
2219 end if;
2221 if Position.Container.Count = 0 then
2222 pragma Assert (Is_Root (Position));
2223 return No_Element;
2224 end if;
2226 declare
2227 T : Tree renames Position.Container.all;
2228 NN : Tree_Node_Array renames T.Nodes;
2229 N : Tree_Node_Type renames NN (Position.Node);
2231 begin
2232 if N.Parent < 0 then
2233 pragma Assert (Position.Node = Root_Node (T));
2234 return No_Element;
2235 end if;
2237 return Cursor'(Position.Container, N.Parent);
2238 end;
2239 end Parent;
2241 -------------------
2242 -- Prepend_Child --
2243 -------------------
2245 procedure Prepend_Child
2246 (Container : in out Tree;
2247 Parent : Cursor;
2248 New_Item : Element_Type;
2249 Count : Count_Type := 1)
2251 Nodes : Tree_Node_Array renames Container.Nodes;
2252 First, Last : Count_Type;
2254 begin
2255 if Parent = No_Element then
2256 raise Constraint_Error with "Parent cursor has no element";
2257 end if;
2259 if Parent.Container /= Container'Unrestricted_Access then
2260 raise Program_Error with "Parent cursor not in container";
2261 end if;
2263 if Count = 0 then
2264 return;
2265 end if;
2267 if Container.Count > Container.Capacity - Count then
2268 raise Capacity_Error
2269 with "requested count exceeds available storage";
2270 end if;
2272 if Container.Busy > 0 then
2273 raise Program_Error
2274 with "attempt to tamper with cursors (tree is busy)";
2275 end if;
2277 if Container.Count = 0 then
2278 Initialize_Root (Container);
2279 end if;
2281 Allocate_Node (Container, New_Item, First);
2282 Nodes (First).Parent := Parent.Node;
2284 Last := First;
2285 for J in Count_Type'(2) .. Count loop
2286 Allocate_Node (Container, New_Item, Nodes (Last).Next);
2287 Nodes (Nodes (Last).Next).Parent := Parent.Node;
2288 Nodes (Nodes (Last).Next).Prev := Last;
2290 Last := Nodes (Last).Next;
2291 end loop;
2293 Insert_Subtree_List
2294 (Container => Container,
2295 First => First,
2296 Last => Last,
2297 Parent => Parent.Node,
2298 Before => Nodes (Parent.Node).Children.First);
2300 Container.Count := Container.Count + Count;
2301 end Prepend_Child;
2303 --------------
2304 -- Previous --
2305 --------------
2307 overriding function Previous
2308 (Object : Child_Iterator;
2309 Position : Cursor) return Cursor
2311 begin
2312 if Position.Container = null then
2313 return No_Element;
2314 end if;
2316 if Position.Container /= Object.Container then
2317 raise Program_Error with
2318 "Position cursor of Previous designates wrong tree";
2319 end if;
2321 return Previous_Sibling (Position);
2322 end Previous;
2324 ----------------------
2325 -- Previous_Sibling --
2326 ----------------------
2328 function Previous_Sibling (Position : Cursor) return Cursor is
2329 begin
2330 if Position = No_Element then
2331 return No_Element;
2332 end if;
2334 if Position.Container.Count = 0 then
2335 pragma Assert (Is_Root (Position));
2336 return No_Element;
2337 end if;
2339 declare
2340 T : Tree renames Position.Container.all;
2341 NN : Tree_Node_Array renames T.Nodes;
2342 N : Tree_Node_Type renames NN (Position.Node);
2344 begin
2345 if N.Prev <= 0 then
2346 return No_Element;
2347 end if;
2349 return Cursor'(Position.Container, N.Prev);
2350 end;
2351 end Previous_Sibling;
2353 procedure Previous_Sibling (Position : in out Cursor) is
2354 begin
2355 Position := Previous_Sibling (Position);
2356 end Previous_Sibling;
2358 -------------------
2359 -- Query_Element --
2360 -------------------
2362 procedure Query_Element
2363 (Position : Cursor;
2364 Process : not null access procedure (Element : Element_Type))
2366 begin
2367 if Position = No_Element then
2368 raise Constraint_Error with "Position cursor has no element";
2369 end if;
2371 if Is_Root (Position) then
2372 raise Program_Error with "Position cursor designates root";
2373 end if;
2375 declare
2376 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2377 B : Natural renames T.Busy;
2378 L : Natural renames T.Lock;
2380 begin
2381 B := B + 1;
2382 L := L + 1;
2384 Process (Element => T.Elements (Position.Node));
2386 L := L - 1;
2387 B := B - 1;
2389 exception
2390 when others =>
2391 L := L - 1;
2392 B := B - 1;
2393 raise;
2394 end;
2395 end Query_Element;
2397 ----------
2398 -- Read --
2399 ----------
2401 procedure Read
2402 (Stream : not null access Root_Stream_Type'Class;
2403 Container : out Tree)
2405 procedure Read_Children (Subtree : Count_Type);
2407 function Read_Subtree
2408 (Parent : Count_Type) return Count_Type;
2410 NN : Tree_Node_Array renames Container.Nodes;
2412 Total_Count : Count_Type'Base;
2413 -- Value read from the stream that says how many elements follow
2415 Read_Count : Count_Type'Base;
2416 -- Actual number of elements read from the stream
2418 -------------------
2419 -- Read_Children --
2420 -------------------
2422 procedure Read_Children (Subtree : Count_Type) is
2423 Count : Count_Type'Base;
2424 -- number of child subtrees
2426 CC : Children_Type;
2428 begin
2429 Count_Type'Read (Stream, Count);
2431 if Count < 0 then
2432 raise Program_Error with "attempt to read from corrupt stream";
2433 end if;
2435 if Count = 0 then
2436 return;
2437 end if;
2439 CC.First := Read_Subtree (Parent => Subtree);
2440 CC.Last := CC.First;
2442 for J in Count_Type'(2) .. Count loop
2443 NN (CC.Last).Next := Read_Subtree (Parent => Subtree);
2444 NN (NN (CC.Last).Next).Prev := CC.Last;
2445 CC.Last := NN (CC.Last).Next;
2446 end loop;
2448 -- Now that the allocation and reads have completed successfully, it
2449 -- is safe to link the children to their parent.
2451 NN (Subtree).Children := CC;
2452 end Read_Children;
2454 ------------------
2455 -- Read_Subtree --
2456 ------------------
2458 function Read_Subtree
2459 (Parent : Count_Type) return Count_Type
2461 Subtree : Count_Type;
2463 begin
2464 Allocate_Node (Container, Stream, Subtree);
2465 Container.Nodes (Subtree).Parent := Parent;
2467 Read_Count := Read_Count + 1;
2469 Read_Children (Subtree);
2471 return Subtree;
2472 end Read_Subtree;
2474 -- Start of processing for Read
2476 begin
2477 Container.Clear; -- checks busy bit
2479 Count_Type'Read (Stream, Total_Count);
2481 if Total_Count < 0 then
2482 raise Program_Error with "attempt to read from corrupt stream";
2483 end if;
2485 if Total_Count = 0 then
2486 return;
2487 end if;
2489 if Total_Count > Container.Capacity then
2490 raise Capacity_Error -- ???
2491 with "node count in stream exceeds container capacity";
2492 end if;
2494 Initialize_Root (Container);
2496 Read_Count := 0;
2498 Read_Children (Root_Node (Container));
2500 if Read_Count /= Total_Count then
2501 raise Program_Error with "attempt to read from corrupt stream";
2502 end if;
2504 Container.Count := Total_Count;
2505 end Read;
2507 procedure Read
2508 (Stream : not null access Root_Stream_Type'Class;
2509 Position : out Cursor)
2511 begin
2512 raise Program_Error with "attempt to read tree cursor from stream";
2513 end Read;
2515 procedure Read
2516 (Stream : not null access Root_Stream_Type'Class;
2517 Item : out Reference_Type)
2519 begin
2520 raise Program_Error with "attempt to stream reference";
2521 end Read;
2523 procedure Read
2524 (Stream : not null access Root_Stream_Type'Class;
2525 Item : out Constant_Reference_Type)
2527 begin
2528 raise Program_Error with "attempt to stream reference";
2529 end Read;
2531 ---------------
2532 -- Reference --
2533 ---------------
2535 function Reference
2536 (Container : aliased in out Tree;
2537 Position : Cursor) return Reference_Type
2539 begin
2540 if Position.Container = null then
2541 raise Constraint_Error with
2542 "Position cursor has no element";
2543 end if;
2545 if Position.Container /= Container'Unrestricted_Access then
2546 raise Program_Error with
2547 "Position cursor designates wrong container";
2548 end if;
2550 if Position.Node = Root_Node (Container) then
2551 raise Program_Error with "Position cursor designates root";
2552 end if;
2554 -- Implement Vet for multiway tree???
2555 -- pragma Assert (Vet (Position),
2556 -- "Position cursor in Constant_Reference is bad");
2558 declare
2559 C : Tree renames Position.Container.all;
2560 B : Natural renames C.Busy;
2561 L : Natural renames C.Lock;
2562 begin
2563 return R : constant Reference_Type :=
2564 (Element => Container.Elements (Position.Node)'Access,
2565 Control => (Controlled with Position.Container))
2567 B := B + 1;
2568 L := L + 1;
2569 end return;
2570 end;
2572 end Reference;
2574 --------------------
2575 -- Remove_Subtree --
2576 --------------------
2578 procedure Remove_Subtree
2579 (Container : in out Tree;
2580 Subtree : Count_Type)
2582 NN : Tree_Node_Array renames Container.Nodes;
2583 N : Tree_Node_Type renames NN (Subtree);
2584 CC : Children_Type renames NN (N.Parent).Children;
2586 begin
2587 -- This is a utility operation to remove a subtree node from its
2588 -- parent's list of children.
2590 if CC.First = Subtree then
2591 pragma Assert (N.Prev <= 0);
2593 if CC.Last = Subtree then
2594 pragma Assert (N.Next <= 0);
2595 CC.First := 0;
2596 CC.Last := 0;
2598 else
2599 CC.First := N.Next;
2600 NN (CC.First).Prev := 0;
2601 end if;
2603 elsif CC.Last = Subtree then
2604 pragma Assert (N.Next <= 0);
2605 CC.Last := N.Prev;
2606 NN (CC.Last).Next := 0;
2608 else
2609 NN (N.Prev).Next := N.Next;
2610 NN (N.Next).Prev := N.Prev;
2611 end if;
2612 end Remove_Subtree;
2614 ----------------------
2615 -- Replace_Element --
2616 ----------------------
2618 procedure Replace_Element
2619 (Container : in out Tree;
2620 Position : Cursor;
2621 New_Item : Element_Type)
2623 begin
2624 if Position = No_Element then
2625 raise Constraint_Error with "Position cursor has no element";
2626 end if;
2628 if Position.Container /= Container'Unrestricted_Access then
2629 raise Program_Error with "Position cursor not in container";
2630 end if;
2632 if Is_Root (Position) then
2633 raise Program_Error with "Position cursor designates root";
2634 end if;
2636 if Container.Lock > 0 then
2637 raise Program_Error
2638 with "attempt to tamper with elements (tree is locked)";
2639 end if;
2641 Container.Elements (Position.Node) := New_Item;
2642 end Replace_Element;
2644 ------------------------------
2645 -- Reverse_Iterate_Children --
2646 ------------------------------
2648 procedure Reverse_Iterate_Children
2649 (Parent : Cursor;
2650 Process : not null access procedure (Position : Cursor))
2652 begin
2653 if Parent = No_Element then
2654 raise Constraint_Error with "Parent cursor has no element";
2655 end if;
2657 if Parent.Container.Count = 0 then
2658 pragma Assert (Is_Root (Parent));
2659 return;
2660 end if;
2662 declare
2663 NN : Tree_Node_Array renames Parent.Container.Nodes;
2664 B : Natural renames Parent.Container.Busy;
2665 C : Count_Type;
2667 begin
2668 B := B + 1;
2670 C := NN (Parent.Node).Children.Last;
2671 while C > 0 loop
2672 Process (Cursor'(Parent.Container, Node => C));
2673 C := NN (C).Prev;
2674 end loop;
2676 B := B - 1;
2678 exception
2679 when others =>
2680 B := B - 1;
2681 raise;
2682 end;
2683 end Reverse_Iterate_Children;
2685 ----------
2686 -- Root --
2687 ----------
2689 function Root (Container : Tree) return Cursor is
2690 begin
2691 return (Container'Unrestricted_Access, Root_Node (Container));
2692 end Root;
2694 ---------------
2695 -- Root_Node --
2696 ---------------
2698 function Root_Node (Container : Tree) return Count_Type is
2699 pragma Unreferenced (Container);
2701 begin
2702 return 0;
2703 end Root_Node;
2705 ---------------------
2706 -- Splice_Children --
2707 ---------------------
2709 procedure Splice_Children
2710 (Target : in out Tree;
2711 Target_Parent : Cursor;
2712 Before : Cursor;
2713 Source : in out Tree;
2714 Source_Parent : Cursor)
2716 begin
2717 if Target_Parent = No_Element then
2718 raise Constraint_Error with "Target_Parent cursor has no element";
2719 end if;
2721 if Target_Parent.Container /= Target'Unrestricted_Access then
2722 raise Program_Error
2723 with "Target_Parent cursor not in Target container";
2724 end if;
2726 if Before /= No_Element then
2727 if Before.Container /= Target'Unrestricted_Access then
2728 raise Program_Error
2729 with "Before cursor not in Target container";
2730 end if;
2732 if Target.Nodes (Before.Node).Parent /= Target_Parent.Node then
2733 raise Constraint_Error
2734 with "Before cursor not child of Target_Parent";
2735 end if;
2736 end if;
2738 if Source_Parent = No_Element then
2739 raise Constraint_Error with "Source_Parent cursor has no element";
2740 end if;
2742 if Source_Parent.Container /= Source'Unrestricted_Access then
2743 raise Program_Error
2744 with "Source_Parent cursor not in Source container";
2745 end if;
2747 if Source.Count = 0 then
2748 pragma Assert (Is_Root (Source_Parent));
2749 return;
2750 end if;
2752 if Target'Address = Source'Address then
2753 if Target_Parent = Source_Parent then
2754 return;
2755 end if;
2757 if Target.Busy > 0 then
2758 raise Program_Error
2759 with "attempt to tamper with cursors (Target tree is busy)";
2760 end if;
2762 if Is_Reachable (Container => Target,
2763 From => Target_Parent.Node,
2764 To => Source_Parent.Node)
2765 then
2766 raise Constraint_Error
2767 with "Source_Parent is ancestor of Target_Parent";
2768 end if;
2770 Splice_Children
2771 (Container => Target,
2772 Target_Parent => Target_Parent.Node,
2773 Before => Before.Node,
2774 Source_Parent => Source_Parent.Node);
2776 return;
2777 end if;
2779 if Target.Busy > 0 then
2780 raise Program_Error
2781 with "attempt to tamper with cursors (Target tree is busy)";
2782 end if;
2784 if Source.Busy > 0 then
2785 raise Program_Error
2786 with "attempt to tamper with cursors (Source tree is busy)";
2787 end if;
2789 if Target.Count = 0 then
2790 Initialize_Root (Target);
2791 end if;
2793 Splice_Children
2794 (Target => Target,
2795 Target_Parent => Target_Parent.Node,
2796 Before => Before.Node,
2797 Source => Source,
2798 Source_Parent => Source_Parent.Node);
2799 end Splice_Children;
2801 procedure Splice_Children
2802 (Container : in out Tree;
2803 Target_Parent : Cursor;
2804 Before : Cursor;
2805 Source_Parent : Cursor)
2807 begin
2808 if Target_Parent = No_Element then
2809 raise Constraint_Error with "Target_Parent cursor has no element";
2810 end if;
2812 if Target_Parent.Container /= Container'Unrestricted_Access then
2813 raise Program_Error
2814 with "Target_Parent cursor not in container";
2815 end if;
2817 if Before /= No_Element then
2818 if Before.Container /= Container'Unrestricted_Access then
2819 raise Program_Error
2820 with "Before cursor not in container";
2821 end if;
2823 if Container.Nodes (Before.Node).Parent /= Target_Parent.Node then
2824 raise Constraint_Error
2825 with "Before cursor not child of Target_Parent";
2826 end if;
2827 end if;
2829 if Source_Parent = No_Element then
2830 raise Constraint_Error with "Source_Parent cursor has no element";
2831 end if;
2833 if Source_Parent.Container /= Container'Unrestricted_Access then
2834 raise Program_Error
2835 with "Source_Parent cursor not in container";
2836 end if;
2838 if Target_Parent = Source_Parent then
2839 return;
2840 end if;
2842 pragma Assert (Container.Count > 0);
2844 if Container.Busy > 0 then
2845 raise Program_Error
2846 with "attempt to tamper with cursors (tree is busy)";
2847 end if;
2849 if Is_Reachable (Container => Container,
2850 From => Target_Parent.Node,
2851 To => Source_Parent.Node)
2852 then
2853 raise Constraint_Error
2854 with "Source_Parent is ancestor of Target_Parent";
2855 end if;
2857 Splice_Children
2858 (Container => Container,
2859 Target_Parent => Target_Parent.Node,
2860 Before => Before.Node,
2861 Source_Parent => Source_Parent.Node);
2862 end Splice_Children;
2864 procedure Splice_Children
2865 (Container : in out Tree;
2866 Target_Parent : Count_Type;
2867 Before : Count_Type'Base;
2868 Source_Parent : Count_Type)
2870 NN : Tree_Node_Array renames Container.Nodes;
2871 CC : constant Children_Type := NN (Source_Parent).Children;
2872 C : Count_Type'Base;
2874 begin
2875 -- This is a utility operation to remove the children from Source parent
2876 -- and insert them into Target parent.
2878 NN (Source_Parent).Children := Children_Type'(others => 0);
2880 -- Fix up the Parent pointers of each child to designate its new Target
2881 -- parent.
2883 C := CC.First;
2884 while C > 0 loop
2885 NN (C).Parent := Target_Parent;
2886 C := NN (C).Next;
2887 end loop;
2889 Insert_Subtree_List
2890 (Container => Container,
2891 First => CC.First,
2892 Last => CC.Last,
2893 Parent => Target_Parent,
2894 Before => Before);
2895 end Splice_Children;
2897 procedure Splice_Children
2898 (Target : in out Tree;
2899 Target_Parent : Count_Type;
2900 Before : Count_Type'Base;
2901 Source : in out Tree;
2902 Source_Parent : Count_Type)
2904 S_NN : Tree_Node_Array renames Source.Nodes;
2905 S_CC : Children_Type renames S_NN (Source_Parent).Children;
2907 Target_Count, Source_Count : Count_Type;
2908 T, S : Count_Type'Base;
2910 begin
2911 -- This is a utility operation to copy the children from the Source
2912 -- parent and insert them as children of the Target parent, and then
2913 -- delete them from the Source. (This is not a true splice operation,
2914 -- but it is the best we can do in a bounded form.) The Before position
2915 -- specifies where among the Target parent's exising children the new
2916 -- children are inserted.
2918 -- Before we attempt the insertion, we must count the sources nodes in
2919 -- order to determine whether the target have enough storage
2920 -- available. Note that calculating this value is an O(n) operation.
2922 -- Here is an optimization opportunity: iterate of each children the
2923 -- source explicitly, and keep a running count of the total number of
2924 -- nodes. Compare the running total to the capacity of the target each
2925 -- pass through the loop. This is more efficient than summing the counts
2926 -- of child subtree (which is what Subtree_Node_Count does) and then
2927 -- comparing that total sum to the target's capacity. ???
2929 -- Here is another possibility. We currently treat the splice as an
2930 -- all-or-nothing proposition: either we can insert all of children of
2931 -- the source, or we raise exception with modifying the target. The
2932 -- price for not causing side-effect is an O(n) determination of the
2933 -- source count. If we are willing to tolerate side-effect, then we
2934 -- could loop over the children of the source, counting that subtree and
2935 -- then immediately inserting it in the target. The issue here is that
2936 -- the test for available storage could fail during some later pass,
2937 -- after children have already been inserted into target. ???
2939 Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1;
2941 if Source_Count = 0 then
2942 return;
2943 end if;
2945 if Target.Count > Target.Capacity - Source_Count then
2946 raise Capacity_Error -- ???
2947 with "Source count exceeds available storage on Target";
2948 end if;
2950 -- Copy_Subtree returns a count of the number of nodes it inserts, but
2951 -- it does this by incrementing the value passed in. Therefore we must
2952 -- initialize the count before calling Copy_Subtree.
2954 Target_Count := 0;
2956 S := S_CC.First;
2957 while S > 0 loop
2958 Copy_Subtree
2959 (Source => Source,
2960 Source_Subtree => S,
2961 Target => Target,
2962 Target_Parent => Target_Parent,
2963 Target_Subtree => T,
2964 Count => Target_Count);
2966 Insert_Subtree_Node
2967 (Container => Target,
2968 Subtree => T,
2969 Parent => Target_Parent,
2970 Before => Before);
2972 S := S_NN (S).Next;
2973 end loop;
2975 pragma Assert (Target_Count = Source_Count);
2976 Target.Count := Target.Count + Target_Count;
2978 -- As with Copy_Subtree, operation Deallocate_Children returns a count
2979 -- of the number of nodes it deallocates, but it works by incrementing
2980 -- the value passed in. We must therefore initialize the count before
2981 -- calling it.
2983 Source_Count := 0;
2985 Deallocate_Children (Source, Source_Parent, Source_Count);
2986 pragma Assert (Source_Count = Target_Count);
2988 Source.Count := Source.Count - Source_Count;
2989 end Splice_Children;
2991 --------------------
2992 -- Splice_Subtree --
2993 --------------------
2995 procedure Splice_Subtree
2996 (Target : in out Tree;
2997 Parent : Cursor;
2998 Before : Cursor;
2999 Source : in out Tree;
3000 Position : in out Cursor)
3002 begin
3003 if Parent = No_Element then
3004 raise Constraint_Error with "Parent cursor has no element";
3005 end if;
3007 if Parent.Container /= Target'Unrestricted_Access then
3008 raise Program_Error with "Parent cursor not in Target container";
3009 end if;
3011 if Before /= No_Element then
3012 if Before.Container /= Target'Unrestricted_Access then
3013 raise Program_Error with "Before cursor not in Target container";
3014 end if;
3016 if Target.Nodes (Before.Node).Parent /= Parent.Node then
3017 raise Constraint_Error with "Before cursor not child of Parent";
3018 end if;
3019 end if;
3021 if Position = No_Element then
3022 raise Constraint_Error with "Position cursor has no element";
3023 end if;
3025 if Position.Container /= Source'Unrestricted_Access then
3026 raise Program_Error with "Position cursor not in Source container";
3027 end if;
3029 if Is_Root (Position) then
3030 raise Program_Error with "Position cursor designates root";
3031 end if;
3033 if Target'Address = Source'Address then
3034 if Target.Nodes (Position.Node).Parent = Parent.Node then
3035 if Before = No_Element then
3036 if Target.Nodes (Position.Node).Next <= 0 then -- last child
3037 return;
3038 end if;
3040 elsif Position.Node = Before.Node then
3041 return;
3043 elsif Target.Nodes (Position.Node).Next = Before.Node then
3044 return;
3045 end if;
3046 end if;
3048 if Target.Busy > 0 then
3049 raise Program_Error
3050 with "attempt to tamper with cursors (Target tree is busy)";
3051 end if;
3053 if Is_Reachable (Container => Target,
3054 From => Parent.Node,
3055 To => Position.Node)
3056 then
3057 raise Constraint_Error with "Position is ancestor of Parent";
3058 end if;
3060 Remove_Subtree (Target, Position.Node);
3062 Target.Nodes (Position.Node).Parent := Parent.Node;
3063 Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node);
3065 return;
3066 end if;
3068 if Target.Busy > 0 then
3069 raise Program_Error
3070 with "attempt to tamper with cursors (Target tree is busy)";
3071 end if;
3073 if Source.Busy > 0 then
3074 raise Program_Error
3075 with "attempt to tamper with cursors (Source tree is busy)";
3076 end if;
3078 if Target.Count = 0 then
3079 Initialize_Root (Target);
3080 end if;
3082 Splice_Subtree
3083 (Target => Target,
3084 Parent => Parent.Node,
3085 Before => Before.Node,
3086 Source => Source,
3087 Position => Position.Node); -- modified during call
3089 Position.Container := Target'Unrestricted_Access;
3090 end Splice_Subtree;
3092 procedure Splice_Subtree
3093 (Container : in out Tree;
3094 Parent : Cursor;
3095 Before : Cursor;
3096 Position : Cursor)
3098 begin
3099 if Parent = No_Element then
3100 raise Constraint_Error with "Parent cursor has no element";
3101 end if;
3103 if Parent.Container /= Container'Unrestricted_Access then
3104 raise Program_Error with "Parent cursor not in container";
3105 end if;
3107 if Before /= No_Element then
3108 if Before.Container /= Container'Unrestricted_Access then
3109 raise Program_Error with "Before cursor not in container";
3110 end if;
3112 if Container.Nodes (Before.Node).Parent /= Parent.Node then
3113 raise Constraint_Error with "Before cursor not child of Parent";
3114 end if;
3115 end if;
3117 if Position = No_Element then
3118 raise Constraint_Error with "Position cursor has no element";
3119 end if;
3121 if Position.Container /= Container'Unrestricted_Access then
3122 raise Program_Error with "Position cursor not in container";
3123 end if;
3125 if Is_Root (Position) then
3127 -- Should this be PE instead? Need ARG confirmation. ???
3129 raise Constraint_Error with "Position cursor designates root";
3130 end if;
3132 if Container.Nodes (Position.Node).Parent = Parent.Node then
3133 if Before = No_Element then
3134 if Container.Nodes (Position.Node).Next <= 0 then -- last child
3135 return;
3136 end if;
3138 elsif Position.Node = Before.Node then
3139 return;
3141 elsif Container.Nodes (Position.Node).Next = Before.Node then
3142 return;
3143 end if;
3144 end if;
3146 if Container.Busy > 0 then
3147 raise Program_Error
3148 with "attempt to tamper with cursors (tree is busy)";
3149 end if;
3151 if Is_Reachable (Container => Container,
3152 From => Parent.Node,
3153 To => Position.Node)
3154 then
3155 raise Constraint_Error with "Position is ancestor of Parent";
3156 end if;
3158 Remove_Subtree (Container, Position.Node);
3159 Container.Nodes (Position.Node).Parent := Parent.Node;
3160 Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node);
3161 end Splice_Subtree;
3163 procedure Splice_Subtree
3164 (Target : in out Tree;
3165 Parent : Count_Type;
3166 Before : Count_Type'Base;
3167 Source : in out Tree;
3168 Position : in out Count_Type) -- Source on input, Target on output
3170 Source_Count : Count_Type := Subtree_Node_Count (Source, Position);
3171 pragma Assert (Source_Count >= 1);
3173 Target_Subtree : Count_Type;
3174 Target_Count : Count_Type;
3176 begin
3177 -- This is a utility operation to do the heavy lifting associated with
3178 -- splicing a subtree from one tree to another. Note that "splicing"
3179 -- is a bit of a misnomer here in the case of a bounded tree, because
3180 -- the elements must be copied from the source to the target.
3182 if Target.Count > Target.Capacity - Source_Count then
3183 raise Capacity_Error -- ???
3184 with "Source count exceeds available storage on Target";
3185 end if;
3187 -- Copy_Subtree returns a count of the number of nodes it inserts, but
3188 -- it does this by incrementing the value passed in. Therefore we must
3189 -- initialize the count before calling Copy_Subtree.
3191 Target_Count := 0;
3193 Copy_Subtree
3194 (Source => Source,
3195 Source_Subtree => Position,
3196 Target => Target,
3197 Target_Parent => Parent,
3198 Target_Subtree => Target_Subtree,
3199 Count => Target_Count);
3201 pragma Assert (Target_Count = Source_Count);
3203 -- Now link the newly-allocated subtree into the target.
3205 Insert_Subtree_Node
3206 (Container => Target,
3207 Subtree => Target_Subtree,
3208 Parent => Parent,
3209 Before => Before);
3211 Target.Count := Target.Count + Target_Count;
3213 -- The manipulation of the Target container is complete. Now we remove
3214 -- the subtree from the Source container.
3216 Remove_Subtree (Source, Position); -- unlink the subtree
3218 -- As with Copy_Subtree, operation Deallocate_Subtree returns a count of
3219 -- the number of nodes it deallocates, but it works by incrementing the
3220 -- value passed in. We must therefore initialize the count before
3221 -- calling it.
3223 Source_Count := 0;
3225 Deallocate_Subtree (Source, Position, Source_Count);
3226 pragma Assert (Source_Count = Target_Count);
3228 Source.Count := Source.Count - Source_Count;
3230 Position := Target_Subtree;
3231 end Splice_Subtree;
3233 ------------------------
3234 -- Subtree_Node_Count --
3235 ------------------------
3237 function Subtree_Node_Count (Position : Cursor) return Count_Type is
3238 begin
3239 if Position = No_Element then
3240 return 0;
3241 end if;
3243 if Position.Container.Count = 0 then
3244 pragma Assert (Is_Root (Position));
3245 return 1;
3246 end if;
3248 return Subtree_Node_Count (Position.Container.all, Position.Node);
3249 end Subtree_Node_Count;
3251 function Subtree_Node_Count
3252 (Container : Tree;
3253 Subtree : Count_Type) return Count_Type
3255 Result : Count_Type;
3256 Node : Count_Type'Base;
3258 begin
3259 Result := 1;
3260 Node := Container.Nodes (Subtree).Children.First;
3261 while Node > 0 loop
3262 Result := Result + Subtree_Node_Count (Container, Node);
3263 Node := Container.Nodes (Node).Next;
3264 end loop;
3265 return Result;
3266 end Subtree_Node_Count;
3268 ----------
3269 -- Swap --
3270 ----------
3272 procedure Swap
3273 (Container : in out Tree;
3274 I, J : Cursor)
3276 begin
3277 if I = No_Element then
3278 raise Constraint_Error with "I cursor has no element";
3279 end if;
3281 if I.Container /= Container'Unrestricted_Access then
3282 raise Program_Error with "I cursor not in container";
3283 end if;
3285 if Is_Root (I) then
3286 raise Program_Error with "I cursor designates root";
3287 end if;
3289 if I = J then -- make this test sooner???
3290 return;
3291 end if;
3293 if J = No_Element then
3294 raise Constraint_Error with "J cursor has no element";
3295 end if;
3297 if J.Container /= Container'Unrestricted_Access then
3298 raise Program_Error with "J cursor not in container";
3299 end if;
3301 if Is_Root (J) then
3302 raise Program_Error with "J cursor designates root";
3303 end if;
3305 if Container.Lock > 0 then
3306 raise Program_Error
3307 with "attempt to tamper with elements (tree is locked)";
3308 end if;
3310 declare
3311 EE : Element_Array renames Container.Elements;
3312 EI : constant Element_Type := EE (I.Node);
3314 begin
3315 EE (I.Node) := EE (J.Node);
3316 EE (J.Node) := EI;
3317 end;
3318 end Swap;
3320 --------------------
3321 -- Update_Element --
3322 --------------------
3324 procedure Update_Element
3325 (Container : in out Tree;
3326 Position : Cursor;
3327 Process : not null access procedure (Element : in out Element_Type))
3329 begin
3330 if Position = No_Element then
3331 raise Constraint_Error with "Position cursor has no element";
3332 end if;
3334 if Position.Container /= Container'Unrestricted_Access then
3335 raise Program_Error with "Position cursor not in container";
3336 end if;
3338 if Is_Root (Position) then
3339 raise Program_Error with "Position cursor designates root";
3340 end if;
3342 declare
3343 T : Tree renames Position.Container.all'Unrestricted_Access.all;
3344 B : Natural renames T.Busy;
3345 L : Natural renames T.Lock;
3347 begin
3348 B := B + 1;
3349 L := L + 1;
3351 Process (Element => T.Elements (Position.Node));
3353 L := L - 1;
3354 B := B - 1;
3356 exception
3357 when others =>
3358 L := L - 1;
3359 B := B - 1;
3360 raise;
3361 end;
3362 end Update_Element;
3364 -----------
3365 -- Write --
3366 -----------
3368 procedure Write
3369 (Stream : not null access Root_Stream_Type'Class;
3370 Container : Tree)
3372 procedure Write_Children (Subtree : Count_Type);
3373 procedure Write_Subtree (Subtree : Count_Type);
3375 --------------------
3376 -- Write_Children --
3377 --------------------
3379 procedure Write_Children (Subtree : Count_Type) is
3380 CC : Children_Type renames Container.Nodes (Subtree).Children;
3381 C : Count_Type'Base;
3383 begin
3384 Count_Type'Write (Stream, Child_Count (Container, Subtree));
3386 C := CC.First;
3387 while C > 0 loop
3388 Write_Subtree (C);
3389 C := Container.Nodes (C).Next;
3390 end loop;
3391 end Write_Children;
3393 -------------------
3394 -- Write_Subtree --
3395 -------------------
3397 procedure Write_Subtree (Subtree : Count_Type) is
3398 begin
3399 Element_Type'Write (Stream, Container.Elements (Subtree));
3400 Write_Children (Subtree);
3401 end Write_Subtree;
3403 -- Start of processing for Write
3405 begin
3406 Count_Type'Write (Stream, Container.Count);
3408 if Container.Count = 0 then
3409 return;
3410 end if;
3412 Write_Children (Root_Node (Container));
3413 end Write;
3415 procedure Write
3416 (Stream : not null access Root_Stream_Type'Class;
3417 Position : Cursor)
3419 begin
3420 raise Program_Error with "attempt to write tree cursor to stream";
3421 end Write;
3423 procedure Write
3424 (Stream : not null access Root_Stream_Type'Class;
3425 Item : Reference_Type)
3427 begin
3428 raise Program_Error with "attempt to stream reference";
3429 end Write;
3431 procedure Write
3432 (Stream : not null access Root_Stream_Type'Class;
3433 Item : Constant_Reference_Type)
3435 begin
3436 raise Program_Error with "attempt to stream reference";
3437 end Write;
3439 end Ada.Containers.Bounded_Multiway_Trees;