1------------------------------------------------------------------------------
2--                                                                          --
3--                         GNAT LIBRARY COMPONENTS                          --
4--                                                                          --
5--         A D A . C O N T A I N E R S . M U L T I W A Y _ T R E E S        --
6--                                                                          --
7--                                 B o d y                                  --
8--                                                                          --
9--          Copyright (C) 2004-2020, 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------------------------------------------------------------------------------
29
30with Ada.Unchecked_Conversion;
31with Ada.Unchecked_Deallocation;
32
33with System; use type System.Address;
34with System.Put_Images;
35
36package body Ada.Containers.Multiway_Trees with
37  SPARK_Mode => Off
38is
39
40   pragma Warnings (Off, "variable ""Busy*"" is not referenced");
41   pragma Warnings (Off, "variable ""Lock*"" is not referenced");
42   --  See comment in Ada.Containers.Helpers
43
44   --------------------
45   --  Root_Iterator --
46   --------------------
47
48   type Root_Iterator is abstract new Limited_Controlled and
49     Tree_Iterator_Interfaces.Forward_Iterator with
50   record
51      Container : Tree_Access;
52      Subtree   : Tree_Node_Access;
53   end record
54     with Disable_Controlled => not T_Check;
55
56   overriding procedure Finalize (Object : in out Root_Iterator);
57
58   -----------------------
59   --  Subtree_Iterator --
60   -----------------------
61
62   --  ??? these headers are a bit odd, but for sure they do not substitute
63   --  for documenting things, what *is* a Subtree_Iterator?
64
65   type Subtree_Iterator is new Root_Iterator with null record;
66
67   overriding function First (Object : Subtree_Iterator) return Cursor;
68
69   overriding function Next
70     (Object   : Subtree_Iterator;
71      Position : Cursor) return Cursor;
72
73   ---------------------
74   --  Child_Iterator --
75   ---------------------
76
77   type Child_Iterator is new Root_Iterator and
78     Tree_Iterator_Interfaces.Reversible_Iterator with null record
79       with Disable_Controlled => not T_Check;
80
81   overriding function First (Object : Child_Iterator) return Cursor;
82
83   overriding function Next
84     (Object   : Child_Iterator;
85      Position : Cursor) return Cursor;
86
87   overriding function Last (Object : Child_Iterator) return Cursor;
88
89   overriding function Previous
90     (Object   : Child_Iterator;
91      Position : Cursor) return Cursor;
92
93   -----------------------
94   -- Local Subprograms --
95   -----------------------
96
97   function Root_Node (Container : Tree) return Tree_Node_Access;
98
99   procedure Deallocate_Node is
100      new Ada.Unchecked_Deallocation (Tree_Node_Type, Tree_Node_Access);
101
102   procedure Deallocate_Children
103     (Subtree : Tree_Node_Access;
104      Count   : in out Count_Type);
105
106   procedure Deallocate_Subtree
107     (Subtree : in out Tree_Node_Access;
108      Count   : in out Count_Type);
109
110   function Equal_Children
111     (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
112
113   function Equal_Subtree
114     (Left_Subtree, Right_Subtree : Tree_Node_Access) return Boolean;
115
116   procedure Iterate_Children
117     (Container : Tree_Access;
118      Subtree   : Tree_Node_Access;
119      Process   : not null access procedure (Position : Cursor));
120
121   procedure Iterate_Subtree
122     (Container : Tree_Access;
123      Subtree   : Tree_Node_Access;
124      Process   : not null access procedure (Position : Cursor));
125
126   procedure Copy_Children
127     (Source : Children_Type;
128      Parent : Tree_Node_Access;
129      Count  : in out Count_Type);
130
131   procedure Copy_Subtree
132     (Source : Tree_Node_Access;
133      Parent : Tree_Node_Access;
134      Target : out Tree_Node_Access;
135      Count  : in out Count_Type);
136
137   function Find_In_Children
138     (Subtree : Tree_Node_Access;
139      Item    : Element_Type) return Tree_Node_Access;
140
141   function Find_In_Subtree
142     (Subtree : Tree_Node_Access;
143      Item    : Element_Type) return Tree_Node_Access;
144
145   function Child_Count (Children : Children_Type) return Count_Type;
146
147   function Subtree_Node_Count
148     (Subtree : Tree_Node_Access) return Count_Type;
149
150   function Is_Reachable (From, To : Tree_Node_Access) return Boolean;
151
152   procedure Remove_Subtree (Subtree : Tree_Node_Access);
153
154   procedure Insert_Subtree_Node
155     (Subtree : Tree_Node_Access;
156      Parent  : Tree_Node_Access;
157      Before  : Tree_Node_Access);
158
159   procedure Insert_Subtree_List
160     (First  : Tree_Node_Access;
161      Last   : Tree_Node_Access;
162      Parent : Tree_Node_Access;
163      Before : Tree_Node_Access);
164
165   procedure Splice_Children
166     (Target_Parent : Tree_Node_Access;
167      Before        : Tree_Node_Access;
168      Source_Parent : Tree_Node_Access);
169
170   ---------
171   -- "=" --
172   ---------
173
174   function "=" (Left, Right : Tree) return Boolean is
175   begin
176      return Equal_Children (Root_Node (Left), Root_Node (Right));
177   end "=";
178
179   ------------
180   -- Adjust --
181   ------------
182
183   procedure Adjust (Container : in out Tree) is
184      Source       : constant Children_Type := Container.Root.Children;
185      Source_Count : constant Count_Type := Container.Count;
186      Target_Count : Count_Type;
187
188   begin
189      --  We first restore the target container to its default-initialized
190      --  state, before we attempt any allocation, to ensure that invariants
191      --  are preserved in the event that the allocation fails.
192
193      Container.Root.Children := Children_Type'(others => null);
194      Zero_Counts (Container.TC);
195      Container.Count := 0;
196
197      --  Copy_Children returns a count of the number of nodes that it
198      --  allocates, but it works by incrementing the value that is passed
199      --  in. We must therefore initialize the count value before calling
200      --  Copy_Children.
201
202      Target_Count := 0;
203
204      --  Now we attempt the allocation of subtrees. The invariants are
205      --  satisfied even if the allocation fails.
206
207      Copy_Children (Source, Root_Node (Container), Target_Count);
208      pragma Assert (Target_Count = Source_Count);
209
210      Container.Count := Source_Count;
211   end Adjust;
212
213   -------------------
214   -- Ancestor_Find --
215   -------------------
216
217   function Ancestor_Find
218     (Position : Cursor;
219      Item     : Element_Type) return Cursor
220   is
221      R, N : Tree_Node_Access;
222
223   begin
224      if Checks and then Position = No_Element then
225         raise Constraint_Error with "Position cursor has no element";
226      end if;
227
228      --  Commented-out pending official ruling from ARG.  ???
229
230      --  if Position.Container /= Container'Unrestricted_Access then
231      --     raise Program_Error with "Position cursor not in container";
232      --  end if;
233
234      --  AI-0136 says to raise PE if Position equals the root node. This does
235      --  not seem correct, as this value is just the limiting condition of the
236      --  search. For now we omit this check, pending a ruling from the ARG.???
237
238      --  if Checks and then Is_Root (Position) then
239      --     raise Program_Error with "Position cursor designates root";
240      --  end if;
241
242      R := Root_Node (Position.Container.all);
243      N := Position.Node;
244      while N /= R loop
245         if N.Element = Item then
246            return Cursor'(Position.Container, N);
247         end if;
248
249         N := N.Parent;
250      end loop;
251
252      return No_Element;
253   end Ancestor_Find;
254
255   ------------------
256   -- Append_Child --
257   ------------------
258
259   procedure Append_Child
260     (Container : in out Tree;
261      Parent    : Cursor;
262      New_Item  : Element_Type;
263      Count     : Count_Type := 1)
264   is
265      First : Tree_Node_Access;
266      Last  : Tree_Node_Access;
267
268   begin
269      TC_Check (Container.TC);
270
271      if Checks and then Parent = No_Element then
272         raise Constraint_Error with "Parent cursor has no element";
273      end if;
274
275      if Checks and then Parent.Container /= Container'Unrestricted_Access then
276         raise Program_Error with "Parent cursor not in container";
277      end if;
278
279      if Count = 0 then
280         return;
281      end if;
282
283      First := new Tree_Node_Type'(Parent  => Parent.Node,
284                                   Element => New_Item,
285                                   others  => <>);
286
287      Last := First;
288      for J in Count_Type'(2) .. Count loop
289
290         --  Reclaim other nodes if Storage_Error.  ???
291
292         Last.Next := new Tree_Node_Type'(Parent  => Parent.Node,
293                                          Prev    => Last,
294                                          Element => New_Item,
295                                          others  => <>);
296
297         Last := Last.Next;
298      end loop;
299
300      Insert_Subtree_List
301        (First  => First,
302         Last   => Last,
303         Parent => Parent.Node,
304         Before => null);  -- null means "insert at end of list"
305
306      --  In order for operation Node_Count to complete in O(1) time, we cache
307      --  the count value. Here we increment the total count by the number of
308      --  nodes we just inserted.
309
310      Container.Count := Container.Count + Count;
311   end Append_Child;
312
313   ------------
314   -- Assign --
315   ------------
316
317   procedure Assign (Target : in out Tree; Source : Tree) is
318      Source_Count : constant Count_Type := Source.Count;
319      Target_Count : Count_Type;
320
321   begin
322      if Target'Address = Source'Address then
323         return;
324      end if;
325
326      Target.Clear;  -- checks busy bit
327
328      --  Copy_Children returns the number of nodes that it allocates, but it
329      --  does this by incrementing the count value passed in, so we must
330      --  initialize the count before calling Copy_Children.
331
332      Target_Count := 0;
333
334      --  Note that Copy_Children inserts the newly-allocated children into
335      --  their parent list only after the allocation of all the children has
336      --  succeeded. This preserves invariants even if the allocation fails.
337
338      Copy_Children (Source.Root.Children, Root_Node (Target), Target_Count);
339      pragma Assert (Target_Count = Source_Count);
340
341      Target.Count := Source_Count;
342   end Assign;
343
344   -----------------
345   -- Child_Count --
346   -----------------
347
348   function Child_Count (Parent : Cursor) return Count_Type is
349   begin
350      return (if Parent = No_Element
351              then 0 else Child_Count (Parent.Node.Children));
352   end Child_Count;
353
354   function Child_Count (Children : Children_Type) return Count_Type is
355      Result : Count_Type;
356      Node   : Tree_Node_Access;
357
358   begin
359      Result := 0;
360      Node := Children.First;
361      while Node /= null loop
362         Result := Result + 1;
363         Node := Node.Next;
364      end loop;
365
366      return Result;
367   end Child_Count;
368
369   -----------------
370   -- Child_Depth --
371   -----------------
372
373   function Child_Depth (Parent, Child : Cursor) return Count_Type is
374      Result : Count_Type;
375      N      : Tree_Node_Access;
376
377   begin
378      if Checks and then Parent = No_Element then
379         raise Constraint_Error with "Parent cursor has no element";
380      end if;
381
382      if Checks and then Child = No_Element then
383         raise Constraint_Error with "Child cursor has no element";
384      end if;
385
386      if Checks and then Parent.Container /= Child.Container then
387         raise Program_Error with "Parent and Child in different containers";
388      end if;
389
390      Result := 0;
391      N := Child.Node;
392      while N /= Parent.Node loop
393         Result := Result + 1;
394         N := N.Parent;
395
396         if Checks and then N = null then
397            raise Program_Error with "Parent is not ancestor of Child";
398         end if;
399      end loop;
400
401      return Result;
402   end Child_Depth;
403
404   -----------
405   -- Clear --
406   -----------
407
408   procedure Clear (Container : in out Tree) is
409      Container_Count, Children_Count : Count_Type;
410
411   begin
412      TC_Check (Container.TC);
413
414      --  We first set the container count to 0, in order to preserve
415      --  invariants in case the deallocation fails. (This works because
416      --  Deallocate_Children immediately removes the children from their
417      --  parent, and then does the actual deallocation.)
418
419      Container_Count := Container.Count;
420      Container.Count := 0;
421
422      --  Deallocate_Children returns the number of nodes that it deallocates,
423      --  but it does this by incrementing the count value that is passed in,
424      --  so we must first initialize the count return value before calling it.
425
426      Children_Count := 0;
427
428      --  See comment above. Deallocate_Children immediately removes the
429      --  children list from their parent node (here, the root of the tree),
430      --  and only after that does it attempt the actual deallocation. So even
431      --  if the deallocation fails, the representation invariants for the tree
432      --  are preserved.
433
434      Deallocate_Children (Root_Node (Container), Children_Count);
435      pragma Assert (Children_Count = Container_Count);
436   end Clear;
437
438   ------------------------
439   -- Constant_Reference --
440   ------------------------
441
442   function Constant_Reference
443     (Container : aliased Tree;
444      Position  : Cursor) return Constant_Reference_Type
445   is
446   begin
447      if Checks and then Position.Container = null then
448         raise Constraint_Error with
449           "Position cursor has no element";
450      end if;
451
452      if Checks and then Position.Container /= Container'Unrestricted_Access
453      then
454         raise Program_Error with
455           "Position cursor designates wrong container";
456      end if;
457
458      if Checks and then Position.Node = Root_Node (Container) then
459         raise Program_Error with "Position cursor designates root";
460      end if;
461
462      --  Implement Vet for multiway tree???
463      --  pragma Assert (Vet (Position),
464      --                 "Position cursor in Constant_Reference is bad");
465
466      declare
467         C : Tree renames Position.Container.all;
468         TC : constant Tamper_Counts_Access :=
469           C.TC'Unrestricted_Access;
470      begin
471         return R : constant Constant_Reference_Type :=
472           (Element => Position.Node.Element'Access,
473            Control => (Controlled with TC))
474         do
475            Busy (TC.all);
476         end return;
477      end;
478   end Constant_Reference;
479
480   --------------
481   -- Contains --
482   --------------
483
484   function Contains
485     (Container : Tree;
486      Item      : Element_Type) return Boolean
487   is
488   begin
489      return Find (Container, Item) /= No_Element;
490   end Contains;
491
492   ----------
493   -- Copy --
494   ----------
495
496   function Copy (Source : Tree) return Tree is
497   begin
498      return Target : Tree do
499         Copy_Children
500           (Source => Source.Root.Children,
501            Parent => Root_Node (Target),
502            Count  => Target.Count);
503
504         pragma Assert (Target.Count = Source.Count);
505      end return;
506   end Copy;
507
508   -------------------
509   -- Copy_Children --
510   -------------------
511
512   procedure Copy_Children
513     (Source : Children_Type;
514      Parent : Tree_Node_Access;
515      Count  : in out Count_Type)
516   is
517      pragma Assert (Parent /= null);
518      pragma Assert (Parent.Children.First = null);
519      pragma Assert (Parent.Children.Last = null);
520
521      CC : Children_Type;
522      C  : Tree_Node_Access;
523
524   begin
525      --  We special-case the first allocation, in order to establish the
526      --  representation invariants for type Children_Type.
527
528      C := Source.First;
529
530      if C = null then
531         return;
532      end if;
533
534      Copy_Subtree
535        (Source => C,
536         Parent => Parent,
537         Target => CC.First,
538         Count  => Count);
539
540      CC.Last := CC.First;
541
542      --  The representation invariants for the Children_Type list have been
543      --  established, so we can now copy the remaining children of Source.
544
545      C := C.Next;
546      while C /= null loop
547         Copy_Subtree
548           (Source => C,
549            Parent => Parent,
550            Target => CC.Last.Next,
551            Count  => Count);
552
553         CC.Last.Next.Prev := CC.Last;
554         CC.Last := CC.Last.Next;
555
556         C := C.Next;
557      end loop;
558
559      --  Add the newly-allocated children to their parent list only after the
560      --  allocation has succeeded, so as to preserve invariants of the parent.
561
562      Parent.Children := CC;
563   end Copy_Children;
564
565   ------------------
566   -- Copy_Subtree --
567   ------------------
568
569   procedure Copy_Subtree
570     (Target   : in out Tree;
571      Parent   : Cursor;
572      Before   : Cursor;
573      Source   : Cursor)
574   is
575      Target_Subtree : Tree_Node_Access;
576      Target_Count   : Count_Type;
577
578   begin
579      if Checks and then Parent = No_Element then
580         raise Constraint_Error with "Parent cursor has no element";
581      end if;
582
583      if Checks and then Parent.Container /= Target'Unrestricted_Access then
584         raise Program_Error with "Parent cursor not in container";
585      end if;
586
587      if Before /= No_Element then
588         if Checks and then Before.Container /= Target'Unrestricted_Access then
589            raise Program_Error with "Before cursor not in container";
590         end if;
591
592         if Checks and then Before.Node.Parent /= Parent.Node then
593            raise Constraint_Error with "Before cursor not child of Parent";
594         end if;
595      end if;
596
597      if Source = No_Element then
598         return;
599      end if;
600
601      if Checks and then Is_Root (Source) then
602         raise Constraint_Error with "Source cursor designates root";
603      end if;
604
605      --  Copy_Subtree returns a count of the number of nodes that it
606      --  allocates, but it works by incrementing the value that is passed
607      --  in. We must therefore initialize the count value before calling
608      --  Copy_Subtree.
609
610      Target_Count := 0;
611
612      Copy_Subtree
613        (Source => Source.Node,
614         Parent => Parent.Node,
615         Target => Target_Subtree,
616         Count  => Target_Count);
617
618      pragma Assert (Target_Subtree /= null);
619      pragma Assert (Target_Subtree.Parent = Parent.Node);
620      pragma Assert (Target_Count >= 1);
621
622      Insert_Subtree_Node
623        (Subtree => Target_Subtree,
624         Parent  => Parent.Node,
625         Before  => Before.Node);
626
627      --  In order for operation Node_Count to complete in O(1) time, we cache
628      --  the count value. Here we increment the total count by the number of
629      --  nodes we just inserted.
630
631      Target.Count := Target.Count + Target_Count;
632   end Copy_Subtree;
633
634   procedure Copy_Subtree
635     (Source : Tree_Node_Access;
636      Parent : Tree_Node_Access;
637      Target : out Tree_Node_Access;
638      Count  : in out Count_Type)
639   is
640   begin
641      Target := new Tree_Node_Type'(Element => Source.Element,
642                                    Parent  => Parent,
643                                    others  => <>);
644
645      Count := Count + 1;
646
647      Copy_Children
648        (Source => Source.Children,
649         Parent => Target,
650         Count  => Count);
651   end Copy_Subtree;
652
653   -------------------------
654   -- Deallocate_Children --
655   -------------------------
656
657   procedure Deallocate_Children
658     (Subtree : Tree_Node_Access;
659      Count   : in out Count_Type)
660   is
661      pragma Assert (Subtree /= null);
662
663      CC : Children_Type := Subtree.Children;
664      C  : Tree_Node_Access;
665
666   begin
667      --  We immediately remove the children from their parent, in order to
668      --  preserve invariants in case the deallocation fails.
669
670      Subtree.Children := Children_Type'(others => null);
671
672      while CC.First /= null loop
673         C := CC.First;
674         CC.First := C.Next;
675
676         Deallocate_Subtree (C, Count);
677      end loop;
678   end Deallocate_Children;
679
680   ------------------------
681   -- Deallocate_Subtree --
682   ------------------------
683
684   procedure Deallocate_Subtree
685     (Subtree : in out Tree_Node_Access;
686      Count   : in out Count_Type)
687   is
688   begin
689      Deallocate_Children (Subtree, Count);
690      Deallocate_Node (Subtree);
691      Count := Count + 1;
692   end Deallocate_Subtree;
693
694   ---------------------
695   -- Delete_Children --
696   ---------------------
697
698   procedure Delete_Children
699     (Container : in out Tree;
700      Parent    : Cursor)
701   is
702      Count : Count_Type;
703
704   begin
705      TC_Check (Container.TC);
706
707      if Checks and then Parent = No_Element then
708         raise Constraint_Error with "Parent cursor has no element";
709      end if;
710
711      if Checks and then Parent.Container /= Container'Unrestricted_Access then
712         raise Program_Error with "Parent cursor not in container";
713      end if;
714
715      --  Deallocate_Children returns a count of the number of nodes that it
716      --  deallocates, but it works by incrementing the value that is passed
717      --  in. We must therefore initialize the count value before calling
718      --  Deallocate_Children.
719
720      Count := 0;
721
722      Deallocate_Children (Parent.Node, Count);
723      pragma Assert (Count <= Container.Count);
724
725      Container.Count := Container.Count - Count;
726   end Delete_Children;
727
728   -----------------
729   -- Delete_Leaf --
730   -----------------
731
732   procedure Delete_Leaf
733     (Container : in out Tree;
734      Position  : in out Cursor)
735   is
736      X : Tree_Node_Access;
737
738   begin
739      TC_Check (Container.TC);
740
741      if Checks and then Position = No_Element then
742         raise Constraint_Error with "Position cursor has no element";
743      end if;
744
745      if Checks and then Position.Container /= Container'Unrestricted_Access
746      then
747         raise Program_Error with "Position cursor not in container";
748      end if;
749
750      if Checks and then Is_Root (Position) then
751         raise Program_Error with "Position cursor designates root";
752      end if;
753
754      if Checks and then not Is_Leaf (Position) then
755         raise Constraint_Error with "Position cursor does not designate leaf";
756      end if;
757
758      X := Position.Node;
759      Position := No_Element;
760
761      --  Restore represention invariants before attempting the actual
762      --  deallocation.
763
764      Remove_Subtree (X);
765      Container.Count := Container.Count - 1;
766
767      --  It is now safe to attempt the deallocation. This leaf node has been
768      --  disassociated from the tree, so even if the deallocation fails,
769      --  representation invariants will remain satisfied.
770
771      Deallocate_Node (X);
772   end Delete_Leaf;
773
774   --------------------
775   -- Delete_Subtree --
776   --------------------
777
778   procedure Delete_Subtree
779     (Container : in out Tree;
780      Position  : in out Cursor)
781   is
782      X     : Tree_Node_Access;
783      Count : Count_Type;
784
785   begin
786      TC_Check (Container.TC);
787
788      if Checks and then Position = No_Element then
789         raise Constraint_Error with "Position cursor has no element";
790      end if;
791
792      if Checks and then Position.Container /= Container'Unrestricted_Access
793      then
794         raise Program_Error with "Position cursor not in container";
795      end if;
796
797      if Checks and then Is_Root (Position) then
798         raise Program_Error with "Position cursor designates root";
799      end if;
800
801      X := Position.Node;
802      Position := No_Element;
803
804      --  Here is one case where a deallocation failure can result in the
805      --  violation of a representation invariant. We disassociate the subtree
806      --  from the tree now, but we only decrement the total node count after
807      --  we attempt the deallocation. However, if the deallocation fails, the
808      --  total node count will not get decremented.
809
810      --  One way around this dilemma is to count the nodes in the subtree
811      --  before attempt to delete the subtree, but that is an O(n) operation,
812      --  so it does not seem worth it.
813
814      --  Perhaps this is much ado about nothing, since the only way
815      --  deallocation can fail is if Controlled Finalization fails: this
816      --  propagates Program_Error so all bets are off anyway. ???
817
818      Remove_Subtree (X);
819
820      --  Deallocate_Subtree returns a count of the number of nodes that it
821      --  deallocates, but it works by incrementing the value that is passed
822      --  in. We must therefore initialize the count value before calling
823      --  Deallocate_Subtree.
824
825      Count := 0;
826
827      Deallocate_Subtree (X, Count);
828      pragma Assert (Count <= Container.Count);
829
830      --  See comments above. We would prefer to do this sooner, but there's no
831      --  way to satisfy that goal without a potentially severe execution
832      --  penalty.
833
834      Container.Count := Container.Count - Count;
835   end Delete_Subtree;
836
837   -----------
838   -- Depth --
839   -----------
840
841   function Depth (Position : Cursor) return Count_Type is
842      Result : Count_Type;
843      N      : Tree_Node_Access;
844
845   begin
846      Result := 0;
847      N := Position.Node;
848      while N /= null loop
849         N := N.Parent;
850         Result := Result + 1;
851      end loop;
852
853      return Result;
854   end Depth;
855
856   -------------
857   -- Element --
858   -------------
859
860   function Element (Position : Cursor) return Element_Type is
861   begin
862      if Checks and then Position.Container = null then
863         raise Constraint_Error with "Position cursor has no element";
864      end if;
865
866      if Checks and then Position.Node = Root_Node (Position.Container.all)
867      then
868         raise Program_Error with "Position cursor designates root";
869      end if;
870
871      return Position.Node.Element;
872   end Element;
873
874   --------------------
875   -- Equal_Children --
876   --------------------
877
878   function Equal_Children
879     (Left_Subtree  : Tree_Node_Access;
880      Right_Subtree : Tree_Node_Access) return Boolean
881   is
882      Left_Children  : Children_Type renames Left_Subtree.Children;
883      Right_Children : Children_Type renames Right_Subtree.Children;
884
885      L, R : Tree_Node_Access;
886
887   begin
888      if Child_Count (Left_Children) /= Child_Count (Right_Children) then
889         return False;
890      end if;
891
892      L := Left_Children.First;
893      R := Right_Children.First;
894      while L /= null loop
895         if not Equal_Subtree (L, R) then
896            return False;
897         end if;
898
899         L := L.Next;
900         R := R.Next;
901      end loop;
902
903      return True;
904   end Equal_Children;
905
906   -------------------
907   -- Equal_Subtree --
908   -------------------
909
910   function Equal_Subtree
911     (Left_Position  : Cursor;
912      Right_Position : Cursor) return Boolean
913   is
914   begin
915      if Checks and then Left_Position = No_Element then
916         raise Constraint_Error with "Left cursor has no element";
917      end if;
918
919      if Checks and then Right_Position = No_Element then
920         raise Constraint_Error with "Right cursor has no element";
921      end if;
922
923      if Left_Position = Right_Position then
924         return True;
925      end if;
926
927      if Is_Root (Left_Position) then
928         if not Is_Root (Right_Position) then
929            return False;
930         end if;
931
932         return Equal_Children (Left_Position.Node, Right_Position.Node);
933      end if;
934
935      if Is_Root (Right_Position) then
936         return False;
937      end if;
938
939      return Equal_Subtree (Left_Position.Node, Right_Position.Node);
940   end Equal_Subtree;
941
942   function Equal_Subtree
943     (Left_Subtree  : Tree_Node_Access;
944      Right_Subtree : Tree_Node_Access) return Boolean
945   is
946   begin
947      if Left_Subtree.Element /= Right_Subtree.Element then
948         return False;
949      end if;
950
951      return Equal_Children (Left_Subtree, Right_Subtree);
952   end Equal_Subtree;
953
954   --------------
955   -- Finalize --
956   --------------
957
958   procedure Finalize (Object : in out Root_Iterator) is
959   begin
960      Unbusy (Object.Container.TC);
961   end Finalize;
962
963   ----------
964   -- Find --
965   ----------
966
967   function Find
968     (Container : Tree;
969      Item      : Element_Type) return Cursor
970   is
971      N : constant Tree_Node_Access :=
972        Find_In_Children (Root_Node (Container), Item);
973   begin
974      if N = null then
975         return No_Element;
976      else
977         return Cursor'(Container'Unrestricted_Access, N);
978      end if;
979   end Find;
980
981   -----------
982   -- First --
983   -----------
984
985   overriding function First (Object : Subtree_Iterator) return Cursor is
986   begin
987      if Object.Subtree = Root_Node (Object.Container.all) then
988         return First_Child (Root (Object.Container.all));
989      else
990         return Cursor'(Object.Container, Object.Subtree);
991      end if;
992   end First;
993
994   overriding function First (Object : Child_Iterator) return Cursor is
995   begin
996      return First_Child (Cursor'(Object.Container, Object.Subtree));
997   end First;
998
999   -----------------
1000   -- First_Child --
1001   -----------------
1002
1003   function First_Child (Parent : Cursor) return Cursor is
1004      Node : Tree_Node_Access;
1005
1006   begin
1007      if Checks and then Parent = No_Element then
1008         raise Constraint_Error with "Parent cursor has no element";
1009      end if;
1010
1011      Node := Parent.Node.Children.First;
1012
1013      if Node = null then
1014         return No_Element;
1015      end if;
1016
1017      return Cursor'(Parent.Container, Node);
1018   end First_Child;
1019
1020   -------------------------
1021   -- First_Child_Element --
1022   -------------------------
1023
1024   function First_Child_Element (Parent : Cursor) return Element_Type is
1025   begin
1026      return Element (First_Child (Parent));
1027   end First_Child_Element;
1028
1029   ----------------------
1030   -- Find_In_Children --
1031   ----------------------
1032
1033   function Find_In_Children
1034     (Subtree : Tree_Node_Access;
1035      Item    : Element_Type) return Tree_Node_Access
1036   is
1037      N, Result : Tree_Node_Access;
1038
1039   begin
1040      N := Subtree.Children.First;
1041      while N /= null loop
1042         Result := Find_In_Subtree (N, Item);
1043
1044         if Result /= null then
1045            return Result;
1046         end if;
1047
1048         N := N.Next;
1049      end loop;
1050
1051      return null;
1052   end Find_In_Children;
1053
1054   ---------------------
1055   -- Find_In_Subtree --
1056   ---------------------
1057
1058   function Find_In_Subtree
1059     (Position : Cursor;
1060      Item     : Element_Type) return Cursor
1061   is
1062      Result : Tree_Node_Access;
1063
1064   begin
1065      if Checks and then Position = No_Element then
1066         raise Constraint_Error with "Position cursor has no element";
1067      end if;
1068
1069      --  Commented out pending official ruling by ARG.  ???
1070
1071      --  if Checks and then
1072      --    Position.Container /= Container'Unrestricted_Access
1073      --  then
1074      --     raise Program_Error with "Position cursor not in container";
1075      --  end if;
1076
1077      Result :=
1078        (if Is_Root (Position)
1079         then Find_In_Children (Position.Node, Item)
1080         else Find_In_Subtree  (Position.Node, Item));
1081
1082      if Result = null then
1083         return No_Element;
1084      end if;
1085
1086      return Cursor'(Position.Container, Result);
1087   end Find_In_Subtree;
1088
1089   function Find_In_Subtree
1090     (Subtree : Tree_Node_Access;
1091      Item    : Element_Type) return Tree_Node_Access
1092   is
1093   begin
1094      if Subtree.Element = Item then
1095         return Subtree;
1096      end if;
1097
1098      return Find_In_Children (Subtree, Item);
1099   end Find_In_Subtree;
1100
1101   ------------------------
1102   -- Get_Element_Access --
1103   ------------------------
1104
1105   function Get_Element_Access
1106     (Position : Cursor) return not null Element_Access is
1107   begin
1108      return Position.Node.Element'Access;
1109   end Get_Element_Access;
1110
1111   -----------------
1112   -- Has_Element --
1113   -----------------
1114
1115   function Has_Element (Position : Cursor) return Boolean is
1116   begin
1117      return (if Position = No_Element then False
1118              else Position.Node.Parent /= null);
1119   end Has_Element;
1120
1121   ------------------
1122   -- Insert_Child --
1123   ------------------
1124
1125   procedure Insert_Child
1126     (Container : in out Tree;
1127      Parent    : Cursor;
1128      Before    : Cursor;
1129      New_Item  : Element_Type;
1130      Count     : Count_Type := 1)
1131   is
1132      Position : Cursor;
1133      pragma Unreferenced (Position);
1134
1135   begin
1136      Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1137   end Insert_Child;
1138
1139   procedure Insert_Child
1140     (Container : in out Tree;
1141      Parent    : Cursor;
1142      Before    : Cursor;
1143      New_Item  : Element_Type;
1144      Position  : out Cursor;
1145      Count     : Count_Type := 1)
1146   is
1147      First : Tree_Node_Access;
1148      Last  : Tree_Node_Access;
1149
1150   begin
1151      TC_Check (Container.TC);
1152
1153      if Checks and then Parent = No_Element then
1154         raise Constraint_Error with "Parent cursor has no element";
1155      end if;
1156
1157      if Checks and then Parent.Container /= Container'Unrestricted_Access then
1158         raise Program_Error with "Parent cursor not in container";
1159      end if;
1160
1161      if Before /= No_Element then
1162         if Checks and then Before.Container /= Container'Unrestricted_Access
1163         then
1164            raise Program_Error with "Before cursor not in container";
1165         end if;
1166
1167         if Checks and then Before.Node.Parent /= Parent.Node then
1168            raise Constraint_Error with "Parent cursor not parent of Before";
1169         end if;
1170      end if;
1171
1172      if Count = 0 then
1173         Position := No_Element;  -- Need ruling from ARG ???
1174         return;
1175      end if;
1176
1177      First := new Tree_Node_Type'(Parent  => Parent.Node,
1178                                   Element => New_Item,
1179                                   others  => <>);
1180
1181      Last := First;
1182      for J in Count_Type'(2) .. Count loop
1183
1184         --  Reclaim other nodes if Storage_Error.  ???
1185
1186         Last.Next := new Tree_Node_Type'(Parent  => Parent.Node,
1187                                          Prev    => Last,
1188                                          Element => New_Item,
1189                                          others  => <>);
1190
1191         Last := Last.Next;
1192      end loop;
1193
1194      Insert_Subtree_List
1195        (First  => First,
1196         Last   => Last,
1197         Parent => Parent.Node,
1198         Before => Before.Node);
1199
1200      --  In order for operation Node_Count to complete in O(1) time, we cache
1201      --  the count value. Here we increment the total count by the number of
1202      --  nodes we just inserted.
1203
1204      Container.Count := Container.Count + Count;
1205
1206      Position := Cursor'(Parent.Container, First);
1207   end Insert_Child;
1208
1209   procedure Insert_Child
1210     (Container : in out Tree;
1211      Parent    : Cursor;
1212      Before    : Cursor;
1213      Position  : out Cursor;
1214      Count     : Count_Type := 1)
1215   is
1216      First : Tree_Node_Access;
1217      Last  : Tree_Node_Access;
1218
1219   begin
1220      TC_Check (Container.TC);
1221
1222      if Checks and then Parent = No_Element then
1223         raise Constraint_Error with "Parent cursor has no element";
1224      end if;
1225
1226      if Checks and then Parent.Container /= Container'Unrestricted_Access then
1227         raise Program_Error with "Parent cursor not in container";
1228      end if;
1229
1230      if Before /= No_Element then
1231         if Checks and then Before.Container /= Container'Unrestricted_Access
1232         then
1233            raise Program_Error with "Before cursor not in container";
1234         end if;
1235
1236         if Checks and then Before.Node.Parent /= Parent.Node then
1237            raise Constraint_Error with "Parent cursor not parent of Before";
1238         end if;
1239      end if;
1240
1241      if Count = 0 then
1242         Position := No_Element;  -- Need ruling from ARG  ???
1243         return;
1244      end if;
1245
1246      First := new Tree_Node_Type'(Parent  => Parent.Node,
1247                                   Element => <>,
1248                                   others  => <>);
1249
1250      Last := First;
1251      for J in Count_Type'(2) .. Count loop
1252
1253         --  Reclaim other nodes if Storage_Error.  ???
1254
1255         Last.Next := new Tree_Node_Type'(Parent  => Parent.Node,
1256                                          Prev    => Last,
1257                                          Element => <>,
1258                                          others  => <>);
1259
1260         Last := Last.Next;
1261      end loop;
1262
1263      Insert_Subtree_List
1264        (First  => First,
1265         Last   => Last,
1266         Parent => Parent.Node,
1267         Before => Before.Node);
1268
1269      --  In order for operation Node_Count to complete in O(1) time, we cache
1270      --  the count value. Here we increment the total count by the number of
1271      --  nodes we just inserted.
1272
1273      Container.Count := Container.Count + Count;
1274
1275      Position := Cursor'(Parent.Container, First);
1276   end Insert_Child;
1277
1278   -------------------------
1279   -- Insert_Subtree_List --
1280   -------------------------
1281
1282   procedure Insert_Subtree_List
1283     (First  : Tree_Node_Access;
1284      Last   : Tree_Node_Access;
1285      Parent : Tree_Node_Access;
1286      Before : Tree_Node_Access)
1287   is
1288      pragma Assert (Parent /= null);
1289      C : Children_Type renames Parent.Children;
1290
1291   begin
1292      --  This is a simple utility operation to insert a list of nodes (from
1293      --  First..Last) as children of Parent. The Before node specifies where
1294      --  the new children should be inserted relative to the existing
1295      --  children.
1296
1297      if First = null then
1298         pragma Assert (Last = null);
1299         return;
1300      end if;
1301
1302      pragma Assert (Last /= null);
1303      pragma Assert (Before = null or else Before.Parent = Parent);
1304
1305      if C.First = null then
1306         C.First := First;
1307         C.First.Prev := null;
1308         C.Last := Last;
1309         C.Last.Next := null;
1310
1311      elsif Before = null then  -- means "insert after existing nodes"
1312         C.Last.Next := First;
1313         First.Prev := C.Last;
1314         C.Last := Last;
1315         C.Last.Next := null;
1316
1317      elsif Before = C.First then
1318         Last.Next := C.First;
1319         C.First.Prev := Last;
1320         C.First := First;
1321         C.First.Prev := null;
1322
1323      else
1324         Before.Prev.Next := First;
1325         First.Prev := Before.Prev;
1326         Last.Next := Before;
1327         Before.Prev := Last;
1328      end if;
1329   end Insert_Subtree_List;
1330
1331   -------------------------
1332   -- Insert_Subtree_Node --
1333   -------------------------
1334
1335   procedure Insert_Subtree_Node
1336     (Subtree : Tree_Node_Access;
1337      Parent  : Tree_Node_Access;
1338      Before  : Tree_Node_Access)
1339   is
1340   begin
1341      --  This is a simple wrapper operation to insert a single child into the
1342      --  Parent's children list.
1343
1344      Insert_Subtree_List
1345        (First  => Subtree,
1346         Last   => Subtree,
1347         Parent => Parent,
1348         Before => Before);
1349   end Insert_Subtree_Node;
1350
1351   --------------
1352   -- Is_Empty --
1353   --------------
1354
1355   function Is_Empty (Container : Tree) return Boolean is
1356   begin
1357      return Container.Root.Children.First = null;
1358   end Is_Empty;
1359
1360   -------------
1361   -- Is_Leaf --
1362   -------------
1363
1364   function Is_Leaf (Position : Cursor) return Boolean is
1365   begin
1366      return (if Position = No_Element then False
1367              else Position.Node.Children.First = null);
1368   end Is_Leaf;
1369
1370   ------------------
1371   -- Is_Reachable --
1372   ------------------
1373
1374   function Is_Reachable (From, To : Tree_Node_Access) return Boolean is
1375      pragma Assert (From /= null);
1376      pragma Assert (To /= null);
1377
1378      N : Tree_Node_Access;
1379
1380   begin
1381      N := From;
1382      while N /= null loop
1383         if N = To then
1384            return True;
1385         end if;
1386
1387         N := N.Parent;
1388      end loop;
1389
1390      return False;
1391   end Is_Reachable;
1392
1393   -------------
1394   -- Is_Root --
1395   -------------
1396
1397   function Is_Root (Position : Cursor) return Boolean is
1398   begin
1399      return (if Position.Container = null then False
1400              else Position = Root (Position.Container.all));
1401   end Is_Root;
1402
1403   -------------
1404   -- Iterate --
1405   -------------
1406
1407   procedure Iterate
1408     (Container : Tree;
1409      Process   : not null access procedure (Position : Cursor))
1410   is
1411      Busy : With_Busy (Container.TC'Unrestricted_Access);
1412   begin
1413      Iterate_Children
1414        (Container => Container'Unrestricted_Access,
1415         Subtree   => Root_Node (Container),
1416         Process   => Process);
1417   end Iterate;
1418
1419   function Iterate (Container : Tree)
1420     return Tree_Iterator_Interfaces.Forward_Iterator'Class
1421   is
1422   begin
1423      return Iterate_Subtree (Root (Container));
1424   end Iterate;
1425
1426   ----------------------
1427   -- Iterate_Children --
1428   ----------------------
1429
1430   procedure Iterate_Children
1431     (Parent  : Cursor;
1432      Process : not null access procedure (Position : Cursor))
1433   is
1434      C : Tree_Node_Access;
1435      Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
1436   begin
1437      if Checks and then Parent = No_Element then
1438         raise Constraint_Error with "Parent cursor has no element";
1439      end if;
1440
1441      C := Parent.Node.Children.First;
1442      while C /= null loop
1443         Process (Position => Cursor'(Parent.Container, Node => C));
1444         C := C.Next;
1445      end loop;
1446   end Iterate_Children;
1447
1448   procedure Iterate_Children
1449     (Container : Tree_Access;
1450      Subtree   : Tree_Node_Access;
1451      Process   : not null access procedure (Position : Cursor))
1452   is
1453      Node : Tree_Node_Access;
1454
1455   begin
1456      --  This is a helper function to recursively iterate over all the nodes
1457      --  in a subtree, in depth-first fashion. This particular helper just
1458      --  visits the children of this subtree, not the root of the subtree node
1459      --  itself. This is useful when starting from the ultimate root of the
1460      --  entire tree (see Iterate), as that root does not have an element.
1461
1462      Node := Subtree.Children.First;
1463      while Node /= null loop
1464         Iterate_Subtree (Container, Node, Process);
1465         Node := Node.Next;
1466      end loop;
1467   end Iterate_Children;
1468
1469   function Iterate_Children
1470     (Container : Tree;
1471      Parent    : Cursor)
1472      return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1473   is
1474      C : constant Tree_Access := Container'Unrestricted_Access;
1475   begin
1476      if Checks and then Parent = No_Element then
1477         raise Constraint_Error with "Parent cursor has no element";
1478      end if;
1479
1480      if Checks and then Parent.Container /= C then
1481         raise Program_Error with "Parent cursor not in container";
1482      end if;
1483
1484      return It : constant Child_Iterator :=
1485        (Limited_Controlled with
1486           Container => C,
1487           Subtree   => Parent.Node)
1488      do
1489         Busy (C.TC);
1490      end return;
1491   end Iterate_Children;
1492
1493   ---------------------
1494   -- Iterate_Subtree --
1495   ---------------------
1496
1497   function Iterate_Subtree
1498     (Position : Cursor)
1499      return Tree_Iterator_Interfaces.Forward_Iterator'Class
1500   is
1501      C : constant Tree_Access := Position.Container;
1502   begin
1503      if Checks and then Position = No_Element then
1504         raise Constraint_Error with "Position cursor has no element";
1505      end if;
1506
1507      --  Implement Vet for multiway trees???
1508      --  pragma Assert (Vet (Position), "bad subtree cursor");
1509
1510      return It : constant Subtree_Iterator :=
1511        (Limited_Controlled with
1512           Container => C,
1513           Subtree   => Position.Node)
1514      do
1515         Busy (C.TC);
1516      end return;
1517   end Iterate_Subtree;
1518
1519   procedure Iterate_Subtree
1520     (Position : Cursor;
1521      Process  : not null access procedure (Position : Cursor))
1522   is
1523      Busy : With_Busy (Position.Container.TC'Unrestricted_Access);
1524   begin
1525      if Checks and then Position = No_Element then
1526         raise Constraint_Error with "Position cursor has no element";
1527      end if;
1528
1529      if Is_Root (Position) then
1530         Iterate_Children (Position.Container, Position.Node, Process);
1531      else
1532         Iterate_Subtree (Position.Container, Position.Node, Process);
1533      end if;
1534   end Iterate_Subtree;
1535
1536   procedure Iterate_Subtree
1537     (Container : Tree_Access;
1538      Subtree   : Tree_Node_Access;
1539      Process   : not null access procedure (Position : Cursor))
1540   is
1541   begin
1542      --  This is a helper function to recursively iterate over all the nodes
1543      --  in a subtree, in depth-first fashion. It first visits the root of the
1544      --  subtree, then visits its children.
1545
1546      Process (Cursor'(Container, Subtree));
1547      Iterate_Children (Container, Subtree, Process);
1548   end Iterate_Subtree;
1549
1550   ----------
1551   -- Last --
1552   ----------
1553
1554   overriding function Last (Object : Child_Iterator) return Cursor is
1555   begin
1556      return Last_Child (Cursor'(Object.Container, Object.Subtree));
1557   end Last;
1558
1559   ----------------
1560   -- Last_Child --
1561   ----------------
1562
1563   function Last_Child (Parent : Cursor) return Cursor is
1564      Node : Tree_Node_Access;
1565
1566   begin
1567      if Checks and then Parent = No_Element then
1568         raise Constraint_Error with "Parent cursor has no element";
1569      end if;
1570
1571      Node := Parent.Node.Children.Last;
1572
1573      if Node = null then
1574         return No_Element;
1575      end if;
1576
1577      return (Parent.Container, Node);
1578   end Last_Child;
1579
1580   ------------------------
1581   -- Last_Child_Element --
1582   ------------------------
1583
1584   function Last_Child_Element (Parent : Cursor) return Element_Type is
1585   begin
1586      return Element (Last_Child (Parent));
1587   end Last_Child_Element;
1588
1589   ----------
1590   -- Move --
1591   ----------
1592
1593   procedure Move (Target : in out Tree; Source : in out Tree) is
1594      Node : Tree_Node_Access;
1595
1596   begin
1597      if Target'Address = Source'Address then
1598         return;
1599      end if;
1600
1601      TC_Check (Source.TC);
1602
1603      Target.Clear;  -- checks busy bit
1604
1605      Target.Root.Children := Source.Root.Children;
1606      Source.Root.Children := Children_Type'(others => null);
1607
1608      Node := Target.Root.Children.First;
1609      while Node /= null loop
1610         Node.Parent := Root_Node (Target);
1611         Node := Node.Next;
1612      end loop;
1613
1614      Target.Count := Source.Count;
1615      Source.Count := 0;
1616   end Move;
1617
1618   ----------
1619   -- Next --
1620   ----------
1621
1622   function Next
1623     (Object   : Subtree_Iterator;
1624      Position : Cursor) return Cursor
1625   is
1626      Node : Tree_Node_Access;
1627
1628   begin
1629      if Position.Container = null then
1630         return No_Element;
1631      end if;
1632
1633      if Checks and then Position.Container /= Object.Container then
1634         raise Program_Error with
1635           "Position cursor of Next designates wrong tree";
1636      end if;
1637
1638      Node := Position.Node;
1639
1640      if Node.Children.First /= null then
1641         return Cursor'(Object.Container, Node.Children.First);
1642      end if;
1643
1644      while Node /= Object.Subtree loop
1645         if Node.Next /= null then
1646            return Cursor'(Object.Container, Node.Next);
1647         end if;
1648
1649         Node := Node.Parent;
1650      end loop;
1651
1652      return No_Element;
1653   end Next;
1654
1655   function Next
1656     (Object   : Child_Iterator;
1657      Position : Cursor) return Cursor
1658   is
1659   begin
1660      if Position.Container = null then
1661         return No_Element;
1662      end if;
1663
1664      if Checks and then Position.Container /= Object.Container then
1665         raise Program_Error with
1666           "Position cursor of Next designates wrong tree";
1667      end if;
1668
1669      return Next_Sibling (Position);
1670   end Next;
1671
1672   ------------------
1673   -- Next_Sibling --
1674   ------------------
1675
1676   function Next_Sibling (Position : Cursor) return Cursor is
1677   begin
1678      if Position = No_Element then
1679         return No_Element;
1680      end if;
1681
1682      if Position.Node.Next = null then
1683         return No_Element;
1684      end if;
1685
1686      return Cursor'(Position.Container, Position.Node.Next);
1687   end Next_Sibling;
1688
1689   procedure Next_Sibling (Position : in out Cursor) is
1690   begin
1691      Position := Next_Sibling (Position);
1692   end Next_Sibling;
1693
1694   ----------------
1695   -- Node_Count --
1696   ----------------
1697
1698   function Node_Count (Container : Tree) return Count_Type is
1699   begin
1700      --  Container.Count is the number of nodes we have actually allocated. We
1701      --  cache the value specifically so this Node_Count operation can execute
1702      --  in O(1) time, which makes it behave similarly to how the Length
1703      --  selector function behaves for other containers.
1704
1705      --  The cached node count value only describes the nodes we have
1706      --  allocated; the root node itself is not included in that count. The
1707      --  Node_Count operation returns a value that includes the root node
1708      --  (because the RM says so), so we must add 1 to our cached value.
1709
1710      return 1 + Container.Count;
1711   end Node_Count;
1712
1713   ------------
1714   -- Parent --
1715   ------------
1716
1717   function Parent (Position : Cursor) return Cursor is
1718   begin
1719      if Position = No_Element then
1720         return No_Element;
1721      end if;
1722
1723      if Position.Node.Parent = null then
1724         return No_Element;
1725      end if;
1726
1727      return Cursor'(Position.Container, Position.Node.Parent);
1728   end Parent;
1729
1730   -------------------
1731   -- Prepend_Child --
1732   -------------------
1733
1734   procedure Prepend_Child
1735     (Container : in out Tree;
1736      Parent    : Cursor;
1737      New_Item  : Element_Type;
1738      Count     : Count_Type := 1)
1739   is
1740      First, Last : Tree_Node_Access;
1741
1742   begin
1743      TC_Check (Container.TC);
1744
1745      if Checks and then Parent = No_Element then
1746         raise Constraint_Error with "Parent cursor has no element";
1747      end if;
1748
1749      if Checks and then Parent.Container /= Container'Unrestricted_Access then
1750         raise Program_Error with "Parent cursor not in container";
1751      end if;
1752
1753      if Count = 0 then
1754         return;
1755      end if;
1756
1757      First := new Tree_Node_Type'(Parent  => Parent.Node,
1758                                   Element => New_Item,
1759                                   others  => <>);
1760
1761      Last := First;
1762
1763      for J in Count_Type'(2) .. Count loop
1764
1765         --  Reclaim other nodes if Storage_Error???
1766
1767         Last.Next := new Tree_Node_Type'(Parent  => Parent.Node,
1768                                          Prev    => Last,
1769                                          Element => New_Item,
1770                                          others  => <>);
1771
1772         Last := Last.Next;
1773      end loop;
1774
1775      Insert_Subtree_List
1776        (First  => First,
1777         Last   => Last,
1778         Parent => Parent.Node,
1779         Before => Parent.Node.Children.First);
1780
1781      --  In order for operation Node_Count to complete in O(1) time, we cache
1782      --  the count value. Here we increment the total count by the number of
1783      --  nodes we just inserted.
1784
1785      Container.Count := Container.Count + Count;
1786   end Prepend_Child;
1787
1788   --------------
1789   -- Previous --
1790   --------------
1791
1792   overriding function Previous
1793     (Object   : Child_Iterator;
1794      Position : Cursor) return Cursor
1795   is
1796   begin
1797      if Position.Container = null then
1798         return No_Element;
1799      end if;
1800
1801      if Checks and then Position.Container /= Object.Container then
1802         raise Program_Error with
1803           "Position cursor of Previous designates wrong tree";
1804      end if;
1805
1806      return Previous_Sibling (Position);
1807   end Previous;
1808
1809   ----------------------
1810   -- Previous_Sibling --
1811   ----------------------
1812
1813   function Previous_Sibling (Position : Cursor) return Cursor is
1814   begin
1815      return
1816        (if Position = No_Element        then No_Element
1817         elsif Position.Node.Prev = null then No_Element
1818         else Cursor'(Position.Container, Position.Node.Prev));
1819   end Previous_Sibling;
1820
1821   procedure Previous_Sibling (Position : in out Cursor) is
1822   begin
1823      Position := Previous_Sibling (Position);
1824   end Previous_Sibling;
1825
1826   ----------------------
1827   -- Pseudo_Reference --
1828   ----------------------
1829
1830   function Pseudo_Reference
1831     (Container : aliased Tree'Class) return Reference_Control_Type
1832   is
1833      TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
1834   begin
1835      return R : constant Reference_Control_Type := (Controlled with TC) do
1836         Busy (TC.all);
1837      end return;
1838   end Pseudo_Reference;
1839
1840   -------------------
1841   -- Query_Element --
1842   -------------------
1843
1844   procedure Query_Element
1845     (Position : Cursor;
1846      Process  : not null access procedure (Element : Element_Type))
1847   is
1848      T : Tree renames Position.Container.all'Unrestricted_Access.all;
1849      Lock : With_Lock (T.TC'Unrestricted_Access);
1850   begin
1851      if Checks and then Position = No_Element then
1852         raise Constraint_Error with "Position cursor has no element";
1853      end if;
1854
1855      if Checks and then Is_Root (Position) then
1856         raise Program_Error with "Position cursor designates root";
1857      end if;
1858
1859      Process (Position.Node.Element);
1860   end Query_Element;
1861
1862   ---------------
1863   -- Put_Image --
1864   ---------------
1865
1866   procedure Put_Image
1867     (S : in out Ada.Strings.Text_Output.Sink'Class; V : Tree)
1868   is
1869      use System.Put_Images;
1870
1871      procedure Rec (Position : Cursor);
1872      --  Recursive routine operating on cursors
1873
1874      procedure Rec (Position : Cursor) is
1875         First_Time : Boolean := True;
1876      begin
1877         Array_Before (S);
1878
1879         for X in Iterate_Children (V, Position) loop
1880            if First_Time then
1881               First_Time := False;
1882            else
1883               Array_Between (S);
1884            end if;
1885
1886            Element_Type'Put_Image (S, Element (X));
1887            if Child_Count (X) > 0 then
1888               Simple_Array_Between (S);
1889               Rec (X);
1890            end if;
1891         end loop;
1892
1893         Array_After (S);
1894      end Rec;
1895
1896   begin
1897      if First_Child (Root (V)) = No_Element then
1898         Array_Before (S);
1899         Array_After (S);
1900      else
1901         Rec (First_Child (Root (V)));
1902      end if;
1903   end Put_Image;
1904
1905   ----------
1906   -- Read --
1907   ----------
1908
1909   procedure Read
1910     (Stream    : not null access Root_Stream_Type'Class;
1911      Container : out Tree)
1912   is
1913      procedure Read_Children (Subtree : Tree_Node_Access);
1914
1915      function Read_Subtree
1916        (Parent : Tree_Node_Access) return Tree_Node_Access;
1917
1918      Total_Count : Count_Type'Base;
1919      --  Value read from the stream that says how many elements follow
1920
1921      Read_Count : Count_Type'Base;
1922      --  Actual number of elements read from the stream
1923
1924      -------------------
1925      -- Read_Children --
1926      -------------------
1927
1928      procedure Read_Children (Subtree : Tree_Node_Access) is
1929         pragma Assert (Subtree /= null);
1930         pragma Assert (Subtree.Children.First = null);
1931         pragma Assert (Subtree.Children.Last = null);
1932
1933         Count : Count_Type'Base;
1934         --  Number of child subtrees
1935
1936         C : Children_Type;
1937
1938      begin
1939         Count_Type'Read (Stream, Count);
1940
1941         if Checks and then Count < 0 then
1942            raise Program_Error with "attempt to read from corrupt stream";
1943         end if;
1944
1945         if Count = 0 then
1946            return;
1947         end if;
1948
1949         C.First := Read_Subtree (Parent => Subtree);
1950         C.Last := C.First;
1951
1952         for J in Count_Type'(2) .. Count loop
1953            C.Last.Next := Read_Subtree (Parent => Subtree);
1954            C.Last.Next.Prev := C.Last;
1955            C.Last := C.Last.Next;
1956         end loop;
1957
1958         --  Now that the allocation and reads have completed successfully, it
1959         --  is safe to link the children to their parent.
1960
1961         Subtree.Children := C;
1962      end Read_Children;
1963
1964      ------------------
1965      -- Read_Subtree --
1966      ------------------
1967
1968      function Read_Subtree
1969        (Parent : Tree_Node_Access) return Tree_Node_Access
1970      is
1971         Subtree : constant Tree_Node_Access :=
1972           new Tree_Node_Type'
1973             (Parent  => Parent,
1974              Element => Element_Type'Input (Stream),
1975              others  => <>);
1976
1977      begin
1978         Read_Count := Read_Count + 1;
1979
1980         Read_Children (Subtree);
1981
1982         return Subtree;
1983      end Read_Subtree;
1984
1985   --  Start of processing for Read
1986
1987   begin
1988      Container.Clear;  -- checks busy bit
1989
1990      Count_Type'Read (Stream, Total_Count);
1991
1992      if Checks and then Total_Count < 0 then
1993         raise Program_Error with "attempt to read from corrupt stream";
1994      end if;
1995
1996      if Total_Count = 0 then
1997         return;
1998      end if;
1999
2000      Read_Count := 0;
2001
2002      Read_Children (Root_Node (Container));
2003
2004      if Checks and then Read_Count /= Total_Count then
2005         raise Program_Error with "attempt to read from corrupt stream";
2006      end if;
2007
2008      Container.Count := Total_Count;
2009   end Read;
2010
2011   procedure Read
2012     (Stream   : not null access Root_Stream_Type'Class;
2013      Position : out Cursor)
2014   is
2015   begin
2016      raise Program_Error with "attempt to read tree cursor from stream";
2017   end Read;
2018
2019   procedure Read
2020     (Stream : not null access Root_Stream_Type'Class;
2021      Item   : out Reference_Type)
2022   is
2023   begin
2024      raise Program_Error with "attempt to stream reference";
2025   end Read;
2026
2027   procedure Read
2028     (Stream : not null access Root_Stream_Type'Class;
2029      Item   : out Constant_Reference_Type)
2030   is
2031   begin
2032      raise Program_Error with "attempt to stream reference";
2033   end Read;
2034
2035   ---------------
2036   -- Reference --
2037   ---------------
2038
2039   function Reference
2040     (Container : aliased in out Tree;
2041      Position  : Cursor) return Reference_Type
2042   is
2043   begin
2044      if Checks and then Position.Container = null then
2045         raise Constraint_Error with
2046           "Position cursor has no element";
2047      end if;
2048
2049      if Checks and then Position.Container /= Container'Unrestricted_Access
2050      then
2051         raise Program_Error with
2052           "Position cursor designates wrong container";
2053      end if;
2054
2055      if Checks and then Position.Node = Root_Node (Container) then
2056         raise Program_Error with "Position cursor designates root";
2057      end if;
2058
2059      --  Implement Vet for multiway tree???
2060      --  pragma Assert (Vet (Position),
2061      --                 "Position cursor in Constant_Reference is bad");
2062
2063      declare
2064         C : Tree renames Position.Container.all;
2065         TC : constant Tamper_Counts_Access :=
2066           C.TC'Unrestricted_Access;
2067      begin
2068         return R : constant Reference_Type :=
2069           (Element => Position.Node.Element'Access,
2070            Control => (Controlled with TC))
2071         do
2072            Busy (TC.all);
2073         end return;
2074      end;
2075   end Reference;
2076
2077   --------------------
2078   -- Remove_Subtree --
2079   --------------------
2080
2081   procedure Remove_Subtree (Subtree : Tree_Node_Access) is
2082      C : Children_Type renames Subtree.Parent.Children;
2083
2084   begin
2085      --  This is a utility operation to remove a subtree node from its
2086      --  parent's list of children.
2087
2088      if C.First = Subtree then
2089         pragma Assert (Subtree.Prev = null);
2090
2091         if C.Last = Subtree then
2092            pragma Assert (Subtree.Next = null);
2093            C.First := null;
2094            C.Last := null;
2095
2096         else
2097            C.First := Subtree.Next;
2098            C.First.Prev := null;
2099         end if;
2100
2101      elsif C.Last = Subtree then
2102         pragma Assert (Subtree.Next = null);
2103         C.Last := Subtree.Prev;
2104         C.Last.Next := null;
2105
2106      else
2107         Subtree.Prev.Next := Subtree.Next;
2108         Subtree.Next.Prev := Subtree.Prev;
2109      end if;
2110   end Remove_Subtree;
2111
2112   ----------------------
2113   -- Replace_Element --
2114   ----------------------
2115
2116   procedure Replace_Element
2117     (Container : in out Tree;
2118      Position  : Cursor;
2119      New_Item  : Element_Type)
2120   is
2121   begin
2122      TE_Check (Container.TC);
2123
2124      if Checks and then Position = No_Element then
2125         raise Constraint_Error with "Position cursor has no element";
2126      end if;
2127
2128      if Checks and then Position.Container /= Container'Unrestricted_Access
2129      then
2130         raise Program_Error with "Position cursor not in container";
2131      end if;
2132
2133      if Checks and then Is_Root (Position) then
2134         raise Program_Error with "Position cursor designates root";
2135      end if;
2136
2137      Position.Node.Element := New_Item;
2138   end Replace_Element;
2139
2140   ------------------------------
2141   -- Reverse_Iterate_Children --
2142   ------------------------------
2143
2144   procedure Reverse_Iterate_Children
2145     (Parent  : Cursor;
2146      Process : not null access procedure (Position : Cursor))
2147   is
2148      C : Tree_Node_Access;
2149      Busy : With_Busy (Parent.Container.TC'Unrestricted_Access);
2150   begin
2151      if Checks and then Parent = No_Element then
2152         raise Constraint_Error with "Parent cursor has no element";
2153      end if;
2154
2155      C := Parent.Node.Children.Last;
2156      while C /= null loop
2157         Process (Position => Cursor'(Parent.Container, Node => C));
2158         C := C.Prev;
2159      end loop;
2160   end Reverse_Iterate_Children;
2161
2162   ----------
2163   -- Root --
2164   ----------
2165
2166   function Root (Container : Tree) return Cursor is
2167   begin
2168      return (Container'Unrestricted_Access, Root_Node (Container));
2169   end Root;
2170
2171   ---------------
2172   -- Root_Node --
2173   ---------------
2174
2175   function Root_Node (Container : Tree) return Tree_Node_Access is
2176      type Root_Node_Access is access all Root_Node_Type;
2177      for Root_Node_Access'Storage_Size use 0;
2178      pragma Convention (C, Root_Node_Access);
2179
2180      function To_Tree_Node_Access is
2181         new Ada.Unchecked_Conversion (Root_Node_Access, Tree_Node_Access);
2182
2183   --  Start of processing for Root_Node
2184
2185   begin
2186      --  This is a utility function for converting from an access type that
2187      --  designates the distinguished root node to an access type designating
2188      --  a non-root node. The representation of a root node does not have an
2189      --  element, but is otherwise identical to a non-root node, so the
2190      --  conversion itself is safe.
2191
2192      return To_Tree_Node_Access (Container.Root'Unrestricted_Access);
2193   end Root_Node;
2194
2195   ---------------------
2196   -- Splice_Children --
2197   ---------------------
2198
2199   procedure Splice_Children
2200     (Target          : in out Tree;
2201      Target_Parent   : Cursor;
2202      Before          : Cursor;
2203      Source          : in out Tree;
2204      Source_Parent   : Cursor)
2205   is
2206      Count : Count_Type;
2207
2208   begin
2209      TC_Check (Target.TC);
2210      TC_Check (Source.TC);
2211
2212      if Checks and then Target_Parent = No_Element then
2213         raise Constraint_Error with "Target_Parent cursor has no element";
2214      end if;
2215
2216      if Checks and then Target_Parent.Container /= Target'Unrestricted_Access
2217      then
2218         raise Program_Error
2219           with "Target_Parent cursor not in Target container";
2220      end if;
2221
2222      if Before /= No_Element then
2223         if Checks and then Before.Container /= Target'Unrestricted_Access then
2224            raise Program_Error
2225              with "Before cursor not in Target container";
2226         end if;
2227
2228         if Checks and then Before.Node.Parent /= Target_Parent.Node then
2229            raise Constraint_Error
2230              with "Before cursor not child of Target_Parent";
2231         end if;
2232      end if;
2233
2234      if Checks and then Source_Parent = No_Element then
2235         raise Constraint_Error with "Source_Parent cursor has no element";
2236      end if;
2237
2238      if Checks and then Source_Parent.Container /= Source'Unrestricted_Access
2239      then
2240         raise Program_Error
2241           with "Source_Parent cursor not in Source container";
2242      end if;
2243
2244      if Target'Address = Source'Address then
2245         if Target_Parent = Source_Parent then
2246            return;
2247         end if;
2248
2249         if Checks and then Is_Reachable (From => Target_Parent.Node,
2250                          To   => Source_Parent.Node)
2251         then
2252            raise Constraint_Error
2253              with "Source_Parent is ancestor of Target_Parent";
2254         end if;
2255
2256         Splice_Children
2257           (Target_Parent => Target_Parent.Node,
2258            Before        => Before.Node,
2259            Source_Parent => Source_Parent.Node);
2260
2261         return;
2262      end if;
2263
2264      --  We cache the count of the nodes we have allocated, so that operation
2265      --  Node_Count can execute in O(1) time. But that means we must count the
2266      --  nodes in the subtree we remove from Source and insert into Target, in
2267      --  order to keep the count accurate.
2268
2269      Count := Subtree_Node_Count (Source_Parent.Node);
2270      pragma Assert (Count >= 1);
2271
2272      Count := Count - 1;  -- because Source_Parent node does not move
2273
2274      Splice_Children
2275        (Target_Parent => Target_Parent.Node,
2276         Before        => Before.Node,
2277         Source_Parent => Source_Parent.Node);
2278
2279      Source.Count := Source.Count - Count;
2280      Target.Count := Target.Count + Count;
2281   end Splice_Children;
2282
2283   procedure Splice_Children
2284     (Container       : in out Tree;
2285      Target_Parent   : Cursor;
2286      Before          : Cursor;
2287      Source_Parent   : Cursor)
2288   is
2289   begin
2290      TC_Check (Container.TC);
2291
2292      if Checks and then Target_Parent = No_Element then
2293         raise Constraint_Error with "Target_Parent cursor has no element";
2294      end if;
2295
2296      if Checks and then
2297        Target_Parent.Container /= Container'Unrestricted_Access
2298      then
2299         raise Program_Error
2300           with "Target_Parent cursor not in container";
2301      end if;
2302
2303      if Before /= No_Element then
2304         if Checks and then Before.Container /= Container'Unrestricted_Access
2305         then
2306            raise Program_Error
2307              with "Before cursor not in container";
2308         end if;
2309
2310         if Checks and then Before.Node.Parent /= Target_Parent.Node then
2311            raise Constraint_Error
2312              with "Before cursor not child of Target_Parent";
2313         end if;
2314      end if;
2315
2316      if Checks and then Source_Parent = No_Element then
2317         raise Constraint_Error with "Source_Parent cursor has no element";
2318      end if;
2319
2320      if Checks and then
2321        Source_Parent.Container /= Container'Unrestricted_Access
2322      then
2323         raise Program_Error
2324           with "Source_Parent cursor not in container";
2325      end if;
2326
2327      if Target_Parent = Source_Parent then
2328         return;
2329      end if;
2330
2331      if Checks and then Is_Reachable (From => Target_Parent.Node,
2332                       To   => Source_Parent.Node)
2333      then
2334         raise Constraint_Error
2335           with "Source_Parent is ancestor of Target_Parent";
2336      end if;
2337
2338      Splice_Children
2339        (Target_Parent => Target_Parent.Node,
2340         Before        => Before.Node,
2341         Source_Parent => Source_Parent.Node);
2342   end Splice_Children;
2343
2344   procedure Splice_Children
2345     (Target_Parent : Tree_Node_Access;
2346      Before        : Tree_Node_Access;
2347      Source_Parent : Tree_Node_Access)
2348   is
2349      CC : constant Children_Type := Source_Parent.Children;
2350      C  : Tree_Node_Access;
2351
2352   begin
2353      --  This is a utility operation to remove the children from
2354      --  Source parent and insert them into Target parent.
2355
2356      Source_Parent.Children := Children_Type'(others => null);
2357
2358      --  Fix up the Parent pointers of each child to designate
2359      --  its new Target parent.
2360
2361      C := CC.First;
2362      while C /= null loop
2363         C.Parent := Target_Parent;
2364         C := C.Next;
2365      end loop;
2366
2367      Insert_Subtree_List
2368        (First  => CC.First,
2369         Last   => CC.Last,
2370         Parent => Target_Parent,
2371         Before => Before);
2372   end Splice_Children;
2373
2374   --------------------
2375   -- Splice_Subtree --
2376   --------------------
2377
2378   procedure Splice_Subtree
2379     (Target   : in out Tree;
2380      Parent   : Cursor;
2381      Before   : Cursor;
2382      Source   : in out Tree;
2383      Position : in out Cursor)
2384   is
2385      Subtree_Count : Count_Type;
2386
2387   begin
2388      TC_Check (Target.TC);
2389      TC_Check (Source.TC);
2390
2391      if Checks and then Parent = No_Element then
2392         raise Constraint_Error with "Parent cursor has no element";
2393      end if;
2394
2395      if Checks and then Parent.Container /= Target'Unrestricted_Access then
2396         raise Program_Error with "Parent cursor not in Target container";
2397      end if;
2398
2399      if Before /= No_Element then
2400         if Checks and then Before.Container /= Target'Unrestricted_Access then
2401            raise Program_Error with "Before cursor not in Target container";
2402         end if;
2403
2404         if Checks and then Before.Node.Parent /= Parent.Node then
2405            raise Constraint_Error with "Before cursor not child of Parent";
2406         end if;
2407      end if;
2408
2409      if Checks and then Position = No_Element then
2410         raise Constraint_Error with "Position cursor has no element";
2411      end if;
2412
2413      if Checks and then Position.Container /= Source'Unrestricted_Access then
2414         raise Program_Error with "Position cursor not in Source container";
2415      end if;
2416
2417      if Checks and then Is_Root (Position) then
2418         raise Program_Error with "Position cursor designates root";
2419      end if;
2420
2421      if Target'Address = Source'Address then
2422         if Position.Node.Parent = Parent.Node then
2423            if Position.Node = Before.Node then
2424               return;
2425            end if;
2426
2427            if Position.Node.Next = Before.Node then
2428               return;
2429            end if;
2430         end if;
2431
2432         if Checks and then
2433           Is_Reachable (From => Parent.Node, To => Position.Node)
2434         then
2435            raise Constraint_Error with "Position is ancestor of Parent";
2436         end if;
2437
2438         Remove_Subtree (Position.Node);
2439
2440         Position.Node.Parent := Parent.Node;
2441         Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2442
2443         return;
2444      end if;
2445
2446      --  This is an unfortunate feature of this API: we must count the nodes
2447      --  in the subtree that we remove from the source tree, which is an O(n)
2448      --  operation. It would have been better if the Tree container did not
2449      --  have a Node_Count selector; a user that wants the number of nodes in
2450      --  the tree could simply call Subtree_Node_Count, with the understanding
2451      --  that such an operation is O(n).
2452
2453      --  Of course, we could choose to implement the Node_Count selector as an
2454      --  O(n) operation, which would turn this splice operation into an O(1)
2455      --  operation. ???
2456
2457      Subtree_Count := Subtree_Node_Count (Position.Node);
2458      pragma Assert (Subtree_Count <= Source.Count);
2459
2460      Remove_Subtree (Position.Node);
2461      Source.Count := Source.Count - Subtree_Count;
2462
2463      Position.Node.Parent := Parent.Node;
2464      Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2465
2466      Target.Count := Target.Count + Subtree_Count;
2467
2468      Position.Container := Target'Unrestricted_Access;
2469   end Splice_Subtree;
2470
2471   procedure Splice_Subtree
2472     (Container : in out Tree;
2473      Parent    : Cursor;
2474      Before    : Cursor;
2475      Position  : Cursor)
2476   is
2477   begin
2478      TC_Check (Container.TC);
2479
2480      if Checks and then Parent = No_Element then
2481         raise Constraint_Error with "Parent cursor has no element";
2482      end if;
2483
2484      if Checks and then Parent.Container /= Container'Unrestricted_Access then
2485         raise Program_Error with "Parent cursor not in container";
2486      end if;
2487
2488      if Before /= No_Element then
2489         if Checks and then Before.Container /= Container'Unrestricted_Access
2490         then
2491            raise Program_Error with "Before cursor not in container";
2492         end if;
2493
2494         if Checks and then Before.Node.Parent /= Parent.Node then
2495            raise Constraint_Error with "Before cursor not child of Parent";
2496         end if;
2497      end if;
2498
2499      if Checks and then Position = No_Element then
2500         raise Constraint_Error with "Position cursor has no element";
2501      end if;
2502
2503      if Checks and then Position.Container /= Container'Unrestricted_Access
2504      then
2505         raise Program_Error with "Position cursor not in container";
2506      end if;
2507
2508      if Checks and then Is_Root (Position) then
2509
2510         --  Should this be PE instead?  Need ARG confirmation.  ???
2511
2512         raise Constraint_Error with "Position cursor designates root";
2513      end if;
2514
2515      if Position.Node.Parent = Parent.Node then
2516         if Position.Node = Before.Node then
2517            return;
2518         end if;
2519
2520         if Position.Node.Next = Before.Node then
2521            return;
2522         end if;
2523      end if;
2524
2525      if Checks and then
2526        Is_Reachable (From => Parent.Node, To => Position.Node)
2527      then
2528         raise Constraint_Error with "Position is ancestor of Parent";
2529      end if;
2530
2531      Remove_Subtree (Position.Node);
2532
2533      Position.Node.Parent := Parent.Node;
2534      Insert_Subtree_Node (Position.Node, Parent.Node, Before.Node);
2535   end Splice_Subtree;
2536
2537   ------------------------
2538   -- Subtree_Node_Count --
2539   ------------------------
2540
2541   function Subtree_Node_Count (Position : Cursor) return Count_Type is
2542   begin
2543      if Position = No_Element then
2544         return 0;
2545      end if;
2546
2547      return Subtree_Node_Count (Position.Node);
2548   end Subtree_Node_Count;
2549
2550   function Subtree_Node_Count
2551     (Subtree : Tree_Node_Access) return Count_Type
2552   is
2553      Result : Count_Type;
2554      Node   : Tree_Node_Access;
2555
2556   begin
2557      Result := 1;
2558      Node := Subtree.Children.First;
2559      while Node /= null loop
2560         Result := Result + Subtree_Node_Count (Node);
2561         Node := Node.Next;
2562      end loop;
2563
2564      return Result;
2565   end Subtree_Node_Count;
2566
2567   ----------
2568   -- Swap --
2569   ----------
2570
2571   procedure Swap
2572     (Container : in out Tree;
2573      I, J      : Cursor)
2574   is
2575   begin
2576      TE_Check (Container.TC);
2577
2578      if Checks and then I = No_Element then
2579         raise Constraint_Error with "I cursor has no element";
2580      end if;
2581
2582      if Checks and then I.Container /= Container'Unrestricted_Access then
2583         raise Program_Error with "I cursor not in container";
2584      end if;
2585
2586      if Checks and then Is_Root (I) then
2587         raise Program_Error with "I cursor designates root";
2588      end if;
2589
2590      if I = J then -- make this test sooner???
2591         return;
2592      end if;
2593
2594      if Checks and then J = No_Element then
2595         raise Constraint_Error with "J cursor has no element";
2596      end if;
2597
2598      if Checks and then J.Container /= Container'Unrestricted_Access then
2599         raise Program_Error with "J cursor not in container";
2600      end if;
2601
2602      if Checks and then Is_Root (J) then
2603         raise Program_Error with "J cursor designates root";
2604      end if;
2605
2606      declare
2607         EI : constant Element_Type := I.Node.Element;
2608
2609      begin
2610         I.Node.Element := J.Node.Element;
2611         J.Node.Element := EI;
2612      end;
2613   end Swap;
2614
2615   --------------------
2616   -- Update_Element --
2617   --------------------
2618
2619   procedure Update_Element
2620     (Container : in out Tree;
2621      Position  : Cursor;
2622      Process   : not null access procedure (Element : in out Element_Type))
2623   is
2624      T : Tree renames Position.Container.all'Unrestricted_Access.all;
2625      Lock : With_Lock (T.TC'Unrestricted_Access);
2626   begin
2627      if Checks and then Position = No_Element then
2628         raise Constraint_Error with "Position cursor has no element";
2629      end if;
2630
2631      if Checks and then Position.Container /= Container'Unrestricted_Access
2632      then
2633         raise Program_Error with "Position cursor not in container";
2634      end if;
2635
2636      if Checks and then Is_Root (Position) then
2637         raise Program_Error with "Position cursor designates root";
2638      end if;
2639
2640      Process (Position.Node.Element);
2641   end Update_Element;
2642
2643   -----------
2644   -- Write --
2645   -----------
2646
2647   procedure Write
2648     (Stream    : not null access Root_Stream_Type'Class;
2649      Container : Tree)
2650   is
2651      procedure Write_Children (Subtree : Tree_Node_Access);
2652      procedure Write_Subtree (Subtree : Tree_Node_Access);
2653
2654      --------------------
2655      -- Write_Children --
2656      --------------------
2657
2658      procedure Write_Children (Subtree : Tree_Node_Access) is
2659         CC : Children_Type renames Subtree.Children;
2660         C  : Tree_Node_Access;
2661
2662      begin
2663         Count_Type'Write (Stream, Child_Count (CC));
2664
2665         C := CC.First;
2666         while C /= null loop
2667            Write_Subtree (C);
2668            C := C.Next;
2669         end loop;
2670      end Write_Children;
2671
2672      -------------------
2673      -- Write_Subtree --
2674      -------------------
2675
2676      procedure Write_Subtree (Subtree : Tree_Node_Access) is
2677      begin
2678         Element_Type'Output (Stream, Subtree.Element);
2679         Write_Children (Subtree);
2680      end Write_Subtree;
2681
2682   --  Start of processing for Write
2683
2684   begin
2685      Count_Type'Write (Stream, Container.Count);
2686
2687      if Container.Count = 0 then
2688         return;
2689      end if;
2690
2691      Write_Children (Root_Node (Container));
2692   end Write;
2693
2694   procedure Write
2695     (Stream   : not null access Root_Stream_Type'Class;
2696      Position : Cursor)
2697   is
2698   begin
2699      raise Program_Error with "attempt to write tree cursor to stream";
2700   end Write;
2701
2702   procedure Write
2703     (Stream : not null access Root_Stream_Type'Class;
2704      Item   : Reference_Type)
2705   is
2706   begin
2707      raise Program_Error with "attempt to stream reference";
2708   end Write;
2709
2710   procedure Write
2711     (Stream : not null access Root_Stream_Type'Class;
2712      Item   : Constant_Reference_Type)
2713   is
2714   begin
2715      raise Program_Error with "attempt to stream reference";
2716   end Write;
2717
2718end Ada.Containers.Multiway_Trees;
2719