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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [a-cbmutr.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.BOUNDED_MULTIWAY_TREES                  --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--             Copyright (C) 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.Finalization; use Ada.Finalization;
31
 
32
with System; use type System.Address;
33
 
34
package body Ada.Containers.Bounded_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   : Count_Type;
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
   procedure Initialize_Node (Container : in out Tree; Index : Count_Type);
85
   procedure Initialize_Root (Container : in out Tree);
86
 
87
   procedure Allocate_Node
88
     (Container          : in out Tree;
89
      Initialize_Element : not null access procedure (Index : Count_Type);
90
      New_Node           : out Count_Type);
91
 
92
   procedure Allocate_Node
93
     (Container : in out Tree;
94
      New_Item  : Element_Type;
95
      New_Node  : out Count_Type);
96
 
97
   procedure Allocate_Node
98
     (Container : in out Tree;
99
      New_Node  : out Count_Type);
100
 
101
   procedure Allocate_Node
102
     (Container : in out Tree;
103
      Stream    : not null access Root_Stream_Type'Class;
104
      New_Node  : out Count_Type);
105
 
106
   procedure Deallocate_Node
107
     (Container : in out Tree;
108
      X         : Count_Type);
109
 
110
   procedure Deallocate_Children
111
     (Container : in out Tree;
112
      Subtree   : Count_Type;
113
      Count     : in out Count_Type);
114
 
115
   procedure Deallocate_Subtree
116
     (Container : in out Tree;
117
      Subtree   : Count_Type;
118
      Count     : in out Count_Type);
119
 
120
   function Equal_Children
121
     (Left_Tree     : Tree;
122
      Left_Subtree  : Count_Type;
123
      Right_Tree    : Tree;
124
      Right_Subtree : Count_Type) return Boolean;
125
 
126
   function Equal_Subtree
127
     (Left_Tree     : Tree;
128
      Left_Subtree  : Count_Type;
129
      Right_Tree    : Tree;
130
      Right_Subtree : Count_Type) return Boolean;
131
 
132
   procedure Iterate_Children
133
     (Container : Tree;
134
      Subtree   : Count_Type;
135
      Process   : not null access procedure (Position : Cursor));
136
 
137
   procedure Iterate_Subtree
138
     (Container : Tree;
139
      Subtree   : Count_Type;
140
      Process   : not null access procedure (Position : Cursor));
141
 
142
   procedure Copy_Children
143
     (Source        : Tree;
144
      Source_Parent : Count_Type;
145
      Target        : in out Tree;
146
      Target_Parent : Count_Type;
147
      Count         : in out Count_Type);
148
 
149
   procedure Copy_Subtree
150
     (Source         : Tree;
151
      Source_Subtree : Count_Type;
152
      Target         : in out Tree;
153
      Target_Parent  : Count_Type;
154
      Target_Subtree : out Count_Type;
155
      Count          : in out Count_Type);
156
 
157
   function Find_In_Children
158
     (Container : Tree;
159
      Subtree   : Count_Type;
160
      Item      : Element_Type) return Count_Type;
161
 
162
   function Find_In_Subtree
163
     (Container : Tree;
164
      Subtree   : Count_Type;
165
      Item      : Element_Type) return Count_Type;
166
 
167
   function Child_Count
168
     (Container : Tree;
169
      Parent    : Count_Type) return Count_Type;
170
 
171
   function Subtree_Node_Count
172
     (Container : Tree;
173
      Subtree   : Count_Type) return Count_Type;
174
 
175
   function Is_Reachable
176
     (Container : Tree;
177
      From, To  : Count_Type) return Boolean;
178
 
179
   function Root_Node (Container : Tree) return Count_Type;
180
 
181
   procedure Remove_Subtree
182
     (Container : in out Tree;
183
      Subtree   : Count_Type);
184
 
185
   procedure Insert_Subtree_Node
186
     (Container : in out Tree;
187
      Subtree   : Count_Type'Base;
188
      Parent    : Count_Type;
189
      Before    : Count_Type'Base);
190
 
191
   procedure Insert_Subtree_List
192
     (Container : in out Tree;
193
      First     : Count_Type'Base;
194
      Last      : Count_Type'Base;
195
      Parent    : Count_Type;
196
      Before    : Count_Type'Base);
197
 
198
   procedure Splice_Children
199
     (Container     : in out Tree;
200
      Target_Parent : Count_Type;
201
      Before        : Count_Type'Base;
202
      Source_Parent : Count_Type);
203
 
204
   procedure Splice_Children
205
     (Target        : in out Tree;
206
      Target_Parent : Count_Type;
207
      Before        : Count_Type'Base;
208
      Source        : in out Tree;
209
      Source_Parent : Count_Type);
210
 
211
   procedure Splice_Subtree
212
     (Target   : in out Tree;
213
      Parent   : Count_Type;
214
      Before   : Count_Type'Base;
215
      Source   : in out Tree;
216
      Position : in out Count_Type);  -- source on input, target on output
217
 
218
   ---------
219
   -- "=" --
220
   ---------
221
 
222
   function "=" (Left, Right : Tree) return Boolean is
223
   begin
224
      if Left'Address = Right'Address then
225
         return True;
226
      end if;
227
 
228
      if Left.Count /= Right.Count then
229
         return False;
230
      end if;
231
 
232
      if Left.Count = 0 then
233
         return True;
234
      end if;
235
 
236
      return Equal_Children
237
               (Left_Tree     => Left,
238
                Left_Subtree  => Root_Node (Left),
239
                Right_Tree    => Right,
240
                Right_Subtree => Root_Node (Right));
241
   end "=";
242
 
243
   -------------------
244
   -- Allocate_Node --
245
   -------------------
246
 
247
   procedure Allocate_Node
248
     (Container          : in out Tree;
249
      Initialize_Element : not null access procedure (Index : Count_Type);
250
      New_Node           : out Count_Type)
251
   is
252
   begin
253
      if Container.Free >= 0 then
254
         New_Node := Container.Free;
255
         pragma Assert (New_Node in Container.Elements'Range);
256
 
257
         --  We always perform the assignment first, before we change container
258
         --  state, in order to defend against exceptions duration assignment.
259
 
260
         Initialize_Element (New_Node);
261
 
262
         Container.Free := Container.Nodes (New_Node).Next;
263
 
264
      else
265
         --  A negative free store value means that the links of the nodes in
266
         --  the free store have not been initialized. In this case, the nodes
267
         --  are physically contiguous in the array, starting at the index that
268
         --  is the absolute value of the Container.Free, and continuing until
269
         --  the end of the array (Nodes'Last).
270
 
271
         New_Node := abs Container.Free;
272
         pragma Assert (New_Node in Container.Elements'Range);
273
 
274
         --  As above, we perform this assignment first, before modifying any
275
         --  container state.
276
 
277
         Initialize_Element (New_Node);
278
 
279
         Container.Free := Container.Free - 1;
280
 
281
         if abs Container.Free > Container.Capacity then
282
            Container.Free := 0;
283
         end if;
284
      end if;
285
 
286
      Initialize_Node (Container, New_Node);
287
   end Allocate_Node;
288
 
289
   procedure Allocate_Node
290
     (Container : in out Tree;
291
      New_Item  : Element_Type;
292
      New_Node  : out Count_Type)
293
   is
294
      procedure Initialize_Element (Index : Count_Type);
295
 
296
      procedure Initialize_Element (Index : Count_Type) is
297
      begin
298
         Container.Elements (Index) := New_Item;
299
      end Initialize_Element;
300
 
301
   begin
302
      Allocate_Node (Container, Initialize_Element'Access, New_Node);
303
   end Allocate_Node;
304
 
305
   procedure Allocate_Node
306
     (Container : in out Tree;
307
      Stream    : not null access Root_Stream_Type'Class;
308
      New_Node  : out Count_Type)
309
   is
310
      procedure Initialize_Element (Index : Count_Type);
311
 
312
      procedure Initialize_Element (Index : Count_Type) is
313
      begin
314
         Element_Type'Read (Stream, Container.Elements (Index));
315
      end Initialize_Element;
316
 
317
   begin
318
      Allocate_Node (Container, Initialize_Element'Access, New_Node);
319
   end Allocate_Node;
320
 
321
   procedure Allocate_Node
322
     (Container : in out Tree;
323
      New_Node  : out Count_Type)
324
   is
325
      procedure Initialize_Element (Index : Count_Type) is null;
326
   begin
327
      Allocate_Node (Container, Initialize_Element'Access, New_Node);
328
   end Allocate_Node;
329
 
330
   -------------------
331
   -- Ancestor_Find --
332
   -------------------
333
 
334
   function Ancestor_Find
335
     (Position : Cursor;
336
      Item     : Element_Type) return Cursor
337
   is
338
      R, N : Count_Type;
339
 
340
   begin
341
      if Position = No_Element then
342
         raise Constraint_Error with "Position cursor has no element";
343
      end if;
344
 
345
      --  Commented-out pending ruling by ARG.  ???
346
 
347
      --  if Position.Container /= Container'Unrestricted_Access then
348
      --     raise Program_Error with "Position cursor not in container";
349
      --  end if;
350
 
351
      --  AI-0136 says to raise PE if Position equals the root node. This does
352
      --  not seem correct, as this value is just the limiting condition of the
353
      --  search. For now we omit this check, pending a ruling from the ARG.
354
      --  ???
355
      --
356
      --  if Is_Root (Position) then
357
      --     raise Program_Error with "Position cursor designates root";
358
      --  end if;
359
 
360
      R := Root_Node (Position.Container.all);
361
      N := Position.Node;
362
      while N /= R loop
363
         if Position.Container.Elements (N) = Item then
364
            return Cursor'(Position.Container, N);
365
         end if;
366
 
367
         N := Position.Container.Nodes (N).Parent;
368
      end loop;
369
 
370
      return No_Element;
371
   end Ancestor_Find;
372
 
373
   ------------------
374
   -- Append_Child --
375
   ------------------
376
 
377
   procedure Append_Child
378
     (Container : in out Tree;
379
      Parent    : Cursor;
380
      New_Item  : Element_Type;
381
      Count     : Count_Type := 1)
382
   is
383
      Nodes       : Tree_Node_Array renames Container.Nodes;
384
      First, Last : Count_Type;
385
 
386
   begin
387
      if Parent = No_Element then
388
         raise Constraint_Error with "Parent cursor has no element";
389
      end if;
390
 
391
      if Parent.Container /= Container'Unrestricted_Access then
392
         raise Program_Error with "Parent cursor not in container";
393
      end if;
394
 
395
      if Count = 0 then
396
         return;
397
      end if;
398
 
399
      if Container.Count > Container.Capacity - Count then
400
         raise Constraint_Error
401
           with "requested count exceeds available storage";
402
      end if;
403
 
404
      if Container.Busy > 0 then
405
         raise Program_Error
406
           with "attempt to tamper with cursors (tree is busy)";
407
      end if;
408
 
409
      if Container.Count = 0 then
410
         Initialize_Root (Container);
411
      end if;
412
 
413
      Allocate_Node (Container, New_Item, First);
414
      Nodes (First).Parent := Parent.Node;
415
 
416
      Last := First;
417
      for J in Count_Type'(2) .. Count loop
418
         Allocate_Node (Container, New_Item, Nodes (Last).Next);
419
         Nodes (Nodes (Last).Next).Parent := Parent.Node;
420
         Nodes (Nodes (Last).Next).Prev := Last;
421
 
422
         Last := Nodes (Last).Next;
423
      end loop;
424
 
425
      Insert_Subtree_List
426
        (Container => Container,
427
         First     => First,
428
         Last      => Last,
429
         Parent    => Parent.Node,
430
         Before    => No_Node);  -- means "insert at end of list"
431
 
432
      Container.Count := Container.Count + Count;
433
   end Append_Child;
434
 
435
   ------------
436
   -- Assign --
437
   ------------
438
 
439
   procedure Assign (Target : in out Tree; Source : Tree) is
440
      Target_Count : Count_Type;
441
 
442
   begin
443
      if Target'Address = Source'Address then
444
         return;
445
      end if;
446
 
447
      if Target.Capacity < Source.Count then
448
         raise Capacity_Error  -- ???
449
           with "Target capacity is less than Source count";
450
      end if;
451
 
452
      Target.Clear;  -- Checks busy bit
453
 
454
      if Source.Count = 0 then
455
         return;
456
      end if;
457
 
458
      Initialize_Root (Target);
459
 
460
      --  Copy_Children returns the number of nodes that it allocates, but it
461
      --  does this by incrementing the count value passed in, so we must
462
      --  initialize the count before calling Copy_Children.
463
 
464
      Target_Count := 0;
465
 
466
      Copy_Children
467
        (Source        => Source,
468
         Source_Parent => Root_Node (Source),
469
         Target        => Target,
470
         Target_Parent => Root_Node (Target),
471
         Count         => Target_Count);
472
 
473
      pragma Assert (Target_Count = Source.Count);
474
      Target.Count := Source.Count;
475
   end Assign;
476
 
477
   -----------------
478
   -- Child_Count --
479
   -----------------
480
 
481
   function Child_Count (Parent : Cursor) return Count_Type is
482
   begin
483
      if Parent = No_Element then
484
         return 0;
485
 
486
      elsif Parent.Container.Count = 0 then
487
         pragma Assert (Is_Root (Parent));
488
         return 0;
489
 
490
      else
491
         return Child_Count (Parent.Container.all, Parent.Node);
492
      end if;
493
   end Child_Count;
494
 
495
   function Child_Count
496
     (Container : Tree;
497
      Parent    : Count_Type) return Count_Type
498
   is
499
      NN : Tree_Node_Array renames Container.Nodes;
500
      CC : Children_Type renames NN (Parent).Children;
501
 
502
      Result : Count_Type;
503
      Node   : Count_Type'Base;
504
 
505
   begin
506
      Result := 0;
507
      Node := CC.First;
508
      while Node > 0 loop
509
         Result := Result + 1;
510
         Node := NN (Node).Next;
511
      end loop;
512
 
513
      return Result;
514
   end Child_Count;
515
 
516
   -----------------
517
   -- Child_Depth --
518
   -----------------
519
 
520
   function Child_Depth (Parent, Child : Cursor) return Count_Type is
521
      Result : Count_Type;
522
      N      : Count_Type'Base;
523
 
524
   begin
525
      if Parent = No_Element then
526
         raise Constraint_Error with "Parent cursor has no element";
527
      end if;
528
 
529
      if Child = No_Element then
530
         raise Constraint_Error with "Child cursor has no element";
531
      end if;
532
 
533
      if Parent.Container /= Child.Container then
534
         raise Program_Error with "Parent and Child in different containers";
535
      end if;
536
 
537
      if Parent.Container.Count = 0 then
538
         pragma Assert (Is_Root (Parent));
539
         pragma Assert (Child = Parent);
540
         return 0;
541
      end if;
542
 
543
      Result := 0;
544
      N := Child.Node;
545
      while N /= Parent.Node loop
546
         Result := Result + 1;
547
         N := Parent.Container.Nodes (N).Parent;
548
 
549
         if N < 0 then
550
            raise Program_Error with "Parent is not ancestor of Child";
551
         end if;
552
      end loop;
553
 
554
      return Result;
555
   end Child_Depth;
556
 
557
   -----------
558
   -- Clear --
559
   -----------
560
 
561
   procedure Clear (Container : in out Tree) is
562
      Container_Count : constant Count_Type := Container.Count;
563
      Count           : Count_Type;
564
 
565
   begin
566
      if Container.Busy > 0 then
567
         raise Program_Error
568
           with "attempt to tamper with cursors (tree is busy)";
569
      end if;
570
 
571
      if Container_Count = 0 then
572
         return;
573
      end if;
574
 
575
      Container.Count := 0;
576
 
577
      --  Deallocate_Children returns the number of nodes that it deallocates,
578
      --  but it does this by incrementing the count value that is passed in,
579
      --  so we must first initialize the count return value before calling it.
580
 
581
      Count := 0;
582
 
583
      Deallocate_Children
584
        (Container => Container,
585
         Subtree   => Root_Node (Container),
586
         Count     => Count);
587
 
588
      pragma Assert (Count = Container_Count);
589
   end Clear;
590
 
591
   ------------------------
592
   -- Constant_Reference --
593
   ------------------------
594
 
595
   function Constant_Reference
596
     (Container : aliased Tree;
597
      Position  : Cursor) return Constant_Reference_Type
598
   is
599
   begin
600
      if Position.Container = null then
601
         raise Constraint_Error with
602
           "Position cursor has no element";
603
      end if;
604
 
605
      if Position.Container /= Container'Unrestricted_Access then
606
         raise Program_Error with
607
           "Position cursor designates wrong container";
608
      end if;
609
 
610
      if Position.Node = Root_Node (Container) then
611
         raise Program_Error with "Position cursor designates root";
612
      end if;
613
 
614
      --  Implement Vet for multiway tree???
615
      --  pragma Assert (Vet (Position),
616
      --                 "Position cursor in Constant_Reference is bad");
617
 
618
      return (Element => Container.Elements (Position.Node)'Access);
619
   end Constant_Reference;
620
 
621
   --------------
622
   -- Contains --
623
   --------------
624
 
625
   function Contains
626
     (Container : Tree;
627
      Item      : Element_Type) return Boolean
628
   is
629
   begin
630
      return Find (Container, Item) /= No_Element;
631
   end Contains;
632
 
633
   ----------
634
   -- Copy --
635
   ----------
636
 
637
   function Copy
638
     (Source   : Tree;
639
      Capacity : Count_Type := 0) return Tree
640
   is
641
      C : Count_Type;
642
 
643
   begin
644
      if Capacity = 0 then
645
         C := Source.Count;
646
      elsif Capacity >= Source.Count then
647
         C := Capacity;
648
      else
649
         raise Capacity_Error with "Capacity value too small";
650
      end if;
651
 
652
      return Target : Tree (Capacity => C) do
653
         Initialize_Root (Target);
654
 
655
         if Source.Count = 0 then
656
            return;
657
         end if;
658
 
659
         Copy_Children
660
           (Source        => Source,
661
            Source_Parent => Root_Node (Source),
662
            Target        => Target,
663
            Target_Parent => Root_Node (Target),
664
            Count         => Target.Count);
665
 
666
         pragma Assert (Target.Count = Source.Count);
667
      end return;
668
   end Copy;
669
 
670
   -------------------
671
   -- Copy_Children --
672
   -------------------
673
 
674
   procedure Copy_Children
675
     (Source        : Tree;
676
      Source_Parent : Count_Type;
677
      Target        : in out Tree;
678
      Target_Parent : Count_Type;
679
      Count         : in out Count_Type)
680
   is
681
      S_Nodes : Tree_Node_Array renames Source.Nodes;
682
      S_Node  : Tree_Node_Type renames S_Nodes (Source_Parent);
683
 
684
      T_Nodes : Tree_Node_Array renames Target.Nodes;
685
      T_Node  : Tree_Node_Type renames T_Nodes (Target_Parent);
686
 
687
      pragma Assert (T_Node.Children.First <= 0);
688
      pragma Assert (T_Node.Children.Last <= 0);
689
 
690
      T_CC : Children_Type;
691
      C    : Count_Type'Base;
692
 
693
   begin
694
      --  We special-case the first allocation, in order to establish the
695
      --  representation invariants for type Children_Type.
696
 
697
      C := S_Node.Children.First;
698
 
699
      if C <= 0 then  -- source parent has no children
700
         return;
701
      end if;
702
 
703
      Copy_Subtree
704
        (Source         => Source,
705
         Source_Subtree => C,
706
         Target         => Target,
707
         Target_Parent  => Target_Parent,
708
         Target_Subtree => T_CC.First,
709
         Count          => Count);
710
 
711
      T_CC.Last := T_CC.First;
712
 
713
      --  The representation invariants for the Children_Type list have been
714
      --  established, so we can now copy the remaining children of Source.
715
 
716
      C := S_Nodes (C).Next;
717
      while C > 0 loop
718
         Copy_Subtree
719
           (Source         => Source,
720
            Source_Subtree => C,
721
            Target         => Target,
722
            Target_Parent  => Target_Parent,
723
            Target_Subtree => T_Nodes (T_CC.Last).Next,
724
            Count          => Count);
725
 
726
         T_Nodes (T_Nodes (T_CC.Last).Next).Prev := T_CC.Last;
727
         T_CC.Last := T_Nodes (T_CC.Last).Next;
728
 
729
         C := S_Nodes (C).Next;
730
      end loop;
731
 
732
      --  We add the newly-allocated children to their parent list only after
733
      --  the allocation has succeeded, in order to preserve invariants of the
734
      --  parent.
735
 
736
      T_Node.Children := T_CC;
737
   end Copy_Children;
738
 
739
   ------------------
740
   -- Copy_Subtree --
741
   ------------------
742
 
743
   procedure Copy_Subtree
744
     (Target   : in out Tree;
745
      Parent   : Cursor;
746
      Before   : Cursor;
747
      Source   : Cursor)
748
   is
749
      Target_Subtree : Count_Type;
750
      Target_Count   : Count_Type;
751
 
752
   begin
753
      if Parent = No_Element then
754
         raise Constraint_Error with "Parent cursor has no element";
755
      end if;
756
 
757
      if Parent.Container /= Target'Unrestricted_Access then
758
         raise Program_Error with "Parent cursor not in container";
759
      end if;
760
 
761
      if Before /= No_Element then
762
         if Before.Container /= Target'Unrestricted_Access then
763
            raise Program_Error with "Before cursor not in container";
764
         end if;
765
 
766
         if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
767
            raise Constraint_Error with "Before cursor not child of Parent";
768
         end if;
769
      end if;
770
 
771
      if Source = No_Element then
772
         return;
773
      end if;
774
 
775
      if Is_Root (Source) then
776
         raise Constraint_Error with "Source cursor designates root";
777
      end if;
778
 
779
      if Target.Count = 0 then
780
         Initialize_Root (Target);
781
      end if;
782
 
783
      --  Copy_Subtree returns a count of the number of nodes that it
784
      --  allocates, but it works by incrementing the value that is passed
785
      --  in. We must therefore initialize the count value before calling
786
      --  Copy_Subtree.
787
 
788
      Target_Count := 0;
789
 
790
      Copy_Subtree
791
        (Source         => Source.Container.all,
792
         Source_Subtree => Source.Node,
793
         Target         => Target,
794
         Target_Parent  => Parent.Node,
795
         Target_Subtree => Target_Subtree,
796
         Count          => Target_Count);
797
 
798
      Insert_Subtree_Node
799
        (Container => Target,
800
         Subtree   => Target_Subtree,
801
         Parent    => Parent.Node,
802
         Before    => Before.Node);
803
 
804
      Target.Count := Target.Count + Target_Count;
805
   end Copy_Subtree;
806
 
807
   procedure Copy_Subtree
808
     (Source         : Tree;
809
      Source_Subtree : Count_Type;
810
      Target         : in out Tree;
811
      Target_Parent  : Count_Type;
812
      Target_Subtree : out Count_Type;
813
      Count          : in out Count_Type)
814
   is
815
      T_Nodes : Tree_Node_Array renames Target.Nodes;
816
 
817
   begin
818
      --  First we allocate the root of the target subtree.
819
 
820
      Allocate_Node
821
        (Container => Target,
822
         New_Item  => Source.Elements (Source_Subtree),
823
         New_Node  => Target_Subtree);
824
 
825
      T_Nodes (Target_Subtree).Parent := Target_Parent;
826
      Count := Count + 1;
827
 
828
      --  We now have a new subtree (for the Target tree), containing only a
829
      --  copy of the corresponding element in the Source subtree. Next we copy
830
      --  the children of the Source subtree as children of the new Target
831
      --  subtree.
832
 
833
      Copy_Children
834
        (Source        => Source,
835
         Source_Parent => Source_Subtree,
836
         Target        => Target,
837
         Target_Parent => Target_Subtree,
838
         Count         => Count);
839
   end Copy_Subtree;
840
 
841
   -------------------------
842
   -- Deallocate_Children --
843
   -------------------------
844
 
845
   procedure Deallocate_Children
846
     (Container : in out Tree;
847
      Subtree   : Count_Type;
848
      Count     : in out Count_Type)
849
   is
850
      Nodes : Tree_Node_Array renames Container.Nodes;
851
      Node  : Tree_Node_Type renames Nodes (Subtree);  -- parent
852
      CC    : Children_Type renames Node.Children;
853
      C     : Count_Type'Base;
854
 
855
   begin
856
      while CC.First > 0 loop
857
         C := CC.First;
858
         CC.First := Nodes (C).Next;
859
 
860
         Deallocate_Subtree (Container, C, Count);
861
      end loop;
862
 
863
      CC.Last := 0;
864
   end Deallocate_Children;
865
 
866
   ---------------------
867
   -- Deallocate_Node --
868
   ---------------------
869
 
870
   procedure Deallocate_Node
871
     (Container : in out Tree;
872
      X         : Count_Type)
873
   is
874
      NN : Tree_Node_Array renames Container.Nodes;
875
      pragma Assert (X > 0);
876
      pragma Assert (X <= NN'Last);
877
 
878
      N : Tree_Node_Type renames NN (X);
879
      pragma Assert (N.Parent /= X);  -- node is active
880
 
881
   begin
882
      --  The tree container actually contains two lists: one for the "active"
883
      --  nodes that contain elements that have been inserted onto the tree,
884
      --  and another for the "inactive" nodes of the free store, from which
885
      --  nodes are allocated when a new child is inserted in the tree.
886
 
887
      --  We desire that merely declaring a tree object should have only
888
      --  minimal cost; specially, we want to avoid having to initialize the
889
      --  free store (to fill in the links), especially if the capacity of the
890
      --  tree object is large.
891
 
892
      --  The head of the free list is indicated by Container.Free. If its
893
      --  value is non-negative, then the free store has been initialized in
894
      --  the "normal" way: Container.Free points to the head of the list of
895
      --  free (inactive) nodes, and the value 0 means the free list is
896
      --  empty. Each node on the free list has been initialized to point to
897
      --  the next free node (via its Next component), and the value 0 means
898
      --  that this is the last node of the free list.
899
 
900
      --  If Container.Free is negative, then the links on the free store have
901
      --  not been initialized. In this case the link values are implied: the
902
      --  free store comprises the components of the node array started with
903
      --  the absolute value of Container.Free, and continuing until the end of
904
      --  the array (Nodes'Last).
905
 
906
      --  We prefer to lazy-init the free store (in fact, we would prefer to
907
      --  not initialize it at all, because such initialization is an O(n)
908
      --  operation). The time when we need to actually initialize the nodes in
909
      --  the free store is when the node that becomes inactive is not at the
910
      --  end of the active list. The free store would then be discontigous and
911
      --  so its nodes would need to be linked in the traditional way.
912
 
913
      --  It might be possible to perform an optimization here. Suppose that
914
      --  the free store can be represented as having two parts: one comprising
915
      --  the non-contiguous inactive nodes linked together in the normal way,
916
      --  and the other comprising the contiguous inactive nodes (that are not
917
      --  linked together, at the end of the nodes array). This would allow us
918
      --  to never have to initialize the free store, except in a lazy way as
919
      --  nodes become inactive. ???
920
 
921
      --  When an element is deleted from the list container, its node becomes
922
      --  inactive, and so we set its Parent and Prev components to an
923
      --  impossible value (the index of the node itself), to indicate that it
924
      --  is now inactive. This provides a useful way to detect a dangling
925
      --  cursor reference.
926
 
927
      N.Parent := X;  -- Node is deallocated (not on active list)
928
      N.Prev := X;
929
 
930
      if Container.Free >= 0 then
931
         --  The free store has previously been initialized. All we need to do
932
         --  here is link the newly-free'd node onto the free list.
933
 
934
         N.Next := Container.Free;
935
         Container.Free := X;
936
 
937
      elsif X + 1 = abs Container.Free then
938
         --  The free store has not been initialized, and the node becoming
939
         --  inactive immediately precedes the start of the free store. All
940
         --  we need to do is move the start of the free store back by one.
941
 
942
         N.Next := X;  -- Not strictly necessary, but marginally safer
943
         Container.Free := Container.Free + 1;
944
 
945
      else
946
         --  The free store has not been initialized, and the node becoming
947
         --  inactive does not immediately precede the free store. Here we
948
         --  first initialize the free store (meaning the links are given
949
         --  values in the traditional way), and then link the newly-free'd
950
         --  node onto the head of the free store.
951
 
952
         --  See the comments above for an optimization opportunity. If the
953
         --  next link for a node on the free store is negative, then this
954
         --  means the remaining nodes on the free store are physically
955
         --  contiguous, starting at the absolute value of that index value.
956
         --  ???
957
 
958
         Container.Free := abs Container.Free;
959
 
960
         if Container.Free > Container.Capacity then
961
            Container.Free := 0;
962
 
963
         else
964
            for J in Container.Free .. Container.Capacity - 1 loop
965
               NN (J).Next := J + 1;
966
            end loop;
967
 
968
            NN (Container.Capacity).Next := 0;
969
         end if;
970
 
971
         NN (X).Next := Container.Free;
972
         Container.Free := X;
973
      end if;
974
   end Deallocate_Node;
975
 
976
   ------------------------
977
   -- Deallocate_Subtree --
978
   ------------------------
979
 
980
   procedure Deallocate_Subtree
981
     (Container : in out Tree;
982
      Subtree   : Count_Type;
983
      Count     : in out Count_Type)
984
   is
985
   begin
986
      Deallocate_Children (Container, Subtree, Count);
987
      Deallocate_Node (Container, Subtree);
988
      Count := Count + 1;
989
   end Deallocate_Subtree;
990
 
991
   ---------------------
992
   -- Delete_Children --
993
   ---------------------
994
 
995
   procedure Delete_Children
996
     (Container : in out Tree;
997
      Parent    : Cursor)
998
   is
999
      Count : Count_Type;
1000
 
1001
   begin
1002
      if Parent = No_Element then
1003
         raise Constraint_Error with "Parent cursor has no element";
1004
      end if;
1005
 
1006
      if Parent.Container /= Container'Unrestricted_Access then
1007
         raise Program_Error with "Parent cursor not in container";
1008
      end if;
1009
 
1010
      if Container.Busy > 0 then
1011
         raise Program_Error
1012
           with "attempt to tamper with cursors (tree is busy)";
1013
      end if;
1014
 
1015
      if Container.Count = 0 then
1016
         pragma Assert (Is_Root (Parent));
1017
         return;
1018
      end if;
1019
 
1020
      --  Deallocate_Children returns a count of the number of nodes that it
1021
      --  deallocates, but it works by incrementing the value that is passed
1022
      --  in. We must therefore initialize the count value before calling
1023
      --  Deallocate_Children.
1024
 
1025
      Count := 0;
1026
 
1027
      Deallocate_Children (Container, Parent.Node, Count);
1028
      pragma Assert (Count <= Container.Count);
1029
 
1030
      Container.Count := Container.Count - Count;
1031
   end Delete_Children;
1032
 
1033
   -----------------
1034
   -- Delete_Leaf --
1035
   -----------------
1036
 
1037
   procedure Delete_Leaf
1038
     (Container : in out Tree;
1039
      Position  : in out Cursor)
1040
   is
1041
      X : Count_Type;
1042
 
1043
   begin
1044
      if Position = No_Element then
1045
         raise Constraint_Error with "Position cursor has no element";
1046
      end if;
1047
 
1048
      if Position.Container /= Container'Unrestricted_Access then
1049
         raise Program_Error with "Position cursor not in container";
1050
      end if;
1051
 
1052
      if Is_Root (Position) then
1053
         raise Program_Error with "Position cursor designates root";
1054
      end if;
1055
 
1056
      if not Is_Leaf (Position) then
1057
         raise Constraint_Error with "Position cursor does not designate leaf";
1058
      end if;
1059
 
1060
      if Container.Busy > 0 then
1061
         raise Program_Error
1062
           with "attempt to tamper with cursors (tree is busy)";
1063
      end if;
1064
 
1065
      X := Position.Node;
1066
      Position := No_Element;
1067
 
1068
      Remove_Subtree (Container, X);
1069
      Container.Count := Container.Count - 1;
1070
 
1071
      Deallocate_Node (Container, X);
1072
   end Delete_Leaf;
1073
 
1074
   --------------------
1075
   -- Delete_Subtree --
1076
   --------------------
1077
 
1078
   procedure Delete_Subtree
1079
     (Container : in out Tree;
1080
      Position  : in out Cursor)
1081
   is
1082
      X     : Count_Type;
1083
      Count : Count_Type;
1084
 
1085
   begin
1086
      if Position = No_Element then
1087
         raise Constraint_Error with "Position cursor has no element";
1088
      end if;
1089
 
1090
      if Position.Container /= Container'Unrestricted_Access then
1091
         raise Program_Error with "Position cursor not in container";
1092
      end if;
1093
 
1094
      if Is_Root (Position) then
1095
         raise Program_Error with "Position cursor designates root";
1096
      end if;
1097
 
1098
      if Container.Busy > 0 then
1099
         raise Program_Error
1100
           with "attempt to tamper with cursors (tree is busy)";
1101
      end if;
1102
 
1103
      X := Position.Node;
1104
      Position := No_Element;
1105
 
1106
      Remove_Subtree (Container, X);
1107
 
1108
      --  Deallocate_Subtree returns a count of the number of nodes that it
1109
      --  deallocates, but it works by incrementing the value that is passed
1110
      --  in. We must therefore initialize the count value before calling
1111
      --  Deallocate_Subtree.
1112
 
1113
      Count := 0;
1114
 
1115
      Deallocate_Subtree (Container, X, Count);
1116
      pragma Assert (Count <= Container.Count);
1117
 
1118
      Container.Count := Container.Count - Count;
1119
   end Delete_Subtree;
1120
 
1121
   -----------
1122
   -- Depth --
1123
   -----------
1124
 
1125
   function Depth (Position : Cursor) return Count_Type is
1126
      Result : Count_Type;
1127
      N      : Count_Type'Base;
1128
 
1129
   begin
1130
      if Position = No_Element then
1131
         return 0;
1132
      end if;
1133
 
1134
      if Is_Root (Position) then
1135
         return 1;
1136
      end if;
1137
 
1138
      Result := 0;
1139
      N := Position.Node;
1140
      while N >= 0 loop
1141
         N := Position.Container.Nodes (N).Parent;
1142
         Result := Result + 1;
1143
      end loop;
1144
 
1145
      return Result;
1146
   end Depth;
1147
 
1148
   -------------
1149
   -- Element --
1150
   -------------
1151
 
1152
   function Element (Position : Cursor) return Element_Type is
1153
   begin
1154
      if Position.Container = null then
1155
         raise Constraint_Error with "Position cursor has no element";
1156
      end if;
1157
 
1158
      if Position.Node = Root_Node (Position.Container.all) then
1159
         raise Program_Error with "Position cursor designates root";
1160
      end if;
1161
 
1162
      return Position.Container.Elements (Position.Node);
1163
   end Element;
1164
 
1165
   --------------------
1166
   -- Equal_Children --
1167
   --------------------
1168
 
1169
   function Equal_Children
1170
     (Left_Tree     : Tree;
1171
      Left_Subtree  : Count_Type;
1172
      Right_Tree    : Tree;
1173
      Right_Subtree : Count_Type) return Boolean
1174
   is
1175
      L_NN : Tree_Node_Array renames Left_Tree.Nodes;
1176
      R_NN : Tree_Node_Array renames Right_Tree.Nodes;
1177
 
1178
      Left_Children  : Children_Type renames L_NN (Left_Subtree).Children;
1179
      Right_Children : Children_Type renames R_NN (Right_Subtree).Children;
1180
 
1181
      L, R : Count_Type'Base;
1182
 
1183
   begin
1184
      if Child_Count (Left_Tree, Left_Subtree)
1185
        /= Child_Count (Right_Tree, Right_Subtree)
1186
      then
1187
         return False;
1188
      end if;
1189
 
1190
      L := Left_Children.First;
1191
      R := Right_Children.First;
1192
      while L > 0 loop
1193
         if not Equal_Subtree (Left_Tree, L, Right_Tree, R) then
1194
            return False;
1195
         end if;
1196
 
1197
         L := L_NN (L).Next;
1198
         R := R_NN (R).Next;
1199
      end loop;
1200
 
1201
      return True;
1202
   end Equal_Children;
1203
 
1204
   -------------------
1205
   -- Equal_Subtree --
1206
   -------------------
1207
 
1208
   function Equal_Subtree
1209
     (Left_Position  : Cursor;
1210
      Right_Position : Cursor) return Boolean
1211
   is
1212
   begin
1213
      if Left_Position = No_Element then
1214
         raise Constraint_Error with "Left cursor has no element";
1215
      end if;
1216
 
1217
      if Right_Position = No_Element then
1218
         raise Constraint_Error with "Right cursor has no element";
1219
      end if;
1220
 
1221
      if Left_Position = Right_Position then
1222
         return True;
1223
      end if;
1224
 
1225
      if Is_Root (Left_Position) then
1226
         if not Is_Root (Right_Position) then
1227
            return False;
1228
         end if;
1229
 
1230
         if Left_Position.Container.Count = 0 then
1231
            return Right_Position.Container.Count = 0;
1232
         end if;
1233
 
1234
         if Right_Position.Container.Count = 0 then
1235
            return False;
1236
         end if;
1237
 
1238
         return Equal_Children
1239
                  (Left_Tree     => Left_Position.Container.all,
1240
                   Left_Subtree  => Left_Position.Node,
1241
                   Right_Tree    => Right_Position.Container.all,
1242
                   Right_Subtree => Right_Position.Node);
1243
      end if;
1244
 
1245
      if Is_Root (Right_Position) then
1246
         return False;
1247
      end if;
1248
 
1249
      return Equal_Subtree
1250
               (Left_Tree     => Left_Position.Container.all,
1251
                Left_Subtree  => Left_Position.Node,
1252
                Right_Tree    => Right_Position.Container.all,
1253
                Right_Subtree => Right_Position.Node);
1254
   end Equal_Subtree;
1255
 
1256
   function Equal_Subtree
1257
     (Left_Tree     : Tree;
1258
      Left_Subtree  : Count_Type;
1259
      Right_Tree    : Tree;
1260
      Right_Subtree : Count_Type) return Boolean
1261
   is
1262
   begin
1263
      if Left_Tree.Elements  (Left_Subtree) /=
1264
         Right_Tree.Elements (Right_Subtree)
1265
      then
1266
         return False;
1267
      end if;
1268
 
1269
      return Equal_Children
1270
               (Left_Tree     => Left_Tree,
1271
                Left_Subtree  => Left_Subtree,
1272
                Right_Tree    => Right_Tree,
1273
                Right_Subtree => Right_Subtree);
1274
   end Equal_Subtree;
1275
 
1276
   --------------
1277
   -- Finalize --
1278
   --------------
1279
 
1280
   procedure Finalize (Object : in out Root_Iterator) is
1281
      B : Natural renames Object.Container.Busy;
1282
   begin
1283
      B := B - 1;
1284
   end Finalize;
1285
 
1286
   ----------
1287
   -- Find --
1288
   ----------
1289
 
1290
   function Find
1291
     (Container : Tree;
1292
      Item      : Element_Type) return Cursor
1293
   is
1294
      Node : Count_Type;
1295
 
1296
   begin
1297
      if Container.Count = 0 then
1298
         return No_Element;
1299
      end if;
1300
 
1301
      Node := Find_In_Children (Container, Root_Node (Container), Item);
1302
 
1303
      if Node = 0 then
1304
         return No_Element;
1305
      end if;
1306
 
1307
      return Cursor'(Container'Unrestricted_Access, Node);
1308
   end Find;
1309
 
1310
   -----------
1311
   -- First --
1312
   -----------
1313
 
1314
   overriding function First (Object : Subtree_Iterator) return Cursor is
1315
   begin
1316
      if Object.Subtree = Root_Node (Object.Container.all) then
1317
         return First_Child (Root (Object.Container.all));
1318
      else
1319
         return Cursor'(Object.Container, Object.Subtree);
1320
      end if;
1321
   end First;
1322
 
1323
   overriding function First (Object : Child_Iterator) return Cursor is
1324
   begin
1325
      return First_Child (Cursor'(Object.Container, Object.Subtree));
1326
   end First;
1327
 
1328
   -----------------
1329
   -- First_Child --
1330
   -----------------
1331
 
1332
   function First_Child (Parent : Cursor) return Cursor is
1333
      Node : Count_Type'Base;
1334
 
1335
   begin
1336
      if Parent = No_Element then
1337
         raise Constraint_Error with "Parent cursor has no element";
1338
      end if;
1339
 
1340
      if Parent.Container.Count = 0 then
1341
         pragma Assert (Is_Root (Parent));
1342
         return No_Element;
1343
      end if;
1344
 
1345
      Node := Parent.Container.Nodes (Parent.Node).Children.First;
1346
 
1347
      if Node <= 0 then
1348
         return No_Element;
1349
      end if;
1350
 
1351
      return Cursor'(Parent.Container, Node);
1352
   end First_Child;
1353
 
1354
   -------------------------
1355
   -- First_Child_Element --
1356
   -------------------------
1357
 
1358
   function First_Child_Element (Parent : Cursor) return Element_Type is
1359
   begin
1360
      return Element (First_Child (Parent));
1361
   end First_Child_Element;
1362
 
1363
   ----------------------
1364
   -- Find_In_Children --
1365
   ----------------------
1366
 
1367
   function Find_In_Children
1368
     (Container : Tree;
1369
      Subtree   : Count_Type;
1370
      Item      : Element_Type) return Count_Type
1371
   is
1372
      N      : Count_Type'Base;
1373
      Result : Count_Type;
1374
 
1375
   begin
1376
      N := Container.Nodes (Subtree).Children.First;
1377
      while N > 0 loop
1378
         Result := Find_In_Subtree (Container, N, Item);
1379
 
1380
         if Result > 0 then
1381
            return Result;
1382
         end if;
1383
 
1384
         N := Container.Nodes (N).Next;
1385
      end loop;
1386
 
1387
      return 0;
1388
   end Find_In_Children;
1389
 
1390
   ---------------------
1391
   -- Find_In_Subtree --
1392
   ---------------------
1393
 
1394
   function Find_In_Subtree
1395
     (Position : Cursor;
1396
      Item     : Element_Type) return Cursor
1397
   is
1398
      Result : Count_Type;
1399
 
1400
   begin
1401
      if Position = No_Element then
1402
         raise Constraint_Error with "Position cursor has no element";
1403
      end if;
1404
 
1405
      --  Commented-out pending ruling by ARG.  ???
1406
 
1407
      --  if Position.Container /= Container'Unrestricted_Access then
1408
      --     raise Program_Error with "Position cursor not in container";
1409
      --  end if;
1410
 
1411
      if Position.Container.Count = 0 then
1412
         pragma Assert (Is_Root (Position));
1413
         return No_Element;
1414
      end if;
1415
 
1416
      if Is_Root (Position) then
1417
         Result := Find_In_Children
1418
                     (Container => Position.Container.all,
1419
                      Subtree   => Position.Node,
1420
                      Item      => Item);
1421
 
1422
      else
1423
         Result := Find_In_Subtree
1424
                     (Container => Position.Container.all,
1425
                      Subtree   => Position.Node,
1426
                      Item      => Item);
1427
      end if;
1428
 
1429
      if Result = 0 then
1430
         return No_Element;
1431
      end if;
1432
 
1433
      return Cursor'(Position.Container, Result);
1434
   end Find_In_Subtree;
1435
 
1436
   function Find_In_Subtree
1437
     (Container : Tree;
1438
      Subtree   : Count_Type;
1439
      Item      : Element_Type) return Count_Type
1440
   is
1441
   begin
1442
      if Container.Elements (Subtree) = Item then
1443
         return Subtree;
1444
      end if;
1445
 
1446
      return Find_In_Children (Container, Subtree, Item);
1447
   end Find_In_Subtree;
1448
 
1449
   -----------------
1450
   -- Has_Element --
1451
   -----------------
1452
 
1453
   function Has_Element (Position : Cursor) return Boolean is
1454
   begin
1455
      if Position = No_Element then
1456
         return False;
1457
      end if;
1458
 
1459
      return Position.Node /= Root_Node (Position.Container.all);
1460
   end Has_Element;
1461
 
1462
   ---------------------
1463
   -- Initialize_Node --
1464
   ---------------------
1465
 
1466
   procedure Initialize_Node
1467
     (Container : in out Tree;
1468
      Index     : Count_Type)
1469
   is
1470
   begin
1471
      Container.Nodes (Index) :=
1472
        (Parent   => No_Node,
1473
         Prev     => 0,
1474
         Next     => 0,
1475
         Children => (others => 0));
1476
   end Initialize_Node;
1477
 
1478
   ---------------------
1479
   -- Initialize_Root --
1480
   ---------------------
1481
 
1482
   procedure Initialize_Root (Container : in out Tree) is
1483
   begin
1484
      Initialize_Node (Container, Root_Node (Container));
1485
   end Initialize_Root;
1486
 
1487
   ------------------
1488
   -- Insert_Child --
1489
   ------------------
1490
 
1491
   procedure Insert_Child
1492
     (Container : in out Tree;
1493
      Parent    : Cursor;
1494
      Before    : Cursor;
1495
      New_Item  : Element_Type;
1496
      Count     : Count_Type := 1)
1497
   is
1498
      Position : Cursor;
1499
      pragma Unreferenced (Position);
1500
 
1501
   begin
1502
      Insert_Child (Container, Parent, Before, New_Item, Position, Count);
1503
   end Insert_Child;
1504
 
1505
   procedure Insert_Child
1506
     (Container : in out Tree;
1507
      Parent    : Cursor;
1508
      Before    : Cursor;
1509
      New_Item  : Element_Type;
1510
      Position  : out Cursor;
1511
      Count     : Count_Type := 1)
1512
   is
1513
      Nodes : Tree_Node_Array renames Container.Nodes;
1514
      Last  : Count_Type;
1515
 
1516
   begin
1517
      if Parent = No_Element then
1518
         raise Constraint_Error with "Parent cursor has no element";
1519
      end if;
1520
 
1521
      if Parent.Container /= Container'Unrestricted_Access then
1522
         raise Program_Error with "Parent cursor not in container";
1523
      end if;
1524
 
1525
      if Before /= No_Element then
1526
         if Before.Container /= Container'Unrestricted_Access then
1527
            raise Program_Error with "Before cursor not in container";
1528
         end if;
1529
 
1530
         if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1531
            raise Constraint_Error with "Parent cursor not parent of Before";
1532
         end if;
1533
      end if;
1534
 
1535
      if Count = 0 then
1536
         Position := No_Element;  -- Need ruling from ARG ???
1537
         return;
1538
      end if;
1539
 
1540
      if Container.Count > Container.Capacity - Count then
1541
         raise Constraint_Error
1542
           with "requested count exceeds available storage";
1543
      end if;
1544
 
1545
      if Container.Busy > 0 then
1546
         raise Program_Error
1547
           with "attempt to tamper with cursors (tree is busy)";
1548
      end if;
1549
 
1550
      if Container.Count = 0 then
1551
         Initialize_Root (Container);
1552
      end if;
1553
 
1554
      Allocate_Node (Container, New_Item, Position.Node);
1555
      Nodes (Position.Node).Parent := Parent.Node;
1556
 
1557
      Last := Position.Node;
1558
      for J in Count_Type'(2) .. Count loop
1559
         Allocate_Node (Container, New_Item, Nodes (Last).Next);
1560
         Nodes (Nodes (Last).Next).Parent := Parent.Node;
1561
         Nodes (Nodes (Last).Next).Prev := Last;
1562
 
1563
         Last := Nodes (Last).Next;
1564
      end loop;
1565
 
1566
      Insert_Subtree_List
1567
        (Container => Container,
1568
         First     => Position.Node,
1569
         Last      => Last,
1570
         Parent    => Parent.Node,
1571
         Before    => Before.Node);
1572
 
1573
      Container.Count := Container.Count + Count;
1574
 
1575
      Position.Container := Parent.Container;
1576
   end Insert_Child;
1577
 
1578
   procedure Insert_Child
1579
     (Container : in out Tree;
1580
      Parent    : Cursor;
1581
      Before    : Cursor;
1582
      Position  : out Cursor;
1583
      Count     : Count_Type := 1)
1584
   is
1585
      Nodes : Tree_Node_Array renames Container.Nodes;
1586
      Last  : Count_Type;
1587
 
1588
   begin
1589
      if Parent = No_Element then
1590
         raise Constraint_Error with "Parent cursor has no element";
1591
      end if;
1592
 
1593
      if Parent.Container /= Container'Unrestricted_Access then
1594
         raise Program_Error with "Parent cursor not in container";
1595
      end if;
1596
 
1597
      if Before /= No_Element then
1598
         if Before.Container /= Container'Unrestricted_Access then
1599
            raise Program_Error with "Before cursor not in container";
1600
         end if;
1601
 
1602
         if Before.Container.Nodes (Before.Node).Parent /= Parent.Node then
1603
            raise Constraint_Error with "Parent cursor not parent of Before";
1604
         end if;
1605
      end if;
1606
 
1607
      if Count = 0 then
1608
         Position := No_Element;  -- Need ruling from ARG  ???
1609
         return;
1610
      end if;
1611
 
1612
      if Container.Count > Container.Capacity - Count then
1613
         raise Constraint_Error
1614
           with "requested count exceeds available storage";
1615
      end if;
1616
 
1617
      if Container.Busy > 0 then
1618
         raise Program_Error
1619
           with "attempt to tamper with cursors (tree is busy)";
1620
      end if;
1621
 
1622
      if Container.Count = 0 then
1623
         Initialize_Root (Container);
1624
      end if;
1625
 
1626
      Allocate_Node (Container, Position.Node);
1627
      Nodes (Position.Node).Parent := Parent.Node;
1628
 
1629
      Last := Position.Node;
1630
      for J in Count_Type'(2) .. Count loop
1631
         Allocate_Node (Container, Nodes (Last).Next);
1632
         Nodes (Nodes (Last).Next).Parent := Parent.Node;
1633
         Nodes (Nodes (Last).Next).Prev := Last;
1634
 
1635
         Last := Nodes (Last).Next;
1636
      end loop;
1637
 
1638
      Insert_Subtree_List
1639
        (Container => Container,
1640
         First     => Position.Node,
1641
         Last      => Last,
1642
         Parent    => Parent.Node,
1643
         Before    => Before.Node);
1644
 
1645
      Container.Count := Container.Count + Count;
1646
 
1647
      Position.Container := Parent.Container;
1648
   end Insert_Child;
1649
 
1650
   -------------------------
1651
   -- Insert_Subtree_List --
1652
   -------------------------
1653
 
1654
   procedure Insert_Subtree_List
1655
     (Container : in out Tree;
1656
      First     : Count_Type'Base;
1657
      Last      : Count_Type'Base;
1658
      Parent    : Count_Type;
1659
      Before    : Count_Type'Base)
1660
   is
1661
      NN : Tree_Node_Array renames Container.Nodes;
1662
      N  : Tree_Node_Type renames NN (Parent);
1663
      CC : Children_Type renames N.Children;
1664
 
1665
   begin
1666
      --  This is a simple utility operation to insert a list of nodes
1667
      --  (First..Last) as children of Parent. The Before node specifies where
1668
      --  the new children should be inserted relative to existing children.
1669
 
1670
      if First <= 0 then
1671
         pragma Assert (Last <= 0);
1672
         return;
1673
      end if;
1674
 
1675
      pragma Assert (Last > 0);
1676
      pragma Assert (Before <= 0 or else NN (Before).Parent = Parent);
1677
 
1678
      if CC.First <= 0 then  -- no existing children
1679
         CC.First := First;
1680
         NN (CC.First).Prev := 0;
1681
         CC.Last := Last;
1682
         NN (CC.Last).Next := 0;
1683
 
1684
      elsif Before <= 0 then  -- means "insert after existing nodes"
1685
         NN (CC.Last).Next := First;
1686
         NN (First).Prev := CC.Last;
1687
         CC.Last := Last;
1688
         NN (CC.Last).Next := 0;
1689
 
1690
      elsif Before = CC.First then
1691
         NN (Last).Next := CC.First;
1692
         NN (CC.First).Prev := Last;
1693
         CC.First := First;
1694
         NN (CC.First).Prev := 0;
1695
 
1696
      else
1697
         NN (NN (Before).Prev).Next := First;
1698
         NN (First).Prev := NN (Before).Prev;
1699
         NN (Last).Next := Before;
1700
         NN (Before).Prev := Last;
1701
      end if;
1702
   end Insert_Subtree_List;
1703
 
1704
   -------------------------
1705
   -- Insert_Subtree_Node --
1706
   -------------------------
1707
 
1708
   procedure Insert_Subtree_Node
1709
     (Container : in out Tree;
1710
      Subtree   : Count_Type'Base;
1711
      Parent    : Count_Type;
1712
      Before    : Count_Type'Base)
1713
   is
1714
   begin
1715
      --  This is a simple wrapper operation to insert a single child into the
1716
      --  Parent's children list.
1717
 
1718
      Insert_Subtree_List
1719
        (Container => Container,
1720
         First     => Subtree,
1721
         Last      => Subtree,
1722
         Parent    => Parent,
1723
         Before    => Before);
1724
   end Insert_Subtree_Node;
1725
 
1726
   --------------
1727
   -- Is_Empty --
1728
   --------------
1729
 
1730
   function Is_Empty (Container : Tree) return Boolean is
1731
   begin
1732
      return Container.Count = 0;
1733
   end Is_Empty;
1734
 
1735
   -------------
1736
   -- Is_Leaf --
1737
   -------------
1738
 
1739
   function Is_Leaf (Position : Cursor) return Boolean is
1740
   begin
1741
      if Position = No_Element then
1742
         return False;
1743
      end if;
1744
 
1745
      if Position.Container.Count = 0 then
1746
         pragma Assert (Is_Root (Position));
1747
         return True;
1748
      end if;
1749
 
1750
      return Position.Container.Nodes (Position.Node).Children.First <= 0;
1751
   end Is_Leaf;
1752
 
1753
   ------------------
1754
   -- Is_Reachable --
1755
   ------------------
1756
 
1757
   function Is_Reachable
1758
     (Container : Tree;
1759
      From, To  : Count_Type) return Boolean
1760
   is
1761
      Idx : Count_Type;
1762
 
1763
   begin
1764
      Idx := From;
1765
      while Idx >= 0 loop
1766
         if Idx = To then
1767
            return True;
1768
         end if;
1769
 
1770
         Idx := Container.Nodes (Idx).Parent;
1771
      end loop;
1772
 
1773
      return False;
1774
   end Is_Reachable;
1775
 
1776
   -------------
1777
   -- Is_Root --
1778
   -------------
1779
 
1780
   function Is_Root (Position : Cursor) return Boolean is
1781
   begin
1782
      return
1783
        (if Position.Container = null then False
1784
         else Position.Node = Root_Node (Position.Container.all));
1785
   end Is_Root;
1786
 
1787
   -------------
1788
   -- Iterate --
1789
   -------------
1790
 
1791
   procedure Iterate
1792
     (Container : Tree;
1793
      Process   : not null access procedure (Position : Cursor))
1794
   is
1795
      B : Natural renames Container'Unrestricted_Access.all.Busy;
1796
 
1797
   begin
1798
      if Container.Count = 0 then
1799
         return;
1800
      end if;
1801
 
1802
      B := B + 1;
1803
 
1804
      Iterate_Children
1805
        (Container => Container,
1806
         Subtree   => Root_Node (Container),
1807
         Process   => Process);
1808
 
1809
      B := B - 1;
1810
 
1811
   exception
1812
      when others =>
1813
         B := B - 1;
1814
         raise;
1815
   end Iterate;
1816
 
1817
   function Iterate (Container : Tree)
1818
     return Tree_Iterator_Interfaces.Forward_Iterator'Class
1819
   is
1820
   begin
1821
      return Iterate_Subtree (Root (Container));
1822
   end Iterate;
1823
 
1824
   ----------------------
1825
   -- Iterate_Children --
1826
   ----------------------
1827
 
1828
   procedure Iterate_Children
1829
     (Parent  : Cursor;
1830
      Process : not null access procedure (Position : Cursor))
1831
   is
1832
   begin
1833
      if Parent = No_Element then
1834
         raise Constraint_Error with "Parent cursor has no element";
1835
      end if;
1836
 
1837
      if Parent.Container.Count = 0 then
1838
         pragma Assert (Is_Root (Parent));
1839
         return;
1840
      end if;
1841
 
1842
      declare
1843
         B  : Natural renames Parent.Container.Busy;
1844
         C  : Count_Type;
1845
         NN : Tree_Node_Array renames Parent.Container.Nodes;
1846
 
1847
      begin
1848
         B := B + 1;
1849
 
1850
         C := NN (Parent.Node).Children.First;
1851
         while C > 0 loop
1852
            Process (Cursor'(Parent.Container, Node => C));
1853
            C := NN (C).Next;
1854
         end loop;
1855
 
1856
         B := B - 1;
1857
 
1858
      exception
1859
         when others =>
1860
            B := B - 1;
1861
            raise;
1862
      end;
1863
   end Iterate_Children;
1864
 
1865
   procedure Iterate_Children
1866
     (Container : Tree;
1867
      Subtree   : Count_Type;
1868
      Process   : not null access procedure (Position : Cursor))
1869
   is
1870
      NN : Tree_Node_Array renames Container.Nodes;
1871
      N  : Tree_Node_Type renames NN (Subtree);
1872
      C  : Count_Type;
1873
 
1874
   begin
1875
      --  This is a helper function to recursively iterate over all the nodes
1876
      --  in a subtree, in depth-first fashion. This particular helper just
1877
      --  visits the children of this subtree, not the root of the subtree
1878
      --  itself. This is useful when starting from the ultimate root of the
1879
      --  entire tree (see Iterate), as that root does not have an element.
1880
 
1881
      C := N.Children.First;
1882
      while C > 0 loop
1883
         Iterate_Subtree (Container, C, Process);
1884
         C := NN (C).Next;
1885
      end loop;
1886
   end Iterate_Children;
1887
 
1888
   function Iterate_Children
1889
     (Container : Tree;
1890
      Parent    : Cursor)
1891
      return Tree_Iterator_Interfaces.Reversible_Iterator'Class
1892
   is
1893
      C : constant Tree_Access := Container'Unrestricted_Access;
1894
      B : Natural renames C.Busy;
1895
 
1896
   begin
1897
      if Parent = No_Element then
1898
         raise Constraint_Error with "Parent cursor has no element";
1899
      end if;
1900
 
1901
      if Parent.Container /= C then
1902
         raise Program_Error with "Parent cursor not in container";
1903
      end if;
1904
 
1905
      return It : constant Child_Iterator :=
1906
                    Child_Iterator'(Limited_Controlled with
1907
                                      Container => C,
1908
                                      Subtree   => Parent.Node)
1909
      do
1910
         B := B + 1;
1911
      end return;
1912
   end Iterate_Children;
1913
 
1914
   ---------------------
1915
   -- Iterate_Subtree --
1916
   ---------------------
1917
 
1918
   function Iterate_Subtree
1919
     (Position : Cursor)
1920
      return Tree_Iterator_Interfaces.Forward_Iterator'Class
1921
   is
1922
   begin
1923
      if Position = No_Element then
1924
         raise Constraint_Error with "Position cursor has no element";
1925
      end if;
1926
 
1927
      --  Implement Vet for multiway trees???
1928
      --  pragma Assert (Vet (Position), "bad subtree cursor");
1929
 
1930
      declare
1931
         B : Natural renames Position.Container.Busy;
1932
      begin
1933
         return It : constant Subtree_Iterator :=
1934
                       (Limited_Controlled with
1935
                          Container => Position.Container,
1936
                          Subtree   => Position.Node)
1937
         do
1938
            B := B + 1;
1939
         end return;
1940
      end;
1941
   end Iterate_Subtree;
1942
 
1943
   procedure Iterate_Subtree
1944
     (Position  : Cursor;
1945
      Process   : not null access procedure (Position : Cursor))
1946
   is
1947
   begin
1948
      if Position = No_Element then
1949
         raise Constraint_Error with "Position cursor has no element";
1950
      end if;
1951
 
1952
      if Position.Container.Count = 0 then
1953
         pragma Assert (Is_Root (Position));
1954
         return;
1955
      end if;
1956
 
1957
      declare
1958
         T : Tree renames Position.Container.all;
1959
         B : Natural renames T.Busy;
1960
 
1961
      begin
1962
         B := B + 1;
1963
 
1964
         if Is_Root (Position) then
1965
            Iterate_Children (T, Position.Node, Process);
1966
         else
1967
            Iterate_Subtree (T, Position.Node, Process);
1968
         end if;
1969
 
1970
         B := B - 1;
1971
 
1972
      exception
1973
         when others =>
1974
            B := B - 1;
1975
            raise;
1976
      end;
1977
   end Iterate_Subtree;
1978
 
1979
   procedure Iterate_Subtree
1980
     (Container : Tree;
1981
      Subtree   : Count_Type;
1982
      Process   : not null access procedure (Position : Cursor))
1983
   is
1984
   begin
1985
      --  This is a helper function to recursively iterate over all the nodes
1986
      --  in a subtree, in depth-first fashion. It first visits the root of the
1987
      --  subtree, then visits its children.
1988
 
1989
      Process (Cursor'(Container'Unrestricted_Access, Subtree));
1990
      Iterate_Children (Container, Subtree, Process);
1991
   end Iterate_Subtree;
1992
 
1993
   ----------
1994
   -- Last --
1995
   ----------
1996
 
1997
   overriding function Last (Object : Child_Iterator) return Cursor is
1998
   begin
1999
      return Last_Child (Cursor'(Object.Container, Object.Subtree));
2000
   end Last;
2001
 
2002
   ----------------
2003
   -- Last_Child --
2004
   ----------------
2005
 
2006
   function Last_Child (Parent : Cursor) return Cursor is
2007
      Node : Count_Type'Base;
2008
 
2009
   begin
2010
      if Parent = No_Element then
2011
         raise Constraint_Error with "Parent cursor has no element";
2012
      end if;
2013
 
2014
      if Parent.Container.Count = 0 then
2015
         pragma Assert (Is_Root (Parent));
2016
         return No_Element;
2017
      end if;
2018
 
2019
      Node := Parent.Container.Nodes (Parent.Node).Children.Last;
2020
 
2021
      if Node <= 0 then
2022
         return No_Element;
2023
      end if;
2024
 
2025
      return Cursor'(Parent.Container, Node);
2026
   end Last_Child;
2027
 
2028
   ------------------------
2029
   -- Last_Child_Element --
2030
   ------------------------
2031
 
2032
   function Last_Child_Element (Parent : Cursor) return Element_Type is
2033
   begin
2034
      return Element (Last_Child (Parent));
2035
   end Last_Child_Element;
2036
 
2037
   ----------
2038
   -- Move --
2039
   ----------
2040
 
2041
   procedure Move (Target : in out Tree; Source : in out Tree) is
2042
   begin
2043
      if Target'Address = Source'Address then
2044
         return;
2045
      end if;
2046
 
2047
      if Source.Busy > 0 then
2048
         raise Program_Error
2049
           with "attempt to tamper with cursors of Source (tree is busy)";
2050
      end if;
2051
 
2052
      Target.Assign (Source);
2053
      Source.Clear;
2054
   end Move;
2055
 
2056
   ----------
2057
   -- Next --
2058
   ----------
2059
 
2060
   overriding function Next
2061
     (Object   : Subtree_Iterator;
2062
      Position : Cursor) return Cursor
2063
   is
2064
   begin
2065
      if Position.Container = null then
2066
         return No_Element;
2067
      end if;
2068
 
2069
      if Position.Container /= Object.Container then
2070
         raise Program_Error with
2071
           "Position cursor of Next designates wrong tree";
2072
      end if;
2073
 
2074
      pragma Assert (Object.Container.Count > 0);
2075
      pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2076
 
2077
      declare
2078
         Nodes : Tree_Node_Array renames Object.Container.Nodes;
2079
         Node  : Count_Type;
2080
 
2081
      begin
2082
         Node := Position.Node;
2083
 
2084
         if Nodes (Node).Children.First > 0 then
2085
            return Cursor'(Object.Container, Nodes (Node).Children.First);
2086
         end if;
2087
 
2088
         while Node /= Object.Subtree loop
2089
            if Nodes (Node).Next > 0 then
2090
               return Cursor'(Object.Container, Nodes (Node).Next);
2091
            end if;
2092
 
2093
            Node := Nodes (Node).Parent;
2094
         end loop;
2095
 
2096
         return No_Element;
2097
      end;
2098
   end Next;
2099
 
2100
   overriding function Next
2101
     (Object   : Child_Iterator;
2102
      Position : Cursor) return Cursor
2103
   is
2104
   begin
2105
      if Position.Container = null then
2106
         return No_Element;
2107
      end if;
2108
 
2109
      if Position.Container /= Object.Container then
2110
         raise Program_Error with
2111
           "Position cursor of Next designates wrong tree";
2112
      end if;
2113
 
2114
      pragma Assert (Object.Container.Count > 0);
2115
      pragma Assert (Position.Node /= Root_Node (Object.Container.all));
2116
 
2117
      return Next_Sibling (Position);
2118
   end Next;
2119
 
2120
   ------------------
2121
   -- Next_Sibling --
2122
   ------------------
2123
 
2124
   function Next_Sibling (Position : Cursor) return Cursor is
2125
   begin
2126
      if Position = No_Element then
2127
         return No_Element;
2128
      end if;
2129
 
2130
      if Position.Container.Count = 0 then
2131
         pragma Assert (Is_Root (Position));
2132
         return No_Element;
2133
      end if;
2134
 
2135
      declare
2136
         T  : Tree renames Position.Container.all;
2137
         NN : Tree_Node_Array renames T.Nodes;
2138
         N  : Tree_Node_Type renames NN (Position.Node);
2139
 
2140
      begin
2141
         if N.Next <= 0 then
2142
            return No_Element;
2143
         end if;
2144
 
2145
         return Cursor'(Position.Container, N.Next);
2146
      end;
2147
   end Next_Sibling;
2148
 
2149
   procedure Next_Sibling (Position : in out Cursor) is
2150
   begin
2151
      Position := Next_Sibling (Position);
2152
   end Next_Sibling;
2153
 
2154
   ----------------
2155
   -- Node_Count --
2156
   ----------------
2157
 
2158
   function Node_Count (Container : Tree) return Count_Type is
2159
   begin
2160
      --  Container.Count is the number of nodes we have actually allocated. We
2161
      --  cache the value specifically so this Node_Count operation can execute
2162
      --  in O(1) time, which makes it behave similarly to how the Length
2163
      --  selector function behaves for other containers.
2164
      --
2165
      --  The cached node count value only describes the nodes we have
2166
      --  allocated; the root node itself is not included in that count. The
2167
      --  Node_Count operation returns a value that includes the root node
2168
      --  (because the RM says so), so we must add 1 to our cached value.
2169
 
2170
      return 1 + Container.Count;
2171
   end Node_Count;
2172
 
2173
   ------------
2174
   -- Parent --
2175
   ------------
2176
 
2177
   function Parent (Position : Cursor) return Cursor is
2178
   begin
2179
      if Position = No_Element then
2180
         return No_Element;
2181
      end if;
2182
 
2183
      if Position.Container.Count = 0 then
2184
         pragma Assert (Is_Root (Position));
2185
         return No_Element;
2186
      end if;
2187
 
2188
      declare
2189
         T  : Tree renames Position.Container.all;
2190
         NN : Tree_Node_Array renames T.Nodes;
2191
         N  : Tree_Node_Type renames NN (Position.Node);
2192
 
2193
      begin
2194
         if N.Parent < 0 then
2195
            pragma Assert (Position.Node = Root_Node (T));
2196
            return No_Element;
2197
         end if;
2198
 
2199
         return Cursor'(Position.Container, N.Parent);
2200
      end;
2201
   end Parent;
2202
 
2203
   -------------------
2204
   -- Prepend_Child --
2205
   -------------------
2206
 
2207
   procedure Prepend_Child
2208
     (Container : in out Tree;
2209
      Parent    : Cursor;
2210
      New_Item  : Element_Type;
2211
      Count     : Count_Type := 1)
2212
   is
2213
      Nodes       : Tree_Node_Array renames Container.Nodes;
2214
      First, Last : Count_Type;
2215
 
2216
   begin
2217
      if Parent = No_Element then
2218
         raise Constraint_Error with "Parent cursor has no element";
2219
      end if;
2220
 
2221
      if Parent.Container /= Container'Unrestricted_Access then
2222
         raise Program_Error with "Parent cursor not in container";
2223
      end if;
2224
 
2225
      if Count = 0 then
2226
         return;
2227
      end if;
2228
 
2229
      if Container.Count > Container.Capacity - Count then
2230
         raise Constraint_Error
2231
           with "requested count exceeds available storage";
2232
      end if;
2233
 
2234
      if Container.Busy > 0 then
2235
         raise Program_Error
2236
           with "attempt to tamper with cursors (tree is busy)";
2237
      end if;
2238
 
2239
      if Container.Count = 0 then
2240
         Initialize_Root (Container);
2241
      end if;
2242
 
2243
      Allocate_Node (Container, New_Item, First);
2244
      Nodes (First).Parent := Parent.Node;
2245
 
2246
      Last := First;
2247
      for J in Count_Type'(2) .. Count loop
2248
         Allocate_Node (Container, New_Item, Nodes (Last).Next);
2249
         Nodes (Nodes (Last).Next).Parent := Parent.Node;
2250
         Nodes (Nodes (Last).Next).Prev := Last;
2251
 
2252
         Last := Nodes (Last).Next;
2253
      end loop;
2254
 
2255
      Insert_Subtree_List
2256
        (Container => Container,
2257
         First     => First,
2258
         Last      => Last,
2259
         Parent    => Parent.Node,
2260
         Before    => Nodes (Parent.Node).Children.First);
2261
 
2262
      Container.Count := Container.Count + Count;
2263
   end Prepend_Child;
2264
 
2265
   --------------
2266
   -- Previous --
2267
   --------------
2268
 
2269
   overriding function Previous
2270
     (Object   : Child_Iterator;
2271
      Position : Cursor) return Cursor
2272
   is
2273
   begin
2274
      if Position.Container = null then
2275
         return No_Element;
2276
      end if;
2277
 
2278
      if Position.Container /= Object.Container then
2279
         raise Program_Error with
2280
           "Position cursor of Previous designates wrong tree";
2281
      end if;
2282
 
2283
      return Previous_Sibling (Position);
2284
   end Previous;
2285
 
2286
   ----------------------
2287
   -- Previous_Sibling --
2288
   ----------------------
2289
 
2290
   function Previous_Sibling (Position : Cursor) return Cursor is
2291
   begin
2292
      if Position = No_Element then
2293
         return No_Element;
2294
      end if;
2295
 
2296
      if Position.Container.Count = 0 then
2297
         pragma Assert (Is_Root (Position));
2298
         return No_Element;
2299
      end if;
2300
 
2301
      declare
2302
         T  : Tree renames Position.Container.all;
2303
         NN : Tree_Node_Array renames T.Nodes;
2304
         N  : Tree_Node_Type renames NN (Position.Node);
2305
 
2306
      begin
2307
         if N.Prev <= 0 then
2308
            return No_Element;
2309
         end if;
2310
 
2311
         return Cursor'(Position.Container, N.Prev);
2312
      end;
2313
   end Previous_Sibling;
2314
 
2315
   procedure Previous_Sibling (Position : in out Cursor) is
2316
   begin
2317
      Position := Previous_Sibling (Position);
2318
   end Previous_Sibling;
2319
 
2320
   -------------------
2321
   -- Query_Element --
2322
   -------------------
2323
 
2324
   procedure Query_Element
2325
     (Position : Cursor;
2326
      Process  : not null access procedure (Element : Element_Type))
2327
   is
2328
   begin
2329
      if Position = No_Element then
2330
         raise Constraint_Error with "Position cursor has no element";
2331
      end if;
2332
 
2333
      if Is_Root (Position) then
2334
         raise Program_Error with "Position cursor designates root";
2335
      end if;
2336
 
2337
      declare
2338
         T : Tree renames Position.Container.all'Unrestricted_Access.all;
2339
         B : Natural renames T.Busy;
2340
         L : Natural renames T.Lock;
2341
 
2342
      begin
2343
         B := B + 1;
2344
         L := L + 1;
2345
 
2346
         Process (Element => T.Elements (Position.Node));
2347
 
2348
         L := L - 1;
2349
         B := B - 1;
2350
 
2351
      exception
2352
         when others =>
2353
            L := L - 1;
2354
            B := B - 1;
2355
            raise;
2356
      end;
2357
   end Query_Element;
2358
 
2359
   ----------
2360
   -- Read --
2361
   ----------
2362
 
2363
   procedure Read
2364
     (Stream    : not null access Root_Stream_Type'Class;
2365
      Container : out Tree)
2366
   is
2367
      procedure Read_Children (Subtree : Count_Type);
2368
 
2369
      function Read_Subtree
2370
        (Parent : Count_Type) return Count_Type;
2371
 
2372
      NN : Tree_Node_Array renames Container.Nodes;
2373
 
2374
      Total_Count : Count_Type'Base;
2375
      --  Value read from the stream that says how many elements follow
2376
 
2377
      Read_Count : Count_Type'Base;
2378
      --  Actual number of elements read from the stream
2379
 
2380
      -------------------
2381
      -- Read_Children --
2382
      -------------------
2383
 
2384
      procedure Read_Children (Subtree : Count_Type) is
2385
         Count : Count_Type'Base;
2386
         --  number of child subtrees
2387
 
2388
         CC : Children_Type;
2389
 
2390
      begin
2391
         Count_Type'Read (Stream, Count);
2392
 
2393
         if Count < 0 then
2394
            raise Program_Error with "attempt to read from corrupt stream";
2395
         end if;
2396
 
2397
         if Count = 0 then
2398
            return;
2399
         end if;
2400
 
2401
         CC.First := Read_Subtree (Parent => Subtree);
2402
         CC.Last := CC.First;
2403
 
2404
         for J in Count_Type'(2) .. Count loop
2405
            NN (CC.Last).Next := Read_Subtree (Parent => Subtree);
2406
            NN (NN (CC.Last).Next).Prev := CC.Last;
2407
            CC.Last := NN (CC.Last).Next;
2408
         end loop;
2409
 
2410
         --  Now that the allocation and reads have completed successfully, it
2411
         --  is safe to link the children to their parent.
2412
 
2413
         NN (Subtree).Children := CC;
2414
      end Read_Children;
2415
 
2416
      ------------------
2417
      -- Read_Subtree --
2418
      ------------------
2419
 
2420
      function Read_Subtree
2421
        (Parent : Count_Type) return Count_Type
2422
      is
2423
         Subtree : Count_Type;
2424
 
2425
      begin
2426
         Allocate_Node (Container, Stream, Subtree);
2427
         Container.Nodes (Subtree).Parent := Parent;
2428
 
2429
         Read_Count := Read_Count + 1;
2430
 
2431
         Read_Children (Subtree);
2432
 
2433
         return Subtree;
2434
      end Read_Subtree;
2435
 
2436
   --  Start of processing for Read
2437
 
2438
   begin
2439
      Container.Clear;  -- checks busy bit
2440
 
2441
      Count_Type'Read (Stream, Total_Count);
2442
 
2443
      if Total_Count < 0 then
2444
         raise Program_Error with "attempt to read from corrupt stream";
2445
      end if;
2446
 
2447
      if Total_Count = 0 then
2448
         return;
2449
      end if;
2450
 
2451
      if Total_Count > Container.Capacity then
2452
         raise Capacity_Error  -- ???
2453
           with "node count in stream exceeds container capacity";
2454
      end if;
2455
 
2456
      Initialize_Root (Container);
2457
 
2458
      Read_Count := 0;
2459
 
2460
      Read_Children (Root_Node (Container));
2461
 
2462
      if Read_Count /= Total_Count then
2463
         raise Program_Error with "attempt to read from corrupt stream";
2464
      end if;
2465
 
2466
      Container.Count := Total_Count;
2467
   end Read;
2468
 
2469
   procedure Read
2470
     (Stream   : not null access Root_Stream_Type'Class;
2471
      Position : out Cursor)
2472
   is
2473
   begin
2474
      raise Program_Error with "attempt to read tree cursor from stream";
2475
   end Read;
2476
 
2477
   procedure Read
2478
     (Stream : not null access Root_Stream_Type'Class;
2479
      Item   : out Reference_Type)
2480
   is
2481
   begin
2482
      raise Program_Error with "attempt to stream reference";
2483
   end Read;
2484
 
2485
   procedure Read
2486
     (Stream : not null access Root_Stream_Type'Class;
2487
      Item   : out Constant_Reference_Type)
2488
   is
2489
   begin
2490
      raise Program_Error with "attempt to stream reference";
2491
   end Read;
2492
 
2493
   ---------------
2494
   -- Reference --
2495
   ---------------
2496
 
2497
   function Reference
2498
     (Container : aliased in out Tree;
2499
      Position  : Cursor) return Reference_Type
2500
   is
2501
   begin
2502
      if Position.Container = null then
2503
         raise Constraint_Error with
2504
           "Position cursor has no element";
2505
      end if;
2506
 
2507
      if Position.Container /= Container'Unrestricted_Access then
2508
         raise Program_Error with
2509
           "Position cursor designates wrong container";
2510
      end if;
2511
 
2512
      if Position.Node = Root_Node (Container) then
2513
         raise Program_Error with "Position cursor designates root";
2514
      end if;
2515
 
2516
      --  Implement Vet for multiway tree???
2517
      --  pragma Assert (Vet (Position),
2518
      --                 "Position cursor in Constant_Reference is bad");
2519
 
2520
      return (Element => Container.Elements (Position.Node)'Access);
2521
   end Reference;
2522
 
2523
   --------------------
2524
   -- Remove_Subtree --
2525
   --------------------
2526
 
2527
   procedure Remove_Subtree
2528
     (Container : in out Tree;
2529
      Subtree   : Count_Type)
2530
   is
2531
      NN : Tree_Node_Array renames Container.Nodes;
2532
      N  : Tree_Node_Type renames NN (Subtree);
2533
      CC : Children_Type renames NN (N.Parent).Children;
2534
 
2535
   begin
2536
      --  This is a utility operation to remove a subtree node from its
2537
      --  parent's list of children.
2538
 
2539
      if CC.First = Subtree then
2540
         pragma Assert (N.Prev <= 0);
2541
 
2542
         if CC.Last = Subtree then
2543
            pragma Assert (N.Next <= 0);
2544
            CC.First := 0;
2545
            CC.Last := 0;
2546
 
2547
         else
2548
            CC.First := N.Next;
2549
            NN (CC.First).Prev := 0;
2550
         end if;
2551
 
2552
      elsif CC.Last = Subtree then
2553
         pragma Assert (N.Next <= 0);
2554
         CC.Last := N.Prev;
2555
         NN (CC.Last).Next := 0;
2556
 
2557
      else
2558
         NN (N.Prev).Next := N.Next;
2559
         NN (N.Next).Prev := N.Prev;
2560
      end if;
2561
   end Remove_Subtree;
2562
 
2563
   ----------------------
2564
   -- Replace_Element --
2565
   ----------------------
2566
 
2567
   procedure Replace_Element
2568
     (Container : in out Tree;
2569
      Position  : Cursor;
2570
      New_Item  : Element_Type)
2571
   is
2572
   begin
2573
      if Position = No_Element then
2574
         raise Constraint_Error with "Position cursor has no element";
2575
      end if;
2576
 
2577
      if Position.Container /= Container'Unrestricted_Access then
2578
         raise Program_Error with "Position cursor not in container";
2579
      end if;
2580
 
2581
      if Is_Root (Position) then
2582
         raise Program_Error with "Position cursor designates root";
2583
      end if;
2584
 
2585
      if Container.Lock > 0 then
2586
         raise Program_Error
2587
           with "attempt to tamper with elements (tree is locked)";
2588
      end if;
2589
 
2590
      Container.Elements (Position.Node) := New_Item;
2591
   end Replace_Element;
2592
 
2593
   ------------------------------
2594
   -- Reverse_Iterate_Children --
2595
   ------------------------------
2596
 
2597
   procedure Reverse_Iterate_Children
2598
     (Parent  : Cursor;
2599
      Process : not null access procedure (Position : Cursor))
2600
   is
2601
   begin
2602
      if Parent = No_Element then
2603
         raise Constraint_Error with "Parent cursor has no element";
2604
      end if;
2605
 
2606
      if Parent.Container.Count = 0 then
2607
         pragma Assert (Is_Root (Parent));
2608
         return;
2609
      end if;
2610
 
2611
      declare
2612
         NN : Tree_Node_Array renames Parent.Container.Nodes;
2613
         B  : Natural renames Parent.Container.Busy;
2614
         C  : Count_Type;
2615
 
2616
      begin
2617
         B := B + 1;
2618
 
2619
         C := NN (Parent.Node).Children.Last;
2620
         while C > 0 loop
2621
            Process (Cursor'(Parent.Container, Node => C));
2622
            C := NN (C).Prev;
2623
         end loop;
2624
 
2625
         B := B - 1;
2626
 
2627
      exception
2628
         when others =>
2629
            B := B - 1;
2630
            raise;
2631
      end;
2632
   end Reverse_Iterate_Children;
2633
 
2634
   ----------
2635
   -- Root --
2636
   ----------
2637
 
2638
   function Root (Container : Tree) return Cursor is
2639
   begin
2640
      return (Container'Unrestricted_Access, Root_Node (Container));
2641
   end Root;
2642
 
2643
   ---------------
2644
   -- Root_Node --
2645
   ---------------
2646
 
2647
   function Root_Node (Container : Tree) return Count_Type is
2648
      pragma Unreferenced (Container);
2649
 
2650
   begin
2651
      return 0;
2652
   end Root_Node;
2653
 
2654
   ---------------------
2655
   -- Splice_Children --
2656
   ---------------------
2657
 
2658
   procedure Splice_Children
2659
     (Target        : in out Tree;
2660
      Target_Parent : Cursor;
2661
      Before        : Cursor;
2662
      Source        : in out Tree;
2663
      Source_Parent : Cursor)
2664
   is
2665
   begin
2666
      if Target_Parent = No_Element then
2667
         raise Constraint_Error with "Target_Parent cursor has no element";
2668
      end if;
2669
 
2670
      if Target_Parent.Container /= Target'Unrestricted_Access then
2671
         raise Program_Error
2672
           with "Target_Parent cursor not in Target container";
2673
      end if;
2674
 
2675
      if Before /= No_Element then
2676
         if Before.Container /= Target'Unrestricted_Access then
2677
            raise Program_Error
2678
              with "Before cursor not in Target container";
2679
         end if;
2680
 
2681
         if Target.Nodes (Before.Node).Parent /= Target_Parent.Node then
2682
            raise Constraint_Error
2683
              with "Before cursor not child of Target_Parent";
2684
         end if;
2685
      end if;
2686
 
2687
      if Source_Parent = No_Element then
2688
         raise Constraint_Error with "Source_Parent cursor has no element";
2689
      end if;
2690
 
2691
      if Source_Parent.Container /= Source'Unrestricted_Access then
2692
         raise Program_Error
2693
           with "Source_Parent cursor not in Source container";
2694
      end if;
2695
 
2696
      if Source.Count = 0 then
2697
         pragma Assert (Is_Root (Source_Parent));
2698
         return;
2699
      end if;
2700
 
2701
      if Target'Address = Source'Address then
2702
         if Target_Parent = Source_Parent then
2703
            return;
2704
         end if;
2705
 
2706
         if Target.Busy > 0 then
2707
            raise Program_Error
2708
              with "attempt to tamper with cursors (Target tree is busy)";
2709
         end if;
2710
 
2711
         if Is_Reachable (Container => Target,
2712
                          From      => Target_Parent.Node,
2713
                          To        => Source_Parent.Node)
2714
         then
2715
            raise Constraint_Error
2716
              with "Source_Parent is ancestor of Target_Parent";
2717
         end if;
2718
 
2719
         Splice_Children
2720
           (Container     => Target,
2721
            Target_Parent => Target_Parent.Node,
2722
            Before        => Before.Node,
2723
            Source_Parent => Source_Parent.Node);
2724
 
2725
         return;
2726
      end if;
2727
 
2728
      if Target.Busy > 0 then
2729
         raise Program_Error
2730
           with "attempt to tamper with cursors (Target tree is busy)";
2731
      end if;
2732
 
2733
      if Source.Busy > 0 then
2734
         raise Program_Error
2735
           with "attempt to tamper with cursors (Source tree is busy)";
2736
      end if;
2737
 
2738
      if Target.Count = 0 then
2739
         Initialize_Root (Target);
2740
      end if;
2741
 
2742
      Splice_Children
2743
        (Target        => Target,
2744
         Target_Parent => Target_Parent.Node,
2745
         Before        => Before.Node,
2746
         Source        => Source,
2747
         Source_Parent => Source_Parent.Node);
2748
   end Splice_Children;
2749
 
2750
   procedure Splice_Children
2751
     (Container       : in out Tree;
2752
      Target_Parent   : Cursor;
2753
      Before          : Cursor;
2754
      Source_Parent   : Cursor)
2755
   is
2756
   begin
2757
      if Target_Parent = No_Element then
2758
         raise Constraint_Error with "Target_Parent cursor has no element";
2759
      end if;
2760
 
2761
      if Target_Parent.Container /= Container'Unrestricted_Access then
2762
         raise Program_Error
2763
           with "Target_Parent cursor not in container";
2764
      end if;
2765
 
2766
      if Before /= No_Element then
2767
         if Before.Container /= Container'Unrestricted_Access then
2768
            raise Program_Error
2769
              with "Before cursor not in container";
2770
         end if;
2771
 
2772
         if Container.Nodes (Before.Node).Parent /= Target_Parent.Node then
2773
            raise Constraint_Error
2774
              with "Before cursor not child of Target_Parent";
2775
         end if;
2776
      end if;
2777
 
2778
      if Source_Parent = No_Element then
2779
         raise Constraint_Error with "Source_Parent cursor has no element";
2780
      end if;
2781
 
2782
      if Source_Parent.Container /= Container'Unrestricted_Access then
2783
         raise Program_Error
2784
           with "Source_Parent cursor not in container";
2785
      end if;
2786
 
2787
      if Target_Parent = Source_Parent then
2788
         return;
2789
      end if;
2790
 
2791
      pragma Assert (Container.Count > 0);
2792
 
2793
      if Container.Busy > 0 then
2794
         raise Program_Error
2795
           with "attempt to tamper with cursors (tree is busy)";
2796
      end if;
2797
 
2798
      if Is_Reachable (Container => Container,
2799
                       From      => Target_Parent.Node,
2800
                       To        => Source_Parent.Node)
2801
      then
2802
         raise Constraint_Error
2803
           with "Source_Parent is ancestor of Target_Parent";
2804
      end if;
2805
 
2806
      Splice_Children
2807
        (Container     => Container,
2808
         Target_Parent => Target_Parent.Node,
2809
         Before        => Before.Node,
2810
         Source_Parent => Source_Parent.Node);
2811
   end Splice_Children;
2812
 
2813
   procedure Splice_Children
2814
     (Container     : in out Tree;
2815
      Target_Parent : Count_Type;
2816
      Before        : Count_Type'Base;
2817
      Source_Parent : Count_Type)
2818
   is
2819
      NN : Tree_Node_Array renames Container.Nodes;
2820
      CC : constant Children_Type := NN (Source_Parent).Children;
2821
      C  : Count_Type'Base;
2822
 
2823
   begin
2824
      --  This is a utility operation to remove the children from Source parent
2825
      --  and insert them into Target parent.
2826
 
2827
      NN (Source_Parent).Children := Children_Type'(others => 0);
2828
 
2829
      --  Fix up the Parent pointers of each child to designate its new Target
2830
      --  parent.
2831
 
2832
      C := CC.First;
2833
      while C > 0 loop
2834
         NN (C).Parent := Target_Parent;
2835
         C := NN (C).Next;
2836
      end loop;
2837
 
2838
      Insert_Subtree_List
2839
        (Container => Container,
2840
         First     => CC.First,
2841
         Last      => CC.Last,
2842
         Parent    => Target_Parent,
2843
         Before    => Before);
2844
   end Splice_Children;
2845
 
2846
   procedure Splice_Children
2847
     (Target        : in out Tree;
2848
      Target_Parent : Count_Type;
2849
      Before        : Count_Type'Base;
2850
      Source        : in out Tree;
2851
      Source_Parent : Count_Type)
2852
   is
2853
      S_NN : Tree_Node_Array renames Source.Nodes;
2854
      S_CC : Children_Type renames S_NN (Source_Parent).Children;
2855
 
2856
      Target_Count, Source_Count : Count_Type;
2857
      T, S                       : Count_Type'Base;
2858
 
2859
   begin
2860
      --  This is a utility operation to copy the children from the Source
2861
      --  parent and insert them as children of the Target parent, and then
2862
      --  delete them from the Source. (This is not a true splice operation,
2863
      --  but it is the best we can do in a bounded form.) The Before position
2864
      --  specifies where among the Target parent's exising children the new
2865
      --  children are inserted.
2866
 
2867
      --  Before we attempt the insertion, we must count the sources nodes in
2868
      --  order to determine whether the target have enough storage
2869
      --  available. Note that calculating this value is an O(n) operation.
2870
 
2871
      --  Here is an optimization opportunity: iterate of each children the
2872
      --  source explicitly, and keep a running count of the total number of
2873
      --  nodes. Compare the running total to the capacity of the target each
2874
      --  pass through the loop. This is more efficient than summing the counts
2875
      --  of child subtree (which is what Subtree_Node_Count does) and then
2876
      --  comparing that total sum to the target's capacity.  ???
2877
 
2878
      --  Here is another possibility. We currently treat the splice as an
2879
      --  all-or-nothing proposition: either we can insert all of children of
2880
      --  the source, or we raise exception with modifying the target. The
2881
      --  price for not causing side-effect is an O(n) determination of the
2882
      --  source count. If we are willing to tolerate side-effect, then we
2883
      --  could loop over the children of the source, counting that subtree and
2884
      --  then immediately inserting it in the target. The issue here is that
2885
      --  the test for available storage could fail during some later pass,
2886
      --  after children have already been inserted into target. ???
2887
 
2888
      Source_Count := Subtree_Node_Count (Source, Source_Parent) - 1;
2889
 
2890
      if Source_Count = 0 then
2891
         return;
2892
      end if;
2893
 
2894
      if Target.Count > Target.Capacity - Source_Count then
2895
         raise Capacity_Error  -- ???
2896
           with "Source count exceeds available storage on Target";
2897
      end if;
2898
 
2899
      --  Copy_Subtree returns a count of the number of nodes it inserts, but
2900
      --  it does this by incrementing the value passed in. Therefore we must
2901
      --  initialize the count before calling Copy_Subtree.
2902
 
2903
      Target_Count := 0;
2904
 
2905
      S := S_CC.First;
2906
      while S > 0 loop
2907
         Copy_Subtree
2908
           (Source         => Source,
2909
            Source_Subtree => S,
2910
            Target         => Target,
2911
            Target_Parent  => Target_Parent,
2912
            Target_Subtree => T,
2913
            Count          => Target_Count);
2914
 
2915
         Insert_Subtree_Node
2916
           (Container => Target,
2917
            Subtree   => T,
2918
            Parent    => Target_Parent,
2919
            Before    => Before);
2920
 
2921
         S := S_NN (S).Next;
2922
      end loop;
2923
 
2924
      pragma Assert (Target_Count = Source_Count);
2925
      Target.Count := Target.Count + Target_Count;
2926
 
2927
      --  As with Copy_Subtree, operation Deallocate_Children returns a count
2928
      --  of the number of nodes it deallocates, but it works by incrementing
2929
      --  the value passed in. We must therefore initialize the count before
2930
      --  calling it.
2931
 
2932
      Source_Count := 0;
2933
 
2934
      Deallocate_Children (Source, Source_Parent, Source_Count);
2935
      pragma Assert (Source_Count = Target_Count);
2936
 
2937
      Source.Count := Source.Count - Source_Count;
2938
   end Splice_Children;
2939
 
2940
   --------------------
2941
   -- Splice_Subtree --
2942
   --------------------
2943
 
2944
   procedure Splice_Subtree
2945
     (Target   : in out Tree;
2946
      Parent   : Cursor;
2947
      Before   : Cursor;
2948
      Source   : in out Tree;
2949
      Position : in out Cursor)
2950
   is
2951
   begin
2952
      if Parent = No_Element then
2953
         raise Constraint_Error with "Parent cursor has no element";
2954
      end if;
2955
 
2956
      if Parent.Container /= Target'Unrestricted_Access then
2957
         raise Program_Error with "Parent cursor not in Target container";
2958
      end if;
2959
 
2960
      if Before /= No_Element then
2961
         if Before.Container /= Target'Unrestricted_Access then
2962
            raise Program_Error with "Before cursor not in Target container";
2963
         end if;
2964
 
2965
         if Target.Nodes (Before.Node).Parent /= Parent.Node then
2966
            raise Constraint_Error with "Before cursor not child of Parent";
2967
         end if;
2968
      end if;
2969
 
2970
      if Position = No_Element then
2971
         raise Constraint_Error with "Position cursor has no element";
2972
      end if;
2973
 
2974
      if Position.Container /= Source'Unrestricted_Access then
2975
         raise Program_Error with "Position cursor not in Source container";
2976
      end if;
2977
 
2978
      if Is_Root (Position) then
2979
         raise Program_Error with "Position cursor designates root";
2980
      end if;
2981
 
2982
      if Target'Address = Source'Address then
2983
         if Target.Nodes (Position.Node).Parent = Parent.Node then
2984
            if Before = No_Element then
2985
               if Target.Nodes (Position.Node).Next <= 0 then  -- last child
2986
                  return;
2987
               end if;
2988
 
2989
            elsif Position.Node = Before.Node then
2990
               return;
2991
 
2992
            elsif Target.Nodes (Position.Node).Next = Before.Node then
2993
               return;
2994
            end if;
2995
         end if;
2996
 
2997
         if Target.Busy > 0 then
2998
            raise Program_Error
2999
              with "attempt to tamper with cursors (Target tree is busy)";
3000
         end if;
3001
 
3002
         if Is_Reachable (Container => Target,
3003
                          From      => Parent.Node,
3004
                          To        => Position.Node)
3005
         then
3006
            raise Constraint_Error with "Position is ancestor of Parent";
3007
         end if;
3008
 
3009
         Remove_Subtree (Target, Position.Node);
3010
 
3011
         Target.Nodes (Position.Node).Parent := Parent.Node;
3012
         Insert_Subtree_Node (Target, Position.Node, Parent.Node, Before.Node);
3013
 
3014
         return;
3015
      end if;
3016
 
3017
      if Target.Busy > 0 then
3018
         raise Program_Error
3019
           with "attempt to tamper with cursors (Target tree is busy)";
3020
      end if;
3021
 
3022
      if Source.Busy > 0 then
3023
         raise Program_Error
3024
           with "attempt to tamper with cursors (Source tree is busy)";
3025
      end if;
3026
 
3027
      if Target.Count = 0 then
3028
         Initialize_Root (Target);
3029
      end if;
3030
 
3031
      Splice_Subtree
3032
        (Target   => Target,
3033
         Parent   => Parent.Node,
3034
         Before   => Before.Node,
3035
         Source   => Source,
3036
         Position => Position.Node);  -- modified during call
3037
 
3038
      Position.Container := Target'Unrestricted_Access;
3039
   end Splice_Subtree;
3040
 
3041
   procedure Splice_Subtree
3042
     (Container : in out Tree;
3043
      Parent    : Cursor;
3044
      Before    : Cursor;
3045
      Position  : Cursor)
3046
   is
3047
   begin
3048
      if Parent = No_Element then
3049
         raise Constraint_Error with "Parent cursor has no element";
3050
      end if;
3051
 
3052
      if Parent.Container /= Container'Unrestricted_Access then
3053
         raise Program_Error with "Parent cursor not in container";
3054
      end if;
3055
 
3056
      if Before /= No_Element then
3057
         if Before.Container /= Container'Unrestricted_Access then
3058
            raise Program_Error with "Before cursor not in container";
3059
         end if;
3060
 
3061
         if Container.Nodes (Before.Node).Parent /= Parent.Node then
3062
            raise Constraint_Error with "Before cursor not child of Parent";
3063
         end if;
3064
      end if;
3065
 
3066
      if Position = No_Element then
3067
         raise Constraint_Error with "Position cursor has no element";
3068
      end if;
3069
 
3070
      if Position.Container /= Container'Unrestricted_Access then
3071
         raise Program_Error with "Position cursor not in container";
3072
      end if;
3073
 
3074
      if Is_Root (Position) then
3075
 
3076
         --  Should this be PE instead?  Need ARG confirmation.  ???
3077
 
3078
         raise Constraint_Error with "Position cursor designates root";
3079
      end if;
3080
 
3081
      if Container.Nodes (Position.Node).Parent = Parent.Node then
3082
         if Before = No_Element then
3083
            if Container.Nodes (Position.Node).Next <= 0 then  -- last child
3084
               return;
3085
            end if;
3086
 
3087
         elsif Position.Node = Before.Node then
3088
            return;
3089
 
3090
         elsif Container.Nodes (Position.Node).Next = Before.Node then
3091
            return;
3092
         end if;
3093
      end if;
3094
 
3095
      if Container.Busy > 0 then
3096
         raise Program_Error
3097
           with "attempt to tamper with cursors (tree is busy)";
3098
      end if;
3099
 
3100
      if Is_Reachable (Container => Container,
3101
                       From      => Parent.Node,
3102
                       To        => Position.Node)
3103
      then
3104
         raise Constraint_Error with "Position is ancestor of Parent";
3105
      end if;
3106
 
3107
      Remove_Subtree (Container, Position.Node);
3108
      Container.Nodes (Position.Node).Parent := Parent.Node;
3109
      Insert_Subtree_Node (Container, Position.Node, Parent.Node, Before.Node);
3110
   end Splice_Subtree;
3111
 
3112
   procedure Splice_Subtree
3113
     (Target   : in out Tree;
3114
      Parent   : Count_Type;
3115
      Before   : Count_Type'Base;
3116
      Source   : in out Tree;
3117
      Position : in out Count_Type)  -- Source on input, Target on output
3118
   is
3119
      Source_Count : Count_Type := Subtree_Node_Count (Source, Position);
3120
      pragma Assert (Source_Count >= 1);
3121
 
3122
      Target_Subtree : Count_Type;
3123
      Target_Count   : Count_Type;
3124
 
3125
   begin
3126
      --  This is a utility operation to do the heavy lifting associated with
3127
      --  splicing a subtree from one tree to another. Note that "splicing"
3128
      --  is a bit of a misnomer here in the case of a bounded tree, because
3129
      --  the elements must be copied from the source to the target.
3130
 
3131
      if Target.Count > Target.Capacity - Source_Count then
3132
         raise Capacity_Error  -- ???
3133
           with "Source count exceeds available storage on Target";
3134
      end if;
3135
 
3136
      --  Copy_Subtree returns a count of the number of nodes it inserts, but
3137
      --  it does this by incrementing the value passed in. Therefore we must
3138
      --  initialize the count before calling Copy_Subtree.
3139
 
3140
      Target_Count := 0;
3141
 
3142
      Copy_Subtree
3143
        (Source         => Source,
3144
         Source_Subtree => Position,
3145
         Target         => Target,
3146
         Target_Parent  => Parent,
3147
         Target_Subtree => Target_Subtree,
3148
         Count          => Target_Count);
3149
 
3150
      pragma Assert (Target_Count = Source_Count);
3151
 
3152
      --  Now link the newly-allocated subtree into the target.
3153
 
3154
      Insert_Subtree_Node
3155
        (Container => Target,
3156
         Subtree   => Target_Subtree,
3157
         Parent    => Parent,
3158
         Before    => Before);
3159
 
3160
      Target.Count := Target.Count + Target_Count;
3161
 
3162
      --  The manipulation of the Target container is complete. Now we remove
3163
      --  the subtree from the Source container.
3164
 
3165
      Remove_Subtree (Source, Position);  -- unlink the subtree
3166
 
3167
      --  As with Copy_Subtree, operation Deallocate_Subtree returns a count of
3168
      --  the number of nodes it deallocates, but it works by incrementing the
3169
      --  value passed in. We must therefore initialize the count before
3170
      --  calling it.
3171
 
3172
      Source_Count := 0;
3173
 
3174
      Deallocate_Subtree (Source, Position, Source_Count);
3175
      pragma Assert (Source_Count = Target_Count);
3176
 
3177
      Source.Count := Source.Count - Source_Count;
3178
 
3179
      Position := Target_Subtree;
3180
   end Splice_Subtree;
3181
 
3182
   ------------------------
3183
   -- Subtree_Node_Count --
3184
   ------------------------
3185
 
3186
   function Subtree_Node_Count (Position : Cursor) return Count_Type is
3187
   begin
3188
      if Position = No_Element then
3189
         return 0;
3190
      end if;
3191
 
3192
      if Position.Container.Count = 0 then
3193
         pragma Assert (Is_Root (Position));
3194
         return 1;
3195
      end if;
3196
 
3197
      return Subtree_Node_Count (Position.Container.all, Position.Node);
3198
   end Subtree_Node_Count;
3199
 
3200
   function Subtree_Node_Count
3201
     (Container : Tree;
3202
      Subtree   : Count_Type) return Count_Type
3203
   is
3204
      Result : Count_Type;
3205
      Node   : Count_Type'Base;
3206
 
3207
   begin
3208
      Result := 1;
3209
      Node := Container.Nodes (Subtree).Children.First;
3210
      while Node > 0 loop
3211
         Result := Result + Subtree_Node_Count (Container, Node);
3212
         Node := Container.Nodes (Node).Next;
3213
      end loop;
3214
      return Result;
3215
   end Subtree_Node_Count;
3216
 
3217
   ----------
3218
   -- Swap --
3219
   ----------
3220
 
3221
   procedure Swap
3222
     (Container : in out Tree;
3223
      I, J      : Cursor)
3224
   is
3225
   begin
3226
      if I = No_Element then
3227
         raise Constraint_Error with "I cursor has no element";
3228
      end if;
3229
 
3230
      if I.Container /= Container'Unrestricted_Access then
3231
         raise Program_Error with "I cursor not in container";
3232
      end if;
3233
 
3234
      if Is_Root (I) then
3235
         raise Program_Error with "I cursor designates root";
3236
      end if;
3237
 
3238
      if I = J then -- make this test sooner???
3239
         return;
3240
      end if;
3241
 
3242
      if J = No_Element then
3243
         raise Constraint_Error with "J cursor has no element";
3244
      end if;
3245
 
3246
      if J.Container /= Container'Unrestricted_Access then
3247
         raise Program_Error with "J cursor not in container";
3248
      end if;
3249
 
3250
      if Is_Root (J) then
3251
         raise Program_Error with "J cursor designates root";
3252
      end if;
3253
 
3254
      if Container.Lock > 0 then
3255
         raise Program_Error
3256
           with "attempt to tamper with elements (tree is locked)";
3257
      end if;
3258
 
3259
      declare
3260
         EE : Element_Array renames Container.Elements;
3261
         EI : constant Element_Type := EE (I.Node);
3262
 
3263
      begin
3264
         EE (I.Node) := EE (J.Node);
3265
         EE (J.Node) := EI;
3266
      end;
3267
   end Swap;
3268
 
3269
   --------------------
3270
   -- Update_Element --
3271
   --------------------
3272
 
3273
   procedure Update_Element
3274
     (Container : in out Tree;
3275
      Position  : Cursor;
3276
      Process   : not null access procedure (Element : in out Element_Type))
3277
   is
3278
   begin
3279
      if Position = No_Element then
3280
         raise Constraint_Error with "Position cursor has no element";
3281
      end if;
3282
 
3283
      if Position.Container /= Container'Unrestricted_Access then
3284
         raise Program_Error with "Position cursor not in container";
3285
      end if;
3286
 
3287
      if Is_Root (Position) then
3288
         raise Program_Error with "Position cursor designates root";
3289
      end if;
3290
 
3291
      declare
3292
         T : Tree renames Position.Container.all'Unrestricted_Access.all;
3293
         B : Natural renames T.Busy;
3294
         L : Natural renames T.Lock;
3295
 
3296
      begin
3297
         B := B + 1;
3298
         L := L + 1;
3299
 
3300
         Process (Element => T.Elements (Position.Node));
3301
 
3302
         L := L - 1;
3303
         B := B - 1;
3304
 
3305
      exception
3306
         when others =>
3307
            L := L - 1;
3308
            B := B - 1;
3309
            raise;
3310
      end;
3311
   end Update_Element;
3312
 
3313
   -----------
3314
   -- Write --
3315
   -----------
3316
 
3317
   procedure Write
3318
     (Stream    : not null access Root_Stream_Type'Class;
3319
      Container : Tree)
3320
   is
3321
      procedure Write_Children (Subtree : Count_Type);
3322
      procedure Write_Subtree (Subtree : Count_Type);
3323
 
3324
      --------------------
3325
      -- Write_Children --
3326
      --------------------
3327
 
3328
      procedure Write_Children (Subtree : Count_Type) is
3329
         CC : Children_Type renames Container.Nodes (Subtree).Children;
3330
         C  : Count_Type'Base;
3331
 
3332
      begin
3333
         Count_Type'Write (Stream, Child_Count (Container, Subtree));
3334
 
3335
         C := CC.First;
3336
         while C > 0 loop
3337
            Write_Subtree (C);
3338
            C := Container.Nodes (C).Next;
3339
         end loop;
3340
      end Write_Children;
3341
 
3342
      -------------------
3343
      -- Write_Subtree --
3344
      -------------------
3345
 
3346
      procedure Write_Subtree (Subtree : Count_Type) is
3347
      begin
3348
         Element_Type'Write (Stream, Container.Elements (Subtree));
3349
         Write_Children (Subtree);
3350
      end Write_Subtree;
3351
 
3352
   --  Start of processing for Write
3353
 
3354
   begin
3355
      Count_Type'Write (Stream, Container.Count);
3356
 
3357
      if Container.Count = 0 then
3358
         return;
3359
      end if;
3360
 
3361
      Write_Children (Root_Node (Container));
3362
   end Write;
3363
 
3364
   procedure Write
3365
     (Stream   : not null access Root_Stream_Type'Class;
3366
      Position : Cursor)
3367
   is
3368
   begin
3369
      raise Program_Error with "attempt to write tree cursor to stream";
3370
   end Write;
3371
 
3372
   procedure Write
3373
     (Stream : not null access Root_Stream_Type'Class;
3374
      Item   : Reference_Type)
3375
   is
3376
   begin
3377
      raise Program_Error with "attempt to stream reference";
3378
   end Write;
3379
 
3380
   procedure Write
3381
     (Stream : not null access Root_Stream_Type'Class;
3382
      Item   : Constant_Reference_Type)
3383
   is
3384
   begin
3385
      raise Program_Error with "attempt to stream reference";
3386
   end Write;
3387
 
3388
end Ada.Containers.Bounded_Multiway_Trees;

powered by: WebSVN 2.1.0

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