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