OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [a-cimutr.adb] - Blame information for rev 749

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.