2014-03-25 Richard Biener <rguenther@suse.de>
[official-gcc.git] / gcc / ada / a-cbmutr.adb
blobaa754149067dc4ed0aa929cd3423743129c1fce1
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.BOUNDED_MULTIWAY_TREES --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2011-2013, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Finalization; use Ada.Finalization;
32 with System; use type System.Address;
34 package body Ada.Containers.Bounded_Multiway_Trees is
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 New_Node : out Count_Type);
101 procedure Allocate_Node
102 (Container : in out Tree;
103 Stream : not null access Root_Stream_Type'Class;
104 New_Node : out Count_Type);
106 procedure Deallocate_Node
107 (Container : in out Tree;
108 X : Count_Type);
110 procedure Deallocate_Children
111 (Container : in out Tree;
112 Subtree : Count_Type;
113 Count : in out Count_Type);
115 procedure Deallocate_Subtree
116 (Container : in out Tree;
117 Subtree : Count_Type;
118 Count : in out Count_Type);
120 function Equal_Children
121 (Left_Tree : Tree;
122 Left_Subtree : Count_Type;
123 Right_Tree : Tree;
124 Right_Subtree : Count_Type) return Boolean;
126 function Equal_Subtree
127 (Left_Tree : Tree;
128 Left_Subtree : Count_Type;
129 Right_Tree : Tree;
130 Right_Subtree : Count_Type) return Boolean;
132 procedure Iterate_Children
133 (Container : Tree;
134 Subtree : Count_Type;
135 Process : not null access procedure (Position : Cursor));
137 procedure Iterate_Subtree
138 (Container : Tree;
139 Subtree : Count_Type;
140 Process : not null access procedure (Position : Cursor));
142 procedure Copy_Children
143 (Source : Tree;
144 Source_Parent : Count_Type;
145 Target : in out Tree;
146 Target_Parent : Count_Type;
147 Count : in out Count_Type);
149 procedure Copy_Subtree
150 (Source : Tree;
151 Source_Subtree : Count_Type;
152 Target : in out Tree;
153 Target_Parent : Count_Type;
154 Target_Subtree : out Count_Type;
155 Count : in out Count_Type);
157 function Find_In_Children
158 (Container : Tree;
159 Subtree : Count_Type;
160 Item : Element_Type) return Count_Type;
162 function Find_In_Subtree
163 (Container : Tree;
164 Subtree : Count_Type;
165 Item : Element_Type) return Count_Type;
167 function Child_Count
168 (Container : Tree;
169 Parent : Count_Type) return Count_Type;
171 function Subtree_Node_Count
172 (Container : Tree;
173 Subtree : Count_Type) return Count_Type;
175 function Is_Reachable
176 (Container : Tree;
177 From, To : Count_Type) return Boolean;
179 function Root_Node (Container : Tree) return Count_Type;
181 procedure Remove_Subtree
182 (Container : in out Tree;
183 Subtree : Count_Type);
185 procedure Insert_Subtree_Node
186 (Container : in out Tree;
187 Subtree : Count_Type'Base;
188 Parent : Count_Type;
189 Before : Count_Type'Base);
191 procedure Insert_Subtree_List
192 (Container : in out Tree;
193 First : Count_Type'Base;
194 Last : Count_Type'Base;
195 Parent : Count_Type;
196 Before : Count_Type'Base);
198 procedure Splice_Children
199 (Container : in out Tree;
200 Target_Parent : Count_Type;
201 Before : Count_Type'Base;
202 Source_Parent : Count_Type);
204 procedure Splice_Children
205 (Target : in out Tree;
206 Target_Parent : Count_Type;
207 Before : Count_Type'Base;
208 Source : in out Tree;
209 Source_Parent : Count_Type);
211 procedure Splice_Subtree
212 (Target : in out Tree;
213 Parent : Count_Type;
214 Before : Count_Type'Base;
215 Source : in out Tree;
216 Position : in out Count_Type); -- source on input, target on output
218 ---------
219 -- "=" --
220 ---------
222 function "=" (Left, Right : Tree) return Boolean is
223 begin
224 if Left'Address = Right'Address then
225 return True;
226 end if;
228 if Left.Count /= Right.Count then
229 return False;
230 end if;
232 if Left.Count = 0 then
233 return True;
234 end if;
236 return Equal_Children
237 (Left_Tree => Left,
238 Left_Subtree => Root_Node (Left),
239 Right_Tree => Right,
240 Right_Subtree => Root_Node (Right));
241 end "=";
243 -------------------
244 -- Allocate_Node --
245 -------------------
247 procedure Allocate_Node
248 (Container : in out Tree;
249 Initialize_Element : not null access procedure (Index : Count_Type);
250 New_Node : out Count_Type)
252 begin
253 if Container.Free >= 0 then
254 New_Node := Container.Free;
255 pragma Assert (New_Node in Container.Elements'Range);
257 -- We always perform the assignment first, before we change container
258 -- state, in order to defend against exceptions duration assignment.
260 Initialize_Element (New_Node);
262 Container.Free := Container.Nodes (New_Node).Next;
264 else
265 -- A negative free store value means that the links of the nodes in
266 -- the free store have not been initialized. In this case, the nodes
267 -- are physically contiguous in the array, starting at the index that
268 -- is the absolute value of the Container.Free, and continuing until
269 -- the end of the array (Nodes'Last).
271 New_Node := abs Container.Free;
272 pragma Assert (New_Node in Container.Elements'Range);
274 -- As above, we perform this assignment first, before modifying any
275 -- container state.
277 Initialize_Element (New_Node);
279 Container.Free := Container.Free - 1;
281 if abs Container.Free > Container.Capacity then
282 Container.Free := 0;
283 end if;
284 end if;
286 Initialize_Node (Container, New_Node);
287 end Allocate_Node;
289 procedure Allocate_Node
290 (Container : in out Tree;
291 New_Item : Element_Type;
292 New_Node : out Count_Type)
294 procedure Initialize_Element (Index : Count_Type);
296 procedure Initialize_Element (Index : Count_Type) is
297 begin
298 Container.Elements (Index) := New_Item;
299 end Initialize_Element;
301 begin
302 Allocate_Node (Container, Initialize_Element'Access, New_Node);
303 end Allocate_Node;
305 procedure Allocate_Node
306 (Container : in out Tree;
307 Stream : not null access Root_Stream_Type'Class;
308 New_Node : out Count_Type)
310 procedure Initialize_Element (Index : Count_Type);
312 procedure Initialize_Element (Index : Count_Type) is
313 begin
314 Element_Type'Read (Stream, Container.Elements (Index));
315 end Initialize_Element;
317 begin
318 Allocate_Node (Container, Initialize_Element'Access, New_Node);
319 end Allocate_Node;
321 procedure Allocate_Node
322 (Container : in out Tree;
323 New_Node : out Count_Type)
325 procedure Initialize_Element (Index : Count_Type) is null;
326 begin
327 Allocate_Node (Container, Initialize_Element'Access, New_Node);
328 end Allocate_Node;
330 -------------------
331 -- Ancestor_Find --
332 -------------------
334 function Ancestor_Find
335 (Position : Cursor;
336 Item : Element_Type) return Cursor
338 R, N : Count_Type;
340 begin
341 if Position = No_Element then
342 raise Constraint_Error with "Position cursor has no element";
343 end if;
345 -- Commented-out pending ruling by ARG. ???
347 -- if Position.Container /= Container'Unrestricted_Access then
348 -- raise Program_Error with "Position cursor not in container";
349 -- end if;
351 -- AI-0136 says to raise PE if Position equals the root node. This does
352 -- not seem correct, as this value is just the limiting condition of the
353 -- search. For now we omit this check, pending a ruling from the ARG.
354 -- ???
356 -- if Is_Root (Position) then
357 -- raise Program_Error with "Position cursor designates root";
358 -- end if;
360 R := Root_Node (Position.Container.all);
361 N := Position.Node;
362 while N /= R loop
363 if Position.Container.Elements (N) = Item then
364 return Cursor'(Position.Container, N);
365 end if;
367 N := Position.Container.Nodes (N).Parent;
368 end loop;
370 return No_Element;
371 end Ancestor_Find;
373 ------------------
374 -- Append_Child --
375 ------------------
377 procedure Append_Child
378 (Container : in out Tree;
379 Parent : Cursor;
380 New_Item : Element_Type;
381 Count : Count_Type := 1)
383 Nodes : Tree_Node_Array renames Container.Nodes;
384 First, Last : Count_Type;
386 begin
387 if Parent = No_Element then
388 raise Constraint_Error with "Parent cursor has no element";
389 end if;
391 if Parent.Container /= Container'Unrestricted_Access then
392 raise Program_Error with "Parent cursor not in container";
393 end if;
395 if Count = 0 then
396 return;
397 end if;
399 if Container.Count > Container.Capacity - Count then
400 raise Capacity_Error
401 with "requested count exceeds available storage";
402 end if;
404 if Container.Busy > 0 then
405 raise Program_Error
406 with "attempt to tamper with cursors (tree is busy)";
407 end if;
409 if Container.Count = 0 then
410 Initialize_Root (Container);
411 end if;
413 Allocate_Node (Container, New_Item, First);
414 Nodes (First).Parent := Parent.Node;
416 Last := First;
417 for J in Count_Type'(2) .. Count loop
418 Allocate_Node (Container, New_Item, Nodes (Last).Next);
419 Nodes (Nodes (Last).Next).Parent := Parent.Node;
420 Nodes (Nodes (Last).Next).Prev := Last;
422 Last := Nodes (Last).Next;
423 end loop;
425 Insert_Subtree_List
426 (Container => Container,
427 First => First,
428 Last => Last,
429 Parent => Parent.Node,
430 Before => No_Node); -- means "insert at end of list"
432 Container.Count := Container.Count + Count;
433 end Append_Child;
435 ------------
436 -- Assign --
437 ------------
439 procedure Assign (Target : in out Tree; Source : Tree) is
440 Target_Count : Count_Type;
442 begin
443 if Target'Address = Source'Address then
444 return;
445 end if;
447 if Target.Capacity < Source.Count then
448 raise Capacity_Error -- ???
449 with "Target capacity is less than Source count";
450 end if;
452 Target.Clear; -- Checks busy bit
454 if Source.Count = 0 then
455 return;
456 end if;
458 Initialize_Root (Target);
460 -- Copy_Children returns the number of nodes that it allocates, but it
461 -- does this by incrementing the count value passed in, so we must
462 -- initialize the count before calling Copy_Children.
464 Target_Count := 0;
466 Copy_Children
467 (Source => Source,
468 Source_Parent => Root_Node (Source),
469 Target => Target,
470 Target_Parent => Root_Node (Target),
471 Count => Target_Count);
473 pragma Assert (Target_Count = Source.Count);
474 Target.Count := Source.Count;
475 end Assign;
477 -----------------
478 -- Child_Count --
479 -----------------
481 function Child_Count (Parent : Cursor) return Count_Type is
482 begin
483 if Parent = No_Element then
484 return 0;
486 elsif Parent.Container.Count = 0 then
487 pragma Assert (Is_Root (Parent));
488 return 0;
490 else
491 return Child_Count (Parent.Container.all, Parent.Node);
492 end if;
493 end Child_Count;
495 function Child_Count
496 (Container : Tree;
497 Parent : Count_Type) return Count_Type
499 NN : Tree_Node_Array renames Container.Nodes;
500 CC : Children_Type renames NN (Parent).Children;
502 Result : Count_Type;
503 Node : Count_Type'Base;
505 begin
506 Result := 0;
507 Node := CC.First;
508 while Node > 0 loop
509 Result := Result + 1;
510 Node := NN (Node).Next;
511 end loop;
513 return Result;
514 end Child_Count;
516 -----------------
517 -- Child_Depth --
518 -----------------
520 function Child_Depth (Parent, Child : Cursor) return Count_Type is
521 Result : Count_Type;
522 N : Count_Type'Base;
524 begin
525 if Parent = No_Element then
526 raise Constraint_Error with "Parent cursor has no element";
527 end if;
529 if Child = No_Element then
530 raise Constraint_Error with "Child cursor has no element";
531 end if;
533 if Parent.Container /= Child.Container then
534 raise Program_Error with "Parent and Child in different containers";
535 end if;
537 if Parent.Container.Count = 0 then
538 pragma Assert (Is_Root (Parent));
539 pragma Assert (Child = Parent);
540 return 0;
541 end if;
543 Result := 0;
544 N := Child.Node;
545 while N /= Parent.Node loop
546 Result := Result + 1;
547 N := Parent.Container.Nodes (N).Parent;
549 if N < 0 then
550 raise Program_Error with "Parent is not ancestor of Child";
551 end if;
552 end loop;
554 return Result;
555 end Child_Depth;
557 -----------
558 -- Clear --
559 -----------
561 procedure Clear (Container : in out Tree) is
562 Container_Count : constant Count_Type := Container.Count;
563 Count : Count_Type;
565 begin
566 if Container.Busy > 0 then
567 raise Program_Error
568 with "attempt to tamper with cursors (tree is busy)";
569 end if;
571 if Container_Count = 0 then
572 return;
573 end if;
575 Container.Count := 0;
577 -- Deallocate_Children returns the number of nodes that it deallocates,
578 -- but it does this by incrementing the count value that is passed in,
579 -- so we must first initialize the count return value before calling it.
581 Count := 0;
583 Deallocate_Children
584 (Container => Container,
585 Subtree => Root_Node (Container),
586 Count => Count);
588 pragma Assert (Count = Container_Count);
589 end Clear;
591 ------------------------
592 -- Constant_Reference --
593 ------------------------
595 function Constant_Reference
596 (Container : aliased Tree;
597 Position : Cursor) return Constant_Reference_Type
599 begin
600 if Position.Container = null then
601 raise Constraint_Error with
602 "Position cursor has no element";
603 end if;
605 if Position.Container /= Container'Unrestricted_Access then
606 raise Program_Error with
607 "Position cursor designates wrong container";
608 end if;
610 if Position.Node = Root_Node (Container) then
611 raise Program_Error with "Position cursor designates root";
612 end if;
614 -- Implement Vet for multiway tree???
615 -- pragma Assert (Vet (Position),
616 -- "Position cursor in Constant_Reference is bad");
618 return (Element => Container.Elements (Position.Node)'Access);
619 end Constant_Reference;
621 --------------
622 -- Contains --
623 --------------
625 function Contains
626 (Container : Tree;
627 Item : Element_Type) return Boolean
629 begin
630 return Find (Container, Item) /= No_Element;
631 end Contains;
633 ----------
634 -- Copy --
635 ----------
637 function Copy
638 (Source : Tree;
639 Capacity : Count_Type := 0) return Tree
641 C : Count_Type;
643 begin
644 if Capacity = 0 then
645 C := Source.Count;
646 elsif Capacity >= Source.Count then
647 C := Capacity;
648 else
649 raise Capacity_Error with "Capacity value too small";
650 end if;
652 return Target : Tree (Capacity => C) do
653 Initialize_Root (Target);
655 if Source.Count = 0 then
656 return;
657 end if;
659 Copy_Children
660 (Source => Source,
661 Source_Parent => Root_Node (Source),
662 Target => Target,
663 Target_Parent => Root_Node (Target),
664 Count => Target.Count);
666 pragma Assert (Target.Count = Source.Count);
667 end return;
668 end Copy;
670 -------------------
671 -- Copy_Children --
672 -------------------
674 procedure Copy_Children
675 (Source : Tree;
676 Source_Parent : Count_Type;
677 Target : in out Tree;
678 Target_Parent : Count_Type;
679 Count : in out Count_Type)
681 S_Nodes : Tree_Node_Array renames Source.Nodes;
682 S_Node : Tree_Node_Type renames S_Nodes (Source_Parent);
684 T_Nodes : Tree_Node_Array renames Target.Nodes;
685 T_Node : Tree_Node_Type renames T_Nodes (Target_Parent);
687 pragma Assert (T_Node.Children.First <= 0);
688 pragma Assert (T_Node.Children.Last <= 0);
690 T_CC : Children_Type;
691 C : Count_Type'Base;
693 begin
694 -- We special-case the first allocation, in order to establish the
695 -- representation invariants for type Children_Type.
697 C := S_Node.Children.First;
699 if C <= 0 then -- source parent has no children
700 return;
701 end if;
703 Copy_Subtree
704 (Source => Source,
705 Source_Subtree => C,
706 Target => Target,
707 Target_Parent => Target_Parent,
708 Target_Subtree => T_CC.First,
709 Count => Count);
711 T_CC.Last := T_CC.First;
713 -- The representation invariants for the Children_Type list have been
714 -- established, so we can now copy the remaining children of Source.
716 C := S_Nodes (C).Next;
717 while C > 0 loop
718 Copy_Subtree
719 (Source => Source,
720 Source_Subtree => C,
721 Target => Target,
722 Target_Parent => Target_Parent,
723 Target_Subtree => T_Nodes (T_CC.Last).Next,
724 Count => Count);
726 T_Nodes (T_Nodes (T_CC.Last).Next).Prev := T_CC.Last;
727 T_CC.Last := T_Nodes (T_CC.Last).Next;
729 C := S_Nodes (C).Next;
730 end loop;
732 -- We add the newly-allocated children to their parent list only after
733 -- the allocation has succeeded, in order to preserve invariants of the
734 -- parent.
736 T_Node.Children := T_CC;
737 end Copy_Children;
739 ------------------
740 -- Copy_Subtree --
741 ------------------
743 procedure Copy_Subtree
744 (Target : in out Tree;
745 Parent : Cursor;
746 Before : Cursor;
747 Source : Cursor)
749 Target_Subtree : Count_Type;
750 Target_Count : Count_Type;
752 begin
753 if Parent = No_Element then
754 raise Constraint_Error with "Parent cursor has no element";
755 end if;
757 if Parent.Container /= Target'Unrestricted_Access then
758 raise Program_Error with "Parent cursor not in container";
759 end if;
761 if Before /= No_Element then
762 if Before.Container /= Target'Unrestricted_Access then
763 raise Program_Error with "Before cursor not in container";
764 end if;
766 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
767 raise Constraint_Error with "Before cursor not child of Parent";
768 end if;
769 end if;
771 if Source = No_Element then
772 return;
773 end if;
775 if Is_Root (Source) then
776 raise Constraint_Error with "Source cursor designates root";
777 end if;
779 if Target.Count = 0 then
780 Initialize_Root (Target);
781 end if;
783 -- Copy_Subtree returns a count of the number of nodes that it
784 -- allocates, but it works by incrementing the value that is passed
785 -- in. We must therefore initialize the count value before calling
786 -- Copy_Subtree.
788 Target_Count := 0;
790 Copy_Subtree
791 (Source => Source.Container.all,
792 Source_Subtree => Source.Node,
793 Target => Target,
794 Target_Parent => Parent.Node,
795 Target_Subtree => Target_Subtree,
796 Count => Target_Count);
798 Insert_Subtree_Node
799 (Container => Target,
800 Subtree => Target_Subtree,
801 Parent => Parent.Node,
802 Before => Before.Node);
804 Target.Count := Target.Count + Target_Count;
805 end Copy_Subtree;
807 procedure Copy_Subtree
808 (Source : Tree;
809 Source_Subtree : Count_Type;
810 Target : in out Tree;
811 Target_Parent : Count_Type;
812 Target_Subtree : out Count_Type;
813 Count : in out Count_Type)
815 T_Nodes : Tree_Node_Array renames Target.Nodes;
817 begin
818 -- First we allocate the root of the target subtree.
820 Allocate_Node
821 (Container => Target,
822 New_Item => Source.Elements (Source_Subtree),
823 New_Node => Target_Subtree);
825 T_Nodes (Target_Subtree).Parent := Target_Parent;
826 Count := Count + 1;
828 -- We now have a new subtree (for the Target tree), containing only a
829 -- copy of the corresponding element in the Source subtree. Next we copy
830 -- the children of the Source subtree as children of the new Target
831 -- subtree.
833 Copy_Children
834 (Source => Source,
835 Source_Parent => Source_Subtree,
836 Target => Target,
837 Target_Parent => Target_Subtree,
838 Count => Count);
839 end Copy_Subtree;
841 -------------------------
842 -- Deallocate_Children --
843 -------------------------
845 procedure Deallocate_Children
846 (Container : in out Tree;
847 Subtree : Count_Type;
848 Count : in out Count_Type)
850 Nodes : Tree_Node_Array renames Container.Nodes;
851 Node : Tree_Node_Type renames Nodes (Subtree); -- parent
852 CC : Children_Type renames Node.Children;
853 C : Count_Type'Base;
855 begin
856 while CC.First > 0 loop
857 C := CC.First;
858 CC.First := Nodes (C).Next;
860 Deallocate_Subtree (Container, C, Count);
861 end loop;
863 CC.Last := 0;
864 end Deallocate_Children;
866 ---------------------
867 -- Deallocate_Node --
868 ---------------------
870 procedure Deallocate_Node
871 (Container : in out Tree;
872 X : Count_Type)
874 NN : Tree_Node_Array renames Container.Nodes;
875 pragma Assert (X > 0);
876 pragma Assert (X <= NN'Last);
878 N : Tree_Node_Type renames NN (X);
879 pragma Assert (N.Parent /= X); -- node is active
881 begin
882 -- The tree container actually contains two lists: one for the "active"
883 -- nodes that contain elements that have been inserted onto the tree,
884 -- and another for the "inactive" nodes of the free store, from which
885 -- nodes are allocated when a new child is inserted in the tree.
887 -- We desire that merely declaring a tree object should have only
888 -- minimal cost; specially, we want to avoid having to initialize the
889 -- free store (to fill in the links), especially if the capacity of the
890 -- tree object is large.
892 -- The head of the free list is indicated by Container.Free. If its
893 -- value is non-negative, then the free store has been initialized in
894 -- the "normal" way: Container.Free points to the head of the list of
895 -- free (inactive) nodes, and the value 0 means the free list is
896 -- empty. Each node on the free list has been initialized to point to
897 -- the next free node (via its Next component), and the value 0 means
898 -- that this is the last node of the free list.
900 -- If Container.Free is negative, then the links on the free store have
901 -- not been initialized. In this case the link values are implied: the
902 -- free store comprises the components of the node array started with
903 -- the absolute value of Container.Free, and continuing until the end of
904 -- the array (Nodes'Last).
906 -- We prefer to lazy-init the free store (in fact, we would prefer to
907 -- not initialize it at all, because such initialization is an O(n)
908 -- operation). The time when we need to actually initialize the nodes in
909 -- the free store is when the node that becomes inactive is not at the
910 -- end of the active list. The free store would then be discontigous and
911 -- so its nodes would need to be linked in the traditional way.
913 -- It might be possible to perform an optimization here. Suppose that
914 -- the free store can be represented as having two parts: one comprising
915 -- the non-contiguous inactive nodes linked together in the normal way,
916 -- and the other comprising the contiguous inactive nodes (that are not
917 -- linked together, at the end of the nodes array). This would allow us
918 -- to never have to initialize the free store, except in a lazy way as
919 -- nodes become inactive. ???
921 -- When an element is deleted from the list container, its node becomes
922 -- inactive, and so we set its Parent and Prev components to an
923 -- impossible value (the index of the node itself), to indicate that it
924 -- is now inactive. This provides a useful way to detect a dangling
925 -- cursor reference.
927 N.Parent := X; -- Node is deallocated (not on active list)
928 N.Prev := X;
930 if Container.Free >= 0 then
931 -- The free store has previously been initialized. All we need to do
932 -- here is link the newly-free'd node onto the free list.
934 N.Next := Container.Free;
935 Container.Free := X;
937 elsif X + 1 = abs Container.Free then
938 -- The free store has not been initialized, and the node becoming
939 -- inactive immediately precedes the start of the free store. All
940 -- we need to do is move the start of the free store back by one.
942 N.Next := X; -- Not strictly necessary, but marginally safer
943 Container.Free := Container.Free + 1;
945 else
946 -- The free store has not been initialized, and the node becoming
947 -- inactive does not immediately precede the free store. Here we
948 -- first initialize the free store (meaning the links are given
949 -- values in the traditional way), and then link the newly-free'd
950 -- node onto the head of the free store.
952 -- See the comments above for an optimization opportunity. If the
953 -- next link for a node on the free store is negative, then this
954 -- means the remaining nodes on the free store are physically
955 -- contiguous, starting at the absolute value of that index value.
956 -- ???
958 Container.Free := abs Container.Free;
960 if Container.Free > Container.Capacity then
961 Container.Free := 0;
963 else
964 for J in Container.Free .. Container.Capacity - 1 loop
965 NN (J).Next := J + 1;
966 end loop;
968 NN (Container.Capacity).Next := 0;
969 end if;
971 NN (X).Next := Container.Free;
972 Container.Free := X;
973 end if;
974 end Deallocate_Node;
976 ------------------------
977 -- Deallocate_Subtree --
978 ------------------------
980 procedure Deallocate_Subtree
981 (Container : in out Tree;
982 Subtree : Count_Type;
983 Count : in out Count_Type)
985 begin
986 Deallocate_Children (Container, Subtree, Count);
987 Deallocate_Node (Container, Subtree);
988 Count := Count + 1;
989 end Deallocate_Subtree;
991 ---------------------
992 -- Delete_Children --
993 ---------------------
995 procedure Delete_Children
996 (Container : in out Tree;
997 Parent : Cursor)
999 Count : Count_Type;
1001 begin
1002 if Parent = No_Element then
1003 raise Constraint_Error with "Parent cursor has no element";
1004 end if;
1006 if Parent.Container /= Container'Unrestricted_Access then
1007 raise Program_Error with "Parent cursor not in container";
1008 end if;
1010 if Container.Busy > 0 then
1011 raise Program_Error
1012 with "attempt to tamper with cursors (tree is busy)";
1013 end if;
1015 if Container.Count = 0 then
1016 pragma Assert (Is_Root (Parent));
1017 return;
1018 end if;
1020 -- Deallocate_Children returns a count of the number of nodes that it
1021 -- deallocates, but it works by incrementing the value that is passed
1022 -- in. We must therefore initialize the count value before calling
1023 -- Deallocate_Children.
1025 Count := 0;
1027 Deallocate_Children (Container, Parent.Node, Count);
1028 pragma Assert (Count <= Container.Count);
1030 Container.Count := Container.Count - Count;
1031 end Delete_Children;
1033 -----------------
1034 -- Delete_Leaf --
1035 -----------------
1037 procedure Delete_Leaf
1038 (Container : in out Tree;
1039 Position : in out Cursor)
1041 X : Count_Type;
1043 begin
1044 if Position = No_Element then
1045 raise Constraint_Error with "Position cursor has no element";
1046 end if;
1048 if Position.Container /= Container'Unrestricted_Access then
1049 raise Program_Error with "Position cursor not in container";
1050 end if;
1052 if Is_Root (Position) then
1053 raise Program_Error with "Position cursor designates root";
1054 end if;
1056 if not Is_Leaf (Position) then
1057 raise Constraint_Error with "Position cursor does not designate leaf";
1058 end if;
1060 if Container.Busy > 0 then
1061 raise Program_Error
1062 with "attempt to tamper with cursors (tree is busy)";
1063 end if;
1065 X := Position.Node;
1066 Position := No_Element;
1068 Remove_Subtree (Container, X);
1069 Container.Count := Container.Count - 1;
1071 Deallocate_Node (Container, X);
1072 end Delete_Leaf;
1074 --------------------
1075 -- Delete_Subtree --
1076 --------------------
1078 procedure Delete_Subtree
1079 (Container : in out Tree;
1080 Position : in out Cursor)
1082 X : Count_Type;
1083 Count : Count_Type;
1085 begin
1086 if Position = No_Element then
1087 raise Constraint_Error with "Position cursor has no element";
1088 end if;
1090 if Position.Container /= Container'Unrestricted_Access then
1091 raise Program_Error with "Position cursor not in container";
1092 end if;
1094 if Is_Root (Position) then
1095 raise Program_Error with "Position cursor designates root";
1096 end if;
1098 if Container.Busy > 0 then
1099 raise Program_Error
1100 with "attempt to tamper with cursors (tree is busy)";
1101 end if;
1103 X := Position.Node;
1104 Position := No_Element;
1106 Remove_Subtree (Container, X);
1108 -- Deallocate_Subtree returns a count of the number of nodes that it
1109 -- deallocates, but it works by incrementing the value that is passed
1110 -- in. We must therefore initialize the count value before calling
1111 -- Deallocate_Subtree.
1113 Count := 0;
1115 Deallocate_Subtree (Container, X, Count);
1116 pragma Assert (Count <= Container.Count);
1118 Container.Count := Container.Count - Count;
1119 end Delete_Subtree;
1121 -----------
1122 -- Depth --
1123 -----------
1125 function Depth (Position : Cursor) return Count_Type is
1126 Result : Count_Type;
1127 N : Count_Type'Base;
1129 begin
1130 if Position = No_Element then
1131 return 0;
1132 end if;
1134 if Is_Root (Position) then
1135 return 1;
1136 end if;
1138 Result := 0;
1139 N := Position.Node;
1140 while N >= 0 loop
1141 N := Position.Container.Nodes (N).Parent;
1142 Result := Result + 1;
1143 end loop;
1145 return Result;
1146 end Depth;
1148 -------------
1149 -- Element --
1150 -------------
1152 function Element (Position : Cursor) return Element_Type is
1153 begin
1154 if Position.Container = null then
1155 raise Constraint_Error with "Position cursor has no element";
1156 end if;
1158 if Position.Node = Root_Node (Position.Container.all) then
1159 raise Program_Error with "Position cursor designates root";
1160 end if;
1162 return Position.Container.Elements (Position.Node);
1163 end Element;
1165 --------------------
1166 -- Equal_Children --
1167 --------------------
1169 function Equal_Children
1170 (Left_Tree : Tree;
1171 Left_Subtree : Count_Type;
1172 Right_Tree : Tree;
1173 Right_Subtree : Count_Type) return Boolean
1175 L_NN : Tree_Node_Array renames Left_Tree.Nodes;
1176 R_NN : Tree_Node_Array renames Right_Tree.Nodes;
1178 Left_Children : Children_Type renames L_NN (Left_Subtree).Children;
1179 Right_Children : Children_Type renames R_NN (Right_Subtree).Children;
1181 L, R : Count_Type'Base;
1183 begin
1184 if Child_Count (Left_Tree, Left_Subtree)
1185 /= Child_Count (Right_Tree, Right_Subtree)
1186 then
1187 return False;
1188 end if;
1190 L := Left_Children.First;
1191 R := Right_Children.First;
1192 while L > 0 loop
1193 if not Equal_Subtree (Left_Tree, L, Right_Tree, R) then
1194 return False;
1195 end if;
1197 L := L_NN (L).Next;
1198 R := R_NN (R).Next;
1199 end loop;
1201 return True;
1202 end Equal_Children;
1204 -------------------
1205 -- Equal_Subtree --
1206 -------------------
1208 function Equal_Subtree
1209 (Left_Position : Cursor;
1210 Right_Position : Cursor) return Boolean
1212 begin
1213 if Left_Position = No_Element then
1214 raise Constraint_Error with "Left cursor has no element";
1215 end if;
1217 if Right_Position = No_Element then
1218 raise Constraint_Error with "Right cursor has no element";
1219 end if;
1221 if Left_Position = Right_Position then
1222 return True;
1223 end if;
1225 if Is_Root (Left_Position) then
1226 if not Is_Root (Right_Position) then
1227 return False;
1228 end if;
1230 if Left_Position.Container.Count = 0 then
1231 return Right_Position.Container.Count = 0;
1232 end if;
1234 if Right_Position.Container.Count = 0 then
1235 return False;
1236 end if;
1238 return Equal_Children
1239 (Left_Tree => Left_Position.Container.all,
1240 Left_Subtree => Left_Position.Node,
1241 Right_Tree => Right_Position.Container.all,
1242 Right_Subtree => Right_Position.Node);
1243 end if;
1245 if Is_Root (Right_Position) then
1246 return False;
1247 end if;
1249 return Equal_Subtree
1250 (Left_Tree => Left_Position.Container.all,
1251 Left_Subtree => Left_Position.Node,
1252 Right_Tree => Right_Position.Container.all,
1253 Right_Subtree => Right_Position.Node);
1254 end Equal_Subtree;
1256 function Equal_Subtree
1257 (Left_Tree : Tree;
1258 Left_Subtree : Count_Type;
1259 Right_Tree : Tree;
1260 Right_Subtree : Count_Type) return Boolean
1262 begin
1263 if Left_Tree.Elements (Left_Subtree) /=
1264 Right_Tree.Elements (Right_Subtree)
1265 then
1266 return False;
1267 end if;
1269 return Equal_Children
1270 (Left_Tree => Left_Tree,
1271 Left_Subtree => Left_Subtree,
1272 Right_Tree => Right_Tree,
1273 Right_Subtree => Right_Subtree);
1274 end Equal_Subtree;
1276 --------------
1277 -- Finalize --
1278 --------------
1280 procedure Finalize (Object : in out Root_Iterator) is
1281 B : Natural renames Object.Container.Busy;
1282 begin
1283 B := B - 1;
1284 end Finalize;
1286 ----------
1287 -- Find --
1288 ----------
1290 function Find
1291 (Container : Tree;
1292 Item : Element_Type) return Cursor
1294 Node : Count_Type;
1296 begin
1297 if Container.Count = 0 then
1298 return No_Element;
1299 end if;
1301 Node := Find_In_Children (Container, Root_Node (Container), Item);
1303 if Node = 0 then
1304 return No_Element;
1305 end if;
1307 return Cursor'(Container'Unrestricted_Access, Node);
1308 end Find;
1310 -----------
1311 -- First --
1312 -----------
1314 overriding function First (Object : Subtree_Iterator) return Cursor is
1315 begin
1316 if Object.Subtree = Root_Node (Object.Container.all) then
1317 return First_Child (Root (Object.Container.all));
1318 else
1319 return Cursor'(Object.Container, Object.Subtree);
1320 end if;
1321 end First;
1323 overriding function First (Object : Child_Iterator) return Cursor is
1324 begin
1325 return First_Child (Cursor'(Object.Container, Object.Subtree));
1326 end First;
1328 -----------------
1329 -- First_Child --
1330 -----------------
1332 function First_Child (Parent : Cursor) return Cursor is
1333 Node : Count_Type'Base;
1335 begin
1336 if Parent = No_Element then
1337 raise Constraint_Error with "Parent cursor has no element";
1338 end if;
1340 if Parent.Container.Count = 0 then
1341 pragma Assert (Is_Root (Parent));
1342 return No_Element;
1343 end if;
1345 Node := Parent.Container.Nodes (Parent.Node).Children.First;
1347 if Node <= 0 then
1348 return No_Element;
1349 end if;
1351 return Cursor'(Parent.Container, Node);
1352 end First_Child;
1354 -------------------------
1355 -- First_Child_Element --
1356 -------------------------
1358 function First_Child_Element (Parent : Cursor) return Element_Type is
1359 begin
1360 return Element (First_Child (Parent));
1361 end First_Child_Element;
1363 ----------------------
1364 -- Find_In_Children --
1365 ----------------------
1367 function Find_In_Children
1368 (Container : Tree;
1369 Subtree : Count_Type;
1370 Item : Element_Type) return Count_Type
1372 N : Count_Type'Base;
1373 Result : Count_Type;
1375 begin
1376 N := Container.Nodes (Subtree).Children.First;
1377 while N > 0 loop
1378 Result := Find_In_Subtree (Container, N, Item);
1380 if Result > 0 then
1381 return Result;
1382 end if;
1384 N := Container.Nodes (N).Next;
1385 end loop;
1387 return 0;
1388 end Find_In_Children;
1390 ---------------------
1391 -- Find_In_Subtree --
1392 ---------------------
1394 function Find_In_Subtree
1395 (Position : Cursor;
1396 Item : Element_Type) return Cursor
1398 Result : Count_Type;
1400 begin
1401 if Position = No_Element then
1402 raise Constraint_Error with "Position cursor has no element";
1403 end if;
1405 -- Commented-out pending ruling by ARG. ???
1407 -- if Position.Container /= Container'Unrestricted_Access then
1408 -- raise Program_Error with "Position cursor not in container";
1409 -- end if;
1411 if Position.Container.Count = 0 then
1412 pragma Assert (Is_Root (Position));
1413 return No_Element;
1414 end if;
1416 if Is_Root (Position) then
1417 Result := Find_In_Children
1418 (Container => Position.Container.all,
1419 Subtree => Position.Node,
1420 Item => Item);
1422 else
1423 Result := Find_In_Subtree
1424 (Container => Position.Container.all,
1425 Subtree => Position.Node,
1426 Item => Item);
1427 end if;
1429 if Result = 0 then
1430 return No_Element;
1431 end if;
1433 return Cursor'(Position.Container, Result);
1434 end Find_In_Subtree;
1436 function Find_In_Subtree
1437 (Container : Tree;
1438 Subtree : Count_Type;
1439 Item : Element_Type) return Count_Type
1441 begin
1442 if Container.Elements (Subtree) = Item then
1443 return Subtree;
1444 end if;
1446 return Find_In_Children (Container, Subtree, Item);
1447 end Find_In_Subtree;
1449 -----------------
1450 -- Has_Element --
1451 -----------------
1453 function Has_Element (Position : Cursor) return Boolean is
1454 begin
1455 if Position = No_Element then
1456 return False;
1457 end if;
1459 return Position.Node /= Root_Node (Position.Container.all);
1460 end Has_Element;
1462 ---------------------
1463 -- Initialize_Node --
1464 ---------------------
1466 procedure Initialize_Node
1467 (Container : in out Tree;
1468 Index : Count_Type)
1470 begin
1471 Container.Nodes (Index) :=
1472 (Parent => No_Node,
1473 Prev => 0,
1474 Next => 0,
1475 Children => (others => 0));
1476 end Initialize_Node;
1478 ---------------------
1479 -- Initialize_Root --
1480 ---------------------
1482 procedure Initialize_Root (Container : in out Tree) is
1483 begin
1484 Initialize_Node (Container, Root_Node (Container));
1485 end Initialize_Root;
1487 ------------------
1488 -- Insert_Child --
1489 ------------------
1491 procedure Insert_Child
1492 (Container : in out Tree;
1493 Parent : Cursor;
1494 Before : Cursor;
1495 New_Item : Element_Type;
1496 Count : Count_Type := 1)
1498 Position : Cursor;
1499 pragma Unreferenced (Position);
1501 begin
1502 Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1503 end Insert_Child;
1505 procedure Insert_Child
1506 (Container : in out Tree;
1507 Parent : Cursor;
1508 Before : Cursor;
1509 New_Item : Element_Type;
1510 Position : out Cursor;
1511 Count : Count_Type := 1)
1513 Nodes : Tree_Node_Array renames Container.Nodes;
1514 Last : Count_Type;
1516 begin
1517 if Parent = No_Element then
1518 raise Constraint_Error with "Parent cursor has no element";
1519 end if;
1521 if Parent.Container /= Container'Unrestricted_Access then
1522 raise Program_Error with "Parent cursor not in container";
1523 end if;
1525 if Before /= No_Element then
1526 if Before.Container /= Container'Unrestricted_Access then
1527 raise Program_Error with "Before cursor not in container";
1528 end if;
1530 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1531 raise Constraint_Error with "Parent cursor not parent of Before";
1532 end if;
1533 end if;
1535 if Count = 0 then
1536 Position := No_Element; -- Need ruling from ARG ???
1537 return;
1538 end if;
1540 if Container.Count > Container.Capacity - Count then
1541 raise Capacity_Error
1542 with "requested count exceeds available storage";
1543 end if;
1545 if Container.Busy > 0 then
1546 raise Program_Error
1547 with "attempt to tamper with cursors (tree is busy)";
1548 end if;
1550 if Container.Count = 0 then
1551 Initialize_Root (Container);
1552 end if;
1554 Allocate_Node (Container, New_Item, Position.Node);
1555 Nodes (Position.Node).Parent := Parent.Node;
1557 Last := Position.Node;
1558 for J in Count_Type'(2) .. Count loop
1559 Allocate_Node (Container, New_Item, Nodes (Last).Next);
1560 Nodes (Nodes (Last).Next).Parent := Parent.Node;
1561 Nodes (Nodes (Last).Next).Prev := Last;
1563 Last := Nodes (Last).Next;
1564 end loop;
1566 Insert_Subtree_List
1567 (Container => Container,
1568 First => Position.Node,
1569 Last => Last,
1570 Parent => Parent.Node,
1571 Before => Before.Node);
1573 Container.Count := Container.Count + Count;
1575 Position.Container := Parent.Container;
1576 end Insert_Child;
1578 procedure Insert_Child
1579 (Container : in out Tree;
1580 Parent : Cursor;
1581 Before : Cursor;
1582 Position : out Cursor;
1583 Count : Count_Type := 1)
1585 Nodes : Tree_Node_Array renames Container.Nodes;
1586 Last : Count_Type;
1588 New_Item : Element_Type;
1589 pragma Unmodified (New_Item);
1590 -- OK to reference, see below
1592 begin
1593 if Parent = No_Element then
1594 raise Constraint_Error with "Parent cursor has no element";
1595 end if;
1597 if Parent.Container /= Container'Unrestricted_Access then
1598 raise Program_Error with "Parent cursor not in container";
1599 end if;
1601 if Before /= No_Element then
1602 if Before.Container /= Container'Unrestricted_Access then
1603 raise Program_Error with "Before cursor not in container";
1604 end if;
1606 if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1607 raise Constraint_Error with "Parent cursor not parent of Before";
1608 end if;
1609 end if;
1611 if Count = 0 then
1612 Position := No_Element; -- Need ruling from ARG ???
1613 return;
1614 end if;
1616 if Container.Count > Container.Capacity - Count then
1617 raise Capacity_Error
1618 with "requested count exceeds available storage";
1619 end if;
1621 if Container.Busy > 0 then
1622 raise Program_Error
1623 with "attempt to tamper with cursors (tree is busy)";
1624 end if;
1626 if Container.Count = 0 then
1627 Initialize_Root (Container);
1628 end if;
1630 -- There is no explicit element provided, but in an instance the element
1631 -- type may be a scalar with a Default_Value aspect, or a composite
1632 -- type with such a scalar component, or components with default
1633 -- initialization, so insert the specified number of possibly
1634 -- initialized elements at the given position.
1636 Allocate_Node (Container, New_Item, Position.Node);
1637 Nodes (Position.Node).Parent := Parent.Node;
1639 Last := Position.Node;
1640 for J in Count_Type'(2) .. Count loop
1641 Allocate_Node (Container, Nodes (Last).Next);
1642 Nodes (Nodes (Last).Next).Parent := Parent.Node;
1643 Nodes (Nodes (Last).Next).Prev := Last;
1645 Last := Nodes (Last).Next;
1646 end loop;
1648 Insert_Subtree_List
1649 (Container => Container,
1650 First => Position.Node,
1651 Last => Last,
1652 Parent => Parent.Node,
1653 Before => Before.Node);
1655 Container.Count := Container.Count + Count;
1657 Position.Container := Parent.Container;
1658 end Insert_Child;
1660 -------------------------
1661 -- Insert_Subtree_List --
1662 -------------------------
1664 procedure Insert_Subtree_List
1665 (Container : in out Tree;
1666 First : Count_Type'Base;
1667 Last : Count_Type'Base;
1668 Parent : Count_Type;
1669 Before : Count_Type'Base)
1671 NN : Tree_Node_Array renames Container.Nodes;
1672 N : Tree_Node_Type renames NN (Parent);
1673 CC : Children_Type renames N.Children;
1675 begin
1676 -- This is a simple utility operation to insert a list of nodes
1677 -- (First..Last) as children of Parent. The Before node specifies where
1678 -- the new children should be inserted relative to existing children.
1680 if First <= 0 then
1681 pragma Assert (Last <= 0);
1682 return;
1683 end if;
1685 pragma Assert (Last > 0);
1686 pragma Assert (Before <= 0 or else NN (Before).Parent = Parent);
1688 if CC.First <= 0 then -- no existing children
1689 CC.First := First;
1690 NN (CC.First).Prev := 0;
1691 CC.Last := Last;
1692 NN (CC.Last).Next := 0;
1694 elsif Before <= 0 then -- means "insert after existing nodes"
1695 NN (CC.Last).Next := First;
1696 NN (First).Prev := CC.Last;
1697 CC.Last := Last;
1698 NN (CC.Last).Next := 0;
1700 elsif Before = CC.First then
1701 NN (Last).Next := CC.First;
1702 NN (CC.First).Prev := Last;
1703 CC.First := First;
1704 NN (CC.First).Prev := 0;
1706 else
1707 NN (NN (Before).Prev).Next := First;
1708 NN (First).Prev := NN (Before).Prev;
1709 NN (Last).Next := Before;
1710 NN (Before).Prev := Last;
1711 end if;
1712 end Insert_Subtree_List;
1714 -------------------------
1715 -- Insert_Subtree_Node --
1716 -------------------------
1718 procedure Insert_Subtree_Node
1719 (Container : in out Tree;
1720 Subtree : Count_Type'Base;
1721 Parent : Count_Type;
1722 Before : Count_Type'Base)
1724 begin
1725 -- This is a simple wrapper operation to insert a single child into the
1726 -- Parent's children list.
1728 Insert_Subtree_List
1729 (Container => Container,
1730 First => Subtree,
1731 Last => Subtree,
1732 Parent => Parent,
1733 Before => Before);
1734 end Insert_Subtree_Node;
1736 --------------
1737 -- Is_Empty --
1738 --------------
1740 function Is_Empty (Container : Tree) return Boolean is
1741 begin
1742 return Container.Count = 0;
1743 end Is_Empty;
1745 -------------
1746 -- Is_Leaf --
1747 -------------
1749 function Is_Leaf (Position : Cursor) return Boolean is
1750 begin
1751 if Position = No_Element then
1752 return False;
1753 end if;
1755 if Position.Container.Count = 0 then
1756 pragma Assert (Is_Root (Position));
1757 return True;
1758 end if;
1760 return Position.Container.Nodes (Position.Node).Children.First <= 0;
1761 end Is_Leaf;
1763 ------------------
1764 -- Is_Reachable --
1765 ------------------
1767 function Is_Reachable
1768 (Container : Tree;
1769 From, To : Count_Type) return Boolean
1771 Idx : Count_Type;
1773 begin
1774 Idx := From;
1775 while Idx >= 0 loop
1776 if Idx = To then
1777 return True;
1778 end if;
1780 Idx := Container.Nodes (Idx).Parent;
1781 end loop;
1783 return False;
1784 end Is_Reachable;
1786 -------------
1787 -- Is_Root --
1788 -------------
1790 function Is_Root (Position : Cursor) return Boolean is
1791 begin
1792 return
1793 (if Position.Container = null then False
1794 else Position.Node = Root_Node (Position.Container.all));
1795 end Is_Root;
1797 -------------
1798 -- Iterate --
1799 -------------
1801 procedure Iterate
1802 (Container : Tree;
1803 Process : not null access procedure (Position : Cursor))
1805 B : Natural renames Container'Unrestricted_Access.all.Busy;
1807 begin
1808 if Container.Count = 0 then
1809 return;
1810 end if;
1812 B := B + 1;
1814 Iterate_Children
1815 (Container => Container,
1816 Subtree => Root_Node (Container),
1817 Process => Process);
1819 B := B - 1;
1821 exception
1822 when others =>
1823 B := B - 1;
1824 raise;
1825 end Iterate;
1827 function Iterate (Container : Tree)
1828 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1830 begin
1831 return Iterate_Subtree (Root (Container));
1832 end Iterate;
1834 ----------------------
1835 -- Iterate_Children --
1836 ----------------------
1838 procedure Iterate_Children
1839 (Parent : Cursor;
1840 Process : not null access procedure (Position : Cursor))
1842 begin
1843 if Parent = No_Element then
1844 raise Constraint_Error with "Parent cursor has no element";
1845 end if;
1847 if Parent.Container.Count = 0 then
1848 pragma Assert (Is_Root (Parent));
1849 return;
1850 end if;
1852 declare
1853 B : Natural renames Parent.Container.Busy;
1854 C : Count_Type;
1855 NN : Tree_Node_Array renames Parent.Container.Nodes;
1857 begin
1858 B := B + 1;
1860 C := NN (Parent.Node).Children.First;
1861 while C > 0 loop
1862 Process (Cursor'(Parent.Container, Node => C));
1863 C := NN (C).Next;
1864 end loop;
1866 B := B - 1;
1868 exception
1869 when others =>
1870 B := B - 1;
1871 raise;
1872 end;
1873 end Iterate_Children;
1875 procedure Iterate_Children
1876 (Container : Tree;
1877 Subtree : Count_Type;
1878 Process : not null access procedure (Position : Cursor))
1880 NN : Tree_Node_Array renames Container.Nodes;
1881 N : Tree_Node_Type renames NN (Subtree);
1882 C : Count_Type;
1884 begin
1885 -- This is a helper function to recursively iterate over all the nodes
1886 -- in a subtree, in depth-first fashion. This particular helper just
1887 -- visits the children of this subtree, not the root of the subtree
1888 -- itself. This is useful when starting from the ultimate root of the
1889 -- entire tree (see Iterate), as that root does not have an element.
1891 C := N.Children.First;
1892 while C > 0 loop
1893 Iterate_Subtree (Container, C, Process);
1894 C := NN (C).Next;
1895 end loop;
1896 end Iterate_Children;
1898 function Iterate_Children
1899 (Container : Tree;
1900 Parent : Cursor)
1901 return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1903 C : constant Tree_Access := Container'Unrestricted_Access;
1904 B : Natural renames C.Busy;
1906 begin
1907 if Parent = No_Element then
1908 raise Constraint_Error with "Parent cursor has no element";
1909 end if;
1911 if Parent.Container /= C then
1912 raise Program_Error with "Parent cursor not in container";
1913 end if;
1915 return It : constant Child_Iterator :=
1916 Child_Iterator'(Limited_Controlled with
1917 Container => C,
1918 Subtree => Parent.Node)
1920 B := B + 1;
1921 end return;
1922 end Iterate_Children;
1924 ---------------------
1925 -- Iterate_Subtree --
1926 ---------------------
1928 function Iterate_Subtree
1929 (Position : Cursor)
1930 return Tree_Iterator_Interfaces.Forward_Iterator'Class
1932 begin
1933 if Position = No_Element then
1934 raise Constraint_Error with "Position cursor has no element";
1935 end if;
1937 -- Implement Vet for multiway trees???
1938 -- pragma Assert (Vet (Position), "bad subtree cursor");
1940 declare
1941 B : Natural renames Position.Container.Busy;
1942 begin
1943 return It : constant Subtree_Iterator :=
1944 (Limited_Controlled with
1945 Container => Position.Container,
1946 Subtree => Position.Node)
1948 B := B + 1;
1949 end return;
1950 end;
1951 end Iterate_Subtree;
1953 procedure Iterate_Subtree
1954 (Position : Cursor;
1955 Process : not null access procedure (Position : Cursor))
1957 begin
1958 if Position = No_Element then
1959 raise Constraint_Error with "Position cursor has no element";
1960 end if;
1962 if Position.Container.Count = 0 then
1963 pragma Assert (Is_Root (Position));
1964 return;
1965 end if;
1967 declare
1968 T : Tree renames Position.Container.all;
1969 B : Natural renames T.Busy;
1971 begin
1972 B := B + 1;
1974 if Is_Root (Position) then
1975 Iterate_Children (T, Position.Node, Process);
1976 else
1977 Iterate_Subtree (T, Position.Node, Process);
1978 end if;
1980 B := B - 1;
1982 exception
1983 when others =>
1984 B := B - 1;
1985 raise;
1986 end;
1987 end Iterate_Subtree;
1989 procedure Iterate_Subtree
1990 (Container : Tree;
1991 Subtree : Count_Type;
1992 Process : not null access procedure (Position : Cursor))
1994 begin
1995 -- This is a helper function to recursively iterate over all the nodes
1996 -- in a subtree, in depth-first fashion. It first visits the root of the
1997 -- subtree, then visits its children.
1999 Process (Cursor'(Container'Unrestricted_Access, Subtree));
2000 Iterate_Children (Container, Subtree, Process);
2001 end Iterate_Subtree;
2003 ----------
2004 -- Last --
2005 ----------
2007 overriding function Last (Object : Child_Iterator) return Cursor is
2008 begin
2009 return Last_Child (Cursor'(Object.Container, Object.Subtree));
2010 end Last;
2012 ----------------
2013 -- Last_Child --
2014 ----------------
2016 function Last_Child (Parent : Cursor) return Cursor is
2017 Node : Count_Type'Base;
2019 begin
2020 if Parent = No_Element then
2021 raise Constraint_Error with "Parent cursor has no element";
2022 end if;
2024 if Parent.Container.Count = 0 then
2025 pragma Assert (Is_Root (Parent));
2026 return No_Element;
2027 end if;
2029 Node := Parent.Container.Nodes (Parent.Node).Children.Last;
2031 if Node <= 0 then
2032 return No_Element;
2033 end if;
2035 return Cursor'(Parent.Container, Node);
2036 end Last_Child;
2038 ------------------------
2039 -- Last_Child_Element --
2040 ------------------------
2042 function Last_Child_Element (Parent : Cursor) return Element_Type is
2043 begin
2044 return Element (Last_Child (Parent));
2045 end Last_Child_Element;
2047 ----------
2048 -- Move --
2049 ----------
2051 procedure Move (Target : in out Tree; Source : in out Tree) is
2052 begin
2053 if Target'Address = Source'Address then
2054 return;
2055 end if;
2057 if Source.Busy > 0 then
2058 raise Program_Error
2059 with "attempt to tamper with cursors of Source (tree is busy)";
2060 end if;
2062 Target.Assign (Source);
2063 Source.Clear;
2064 end Move;
2066 ----------
2067 -- Next --
2068 ----------
2070 overriding function Next
2071 (Object : Subtree_Iterator;
2072 Position : Cursor) return Cursor
2074 begin
2075 if Position.Container = null then
2076 return No_Element;
2077 end if;
2079 if Position.Container /= Object.Container then
2080 raise Program_Error with
2081 "Position cursor of Next designates wrong tree";
2082 end if;
2084 pragma Assert (Object.Container.Count > 0);
2085 pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2087 declare
2088 Nodes : Tree_Node_Array renames Object.Container.Nodes;
2089 Node : Count_Type;
2091 begin
2092 Node := Position.Node;
2094 if Nodes (Node).Children.First > 0 then
2095 return Cursor'(Object.Container, Nodes (Node).Children.First);
2096 end if;
2098 while Node /= Object.Subtree loop
2099 if Nodes (Node).Next > 0 then
2100 return Cursor'(Object.Container, Nodes (Node).Next);
2101 end if;
2103 Node := Nodes (Node).Parent;
2104 end loop;
2106 return No_Element;
2107 end;
2108 end Next;
2110 overriding function Next
2111 (Object : Child_Iterator;
2112 Position : Cursor) return Cursor
2114 begin
2115 if Position.Container = null then
2116 return No_Element;
2117 end if;
2119 if Position.Container /= Object.Container then
2120 raise Program_Error with
2121 "Position cursor of Next designates wrong tree";
2122 end if;
2124 pragma Assert (Object.Container.Count > 0);
2125 pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2127 return Next_Sibling (Position);
2128 end Next;
2130 ------------------
2131 -- Next_Sibling --
2132 ------------------
2134 function Next_Sibling (Position : Cursor) return Cursor is
2135 begin
2136 if Position = No_Element then
2137 return No_Element;
2138 end if;
2140 if Position.Container.Count = 0 then
2141 pragma Assert (Is_Root (Position));
2142 return No_Element;
2143 end if;
2145 declare
2146 T : Tree renames Position.Container.all;
2147 NN : Tree_Node_Array renames T.Nodes;
2148 N : Tree_Node_Type renames NN (Position.Node);
2150 begin
2151 if N.Next <= 0 then
2152 return No_Element;
2153 end if;
2155 return Cursor'(Position.Container, N.Next);
2156 end;
2157 end Next_Sibling;
2159 procedure Next_Sibling (Position : in out Cursor) is
2160 begin
2161 Position := Next_Sibling (Position);
2162 end Next_Sibling;
2164 ----------------
2165 -- Node_Count --
2166 ----------------
2168 function Node_Count (Container : Tree) return Count_Type is
2169 begin
2170 -- Container.Count is the number of nodes we have actually allocated. We
2171 -- cache the value specifically so this Node_Count operation can execute
2172 -- in O(1) time, which makes it behave similarly to how the Length
2173 -- selector function behaves for other containers.
2175 -- The cached node count value only describes the nodes we have
2176 -- allocated; the root node itself is not included in that count. The
2177 -- Node_Count operation returns a value that includes the root node
2178 -- (because the RM says so), so we must add 1 to our cached value.
2180 return 1 + Container.Count;
2181 end Node_Count;
2183 ------------
2184 -- Parent --
2185 ------------
2187 function Parent (Position : Cursor) return Cursor is
2188 begin
2189 if Position = No_Element then
2190 return No_Element;
2191 end if;
2193 if Position.Container.Count = 0 then
2194 pragma Assert (Is_Root (Position));
2195 return No_Element;
2196 end if;
2198 declare
2199 T : Tree renames Position.Container.all;
2200 NN : Tree_Node_Array renames T.Nodes;
2201 N : Tree_Node_Type renames NN (Position.Node);
2203 begin
2204 if N.Parent < 0 then
2205 pragma Assert (Position.Node = Root_Node (T));
2206 return No_Element;
2207 end if;
2209 return Cursor'(Position.Container, N.Parent);
2210 end;
2211 end Parent;
2213 -------------------
2214 -- Prepend_Child --
2215 -------------------
2217 procedure Prepend_Child
2218 (Container : in out Tree;
2219 Parent : Cursor;
2220 New_Item : Element_Type;
2221 Count : Count_Type := 1)
2223 Nodes : Tree_Node_Array renames Container.Nodes;
2224 First, Last : Count_Type;
2226 begin
2227 if Parent = No_Element then
2228 raise Constraint_Error with "Parent cursor has no element";
2229 end if;
2231 if Parent.Container /= Container'Unrestricted_Access then
2232 raise Program_Error with "Parent cursor not in container";
2233 end if;
2235 if Count = 0 then
2236 return;
2237 end if;
2239 if Container.Count > Container.Capacity - Count then
2240 raise Capacity_Error
2241 with "requested count exceeds available storage";
2242 end if;
2244 if Container.Busy > 0 then
2245 raise Program_Error
2246 with "attempt to tamper with cursors (tree is busy)";
2247 end if;
2249 if Container.Count = 0 then
2250 Initialize_Root (Container);
2251 end if;
2253 Allocate_Node (Container, New_Item, First);
2254 Nodes (First).Parent := Parent.Node;
2256 Last := First;
2257 for J in Count_Type'(2) .. Count loop
2258 Allocate_Node (Container, New_Item, Nodes (Last).Next);
2259 Nodes (Nodes (Last).Next).Parent := Parent.Node;
2260 Nodes (Nodes (Last).Next).Prev := Last;
2262 Last := Nodes (Last).Next;
2263 end loop;
2265 Insert_Subtree_List
2266 (Container => Container,
2267 First => First,
2268 Last => Last,
2269 Parent => Parent.Node,
2270 Before => Nodes (Parent.Node).Children.First);
2272 Container.Count := Container.Count + Count;
2273 end Prepend_Child;
2275 --------------
2276 -- Previous --
2277 --------------
2279 overriding function Previous
2280 (Object : Child_Iterator;
2281 Position : Cursor) return Cursor
2283 begin
2284 if Position.Container = null then
2285 return No_Element;
2286 end if;
2288 if Position.Container /= Object.Container then
2289 raise Program_Error with
2290 "Position cursor of Previous designates wrong tree";
2291 end if;
2293 return Previous_Sibling (Position);
2294 end Previous;
2296 ----------------------
2297 -- Previous_Sibling --
2298 ----------------------
2300 function Previous_Sibling (Position : Cursor) return Cursor is
2301 begin
2302 if Position = No_Element then
2303 return No_Element;
2304 end if;
2306 if Position.Container.Count = 0 then
2307 pragma Assert (Is_Root (Position));
2308 return No_Element;
2309 end if;
2311 declare
2312 T : Tree renames Position.Container.all;
2313 NN : Tree_Node_Array renames T.Nodes;
2314 N : Tree_Node_Type renames NN (Position.Node);
2316 begin
2317 if N.Prev <= 0 then
2318 return No_Element;
2319 end if;
2321 return Cursor'(Position.Container, N.Prev);
2322 end;
2323 end Previous_Sibling;
2325 procedure Previous_Sibling (Position : in out Cursor) is
2326 begin
2327 Position := Previous_Sibling (Position);
2328 end Previous_Sibling;
2330 -------------------
2331 -- Query_Element --
2332 -------------------
2334 procedure Query_Element
2335 (Position : Cursor;
2336 Process : not null access procedure (Element : Element_Type))
2338 begin
2339 if Position = No_Element then
2340 raise Constraint_Error with "Position cursor has no element";
2341 end if;
2343 if Is_Root (Position) then
2344 raise Program_Error with "Position cursor designates root";
2345 end if;
2347 declare
2348 T : Tree renames Position.Container.all'Unrestricted_Access.all;
2349 B : Natural renames T.Busy;
2350 L : Natural renames T.Lock;
2352 begin
2353 B := B + 1;
2354 L := L + 1;
2356 Process (Element => T.Elements (Position.Node));
2358 L := L - 1;
2359 B := B - 1;
2361 exception
2362 when others =>
2363 L := L - 1;
2364 B := B - 1;
2365 raise;
2366 end;
2367 end Query_Element;
2369 ----------
2370 -- Read --
2371 ----------
2373 procedure Read
2374 (Stream : not null access Root_Stream_Type'Class;
2375 Container : out Tree)
2377 procedure Read_Children (Subtree : Count_Type);
2379 function Read_Subtree
2380 (Parent : Count_Type) return Count_Type;
2382 NN : Tree_Node_Array renames Container.Nodes;
2384 Total_Count : Count_Type'Base;
2385 -- Value read from the stream that says how many elements follow
2387 Read_Count : Count_Type'Base;
2388 -- Actual number of elements read from the stream
2390 -------------------
2391 -- Read_Children --
2392 -------------------
2394 procedure Read_Children (Subtree : Count_Type) is
2395 Count : Count_Type'Base;
2396 -- number of child subtrees
2398 CC : Children_Type;
2400 begin
2401 Count_Type'Read (Stream, Count);
2403 if Count < 0 then
2404 raise Program_Error with "attempt to read from corrupt stream";
2405 end if;
2407 if Count = 0 then
2408 return;
2409 end if;
2411 CC.First := Read_Subtree (Parent => Subtree);
2412 CC.Last := CC.First;
2414 for J in Count_Type'(2) .. Count loop
2415 NN (CC.Last).Next := Read_Subtree (Parent => Subtree);
2416 NN (NN (CC.Last).Next).Prev := CC.Last;
2417 CC.Last := NN (CC.Last).Next;
2418 end loop;
2420 -- Now that the allocation and reads have completed successfully, it
2421 -- is safe to link the children to their parent.
2423 NN (Subtree).Children := CC;
2424 end Read_Children;
2426 ------------------
2427 -- Read_Subtree --
2428 ------------------
2430 function Read_Subtree
2431 (Parent : Count_Type) return Count_Type
2433 Subtree : Count_Type;
2435 begin
2436 Allocate_Node (Container, Stream, Subtree);
2437 Container.Nodes (Subtree).Parent := Parent;
2439 Read_Count := Read_Count + 1;
2441 Read_Children (Subtree);
2443 return Subtree;
2444 end Read_Subtree;
2446 -- Start of processing for Read
2448 begin
2449 Container.Clear; -- checks busy bit
2451 Count_Type'Read (Stream, Total_Count);
2453 if Total_Count < 0 then
2454 raise Program_Error with "attempt to read from corrupt stream";
2455 end if;
2457 if Total_Count = 0 then
2458 return;
2459 end if;
2461 if Total_Count > Container.Capacity then
2462 raise Capacity_Error -- ???
2463 with "node count in stream exceeds container capacity";
2464 end if;
2466 Initialize_Root (Container);
2468 Read_Count := 0;
2470 Read_Children (Root_Node (Container));
2472 if Read_Count /= Total_Count then
2473 raise Program_Error with "attempt to read from corrupt stream";
2474 end if;
2476 Container.Count := Total_Count;
2477 end Read;
2479 procedure Read
2480 (Stream : not null access Root_Stream_Type'Class;
2481 Position : out Cursor)
2483 begin
2484 raise Program_Error with "attempt to read tree cursor from stream";
2485 end Read;
2487 procedure Read
2488 (Stream : not null access Root_Stream_Type'Class;
2489 Item : out Reference_Type)
2491 begin
2492 raise Program_Error with "attempt to stream reference";
2493 end Read;
2495 procedure Read
2496 (Stream : not null access Root_Stream_Type'Class;
2497 Item : out Constant_Reference_Type)
2499 begin
2500 raise Program_Error with "attempt to stream reference";
2501 end Read;
2503 ---------------
2504 -- Reference --
2505 ---------------
2507 function Reference
2508 (Container : aliased in out Tree;
2509 Position : Cursor) return Reference_Type
2511 begin
2512 if Position.Container = null then
2513 raise Constraint_Error with
2514 "Position cursor has no element";
2515 end if;
2517 if Position.Container /= Container'Unrestricted_Access then
2518 raise Program_Error with
2519 "Position cursor designates wrong container";
2520 end if;
2522 if Position.Node = Root_Node (Container) then
2523 raise Program_Error with "Position cursor designates root";
2524 end if;
2526 -- Implement Vet for multiway tree???
2527 -- pragma Assert (Vet (Position),
2528 -- "Position cursor in Constant_Reference is bad");
2530 return (Element => Container.Elements (Position.Node)'Access);
2531 end Reference;
2533 --------------------
2534 -- Remove_Subtree --
2535 --------------------
2537 procedure Remove_Subtree
2538 (Container : in out Tree;
2539 Subtree : Count_Type)
2541 NN : Tree_Node_Array renames Container.Nodes;
2542 N : Tree_Node_Type renames NN (Subtree);
2543 CC : Children_Type renames NN (N.Parent).Children;
2545 begin
2546 -- This is a utility operation to remove a subtree node from its
2547 -- parent's list of children.
2549 if CC.First = Subtree then
2550 pragma Assert (N.Prev <= 0);
2552 if CC.Last = Subtree then
2553 pragma Assert (N.Next <= 0);
2554 CC.First := 0;
2555 CC.Last := 0;
2557 else
2558 CC.First := N.Next;
2559 NN (CC.First).Prev := 0;
2560 end if;
2562 elsif CC.Last = Subtree then
2563 pragma Assert (N.Next <= 0);
2564 CC.Last := N.Prev;
2565 NN (CC.Last).Next := 0;
2567 else
2568 NN (N.Prev).Next := N.Next;
2569 NN (N.Next).Prev := N.Prev;
2570 end if;
2571 end Remove_Subtree;
2573 ----------------------
2574 -- Replace_Element --
2575 ----------------------
2577 procedure Replace_Element
2578 (Container : in out Tree;
2579 Position : Cursor;
2580 New_Item : Element_Type)
2582 begin
2583 if Position = No_Element then
2584 raise Constraint_Error with "Position cursor has no element";
2585 end if;
2587 if Position.Container /= Container'Unrestricted_Access then
2588 raise Program_Error with "Position cursor not in container";
2589 end if;
2591 if Is_Root (Position) then
2592 raise Program_Error with "Position cursor designates root";
2593 end if;
2595 if Container.Lock > 0 then
2596 raise Program_Error
2597 with "attempt to tamper with elements (tree is locked)";
2598 end if;
2600 Container.Elements (Position.Node) := New_Item;
2601 end Replace_Element;
2603 ------------------------------
2604 -- Reverse_Iterate_Children --
2605 ------------------------------
2607 procedure Reverse_Iterate_Children
2608 (Parent : Cursor;
2609 Process : not null access procedure (Position : Cursor))
2611 begin
2612 if Parent = No_Element then
2613 raise Constraint_Error with "Parent cursor has no element";
2614 end if;
2616 if Parent.Container.Count = 0 then
2617 pragma Assert (Is_Root (Parent));
2618 return;
2619 end if;
2621 declare
2622 NN : Tree_Node_Array renames Parent.Container.Nodes;
2623 B : Natural renames Parent.Container.Busy;
2624 C : Count_Type;
2626 begin
2627 B := B + 1;
2629 C := NN (Parent.Node).Children.Last;
2630 while C > 0 loop
2631 Process (Cursor'(Parent.Container, Node => C));
2632 C := NN (C).Prev;
2633 end loop;
2635 B := B - 1;
2637 exception
2638 when others =>
2639 B := B - 1;
2640 raise;
2641 end;
2642 end Reverse_Iterate_Children;
2644 ----------
2645 -- Root --
2646 ----------
2648 function Root (Container : Tree) return Cursor is
2649 begin
2650 return (Container'Unrestricted_Access, Root_Node (Container));
2651 end Root;
2653 ---------------
2654 -- Root_Node --
2655 ---------------
2657 function Root_Node (Container : Tree) return Count_Type is
2658 pragma Unreferenced (Container);
2660 begin
2661 return 0;
2662 end Root_Node;
2664 ---------------------
2665 -- Splice_Children --
2666 ---------------------
2668 procedure Splice_Children
2669 (Target : in out Tree;
2670 Target_Parent : Cursor;
2671 Before : Cursor;
2672 Source : in out Tree;
2673 Source_Parent : Cursor)
2675 begin
2676 if Target_Parent = No_Element then
2677 raise Constraint_Error with "Target_Parent cursor has no element";
2678 end if;
2680 if Target_Parent.Container /= Target'Unrestricted_Access then
2681 raise Program_Error
2682 with "Target_Parent cursor not in Target container";
2683 end if;
2685 if Before /= No_Element then
2686 if Before.Container /= Target'Unrestricted_Access then
2687 raise Program_Error
2688 with "Before cursor not in Target container";
2689 end if;
2691 if Target.Nodes (Before.Node).Parent /= Target_Parent.Node then
2692 raise Constraint_Error
2693 with "Before cursor not child of Target_Parent";
2694 end if;
2695 end if;
2697 if Source_Parent = No_Element then
2698 raise Constraint_Error with "Source_Parent cursor has no element";
2699 end if;
2701 if Source_Parent.Container /= Source'Unrestricted_Access then
2702 raise Program_Error
2703 with "Source_Parent cursor not in Source container";
2704 end if;
2706 if Source.Count = 0 then
2707 pragma Assert (Is_Root (Source_Parent));
2708 return;
2709 end if;
2711 if Target'Address = Source'Address then
2712 if Target_Parent = Source_Parent then
2713 return;
2714 end if;
2716 if Target.Busy > 0 then
2717 raise Program_Error
2718 with "attempt to tamper with cursors (Target tree is busy)";
2719 end if;
2721 if Is_Reachable (Container => Target,
2722 From => Target_Parent.Node,
2723 To => Source_Parent.Node)
2724 then
2725 raise Constraint_Error
2726 with "Source_Parent is ancestor of Target_Parent";
2727 end if;
2729 Splice_Children
2730 (Container => Target,
2731 Target_Parent => Target_Parent.Node,
2732 Before => Before.Node,
2733 Source_Parent => Source_Parent.Node);
2735 return;
2736 end if;
2738 if Target.Busy > 0 then
2739 raise Program_Error
2740 with "attempt to tamper with cursors (Target tree is busy)";
2741 end if;
2743 if Source.Busy > 0 then
2744 raise Program_Error
2745 with "attempt to tamper with cursors (Source tree is busy)";
2746 end if;
2748 if Target.Count = 0 then
2749 Initialize_Root (Target);
2750 end if;
2752 Splice_Children
2753 (Target => Target,
2754 Target_Parent => Target_Parent.Node,
2755 Before => Before.Node,
2756 Source => Source,
2757 Source_Parent => Source_Parent.Node);
2758 end Splice_Children;
2760 procedure Splice_Children
2761 (Container : in out Tree;
2762 Target_Parent : Cursor;
2763 Before : Cursor;
2764 Source_Parent : Cursor)
2766 begin
2767 if Target_Parent = No_Element then
2768 raise Constraint_Error with "Target_Parent cursor has no element";
2769 end if;
2771 if Target_Parent.Container /= Container'Unrestricted_Access then
2772 raise Program_Error
2773 with "Target_Parent cursor not in container";
2774 end if;
2776 if Before /= No_Element then
2777 if Before.Container /= Container'Unrestricted_Access then
2778 raise Program_Error
2779 with "Before cursor not in container";
2780 end if;
2782 if Container.Nodes (Before.Node).Parent /= Target_Parent.Node then
2783 raise Constraint_Error
2784 with "Before cursor not child of Target_Parent";
2785 end if;
2786 end if;
2788 if Source_Parent = No_Element then
2789 raise Constraint_Error with "Source_Parent cursor has no element";
2790 end if;
2792 if Source_Parent.Container /= Container'Unrestricted_Access then
2793 raise Program_Error
2794 with "Source_Parent cursor not in container";
2795 end if;
2797 if Target_Parent = Source_Parent then
2798 return;
2799 end if;
2801 pragma Assert (Container.Count > 0);
2803 if Container.Busy > 0 then
2804 raise Program_Error
2805 with "attempt to tamper with cursors (tree is busy)";
2806 end if;
2808 if Is_Reachable (Container => Container,
2809 From => Target_Parent.Node,
2810 To => Source_Parent.Node)
2811 then
2812 raise Constraint_Error
2813 with "Source_Parent is ancestor of Target_Parent";
2814 end if;
2816 Splice_Children
2817 (Container => Container,
2818 Target_Parent => Target_Parent.Node,
2819 Before => Before.Node,
2820 Source_Parent => Source_Parent.Node);
2821 end Splice_Children;
2823 procedure Splice_Children
2824 (Container : in out Tree;
2825 Target_Parent : Count_Type;
2826 Before : Count_Type'Base;
2827 Source_Parent : Count_Type)
2829 NN : Tree_Node_Array renames Container.Nodes;
2830 CC : constant Children_Type := NN (Source_Parent).Children;
2831 C : Count_Type'Base;
2833 begin
2834 -- This is a utility operation to remove the children from Source parent
2835 -- and insert them into Target parent.
2837 NN (Source_Parent).Children := Children_Type'(others => 0);
2839 -- Fix up the Parent pointers of each child to designate its new Target
2840 -- parent.
2842 C := CC.First;
2843 while C > 0 loop
2844 NN (C).Parent := Target_Parent;
2845 C := NN (C).Next;
2846 end loop;
2848 Insert_Subtree_List
2849 (Container => Container,
2850 First => CC.First,
2851 Last => CC.Last,
2852 Parent => Target_Parent,
2853 Before => Before);
2854 end Splice_Children;
2856 procedure Splice_Children
2857 (Target : in out Tree;
2858 Target_Parent : Count_Type;
2859 Before : Count_Type'Base;
2860 Source : in out Tree;
2861 Source_Parent : Count_Type)
2863 S_NN : Tree_Node_Array renames Source.Nodes;
2864 S_CC : Children_Type renames S_NN (Source_Parent).Children;
2866 Target_Count, Source_Count : Count_Type;
2867 T, S : Count_Type'Base;
2869 begin
2870 -- This is a utility operation to copy the children from the Source
2871 -- parent and insert them as children of the Target parent, and then
2872 -- delete them from the Source. (This is not a true splice operation,
2873 -- but it is the best we can do in a bounded form.) The Before position
2874 -- specifies where among the Target parent's exising children the new
2875 -- children are inserted.
2877 -- Before we attempt the insertion, we must count the sources nodes in
2878 -- order to determine whether the target have enough storage
2879 -- available. Note that calculating this value is an O(n) operation.
2881 -- Here is an optimization opportunity: iterate of each children the
2882 -- source explicitly, and keep a running count of the total number of
2883 -- nodes. Compare the running total to the capacity of the target each
2884 -- pass through the loop. This is more efficient than summing the counts
2885 -- of child subtree (which is what Subtree_Node_Count does) and then
2886 -- comparing that total sum to the target's capacity. ???
2888 -- Here is another possibility. We currently treat the splice as an
2889 -- all-or-nothing proposition: either we can insert all of children of
2890 -- the source, or we raise exception with modifying the target. The
2891 -- price for not causing side-effect is an O(n) determination of the
2892 -- source count. If we are willing to tolerate side-effect, then we
2893 -- could loop over the children of the source, counting that subtree and
2894 -- then immediately inserting it in the target. The issue here is that
2895 -- the test for available storage could fail during some later pass,
2896 -- after children have already been inserted into target. ???
2898 Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1;
2900 if Source_Count = 0 then
2901 return;
2902 end if;
2904 if Target.Count > Target.Capacity - Source_Count then
2905 raise Capacity_Error -- ???
2906 with "Source count exceeds available storage on Target";
2907 end if;
2909 -- Copy_Subtree returns a count of the number of nodes it inserts, but
2910 -- it does this by incrementing the value passed in. Therefore we must
2911 -- initialize the count before calling Copy_Subtree.
2913 Target_Count := 0;
2915 S := S_CC.First;
2916 while S > 0 loop
2917 Copy_Subtree
2918 (Source => Source,
2919 Source_Subtree => S,
2920 Target => Target,
2921 Target_Parent => Target_Parent,
2922 Target_Subtree => T,
2923 Count => Target_Count);
2925 Insert_Subtree_Node
2926 (Container => Target,
2927 Subtree => T,
2928 Parent => Target_Parent,
2929 Before => Before);
2931 S := S_NN (S).Next;
2932 end loop;
2934 pragma Assert (Target_Count = Source_Count);
2935 Target.Count := Target.Count + Target_Count;
2937 -- As with Copy_Subtree, operation Deallocate_Children returns a count
2938 -- of the number of nodes it deallocates, but it works by incrementing
2939 -- the value passed in. We must therefore initialize the count before
2940 -- calling it.
2942 Source_Count := 0;
2944 Deallocate_Children (Source, Source_Parent, Source_Count);
2945 pragma Assert (Source_Count = Target_Count);
2947 Source.Count := Source.Count - Source_Count;
2948 end Splice_Children;
2950 --------------------
2951 -- Splice_Subtree --
2952 --------------------
2954 procedure Splice_Subtree
2955 (Target : in out Tree;
2956 Parent : Cursor;
2957 Before : Cursor;
2958 Source : in out Tree;
2959 Position : in out Cursor)
2961 begin
2962 if Parent = No_Element then
2963 raise Constraint_Error with "Parent cursor has no element";
2964 end if;
2966 if Parent.Container /= Target'Unrestricted_Access then
2967 raise Program_Error with "Parent cursor not in Target container";
2968 end if;
2970 if Before /= No_Element then
2971 if Before.Container /= Target'Unrestricted_Access then
2972 raise Program_Error with "Before cursor not in Target container";
2973 end if;
2975 if Target.Nodes (Before.Node).Parent /= Parent.Node then
2976 raise Constraint_Error with "Before cursor not child of Parent";
2977 end if;
2978 end if;
2980 if Position = No_Element then
2981 raise Constraint_Error with "Position cursor has no element";
2982 end if;
2984 if Position.Container /= Source'Unrestricted_Access then
2985 raise Program_Error with "Position cursor not in Source container";
2986 end if;
2988 if Is_Root (Position) then
2989 raise Program_Error with "Position cursor designates root";
2990 end if;
2992 if Target'Address = Source'Address then
2993 if Target.Nodes (Position.Node).Parent = Parent.Node then
2994 if Before = No_Element then
2995 if Target.Nodes (Position.Node).Next <= 0 then -- last child
2996 return;
2997 end if;
2999 elsif Position.Node = Before.Node then
3000 return;
3002 elsif Target.Nodes (Position.Node).Next = Before.Node then
3003 return;
3004 end if;
3005 end if;
3007 if Target.Busy > 0 then
3008 raise Program_Error
3009 with "attempt to tamper with cursors (Target tree is busy)";
3010 end if;
3012 if Is_Reachable (Container => Target,
3013 From => Parent.Node,
3014 To => Position.Node)
3015 then
3016 raise Constraint_Error with "Position is ancestor of Parent";
3017 end if;
3019 Remove_Subtree (Target, Position.Node);
3021 Target.Nodes (Position.Node).Parent := Parent.Node;
3022 Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node);
3024 return;
3025 end if;
3027 if Target.Busy > 0 then
3028 raise Program_Error
3029 with "attempt to tamper with cursors (Target tree is busy)";
3030 end if;
3032 if Source.Busy > 0 then
3033 raise Program_Error
3034 with "attempt to tamper with cursors (Source tree is busy)";
3035 end if;
3037 if Target.Count = 0 then
3038 Initialize_Root (Target);
3039 end if;
3041 Splice_Subtree
3042 (Target => Target,
3043 Parent => Parent.Node,
3044 Before => Before.Node,
3045 Source => Source,
3046 Position => Position.Node); -- modified during call
3048 Position.Container := Target'Unrestricted_Access;
3049 end Splice_Subtree;
3051 procedure Splice_Subtree
3052 (Container : in out Tree;
3053 Parent : Cursor;
3054 Before : Cursor;
3055 Position : Cursor)
3057 begin
3058 if Parent = No_Element then
3059 raise Constraint_Error with "Parent cursor has no element";
3060 end if;
3062 if Parent.Container /= Container'Unrestricted_Access then
3063 raise Program_Error with "Parent cursor not in container";
3064 end if;
3066 if Before /= No_Element then
3067 if Before.Container /= Container'Unrestricted_Access then
3068 raise Program_Error with "Before cursor not in container";
3069 end if;
3071 if Container.Nodes (Before.Node).Parent /= Parent.Node then
3072 raise Constraint_Error with "Before cursor not child of Parent";
3073 end if;
3074 end if;
3076 if Position = No_Element then
3077 raise Constraint_Error with "Position cursor has no element";
3078 end if;
3080 if Position.Container /= Container'Unrestricted_Access then
3081 raise Program_Error with "Position cursor not in container";
3082 end if;
3084 if Is_Root (Position) then
3086 -- Should this be PE instead? Need ARG confirmation. ???
3088 raise Constraint_Error with "Position cursor designates root";
3089 end if;
3091 if Container.Nodes (Position.Node).Parent = Parent.Node then
3092 if Before = No_Element then
3093 if Container.Nodes (Position.Node).Next <= 0 then -- last child
3094 return;
3095 end if;
3097 elsif Position.Node = Before.Node then
3098 return;
3100 elsif Container.Nodes (Position.Node).Next = Before.Node then
3101 return;
3102 end if;
3103 end if;
3105 if Container.Busy > 0 then
3106 raise Program_Error
3107 with "attempt to tamper with cursors (tree is busy)";
3108 end if;
3110 if Is_Reachable (Container => Container,
3111 From => Parent.Node,
3112 To => Position.Node)
3113 then
3114 raise Constraint_Error with "Position is ancestor of Parent";
3115 end if;
3117 Remove_Subtree (Container, Position.Node);
3118 Container.Nodes (Position.Node).Parent := Parent.Node;
3119 Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node);
3120 end Splice_Subtree;
3122 procedure Splice_Subtree
3123 (Target : in out Tree;
3124 Parent : Count_Type;
3125 Before : Count_Type'Base;
3126 Source : in out Tree;
3127 Position : in out Count_Type) -- Source on input, Target on output
3129 Source_Count : Count_Type := Subtree_Node_Count (Source, Position);
3130 pragma Assert (Source_Count >= 1);
3132 Target_Subtree : Count_Type;
3133 Target_Count : Count_Type;
3135 begin
3136 -- This is a utility operation to do the heavy lifting associated with
3137 -- splicing a subtree from one tree to another. Note that "splicing"
3138 -- is a bit of a misnomer here in the case of a bounded tree, because
3139 -- the elements must be copied from the source to the target.
3141 if Target.Count > Target.Capacity - Source_Count then
3142 raise Capacity_Error -- ???
3143 with "Source count exceeds available storage on Target";
3144 end if;
3146 -- Copy_Subtree returns a count of the number of nodes it inserts, but
3147 -- it does this by incrementing the value passed in. Therefore we must
3148 -- initialize the count before calling Copy_Subtree.
3150 Target_Count := 0;
3152 Copy_Subtree
3153 (Source => Source,
3154 Source_Subtree => Position,
3155 Target => Target,
3156 Target_Parent => Parent,
3157 Target_Subtree => Target_Subtree,
3158 Count => Target_Count);
3160 pragma Assert (Target_Count = Source_Count);
3162 -- Now link the newly-allocated subtree into the target.
3164 Insert_Subtree_Node
3165 (Container => Target,
3166 Subtree => Target_Subtree,
3167 Parent => Parent,
3168 Before => Before);
3170 Target.Count := Target.Count + Target_Count;
3172 -- The manipulation of the Target container is complete. Now we remove
3173 -- the subtree from the Source container.
3175 Remove_Subtree (Source, Position); -- unlink the subtree
3177 -- As with Copy_Subtree, operation Deallocate_Subtree returns a count of
3178 -- the number of nodes it deallocates, but it works by incrementing the
3179 -- value passed in. We must therefore initialize the count before
3180 -- calling it.
3182 Source_Count := 0;
3184 Deallocate_Subtree (Source, Position, Source_Count);
3185 pragma Assert (Source_Count = Target_Count);
3187 Source.Count := Source.Count - Source_Count;
3189 Position := Target_Subtree;
3190 end Splice_Subtree;
3192 ------------------------
3193 -- Subtree_Node_Count --
3194 ------------------------
3196 function Subtree_Node_Count (Position : Cursor) return Count_Type is
3197 begin
3198 if Position = No_Element then
3199 return 0;
3200 end if;
3202 if Position.Container.Count = 0 then
3203 pragma Assert (Is_Root (Position));
3204 return 1;
3205 end if;
3207 return Subtree_Node_Count (Position.Container.all, Position.Node);
3208 end Subtree_Node_Count;
3210 function Subtree_Node_Count
3211 (Container : Tree;
3212 Subtree : Count_Type) return Count_Type
3214 Result : Count_Type;
3215 Node : Count_Type'Base;
3217 begin
3218 Result := 1;
3219 Node := Container.Nodes (Subtree).Children.First;
3220 while Node > 0 loop
3221 Result := Result + Subtree_Node_Count (Container, Node);
3222 Node := Container.Nodes (Node).Next;
3223 end loop;
3224 return Result;
3225 end Subtree_Node_Count;
3227 ----------
3228 -- Swap --
3229 ----------
3231 procedure Swap
3232 (Container : in out Tree;
3233 I, J : Cursor)
3235 begin
3236 if I = No_Element then
3237 raise Constraint_Error with "I cursor has no element";
3238 end if;
3240 if I.Container /= Container'Unrestricted_Access then
3241 raise Program_Error with "I cursor not in container";
3242 end if;
3244 if Is_Root (I) then
3245 raise Program_Error with "I cursor designates root";
3246 end if;
3248 if I = J then -- make this test sooner???
3249 return;
3250 end if;
3252 if J = No_Element then
3253 raise Constraint_Error with "J cursor has no element";
3254 end if;
3256 if J.Container /= Container'Unrestricted_Access then
3257 raise Program_Error with "J cursor not in container";
3258 end if;
3260 if Is_Root (J) then
3261 raise Program_Error with "J cursor designates root";
3262 end if;
3264 if Container.Lock > 0 then
3265 raise Program_Error
3266 with "attempt to tamper with elements (tree is locked)";
3267 end if;
3269 declare
3270 EE : Element_Array renames Container.Elements;
3271 EI : constant Element_Type := EE (I.Node);
3273 begin
3274 EE (I.Node) := EE (J.Node);
3275 EE (J.Node) := EI;
3276 end;
3277 end Swap;
3279 --------------------
3280 -- Update_Element --
3281 --------------------
3283 procedure Update_Element
3284 (Container : in out Tree;
3285 Position : Cursor;
3286 Process : not null access procedure (Element : in out Element_Type))
3288 begin
3289 if Position = No_Element then
3290 raise Constraint_Error with "Position cursor has no element";
3291 end if;
3293 if Position.Container /= Container'Unrestricted_Access then
3294 raise Program_Error with "Position cursor not in container";
3295 end if;
3297 if Is_Root (Position) then
3298 raise Program_Error with "Position cursor designates root";
3299 end if;
3301 declare
3302 T : Tree renames Position.Container.all'Unrestricted_Access.all;
3303 B : Natural renames T.Busy;
3304 L : Natural renames T.Lock;
3306 begin
3307 B := B + 1;
3308 L := L + 1;
3310 Process (Element => T.Elements (Position.Node));
3312 L := L - 1;
3313 B := B - 1;
3315 exception
3316 when others =>
3317 L := L - 1;
3318 B := B - 1;
3319 raise;
3320 end;
3321 end Update_Element;
3323 -----------
3324 -- Write --
3325 -----------
3327 procedure Write
3328 (Stream : not null access Root_Stream_Type'Class;
3329 Container : Tree)
3331 procedure Write_Children (Subtree : Count_Type);
3332 procedure Write_Subtree (Subtree : Count_Type);
3334 --------------------
3335 -- Write_Children --
3336 --------------------
3338 procedure Write_Children (Subtree : Count_Type) is
3339 CC : Children_Type renames Container.Nodes (Subtree).Children;
3340 C : Count_Type'Base;
3342 begin
3343 Count_Type'Write (Stream, Child_Count (Container, Subtree));
3345 C := CC.First;
3346 while C > 0 loop
3347 Write_Subtree (C);
3348 C := Container.Nodes (C).Next;
3349 end loop;
3350 end Write_Children;
3352 -------------------
3353 -- Write_Subtree --
3354 -------------------
3356 procedure Write_Subtree (Subtree : Count_Type) is
3357 begin
3358 Element_Type'Write (Stream, Container.Elements (Subtree));
3359 Write_Children (Subtree);
3360 end Write_Subtree;
3362 -- Start of processing for Write
3364 begin
3365 Count_Type'Write (Stream, Container.Count);
3367 if Container.Count = 0 then
3368 return;
3369 end if;
3371 Write_Children (Root_Node (Container));
3372 end Write;
3374 procedure Write
3375 (Stream : not null access Root_Stream_Type'Class;
3376 Position : Cursor)
3378 begin
3379 raise Program_Error with "attempt to write tree cursor to stream";
3380 end Write;
3382 procedure Write
3383 (Stream : not null access Root_Stream_Type'Class;
3384 Item : Reference_Type)
3386 begin
3387 raise Program_Error with "attempt to stream reference";
3388 end Write;
3390 procedure Write
3391 (Stream : not null access Root_Stream_Type'Class;
3392 Item : Constant_Reference_Type)
3394 begin
3395 raise Program_Error with "attempt to stream reference";
3396 end Write;
3398 end Ada.Containers.Bounded_Multiway_Trees;