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