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