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

Subversion Repositories openrisc

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

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
--                A D A . C O N T A I N E R S . V E C T O R S               --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--          Copyright (C) 2004-2012, Free Software Foundation, Inc.         --
10
--                                                                          --
11
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16
-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17
--                                                                          --
18
-- As a special exception under Section 7 of GPL version 3, you are granted --
19
-- additional permissions described in the GCC Runtime Library Exception,   --
20
-- version 3.1, as published by the Free Software Foundation.               --
21
--                                                                          --
22
-- You should have received a copy of the GNU General Public License and    --
23
-- a copy of the GCC Runtime Library Exception along with this program;     --
24
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25
-- <http://www.gnu.org/licenses/>.                                          --
26
--                                                                          --
27
-- This unit was originally developed by Matthew J Heaney.                  --
28
------------------------------------------------------------------------------
29
 
30
with Ada.Containers.Generic_Array_Sort;
31
with Ada.Unchecked_Deallocation;
32
 
33
with System; use type System.Address;
34
 
35
package body Ada.Containers.Vectors is
36
 
37
   procedure Free is
38
     new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
39
 
40
   type Iterator is new Limited_Controlled and
41
     Vector_Iterator_Interfaces.Reversible_Iterator with
42
   record
43
      Container : Vector_Access;
44
      Index     : Index_Type'Base;
45
   end record;
46
 
47
   overriding procedure Finalize (Object : in out Iterator);
48
 
49
   overriding function First (Object : Iterator) return Cursor;
50
   overriding function Last  (Object : Iterator) return Cursor;
51
 
52
   overriding function Next
53
     (Object   : Iterator;
54
      Position : Cursor) return Cursor;
55
 
56
   overriding function Previous
57
     (Object   : Iterator;
58
      Position : Cursor) return Cursor;
59
 
60
   ---------
61
   -- "&" --
62
   ---------
63
 
64
   function "&" (Left, Right : Vector) return Vector is
65
      LN   : constant Count_Type := Length (Left);
66
      RN   : constant Count_Type := Length (Right);
67
      N    : Count_Type'Base;  -- length of result
68
      J    : Count_Type'Base;  -- for computing intermediate index values
69
      Last : Index_Type'Base;  -- Last index of result
70
 
71
   begin
72
      --  We decide that the capacity of the result is the sum of the lengths
73
      --  of the vector parameters. We could decide to make it larger, but we
74
      --  have no basis for knowing how much larger, so we just allocate the
75
      --  minimum amount of storage.
76
 
77
      --  Here we handle the easy cases first, when one of the vector
78
      --  parameters is empty. (We say "easy" because there's nothing to
79
      --  compute, that can potentially overflow.)
80
 
81
      if LN = 0 then
82
         if RN = 0 then
83
            return Empty_Vector;
84
         end if;
85
 
86
         declare
87
            RE : Elements_Array renames
88
                   Right.Elements.EA (Index_Type'First .. Right.Last);
89
 
90
            Elements : constant Elements_Access :=
91
                         new Elements_Type'(Right.Last, RE);
92
 
93
         begin
94
            return (Controlled with Elements, Right.Last, 0, 0);
95
         end;
96
      end if;
97
 
98
      if RN = 0 then
99
         declare
100
            LE : Elements_Array renames
101
                   Left.Elements.EA (Index_Type'First .. Left.Last);
102
 
103
            Elements : constant Elements_Access :=
104
                         new Elements_Type'(Left.Last, LE);
105
 
106
         begin
107
            return (Controlled with Elements, Left.Last, 0, 0);
108
         end;
109
 
110
      end if;
111
 
112
      --  Neither of the vector parameters is empty, so must compute the length
113
      --  of the result vector and its last index. (This is the harder case,
114
      --  because our computations must avoid overflow.)
115
 
116
      --  There are two constraints we need to satisfy. The first constraint is
117
      --  that a container cannot have more than Count_Type'Last elements, so
118
      --  we must check the sum of the combined lengths. Note that we cannot
119
      --  simply add the lengths, because of the possibility of overflow.
120
 
121
      if LN > Count_Type'Last - RN then
122
         raise Constraint_Error with "new length is out of range";
123
      end if;
124
 
125
      --  It is now safe compute the length of the new vector, without fear of
126
      --  overflow.
127
 
128
      N := LN + RN;
129
 
130
      --  The second constraint is that the new Last index value cannot
131
      --  exceed Index_Type'Last. We use the wider of Index_Type'Base and
132
      --  Count_Type'Base as the type for intermediate values.
133
 
134
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
135
 
136
         --  We perform a two-part test. First we determine whether the
137
         --  computed Last value lies in the base range of the type, and then
138
         --  determine whether it lies in the range of the index (sub)type.
139
 
140
         --  Last must satisfy this relation:
141
         --    First + Length - 1 <= Last
142
         --  We regroup terms:
143
         --    First - 1 <= Last - Length
144
         --  Which can rewrite as:
145
         --    No_Index <= Last - Length
146
 
147
         if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
148
            raise Constraint_Error with "new length is out of range";
149
         end if;
150
 
151
         --  We now know that the computed value of Last is within the base
152
         --  range of the type, so it is safe to compute its value:
153
 
154
         Last := No_Index + Index_Type'Base (N);
155
 
156
         --  Finally we test whether the value is within the range of the
157
         --  generic actual index subtype:
158
 
159
         if Last > Index_Type'Last then
160
            raise Constraint_Error with "new length is out of range";
161
         end if;
162
 
163
      elsif Index_Type'First <= 0 then
164
 
165
         --  Here we can compute Last directly, in the normal way. We know that
166
         --  No_Index is less than 0, so there is no danger of overflow when
167
         --  adding the (positive) value of length.
168
 
169
         J := Count_Type'Base (No_Index) + N;  -- Last
170
 
171
         if J > Count_Type'Base (Index_Type'Last) then
172
            raise Constraint_Error with "new length is out of range";
173
         end if;
174
 
175
         --  We know that the computed value (having type Count_Type) of Last
176
         --  is within the range of the generic actual index subtype, so it is
177
         --  safe to convert to Index_Type:
178
 
179
         Last := Index_Type'Base (J);
180
 
181
      else
182
         --  Here Index_Type'First (and Index_Type'Last) is positive, so we
183
         --  must test the length indirectly (by working backwards from the
184
         --  largest possible value of Last), in order to prevent overflow.
185
 
186
         J := Count_Type'Base (Index_Type'Last) - N;  -- No_Index
187
 
188
         if J < Count_Type'Base (No_Index) then
189
            raise Constraint_Error with "new length is out of range";
190
         end if;
191
 
192
         --  We have determined that the result length would not create a Last
193
         --  index value outside of the range of Index_Type, so we can now
194
         --  safely compute its value.
195
 
196
         Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
197
      end if;
198
 
199
      declare
200
         LE : Elements_Array renames
201
                Left.Elements.EA (Index_Type'First .. Left.Last);
202
 
203
         RE : Elements_Array renames
204
                Right.Elements.EA (Index_Type'First .. Right.Last);
205
 
206
         Elements : constant Elements_Access :=
207
                      new Elements_Type'(Last, LE & RE);
208
 
209
      begin
210
         return (Controlled with Elements, Last, 0, 0);
211
      end;
212
   end "&";
213
 
214
   function "&" (Left  : Vector; Right : Element_Type) return Vector is
215
   begin
216
      --  We decide that the capacity of the result is the sum of the lengths
217
      --  of the parameters. We could decide to make it larger, but we have no
218
      --  basis for knowing how much larger, so we just allocate the minimum
219
      --  amount of storage.
220
 
221
      --  Handle easy case first, when the vector parameter (Left) is empty
222
 
223
      if Left.Is_Empty then
224
         declare
225
            Elements : constant Elements_Access :=
226
                         new Elements_Type'
227
                               (Last => Index_Type'First,
228
                                EA   => (others => Right));
229
 
230
         begin
231
            return (Controlled with Elements, Index_Type'First, 0, 0);
232
         end;
233
      end if;
234
 
235
      --  The vector parameter is not empty, so we must compute the length of
236
      --  the result vector and its last index, but in such a way that overflow
237
      --  is avoided. We must satisfy two constraints: the new length cannot
238
      --  exceed Count_Type'Last, and the new Last index cannot exceed
239
      --  Index_Type'Last.
240
 
241
      if Left.Length = Count_Type'Last then
242
         raise Constraint_Error with "new length is out of range";
243
      end if;
244
 
245
      if Left.Last >= Index_Type'Last then
246
         raise Constraint_Error with "new length is out of range";
247
      end if;
248
 
249
      declare
250
         Last : constant Index_Type := Left.Last + 1;
251
 
252
         LE : Elements_Array renames
253
           Left.Elements.EA (Index_Type'First .. Left.Last);
254
 
255
         Elements : constant Elements_Access :=
256
                      new Elements_Type'(Last => Last, EA => LE & Right);
257
 
258
      begin
259
         return (Controlled with Elements, Last, 0, 0);
260
      end;
261
   end "&";
262
 
263
   function "&" (Left  : Element_Type; Right : Vector) return Vector is
264
   begin
265
      --  We decide that the capacity of the result is the sum of the lengths
266
      --  of the parameters. We could decide to make it larger, but we have no
267
      --  basis for knowing how much larger, so we just allocate the minimum
268
      --  amount of storage.
269
 
270
      --  Handle easy case first, when the vector parameter (Right) is empty
271
 
272
      if Right.Is_Empty then
273
         declare
274
            Elements : constant Elements_Access :=
275
                         new Elements_Type'
276
                               (Last => Index_Type'First,
277
                                EA   => (others => Left));
278
 
279
         begin
280
            return (Controlled with Elements, Index_Type'First, 0, 0);
281
         end;
282
      end if;
283
 
284
      --  The vector parameter is not empty, so we must compute the length of
285
      --  the result vector and its last index, but in such a way that overflow
286
      --  is avoided. We must satisfy two constraints: the new length cannot
287
      --  exceed Count_Type'Last, and the new Last index cannot exceed
288
      --  Index_Type'Last.
289
 
290
      if Right.Length = Count_Type'Last then
291
         raise Constraint_Error with "new length is out of range";
292
      end if;
293
 
294
      if Right.Last >= Index_Type'Last then
295
         raise Constraint_Error with "new length is out of range";
296
      end if;
297
 
298
      declare
299
         Last : constant Index_Type := Right.Last + 1;
300
 
301
         RE : Elements_Array renames
302
                Right.Elements.EA (Index_Type'First .. Right.Last);
303
 
304
         Elements : constant Elements_Access :=
305
                      new Elements_Type'
306
                        (Last => Last,
307
                         EA   => Left & RE);
308
 
309
      begin
310
         return (Controlled with Elements, Last, 0, 0);
311
      end;
312
   end "&";
313
 
314
   function "&" (Left, Right : Element_Type) return Vector is
315
   begin
316
      --  We decide that the capacity of the result is the sum of the lengths
317
      --  of the parameters. We could decide to make it larger, but we have no
318
      --  basis for knowing how much larger, so we just allocate the minimum
319
      --  amount of storage.
320
 
321
      --  We must compute the length of the result vector and its last index,
322
      --  but in such a way that overflow is avoided. We must satisfy two
323
      --  constraints: the new length cannot exceed Count_Type'Last (here, we
324
      --  know that that condition is satisfied), and the new Last index cannot
325
      --  exceed Index_Type'Last.
326
 
327
      if Index_Type'First >= Index_Type'Last then
328
         raise Constraint_Error with "new length is out of range";
329
      end if;
330
 
331
      declare
332
         Last : constant Index_Type := Index_Type'First + 1;
333
 
334
         Elements : constant Elements_Access :=
335
                      new Elements_Type'
336
                            (Last => Last,
337
                             EA   => (Left, Right));
338
 
339
      begin
340
         return (Controlled with Elements, Last, 0, 0);
341
      end;
342
   end "&";
343
 
344
   ---------
345
   -- "=" --
346
   ---------
347
 
348
   overriding function "=" (Left, Right : Vector) return Boolean is
349
   begin
350
      if Left'Address = Right'Address then
351
         return True;
352
      end if;
353
 
354
      if Left.Last /= Right.Last then
355
         return False;
356
      end if;
357
 
358
      for J in Index_Type range Index_Type'First .. Left.Last loop
359
         if Left.Elements.EA (J) /= Right.Elements.EA (J) then
360
            return False;
361
         end if;
362
      end loop;
363
 
364
      return True;
365
   end "=";
366
 
367
   ------------
368
   -- Adjust --
369
   ------------
370
 
371
   procedure Adjust (Container : in out Vector) is
372
   begin
373
      if Container.Last = No_Index then
374
         Container.Elements := null;
375
         return;
376
      end if;
377
 
378
      declare
379
         L  : constant Index_Type := Container.Last;
380
         EA : Elements_Array renames
381
                Container.Elements.EA (Index_Type'First .. L);
382
 
383
      begin
384
         Container.Elements := null;
385
         Container.Busy := 0;
386
         Container.Lock := 0;
387
 
388
         --  Note: it may seem that the following assignment to Container.Last
389
         --  is useless, since we assign it to L below. However this code is
390
         --  used in case 'new Elements_Type' below raises an exception, to
391
         --  keep Container in a consistent state.
392
 
393
         Container.Last := No_Index;
394
         Container.Elements := new Elements_Type'(L, EA);
395
         Container.Last := L;
396
      end;
397
   end Adjust;
398
 
399
   procedure Adjust (Control : in out Reference_Control_Type) is
400
   begin
401
      if Control.Container /= null then
402
         declare
403
            C : Vector renames Control.Container.all;
404
            B : Natural renames C.Busy;
405
            L : Natural renames C.Lock;
406
         begin
407
            B := B + 1;
408
            L := L + 1;
409
         end;
410
      end if;
411
   end Adjust;
412
 
413
   ------------
414
   -- Append --
415
   ------------
416
 
417
   procedure Append (Container : in out Vector; New_Item : Vector) is
418
   begin
419
      if Is_Empty (New_Item) then
420
         return;
421
      end if;
422
 
423
      if Container.Last = Index_Type'Last then
424
         raise Constraint_Error with "vector is already at its maximum length";
425
      end if;
426
 
427
      Insert
428
        (Container,
429
         Container.Last + 1,
430
         New_Item);
431
   end Append;
432
 
433
   procedure Append
434
     (Container : in out Vector;
435
      New_Item  : Element_Type;
436
      Count     : Count_Type := 1)
437
   is
438
   begin
439
      if Count = 0 then
440
         return;
441
      end if;
442
 
443
      if Container.Last = Index_Type'Last then
444
         raise Constraint_Error with "vector is already at its maximum length";
445
      end if;
446
 
447
      Insert
448
        (Container,
449
         Container.Last + 1,
450
         New_Item,
451
         Count);
452
   end Append;
453
 
454
   ------------
455
   -- Assign --
456
   ------------
457
 
458
   procedure Assign (Target : in out Vector; Source : Vector) is
459
   begin
460
      if Target'Address = Source'Address then
461
         return;
462
      end if;
463
 
464
      Target.Clear;
465
      Target.Append (Source);
466
   end Assign;
467
 
468
   --------------
469
   -- Capacity --
470
   --------------
471
 
472
   function Capacity (Container : Vector) return Count_Type is
473
   begin
474
      if Container.Elements = null then
475
         return 0;
476
      else
477
         return Container.Elements.EA'Length;
478
      end if;
479
   end Capacity;
480
 
481
   -----------
482
   -- Clear --
483
   -----------
484
 
485
   procedure Clear (Container : in out Vector) is
486
   begin
487
      if Container.Busy > 0 then
488
         raise Program_Error with
489
           "attempt to tamper with cursors (vector is busy)";
490
      else
491
         Container.Last := No_Index;
492
      end if;
493
   end Clear;
494
 
495
   ------------------------
496
   -- Constant_Reference --
497
   ------------------------
498
 
499
   function Constant_Reference
500
     (Container : aliased Vector;
501
      Position  : Cursor) return Constant_Reference_Type
502
   is
503
   begin
504
      if Position.Container = null then
505
         raise Constraint_Error with "Position cursor has no element";
506
      end if;
507
 
508
      if Position.Container /= Container'Unrestricted_Access then
509
         raise Program_Error with "Position cursor denotes wrong container";
510
      end if;
511
 
512
      if Position.Index > Position.Container.Last then
513
         raise Constraint_Error with "Position cursor is out of range";
514
      end if;
515
 
516
      declare
517
         C : Vector renames Position.Container.all;
518
         B : Natural renames C.Busy;
519
         L : Natural renames C.Lock;
520
      begin
521
         return R : constant Constant_Reference_Type :=
522
                      (Element =>
523
                         Container.Elements.EA (Position.Index)'Access,
524
                       Control =>
525
                         (Controlled with Container'Unrestricted_Access))
526
         do
527
            B := B + 1;
528
            L := L + 1;
529
         end return;
530
      end;
531
   end Constant_Reference;
532
 
533
   function Constant_Reference
534
     (Container : aliased Vector;
535
      Index     : Index_Type) return Constant_Reference_Type
536
   is
537
   begin
538
      if Index > Container.Last then
539
         raise Constraint_Error with "Index is out of range";
540
      else
541
         declare
542
            C : Vector renames Container'Unrestricted_Access.all;
543
            B : Natural renames C.Busy;
544
            L : Natural renames C.Lock;
545
         begin
546
            return R : constant Constant_Reference_Type :=
547
                         (Element => Container.Elements.EA (Index)'Access,
548
                          Control =>
549
                            (Controlled with Container'Unrestricted_Access))
550
            do
551
               B := B + 1;
552
               L := L + 1;
553
            end return;
554
         end;
555
      end if;
556
   end Constant_Reference;
557
 
558
   --------------
559
   -- Contains --
560
   --------------
561
 
562
   function Contains
563
     (Container : Vector;
564
      Item      : Element_Type) return Boolean
565
   is
566
   begin
567
      return Find_Index (Container, Item) /= No_Index;
568
   end Contains;
569
 
570
   ----------
571
   -- Copy --
572
   ----------
573
 
574
   function Copy
575
     (Source   : Vector;
576
      Capacity : Count_Type := 0) return Vector
577
   is
578
      C : Count_Type;
579
 
580
   begin
581
      if Capacity = 0 then
582
         C := Source.Length;
583
 
584
      elsif Capacity >= Source.Length then
585
         C := Capacity;
586
 
587
      else
588
         raise Capacity_Error
589
           with "Requested capacity is less than Source length";
590
      end if;
591
 
592
      return Target : Vector do
593
         Target.Reserve_Capacity (C);
594
         Target.Assign (Source);
595
      end return;
596
   end Copy;
597
 
598
   ------------
599
   -- Delete --
600
   ------------
601
 
602
   procedure Delete
603
     (Container : in out Vector;
604
      Index     : Extended_Index;
605
      Count     : Count_Type := 1)
606
   is
607
      Old_Last : constant Index_Type'Base := Container.Last;
608
      New_Last : Index_Type'Base;
609
      Count2   : Count_Type'Base;  -- count of items from Index to Old_Last
610
      J        : Index_Type'Base;  -- first index of items that slide down
611
 
612
   begin
613
      --  Delete removes items from the vector, the number of which is the
614
      --  minimum of the specified Count and the items (if any) that exist from
615
      --  Index to Container.Last. There are no constraints on the specified
616
      --  value of Count (it can be larger than what's available at this
617
      --  position in the vector, for example), but there are constraints on
618
      --  the allowed values of the Index.
619
 
620
      --  As a precondition on the generic actual Index_Type, the base type
621
      --  must include Index_Type'Pred (Index_Type'First); this is the value
622
      --  that Container.Last assumes when the vector is empty. However, we do
623
      --  not allow that as the value for Index when specifying which items
624
      --  should be deleted, so we must manually check. (That the user is
625
      --  allowed to specify the value at all here is a consequence of the
626
      --  declaration of the Extended_Index subtype, which includes the values
627
      --  in the base range that immediately precede and immediately follow the
628
      --  values in the Index_Type.)
629
 
630
      if Index < Index_Type'First then
631
         raise Constraint_Error with "Index is out of range (too small)";
632
      end if;
633
 
634
      --  We do allow a value greater than Container.Last to be specified as
635
      --  the Index, but only if it's immediately greater. This allows the
636
      --  corner case of deleting no items from the back end of the vector to
637
      --  be treated as a no-op. (It is assumed that specifying an index value
638
      --  greater than Last + 1 indicates some deeper flaw in the caller's
639
      --  algorithm, so that case is treated as a proper error.)
640
 
641
      if Index > Old_Last then
642
         if Index > Old_Last + 1 then
643
            raise Constraint_Error with "Index is out of range (too large)";
644
         end if;
645
 
646
         return;
647
      end if;
648
 
649
      --  Here and elsewhere we treat deleting 0 items from the container as a
650
      --  no-op, even when the container is busy, so we simply return.
651
 
652
      if Count = 0 then
653
         return;
654
      end if;
655
 
656
      --  The tampering bits exist to prevent an item from being deleted (or
657
      --  otherwise harmfully manipulated) while it is being visited. Query,
658
      --  Update, and Iterate increment the busy count on entry, and decrement
659
      --  the count on exit. Delete checks the count to determine whether it is
660
      --  being called while the associated callback procedure is executing.
661
 
662
      if Container.Busy > 0 then
663
         raise Program_Error with
664
           "attempt to tamper with cursors (vector is busy)";
665
      end if;
666
 
667
      --  We first calculate what's available for deletion starting at
668
      --  Index. Here and elsewhere we use the wider of Index_Type'Base and
669
      --  Count_Type'Base as the type for intermediate values. (See function
670
      --  Length for more information.)
671
 
672
      if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
673
         Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
674
 
675
      else
676
         Count2 := Count_Type'Base (Old_Last - Index + 1);
677
      end if;
678
 
679
      --  If more elements are requested (Count) for deletion than are
680
      --  available (Count2) for deletion beginning at Index, then everything
681
      --  from Index is deleted. There are no elements to slide down, and so
682
      --  all we need to do is set the value of Container.Last.
683
 
684
      if Count >= Count2 then
685
         Container.Last := Index - 1;
686
         return;
687
      end if;
688
 
689
      --  There are some elements aren't being deleted (the requested count was
690
      --  less than the available count), so we must slide them down to
691
      --  Index. We first calculate the index values of the respective array
692
      --  slices, using the wider of Index_Type'Base and Count_Type'Base as the
693
      --  type for intermediate calculations. For the elements that slide down,
694
      --  index value New_Last is the last index value of their new home, and
695
      --  index value J is the first index of their old home.
696
 
697
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
698
         New_Last := Old_Last - Index_Type'Base (Count);
699
         J := Index + Index_Type'Base (Count);
700
 
701
      else
702
         New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
703
         J := Index_Type'Base (Count_Type'Base (Index) + Count);
704
      end if;
705
 
706
      --  The internal elements array isn't guaranteed to exist unless we have
707
      --  elements, but we have that guarantee here because we know we have
708
      --  elements to slide.  The array index values for each slice have
709
      --  already been determined, so we just slide down to Index the elements
710
      --  that weren't deleted.
711
 
712
      declare
713
         EA : Elements_Array renames Container.Elements.EA;
714
 
715
      begin
716
         EA (Index .. New_Last) := EA (J .. Old_Last);
717
         Container.Last := New_Last;
718
      end;
719
   end Delete;
720
 
721
   procedure Delete
722
     (Container : in out Vector;
723
      Position  : in out Cursor;
724
      Count     : Count_Type := 1)
725
   is
726
      pragma Warnings (Off, Position);
727
 
728
   begin
729
      if Position.Container = null then
730
         raise Constraint_Error with "Position cursor has no element";
731
      end if;
732
 
733
      if Position.Container /= Container'Unrestricted_Access then
734
         raise Program_Error with "Position cursor denotes wrong container";
735
      end if;
736
 
737
      if Position.Index > Container.Last then
738
         raise Program_Error with "Position index is out of range";
739
      end if;
740
 
741
      Delete (Container, Position.Index, Count);
742
      Position := No_Element;
743
   end Delete;
744
 
745
   ------------------
746
   -- Delete_First --
747
   ------------------
748
 
749
   procedure Delete_First
750
     (Container : in out Vector;
751
      Count     : Count_Type := 1)
752
   is
753
   begin
754
      if Count = 0 then
755
         return;
756
      end if;
757
 
758
      if Count >= Length (Container) then
759
         Clear (Container);
760
         return;
761
      end if;
762
 
763
      Delete (Container, Index_Type'First, Count);
764
   end Delete_First;
765
 
766
   -----------------
767
   -- Delete_Last --
768
   -----------------
769
 
770
   procedure Delete_Last
771
     (Container : in out Vector;
772
      Count     : Count_Type := 1)
773
   is
774
   begin
775
      --  It is not permitted to delete items while the container is busy (for
776
      --  example, we're in the middle of a passive iteration). However, we
777
      --  always treat deleting 0 items as a no-op, even when we're busy, so we
778
      --  simply return without checking.
779
 
780
      if Count = 0 then
781
         return;
782
      end if;
783
 
784
      --  The tampering bits exist to prevent an item from being deleted (or
785
      --  otherwise harmfully manipulated) while it is being visited. Query,
786
      --  Update, and Iterate increment the busy count on entry, and decrement
787
      --  the count on exit. Delete_Last checks the count to determine whether
788
      --  it is being called while the associated callback procedure is
789
      --  executing.
790
 
791
      if Container.Busy > 0 then
792
         raise Program_Error with
793
           "attempt to tamper with cursors (vector is busy)";
794
      end if;
795
 
796
      --  There is no restriction on how large Count can be when deleting
797
      --  items. If it is equal or greater than the current length, then this
798
      --  is equivalent to clearing the vector. (In particular, there's no need
799
      --  for us to actually calculate the new value for Last.)
800
 
801
      --  If the requested count is less than the current length, then we must
802
      --  calculate the new value for Last. For the type we use the widest of
803
      --  Index_Type'Base and Count_Type'Base for the intermediate values of
804
      --  our calculation.  (See the comments in Length for more information.)
805
 
806
      if Count >= Container.Length then
807
         Container.Last := No_Index;
808
 
809
      elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
810
         Container.Last := Container.Last - Index_Type'Base (Count);
811
 
812
      else
813
         Container.Last :=
814
           Index_Type'Base (Count_Type'Base (Container.Last) - Count);
815
      end if;
816
   end Delete_Last;
817
 
818
   -------------
819
   -- Element --
820
   -------------
821
 
822
   function Element
823
     (Container : Vector;
824
      Index     : Index_Type) return Element_Type
825
   is
826
   begin
827
      if Index > Container.Last then
828
         raise Constraint_Error with "Index is out of range";
829
      end if;
830
 
831
      return Container.Elements.EA (Index);
832
   end Element;
833
 
834
   function Element (Position : Cursor) return Element_Type is
835
   begin
836
      if Position.Container = null then
837
         raise Constraint_Error with "Position cursor has no element";
838
      elsif Position.Index > Position.Container.Last then
839
         raise Constraint_Error with "Position cursor is out of range";
840
      else
841
         return Position.Container.Elements.EA (Position.Index);
842
      end if;
843
   end Element;
844
 
845
   --------------
846
   -- Finalize --
847
   --------------
848
 
849
   procedure Finalize (Container : in out Vector) is
850
      X : Elements_Access := Container.Elements;
851
 
852
   begin
853
      if Container.Busy > 0 then
854
         raise Program_Error with
855
           "attempt to tamper with cursors (vector is busy)";
856
      end if;
857
 
858
      Container.Elements := null;
859
      Container.Last := No_Index;
860
      Free (X);
861
   end Finalize;
862
 
863
   procedure Finalize (Object : in out Iterator) is
864
      B : Natural renames Object.Container.Busy;
865
   begin
866
      B := B - 1;
867
   end Finalize;
868
 
869
   procedure Finalize (Control : in out Reference_Control_Type) is
870
   begin
871
      if Control.Container /= null then
872
         declare
873
            C : Vector renames Control.Container.all;
874
            B : Natural renames C.Busy;
875
            L : Natural renames C.Lock;
876
         begin
877
            B := B - 1;
878
            L := L - 1;
879
         end;
880
 
881
         Control.Container := null;
882
      end if;
883
   end Finalize;
884
 
885
   ----------
886
   -- Find --
887
   ----------
888
 
889
   function Find
890
     (Container : Vector;
891
      Item      : Element_Type;
892
      Position  : Cursor := No_Element) return Cursor
893
   is
894
   begin
895
      if Position.Container /= null then
896
         if Position.Container /= Container'Unrestricted_Access then
897
            raise Program_Error with "Position cursor denotes wrong container";
898
         end if;
899
 
900
         if Position.Index > Container.Last then
901
            raise Program_Error with "Position index is out of range";
902
         end if;
903
      end if;
904
 
905
      for J in Position.Index .. Container.Last loop
906
         if Container.Elements.EA (J) = Item then
907
            return (Container'Unrestricted_Access, J);
908
         end if;
909
      end loop;
910
 
911
      return No_Element;
912
   end Find;
913
 
914
   ----------------
915
   -- Find_Index --
916
   ----------------
917
 
918
   function Find_Index
919
     (Container : Vector;
920
      Item      : Element_Type;
921
      Index     : Index_Type := Index_Type'First) return Extended_Index
922
   is
923
   begin
924
      for Indx in Index .. Container.Last loop
925
         if Container.Elements.EA (Indx) = Item then
926
            return Indx;
927
         end if;
928
      end loop;
929
 
930
      return No_Index;
931
   end Find_Index;
932
 
933
   -----------
934
   -- First --
935
   -----------
936
 
937
   function First (Container : Vector) return Cursor is
938
   begin
939
      if Is_Empty (Container) then
940
         return No_Element;
941
      else
942
         return (Container'Unrestricted_Access, Index_Type'First);
943
      end if;
944
   end First;
945
 
946
   function First (Object : Iterator) return Cursor is
947
   begin
948
      --  The value of the iterator object's Index component influences the
949
      --  behavior of the First (and Last) selector function.
950
 
951
      --  When the Index component is No_Index, this means the iterator
952
      --  object was constructed without a start expression, in which case the
953
      --  (forward) iteration starts from the (logical) beginning of the entire
954
      --  sequence of items (corresponding to Container.First, for a forward
955
      --  iterator).
956
 
957
      --  Otherwise, this is iteration over a partial sequence of items.
958
      --  When the Index component isn't No_Index, the iterator object was
959
      --  constructed with a start expression, that specifies the position
960
      --  from which the (forward) partial iteration begins.
961
 
962
      if Object.Index = No_Index then
963
         return First (Object.Container.all);
964
      else
965
         return Cursor'(Object.Container, Object.Index);
966
      end if;
967
   end First;
968
 
969
   -------------------
970
   -- First_Element --
971
   -------------------
972
 
973
   function First_Element (Container : Vector) return Element_Type is
974
   begin
975
      if Container.Last = No_Index then
976
         raise Constraint_Error with "Container is empty";
977
      else
978
         return Container.Elements.EA (Index_Type'First);
979
      end if;
980
   end First_Element;
981
 
982
   -----------------
983
   -- First_Index --
984
   -----------------
985
 
986
   function First_Index (Container : Vector) return Index_Type is
987
      pragma Unreferenced (Container);
988
   begin
989
      return Index_Type'First;
990
   end First_Index;
991
 
992
   ---------------------
993
   -- Generic_Sorting --
994
   ---------------------
995
 
996
   package body Generic_Sorting is
997
 
998
      ---------------
999
      -- Is_Sorted --
1000
      ---------------
1001
 
1002
      function Is_Sorted (Container : Vector) return Boolean is
1003
      begin
1004
         if Container.Last <= Index_Type'First then
1005
            return True;
1006
         end if;
1007
 
1008
         declare
1009
            EA : Elements_Array renames Container.Elements.EA;
1010
         begin
1011
            for J in Index_Type'First .. Container.Last - 1 loop
1012
               if EA (J + 1) < EA (J) then
1013
                  return False;
1014
               end if;
1015
            end loop;
1016
         end;
1017
 
1018
         return True;
1019
      end Is_Sorted;
1020
 
1021
      -----------
1022
      -- Merge --
1023
      -----------
1024
 
1025
      procedure Merge (Target, Source : in out Vector) is
1026
         I : Index_Type'Base := Target.Last;
1027
         J : Index_Type'Base;
1028
 
1029
      begin
1030
         --  The semantics of Merge changed slightly per AI05-0021. It was
1031
         --  originally the case that if Target and Source denoted the same
1032
         --  container object, then the GNAT implementation of Merge did
1033
         --  nothing. However, it was argued that RM05 did not precisely
1034
         --  specify the semantics for this corner case. The decision of the
1035
         --  ARG was that if Target and Source denote the same non-empty
1036
         --  container object, then Program_Error is raised.
1037
 
1038
         if Source.Last < Index_Type'First then  -- Source is empty
1039
            return;
1040
         end if;
1041
 
1042
         if Target'Address = Source'Address then
1043
            raise Program_Error with
1044
              "Target and Source denote same non-empty container";
1045
         end if;
1046
 
1047
         if Target.Last < Index_Type'First then  -- Target is empty
1048
            Move (Target => Target, Source => Source);
1049
            return;
1050
         end if;
1051
 
1052
         if Source.Busy > 0 then
1053
            raise Program_Error with
1054
              "attempt to tamper with cursors (vector is busy)";
1055
         end if;
1056
 
1057
         Target.Set_Length (Length (Target) + Length (Source));
1058
 
1059
         declare
1060
            TA : Elements_Array renames Target.Elements.EA;
1061
            SA : Elements_Array renames Source.Elements.EA;
1062
 
1063
         begin
1064
            J := Target.Last;
1065
            while Source.Last >= Index_Type'First loop
1066
               pragma Assert (Source.Last <= Index_Type'First
1067
                                or else not (SA (Source.Last) <
1068
                                             SA (Source.Last - 1)));
1069
 
1070
               if I < Index_Type'First then
1071
                  TA (Index_Type'First .. J) :=
1072
                    SA (Index_Type'First .. Source.Last);
1073
 
1074
                  Source.Last := No_Index;
1075
                  return;
1076
               end if;
1077
 
1078
               pragma Assert (I <= Index_Type'First
1079
                                or else not (TA (I) < TA (I - 1)));
1080
 
1081
               if SA (Source.Last) < TA (I) then
1082
                  TA (J) := TA (I);
1083
                  I := I - 1;
1084
 
1085
               else
1086
                  TA (J) := SA (Source.Last);
1087
                  Source.Last := Source.Last - 1;
1088
               end if;
1089
 
1090
               J := J - 1;
1091
            end loop;
1092
         end;
1093
      end Merge;
1094
 
1095
      ----------
1096
      -- Sort --
1097
      ----------
1098
 
1099
      procedure Sort (Container : in out Vector) is
1100
         procedure Sort is
1101
            new Generic_Array_Sort
1102
             (Index_Type   => Index_Type,
1103
              Element_Type => Element_Type,
1104
              Array_Type   => Elements_Array,
1105
              "<"          => "<");
1106
 
1107
      begin
1108
         if Container.Last <= Index_Type'First then
1109
            return;
1110
         end if;
1111
 
1112
         --  The exception behavior for the vector container must match that
1113
         --  for the list container, so we check for cursor tampering here
1114
         --  (which will catch more things) instead of for element tampering
1115
         --  (which will catch fewer things). It's true that the elements of
1116
         --  this vector container could be safely moved around while (say) an
1117
         --  iteration is taking place (iteration only increments the busy
1118
         --  counter), and so technically all we would need here is a test for
1119
         --  element tampering (indicated by the lock counter), that's simply
1120
         --  an artifact of our array-based implementation. Logically Sort
1121
         --  requires a check for cursor tampering.
1122
 
1123
         if Container.Busy > 0 then
1124
            raise Program_Error with
1125
              "attempt to tamper with cursors (vector is busy)";
1126
         end if;
1127
 
1128
         Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1129
      end Sort;
1130
 
1131
   end Generic_Sorting;
1132
 
1133
   -----------------
1134
   -- Has_Element --
1135
   -----------------
1136
 
1137
   function Has_Element (Position : Cursor) return Boolean is
1138
   begin
1139
      return Position /= No_Element;
1140
   end Has_Element;
1141
 
1142
   ------------
1143
   -- Insert --
1144
   ------------
1145
 
1146
   procedure Insert
1147
     (Container : in out Vector;
1148
      Before    : Extended_Index;
1149
      New_Item  : Element_Type;
1150
      Count     : Count_Type := 1)
1151
   is
1152
      Old_Length : constant Count_Type := Container.Length;
1153
 
1154
      Max_Length : Count_Type'Base;  -- determined from range of Index_Type
1155
      New_Length : Count_Type'Base;  -- sum of current length and Count
1156
      New_Last   : Index_Type'Base;  -- last index of vector after insertion
1157
 
1158
      Index : Index_Type'Base;  -- scratch for intermediate values
1159
      J     : Count_Type'Base;  -- scratch
1160
 
1161
      New_Capacity : Count_Type'Base;  -- length of new, expanded array
1162
      Dst_Last     : Index_Type'Base;  -- last index of new, expanded array
1163
      Dst          : Elements_Access;  -- new, expanded internal array
1164
 
1165
   begin
1166
      --  As a precondition on the generic actual Index_Type, the base type
1167
      --  must include Index_Type'Pred (Index_Type'First); this is the value
1168
      --  that Container.Last assumes when the vector is empty. However, we do
1169
      --  not allow that as the value for Index when specifying where the new
1170
      --  items should be inserted, so we must manually check. (That the user
1171
      --  is allowed to specify the value at all here is a consequence of the
1172
      --  declaration of the Extended_Index subtype, which includes the values
1173
      --  in the base range that immediately precede and immediately follow the
1174
      --  values in the Index_Type.)
1175
 
1176
      if Before < Index_Type'First then
1177
         raise Constraint_Error with
1178
           "Before index is out of range (too small)";
1179
      end if;
1180
 
1181
      --  We do allow a value greater than Container.Last to be specified as
1182
      --  the Index, but only if it's immediately greater. This allows for the
1183
      --  case of appending items to the back end of the vector. (It is assumed
1184
      --  that specifying an index value greater than Last + 1 indicates some
1185
      --  deeper flaw in the caller's algorithm, so that case is treated as a
1186
      --  proper error.)
1187
 
1188
      if Before > Container.Last
1189
        and then Before > Container.Last + 1
1190
      then
1191
         raise Constraint_Error with
1192
           "Before index is out of range (too large)";
1193
      end if;
1194
 
1195
      --  We treat inserting 0 items into the container as a no-op, even when
1196
      --  the container is busy, so we simply return.
1197
 
1198
      if Count = 0 then
1199
         return;
1200
      end if;
1201
 
1202
      --  There are two constraints we need to satisfy. The first constraint is
1203
      --  that a container cannot have more than Count_Type'Last elements, so
1204
      --  we must check the sum of the current length and the insertion count.
1205
      --  Note: we cannot simply add these values, because of the possibility
1206
      --  of overflow.
1207
 
1208
      if Old_Length > Count_Type'Last - Count then
1209
         raise Constraint_Error with "Count is out of range";
1210
      end if;
1211
 
1212
      --  It is now safe compute the length of the new vector, without fear of
1213
      --  overflow.
1214
 
1215
      New_Length := Old_Length + Count;
1216
 
1217
      --  The second constraint is that the new Last index value cannot exceed
1218
      --  Index_Type'Last. In each branch below, we calculate the maximum
1219
      --  length (computed from the range of values in Index_Type), and then
1220
      --  compare the new length to the maximum length. If the new length is
1221
      --  acceptable, then we compute the new last index from that.
1222
 
1223
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1224
 
1225
         --  We have to handle the case when there might be more values in the
1226
         --  range of Index_Type than in the range of Count_Type.
1227
 
1228
         if Index_Type'First <= 0 then
1229
 
1230
            --  We know that No_Index (the same as Index_Type'First - 1) is
1231
            --  less than 0, so it is safe to compute the following sum without
1232
            --  fear of overflow.
1233
 
1234
            Index := No_Index + Index_Type'Base (Count_Type'Last);
1235
 
1236
            if Index <= Index_Type'Last then
1237
 
1238
               --  We have determined that range of Index_Type has at least as
1239
               --  many values as in Count_Type, so Count_Type'Last is the
1240
               --  maximum number of items that are allowed.
1241
 
1242
               Max_Length := Count_Type'Last;
1243
 
1244
            else
1245
               --  The range of Index_Type has fewer values than in Count_Type,
1246
               --  so the maximum number of items is computed from the range of
1247
               --  the Index_Type.
1248
 
1249
               Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1250
            end if;
1251
 
1252
         else
1253
            --  No_Index is equal or greater than 0, so we can safely compute
1254
            --  the difference without fear of overflow (which we would have to
1255
            --  worry about if No_Index were less than 0, but that case is
1256
            --  handled above).
1257
 
1258
            Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1259
         end if;
1260
 
1261
      elsif Index_Type'First <= 0 then
1262
 
1263
         --  We know that No_Index (the same as Index_Type'First - 1) is less
1264
         --  than 0, so it is safe to compute the following sum without fear of
1265
         --  overflow.
1266
 
1267
         J := Count_Type'Base (No_Index) + Count_Type'Last;
1268
 
1269
         if J <= Count_Type'Base (Index_Type'Last) then
1270
 
1271
            --  We have determined that range of Index_Type has at least as
1272
            --  many values as in Count_Type, so Count_Type'Last is the maximum
1273
            --  number of items that are allowed.
1274
 
1275
            Max_Length := Count_Type'Last;
1276
 
1277
         else
1278
            --  The range of Index_Type has fewer values than Count_Type does,
1279
            --  so the maximum number of items is computed from the range of
1280
            --  the Index_Type.
1281
 
1282
            Max_Length :=
1283
              Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1284
         end if;
1285
 
1286
      else
1287
         --  No_Index is equal or greater than 0, so we can safely compute the
1288
         --  difference without fear of overflow (which we would have to worry
1289
         --  about if No_Index were less than 0, but that case is handled
1290
         --  above).
1291
 
1292
         Max_Length :=
1293
           Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1294
      end if;
1295
 
1296
      --  We have just computed the maximum length (number of items). We must
1297
      --  now compare the requested length to the maximum length, as we do not
1298
      --  allow a vector expand beyond the maximum (because that would create
1299
      --  an internal array with a last index value greater than
1300
      --  Index_Type'Last, with no way to index those elements).
1301
 
1302
      if New_Length > Max_Length then
1303
         raise Constraint_Error with "Count is out of range";
1304
      end if;
1305
 
1306
      --  New_Last is the last index value of the items in the container after
1307
      --  insertion.  Use the wider of Index_Type'Base and Count_Type'Base to
1308
      --  compute its value from the New_Length.
1309
 
1310
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1311
         New_Last := No_Index + Index_Type'Base (New_Length);
1312
      else
1313
         New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1314
      end if;
1315
 
1316
      if Container.Elements = null then
1317
         pragma Assert (Container.Last = No_Index);
1318
 
1319
         --  This is the simplest case, with which we must always begin: we're
1320
         --  inserting items into an empty vector that hasn't allocated an
1321
         --  internal array yet. Note that we don't need to check the busy bit
1322
         --  here, because an empty container cannot be busy.
1323
 
1324
         --  In order to preserve container invariants, we allocate the new
1325
         --  internal array first, before setting the Last index value, in case
1326
         --  the allocation fails (which can happen either because there is no
1327
         --  storage available, or because element initialization fails).
1328
 
1329
         Container.Elements := new Elements_Type'
1330
                                     (Last => New_Last,
1331
                                      EA   => (others => New_Item));
1332
 
1333
         --  The allocation of the new, internal array succeeded, so it is now
1334
         --  safe to update the Last index, restoring container invariants.
1335
 
1336
         Container.Last := New_Last;
1337
 
1338
         return;
1339
      end if;
1340
 
1341
      --  The tampering bits exist to prevent an item from being harmfully
1342
      --  manipulated while it is being visited. Query, Update, and Iterate
1343
      --  increment the busy count on entry, and decrement the count on
1344
      --  exit. Insert checks the count to determine whether it is being called
1345
      --  while the associated callback procedure is executing.
1346
 
1347
      if Container.Busy > 0 then
1348
         raise Program_Error with
1349
           "attempt to tamper with cursors (vector is busy)";
1350
      end if;
1351
 
1352
      --  An internal array has already been allocated, so we must determine
1353
      --  whether there is enough unused storage for the new items.
1354
 
1355
      if New_Length <= Container.Elements.EA'Length then
1356
 
1357
         --  In this case, we're inserting elements into a vector that has
1358
         --  already allocated an internal array, and the existing array has
1359
         --  enough unused storage for the new items.
1360
 
1361
         declare
1362
            EA : Elements_Array renames Container.Elements.EA;
1363
 
1364
         begin
1365
            if Before > Container.Last then
1366
 
1367
               --  The new items are being appended to the vector, so no
1368
               --  sliding of existing elements is required.
1369
 
1370
               EA (Before .. New_Last) := (others => New_Item);
1371
 
1372
            else
1373
               --  The new items are being inserted before some existing
1374
               --  elements, so we must slide the existing elements up to their
1375
               --  new home. We use the wider of Index_Type'Base and
1376
               --  Count_Type'Base as the type for intermediate index values.
1377
 
1378
               if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1379
                  Index := Before + Index_Type'Base (Count);
1380
 
1381
               else
1382
                  Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1383
               end if;
1384
 
1385
               EA (Index .. New_Last) := EA (Before .. Container.Last);
1386
               EA (Before .. Index - 1) := (others => New_Item);
1387
            end if;
1388
         end;
1389
 
1390
         Container.Last := New_Last;
1391
         return;
1392
      end if;
1393
 
1394
      --  In this case, we're inserting elements into a vector that has already
1395
      --  allocated an internal array, but the existing array does not have
1396
      --  enough storage, so we must allocate a new, longer array. In order to
1397
      --  guarantee that the amortized insertion cost is O(1), we always
1398
      --  allocate an array whose length is some power-of-two factor of the
1399
      --  current array length. (The new array cannot have a length less than
1400
      --  the New_Length of the container, but its last index value cannot be
1401
      --  greater than Index_Type'Last.)
1402
 
1403
      New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1404
      while New_Capacity < New_Length loop
1405
         if New_Capacity > Count_Type'Last / 2 then
1406
            New_Capacity := Count_Type'Last;
1407
            exit;
1408
         end if;
1409
 
1410
         New_Capacity := 2 * New_Capacity;
1411
      end loop;
1412
 
1413
      if New_Capacity > Max_Length then
1414
 
1415
         --  We have reached the limit of capacity, so no further expansion
1416
         --  will occur. (This is not a problem, as there is never a need to
1417
         --  have more capacity than the maximum container length.)
1418
 
1419
         New_Capacity := Max_Length;
1420
      end if;
1421
 
1422
      --  We have computed the length of the new internal array (and this is
1423
      --  what "vector capacity" means), so use that to compute its last index.
1424
 
1425
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1426
         Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1427
 
1428
      else
1429
         Dst_Last :=
1430
           Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1431
      end if;
1432
 
1433
      --  Now we allocate the new, longer internal array. If the allocation
1434
      --  fails, we have not changed any container state, so no side-effect
1435
      --  will occur as a result of propagating the exception.
1436
 
1437
      Dst := new Elements_Type (Dst_Last);
1438
 
1439
      --  We have our new internal array. All that needs to be done now is to
1440
      --  copy the existing items (if any) from the old array (the "source"
1441
      --  array, object SA below) to the new array (the "destination" array,
1442
      --  object DA below), and then deallocate the old array.
1443
 
1444
      declare
1445
         SA : Elements_Array renames Container.Elements.EA; -- source
1446
         DA : Elements_Array renames Dst.EA;                -- destination
1447
 
1448
      begin
1449
         DA (Index_Type'First .. Before - 1) :=
1450
           SA (Index_Type'First .. Before - 1);
1451
 
1452
         if Before > Container.Last then
1453
            DA (Before .. New_Last) := (others => New_Item);
1454
 
1455
         else
1456
            --  The new items are being inserted before some existing elements,
1457
            --  so we must slide the existing elements up to their new home.
1458
 
1459
            if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1460
               Index := Before + Index_Type'Base (Count);
1461
 
1462
            else
1463
               Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1464
            end if;
1465
 
1466
            DA (Before .. Index - 1) := (others => New_Item);
1467
            DA (Index .. New_Last) := SA (Before .. Container.Last);
1468
         end if;
1469
 
1470
      exception
1471
         when others =>
1472
            Free (Dst);
1473
            raise;
1474
      end;
1475
 
1476
      --  We have successfully copied the items onto the new array, so the
1477
      --  final thing to do is deallocate the old array.
1478
 
1479
      declare
1480
         X : Elements_Access := Container.Elements;
1481
      begin
1482
         --  We first isolate the old internal array, removing it from the
1483
         --  container and replacing it with the new internal array, before we
1484
         --  deallocate the old array (which can fail if finalization of
1485
         --  elements propagates an exception).
1486
 
1487
         Container.Elements := Dst;
1488
         Container.Last := New_Last;
1489
 
1490
         --  The container invariants have been restored, so it is now safe to
1491
         --  attempt to deallocate the old array.
1492
 
1493
         Free (X);
1494
      end;
1495
   end Insert;
1496
 
1497
   procedure Insert
1498
     (Container : in out Vector;
1499
      Before    : Extended_Index;
1500
      New_Item  : Vector)
1501
   is
1502
      N : constant Count_Type := Length (New_Item);
1503
      J : Index_Type'Base;
1504
 
1505
   begin
1506
      --  Use Insert_Space to create the "hole" (the destination slice) into
1507
      --  which we copy the source items.
1508
 
1509
      Insert_Space (Container, Before, Count => N);
1510
 
1511
      if N = 0 then
1512
 
1513
         --  There's nothing else to do here (vetting of parameters was
1514
         --  performed already in Insert_Space), so we simply return.
1515
 
1516
         return;
1517
      end if;
1518
 
1519
      --  We calculate the last index value of the destination slice using the
1520
      --  wider of Index_Type'Base and count_Type'Base.
1521
 
1522
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1523
         J := (Before - 1) + Index_Type'Base (N);
1524
 
1525
      else
1526
         J := Index_Type'Base (Count_Type'Base (Before - 1) + N);
1527
      end if;
1528
 
1529
      if Container'Address /= New_Item'Address then
1530
 
1531
         --  This is the simple case.  New_Item denotes an object different
1532
         --  from Container, so there's nothing special we need to do to copy
1533
         --  the source items to their destination, because all of the source
1534
         --  items are contiguous.
1535
 
1536
         Container.Elements.EA (Before .. J) :=
1537
           New_Item.Elements.EA (Index_Type'First .. New_Item.Last);
1538
 
1539
         return;
1540
      end if;
1541
 
1542
      --  New_Item denotes the same object as Container, so an insertion has
1543
      --  potentially split the source items. The destination is always the
1544
      --  range [Before, J], but the source is [Index_Type'First, Before) and
1545
      --  (J, Container.Last]. We perform the copy in two steps, using each of
1546
      --  the two slices of the source items.
1547
 
1548
      declare
1549
         L : constant Index_Type'Base := Before - 1;
1550
 
1551
         subtype Src_Index_Subtype is Index_Type'Base range
1552
           Index_Type'First .. L;
1553
 
1554
         Src : Elements_Array renames
1555
           Container.Elements.EA (Src_Index_Subtype);
1556
 
1557
         K : Index_Type'Base;
1558
 
1559
      begin
1560
         --  We first copy the source items that precede the space we
1561
         --  inserted. Index value K is the last index of that portion
1562
         --  destination that receives this slice of the source. (If Before
1563
         --  equals Index_Type'First, then this first source slice will be
1564
         --  empty, which is harmless.)
1565
 
1566
         if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1567
            K := L + Index_Type'Base (Src'Length);
1568
 
1569
         else
1570
            K := Index_Type'Base (Count_Type'Base (L) + Src'Length);
1571
         end if;
1572
 
1573
         Container.Elements.EA (Before .. K) := Src;
1574
 
1575
         if Src'Length = N then
1576
 
1577
            --  The new items were effectively appended to the container, so we
1578
            --  have already copied all of the items that need to be copied.
1579
            --  We return early here, even though the source slice below is
1580
            --  empty (so the assignment would be harmless), because we want to
1581
            --  avoid computing J + 1, which will overflow if J equals
1582
            --  Index_Type'Base'Last.
1583
 
1584
            return;
1585
         end if;
1586
      end;
1587
 
1588
      declare
1589
         --  Note that we want to avoid computing J + 1 here, in case J equals
1590
         --  Index_Type'Base'Last. We prevent that by returning early above,
1591
         --  immediately after copying the first slice of the source, and
1592
         --  determining that this second slice of the source is empty.
1593
 
1594
         F : constant Index_Type'Base := J + 1;
1595
 
1596
         subtype Src_Index_Subtype is Index_Type'Base range
1597
           F .. Container.Last;
1598
 
1599
         Src : Elements_Array renames
1600
           Container.Elements.EA (Src_Index_Subtype);
1601
 
1602
         K : Index_Type'Base;
1603
 
1604
      begin
1605
         --  We next copy the source items that follow the space we inserted.
1606
         --  Index value K is the first index of that portion of the
1607
         --  destination that receives this slice of the source. (For the
1608
         --  reasons given above, this slice is guaranteed to be non-empty.)
1609
 
1610
         if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1611
            K := F - Index_Type'Base (Src'Length);
1612
 
1613
         else
1614
            K := Index_Type'Base (Count_Type'Base (F) - Src'Length);
1615
         end if;
1616
 
1617
         Container.Elements.EA (K .. J) := Src;
1618
      end;
1619
   end Insert;
1620
 
1621
   procedure Insert
1622
     (Container : in out Vector;
1623
      Before    : Cursor;
1624
      New_Item  : Vector)
1625
   is
1626
      Index : Index_Type'Base;
1627
 
1628
   begin
1629
      if Before.Container /= null
1630
        and then Before.Container /= Container'Unrestricted_Access
1631
      then
1632
         raise Program_Error with "Before cursor denotes wrong container";
1633
      end if;
1634
 
1635
      if Is_Empty (New_Item) then
1636
         return;
1637
      end if;
1638
 
1639
      if Before.Container = null
1640
        or else Before.Index > Container.Last
1641
      then
1642
         if Container.Last = Index_Type'Last then
1643
            raise Constraint_Error with
1644
              "vector is already at its maximum length";
1645
         end if;
1646
 
1647
         Index := Container.Last + 1;
1648
 
1649
      else
1650
         Index := Before.Index;
1651
      end if;
1652
 
1653
      Insert (Container, Index, New_Item);
1654
   end Insert;
1655
 
1656
   procedure Insert
1657
     (Container : in out Vector;
1658
      Before    : Cursor;
1659
      New_Item  : Vector;
1660
      Position  : out Cursor)
1661
   is
1662
      Index : Index_Type'Base;
1663
 
1664
   begin
1665
      if Before.Container /= null
1666
        and then Before.Container /= Container'Unrestricted_Access
1667
      then
1668
         raise Program_Error with "Before cursor denotes wrong container";
1669
      end if;
1670
 
1671
      if Is_Empty (New_Item) then
1672
         if Before.Container = null
1673
           or else Before.Index > Container.Last
1674
         then
1675
            Position := No_Element;
1676
         else
1677
            Position := (Container'Unrestricted_Access, Before.Index);
1678
         end if;
1679
 
1680
         return;
1681
      end if;
1682
 
1683
      if Before.Container = null
1684
        or else Before.Index > Container.Last
1685
      then
1686
         if Container.Last = Index_Type'Last then
1687
            raise Constraint_Error with
1688
              "vector is already at its maximum length";
1689
         end if;
1690
 
1691
         Index := Container.Last + 1;
1692
 
1693
      else
1694
         Index := Before.Index;
1695
      end if;
1696
 
1697
      Insert (Container, Index, New_Item);
1698
 
1699
      Position := (Container'Unrestricted_Access, Index);
1700
   end Insert;
1701
 
1702
   procedure Insert
1703
     (Container : in out Vector;
1704
      Before    : Cursor;
1705
      New_Item  : Element_Type;
1706
      Count     : Count_Type := 1)
1707
   is
1708
      Index : Index_Type'Base;
1709
 
1710
   begin
1711
      if Before.Container /= null
1712
        and then Before.Container /= Container'Unrestricted_Access
1713
      then
1714
         raise Program_Error with "Before cursor denotes wrong container";
1715
      end if;
1716
 
1717
      if Count = 0 then
1718
         return;
1719
      end if;
1720
 
1721
      if Before.Container = null
1722
        or else Before.Index > Container.Last
1723
      then
1724
         if Container.Last = Index_Type'Last then
1725
            raise Constraint_Error with
1726
              "vector is already at its maximum length";
1727
         else
1728
            Index := Container.Last + 1;
1729
         end if;
1730
 
1731
      else
1732
         Index := Before.Index;
1733
      end if;
1734
 
1735
      Insert (Container, Index, New_Item, Count);
1736
   end Insert;
1737
 
1738
   procedure Insert
1739
     (Container : in out Vector;
1740
      Before    : Cursor;
1741
      New_Item  : Element_Type;
1742
      Position  : out Cursor;
1743
      Count     : Count_Type := 1)
1744
   is
1745
      Index : Index_Type'Base;
1746
 
1747
   begin
1748
      if Before.Container /= null
1749
        and then Before.Container /= Container'Unrestricted_Access
1750
      then
1751
         raise Program_Error with "Before cursor denotes wrong container";
1752
      end if;
1753
 
1754
      if Count = 0 then
1755
         if Before.Container = null
1756
           or else Before.Index > Container.Last
1757
         then
1758
            Position := No_Element;
1759
         else
1760
            Position := (Container'Unrestricted_Access, Before.Index);
1761
         end if;
1762
 
1763
         return;
1764
      end if;
1765
 
1766
      if Before.Container = null
1767
        or else Before.Index > Container.Last
1768
      then
1769
         if Container.Last = Index_Type'Last then
1770
            raise Constraint_Error with
1771
              "vector is already at its maximum length";
1772
         end if;
1773
 
1774
         Index := Container.Last + 1;
1775
 
1776
      else
1777
         Index := Before.Index;
1778
      end if;
1779
 
1780
      Insert (Container, Index, New_Item, Count);
1781
 
1782
      Position := (Container'Unrestricted_Access, Index);
1783
   end Insert;
1784
 
1785
   procedure Insert
1786
     (Container : in out Vector;
1787
      Before    : Extended_Index;
1788
      Count     : Count_Type := 1)
1789
   is
1790
      New_Item : Element_Type;  -- Default-initialized value
1791
      pragma Warnings (Off, New_Item);
1792
 
1793
   begin
1794
      Insert (Container, Before, New_Item, Count);
1795
   end Insert;
1796
 
1797
   procedure Insert
1798
     (Container : in out Vector;
1799
      Before    : Cursor;
1800
      Position  : out Cursor;
1801
      Count     : Count_Type := 1)
1802
   is
1803
      New_Item : Element_Type;  -- Default-initialized value
1804
      pragma Warnings (Off, New_Item);
1805
 
1806
   begin
1807
      Insert (Container, Before, New_Item, Position, Count);
1808
   end Insert;
1809
 
1810
   ------------------
1811
   -- Insert_Space --
1812
   ------------------
1813
 
1814
   procedure Insert_Space
1815
     (Container : in out Vector;
1816
      Before    : Extended_Index;
1817
      Count     : Count_Type := 1)
1818
   is
1819
      Old_Length : constant Count_Type := Container.Length;
1820
 
1821
      Max_Length : Count_Type'Base;  -- determined from range of Index_Type
1822
      New_Length : Count_Type'Base;  -- sum of current length and Count
1823
      New_Last   : Index_Type'Base;  -- last index of vector after insertion
1824
 
1825
      Index : Index_Type'Base;  -- scratch for intermediate values
1826
      J     : Count_Type'Base;  -- scratch
1827
 
1828
      New_Capacity : Count_Type'Base;  -- length of new, expanded array
1829
      Dst_Last     : Index_Type'Base;  -- last index of new, expanded array
1830
      Dst          : Elements_Access;  -- new, expanded internal array
1831
 
1832
   begin
1833
      --  As a precondition on the generic actual Index_Type, the base type
1834
      --  must include Index_Type'Pred (Index_Type'First); this is the value
1835
      --  that Container.Last assumes when the vector is empty. However, we do
1836
      --  not allow that as the value for Index when specifying where the new
1837
      --  items should be inserted, so we must manually check. (That the user
1838
      --  is allowed to specify the value at all here is a consequence of the
1839
      --  declaration of the Extended_Index subtype, which includes the values
1840
      --  in the base range that immediately precede and immediately follow the
1841
      --  values in the Index_Type.)
1842
 
1843
      if Before < Index_Type'First then
1844
         raise Constraint_Error with
1845
           "Before index is out of range (too small)";
1846
      end if;
1847
 
1848
      --  We do allow a value greater than Container.Last to be specified as
1849
      --  the Index, but only if it's immediately greater. This allows for the
1850
      --  case of appending items to the back end of the vector. (It is assumed
1851
      --  that specifying an index value greater than Last + 1 indicates some
1852
      --  deeper flaw in the caller's algorithm, so that case is treated as a
1853
      --  proper error.)
1854
 
1855
      if Before > Container.Last
1856
        and then Before > Container.Last + 1
1857
      then
1858
         raise Constraint_Error with
1859
           "Before index is out of range (too large)";
1860
      end if;
1861
 
1862
      --  We treat inserting 0 items into the container as a no-op, even when
1863
      --  the container is busy, so we simply return.
1864
 
1865
      if Count = 0 then
1866
         return;
1867
      end if;
1868
 
1869
      --  There are two constraints we need to satisfy. The first constraint is
1870
      --  that a container cannot have more than Count_Type'Last elements, so
1871
      --  we must check the sum of the current length and the insertion count.
1872
      --  Note: we cannot simply add these values, because of the possibility
1873
      --  of overflow.
1874
 
1875
      if Old_Length > Count_Type'Last - Count then
1876
         raise Constraint_Error with "Count is out of range";
1877
      end if;
1878
 
1879
      --  It is now safe compute the length of the new vector, without fear of
1880
      --  overflow.
1881
 
1882
      New_Length := Old_Length + Count;
1883
 
1884
      --  The second constraint is that the new Last index value cannot exceed
1885
      --  Index_Type'Last. In each branch below, we calculate the maximum
1886
      --  length (computed from the range of values in Index_Type), and then
1887
      --  compare the new length to the maximum length. If the new length is
1888
      --  acceptable, then we compute the new last index from that.
1889
 
1890
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1891
 
1892
         --  We have to handle the case when there might be more values in the
1893
         --  range of Index_Type than in the range of Count_Type.
1894
 
1895
         if Index_Type'First <= 0 then
1896
 
1897
            --  We know that No_Index (the same as Index_Type'First - 1) is
1898
            --  less than 0, so it is safe to compute the following sum without
1899
            --  fear of overflow.
1900
 
1901
            Index := No_Index + Index_Type'Base (Count_Type'Last);
1902
 
1903
            if Index <= Index_Type'Last then
1904
 
1905
               --  We have determined that range of Index_Type has at least as
1906
               --  many values as in Count_Type, so Count_Type'Last is the
1907
               --  maximum number of items that are allowed.
1908
 
1909
               Max_Length := Count_Type'Last;
1910
 
1911
            else
1912
               --  The range of Index_Type has fewer values than in Count_Type,
1913
               --  so the maximum number of items is computed from the range of
1914
               --  the Index_Type.
1915
 
1916
               Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1917
            end if;
1918
 
1919
         else
1920
            --  No_Index is equal or greater than 0, so we can safely compute
1921
            --  the difference without fear of overflow (which we would have to
1922
            --  worry about if No_Index were less than 0, but that case is
1923
            --  handled above).
1924
 
1925
            Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1926
         end if;
1927
 
1928
      elsif Index_Type'First <= 0 then
1929
 
1930
         --  We know that No_Index (the same as Index_Type'First - 1) is less
1931
         --  than 0, so it is safe to compute the following sum without fear of
1932
         --  overflow.
1933
 
1934
         J := Count_Type'Base (No_Index) + Count_Type'Last;
1935
 
1936
         if J <= Count_Type'Base (Index_Type'Last) then
1937
 
1938
            --  We have determined that range of Index_Type has at least as
1939
            --  many values as in Count_Type, so Count_Type'Last is the maximum
1940
            --  number of items that are allowed.
1941
 
1942
            Max_Length := Count_Type'Last;
1943
 
1944
         else
1945
            --  The range of Index_Type has fewer values than Count_Type does,
1946
            --  so the maximum number of items is computed from the range of
1947
            --  the Index_Type.
1948
 
1949
            Max_Length :=
1950
              Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1951
         end if;
1952
 
1953
      else
1954
         --  No_Index is equal or greater than 0, so we can safely compute the
1955
         --  difference without fear of overflow (which we would have to worry
1956
         --  about if No_Index were less than 0, but that case is handled
1957
         --  above).
1958
 
1959
         Max_Length :=
1960
           Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1961
      end if;
1962
 
1963
      --  We have just computed the maximum length (number of items). We must
1964
      --  now compare the requested length to the maximum length, as we do not
1965
      --  allow a vector expand beyond the maximum (because that would create
1966
      --  an internal array with a last index value greater than
1967
      --  Index_Type'Last, with no way to index those elements).
1968
 
1969
      if New_Length > Max_Length then
1970
         raise Constraint_Error with "Count is out of range";
1971
      end if;
1972
 
1973
      --  New_Last is the last index value of the items in the container after
1974
      --  insertion.  Use the wider of Index_Type'Base and Count_Type'Base to
1975
      --  compute its value from the New_Length.
1976
 
1977
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1978
         New_Last := No_Index + Index_Type'Base (New_Length);
1979
 
1980
      else
1981
         New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1982
      end if;
1983
 
1984
      if Container.Elements = null then
1985
         pragma Assert (Container.Last = No_Index);
1986
 
1987
         --  This is the simplest case, with which we must always begin: we're
1988
         --  inserting items into an empty vector that hasn't allocated an
1989
         --  internal array yet. Note that we don't need to check the busy bit
1990
         --  here, because an empty container cannot be busy.
1991
 
1992
         --  In order to preserve container invariants, we allocate the new
1993
         --  internal array first, before setting the Last index value, in case
1994
         --  the allocation fails (which can happen either because there is no
1995
         --  storage available, or because default-valued element
1996
         --  initialization fails).
1997
 
1998
         Container.Elements := new Elements_Type (New_Last);
1999
 
2000
         --  The allocation of the new, internal array succeeded, so it is now
2001
         --  safe to update the Last index, restoring container invariants.
2002
 
2003
         Container.Last := New_Last;
2004
 
2005
         return;
2006
      end if;
2007
 
2008
      --  The tampering bits exist to prevent an item from being harmfully
2009
      --  manipulated while it is being visited. Query, Update, and Iterate
2010
      --  increment the busy count on entry, and decrement the count on
2011
      --  exit. Insert checks the count to determine whether it is being called
2012
      --  while the associated callback procedure is executing.
2013
 
2014
      if Container.Busy > 0 then
2015
         raise Program_Error with
2016
           "attempt to tamper with cursors (vector is busy)";
2017
      end if;
2018
 
2019
      --  An internal array has already been allocated, so we must determine
2020
      --  whether there is enough unused storage for the new items.
2021
 
2022
      if New_Last <= Container.Elements.Last then
2023
 
2024
         --  In this case, we're inserting space into a vector that has already
2025
         --  allocated an internal array, and the existing array has enough
2026
         --  unused storage for the new items.
2027
 
2028
         declare
2029
            EA : Elements_Array renames Container.Elements.EA;
2030
 
2031
         begin
2032
            if Before <= Container.Last then
2033
 
2034
               --  The space is being inserted before some existing elements,
2035
               --  so we must slide the existing elements up to their new
2036
               --  home. We use the wider of Index_Type'Base and
2037
               --  Count_Type'Base as the type for intermediate index values.
2038
 
2039
               if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2040
                  Index := Before + Index_Type'Base (Count);
2041
 
2042
               else
2043
                  Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2044
               end if;
2045
 
2046
               EA (Index .. New_Last) := EA (Before .. Container.Last);
2047
            end if;
2048
         end;
2049
 
2050
         Container.Last := New_Last;
2051
         return;
2052
      end if;
2053
 
2054
      --  In this case, we're inserting space into a vector that has already
2055
      --  allocated an internal array, but the existing array does not have
2056
      --  enough storage, so we must allocate a new, longer array. In order to
2057
      --  guarantee that the amortized insertion cost is O(1), we always
2058
      --  allocate an array whose length is some power-of-two factor of the
2059
      --  current array length. (The new array cannot have a length less than
2060
      --  the New_Length of the container, but its last index value cannot be
2061
      --  greater than Index_Type'Last.)
2062
 
2063
      New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
2064
      while New_Capacity < New_Length loop
2065
         if New_Capacity > Count_Type'Last / 2 then
2066
            New_Capacity := Count_Type'Last;
2067
            exit;
2068
         end if;
2069
 
2070
         New_Capacity := 2 * New_Capacity;
2071
      end loop;
2072
 
2073
      if New_Capacity > Max_Length then
2074
 
2075
         --  We have reached the limit of capacity, so no further expansion
2076
         --  will occur. (This is not a problem, as there is never a need to
2077
         --  have more capacity than the maximum container length.)
2078
 
2079
         New_Capacity := Max_Length;
2080
      end if;
2081
 
2082
      --  We have computed the length of the new internal array (and this is
2083
      --  what "vector capacity" means), so use that to compute its last index.
2084
 
2085
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2086
         Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2087
 
2088
      else
2089
         Dst_Last :=
2090
           Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2091
      end if;
2092
 
2093
      --  Now we allocate the new, longer internal array. If the allocation
2094
      --  fails, we have not changed any container state, so no side-effect
2095
      --  will occur as a result of propagating the exception.
2096
 
2097
      Dst := new Elements_Type (Dst_Last);
2098
 
2099
      --  We have our new internal array. All that needs to be done now is to
2100
      --  copy the existing items (if any) from the old array (the "source"
2101
      --  array, object SA below) to the new array (the "destination" array,
2102
      --  object DA below), and then deallocate the old array.
2103
 
2104
      declare
2105
         SA : Elements_Array renames Container.Elements.EA;  -- source
2106
         DA : Elements_Array renames Dst.EA;                 -- destination
2107
 
2108
      begin
2109
         DA (Index_Type'First .. Before - 1) :=
2110
           SA (Index_Type'First .. Before - 1);
2111
 
2112
         if Before <= Container.Last then
2113
 
2114
            --  The space is being inserted before some existing elements, so
2115
            --  we must slide the existing elements up to their new home.
2116
 
2117
            if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2118
               Index := Before + Index_Type'Base (Count);
2119
 
2120
            else
2121
               Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2122
            end if;
2123
 
2124
            DA (Index .. New_Last) := SA (Before .. Container.Last);
2125
         end if;
2126
 
2127
      exception
2128
         when others =>
2129
            Free (Dst);
2130
            raise;
2131
      end;
2132
 
2133
      --  We have successfully copied the items onto the new array, so the
2134
      --  final thing to do is restore invariants, and deallocate the old
2135
      --  array.
2136
 
2137
      declare
2138
         X : Elements_Access := Container.Elements;
2139
 
2140
      begin
2141
         --  We first isolate the old internal array, removing it from the
2142
         --  container and replacing it with the new internal array, before we
2143
         --  deallocate the old array (which can fail if finalization of
2144
         --  elements propagates an exception).
2145
 
2146
         Container.Elements := Dst;
2147
         Container.Last := New_Last;
2148
 
2149
         --  The container invariants have been restored, so it is now safe to
2150
         --  attempt to deallocate the old array.
2151
 
2152
         Free (X);
2153
      end;
2154
   end Insert_Space;
2155
 
2156
   procedure Insert_Space
2157
     (Container : in out Vector;
2158
      Before    : Cursor;
2159
      Position  : out Cursor;
2160
      Count     : Count_Type := 1)
2161
   is
2162
      Index : Index_Type'Base;
2163
 
2164
   begin
2165
      if Before.Container /= null
2166
        and then Before.Container /= Container'Unrestricted_Access
2167
      then
2168
         raise Program_Error with "Before cursor denotes wrong container";
2169
      end if;
2170
 
2171
      if Count = 0 then
2172
         if Before.Container = null
2173
           or else Before.Index > Container.Last
2174
         then
2175
            Position := No_Element;
2176
         else
2177
            Position := (Container'Unrestricted_Access, Before.Index);
2178
         end if;
2179
 
2180
         return;
2181
      end if;
2182
 
2183
      if Before.Container = null
2184
        or else Before.Index > Container.Last
2185
      then
2186
         if Container.Last = Index_Type'Last then
2187
            raise Constraint_Error with
2188
              "vector is already at its maximum length";
2189
         else
2190
            Index := Container.Last + 1;
2191
         end if;
2192
 
2193
      else
2194
         Index := Before.Index;
2195
      end if;
2196
 
2197
      Insert_Space (Container, Index, Count => Count);
2198
 
2199
      Position := (Container'Unrestricted_Access, Index);
2200
   end Insert_Space;
2201
 
2202
   --------------
2203
   -- Is_Empty --
2204
   --------------
2205
 
2206
   function Is_Empty (Container : Vector) return Boolean is
2207
   begin
2208
      return Container.Last < Index_Type'First;
2209
   end Is_Empty;
2210
 
2211
   -------------
2212
   -- Iterate --
2213
   -------------
2214
 
2215
   procedure Iterate
2216
     (Container : Vector;
2217
      Process   : not null access procedure (Position : Cursor))
2218
   is
2219
      B : Natural renames Container'Unrestricted_Access.all.Busy;
2220
 
2221
   begin
2222
      B := B + 1;
2223
 
2224
      begin
2225
         for Indx in Index_Type'First .. Container.Last loop
2226
            Process (Cursor'(Container'Unrestricted_Access, Indx));
2227
         end loop;
2228
      exception
2229
         when others =>
2230
            B := B - 1;
2231
            raise;
2232
      end;
2233
 
2234
      B := B - 1;
2235
   end Iterate;
2236
 
2237
   function Iterate
2238
     (Container : Vector)
2239
      return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2240
   is
2241
      V : constant Vector_Access := Container'Unrestricted_Access;
2242
      B : Natural renames V.Busy;
2243
 
2244
   begin
2245
      --  The value of its Index component influences the behavior of the First
2246
      --  and Last selector functions of the iterator object. When the Index
2247
      --  component is No_Index (as is the case here), this means the iterator
2248
      --  object was constructed without a start expression. This is a complete
2249
      --  iterator, meaning that the iteration starts from the (logical)
2250
      --  beginning of the sequence of items.
2251
 
2252
      --  Note: For a forward iterator, Container.First is the beginning, and
2253
      --  for a reverse iterator, Container.Last is the beginning.
2254
 
2255
      return It : constant Iterator :=
2256
                    (Limited_Controlled with
2257
                       Container => V,
2258
                       Index     => No_Index)
2259
      do
2260
         B := B + 1;
2261
      end return;
2262
   end Iterate;
2263
 
2264
   function Iterate
2265
     (Container : Vector;
2266
      Start     : Cursor)
2267
      return Vector_Iterator_Interfaces.Reversible_Iterator'class
2268
   is
2269
      V : constant Vector_Access := Container'Unrestricted_Access;
2270
      B : Natural renames V.Busy;
2271
 
2272
   begin
2273
      --  It was formerly the case that when Start = No_Element, the partial
2274
      --  iterator was defined to behave the same as for a complete iterator,
2275
      --  and iterate over the entire sequence of items. However, those
2276
      --  semantics were unintuitive and arguably error-prone (it is too easy
2277
      --  to accidentally create an endless loop), and so they were changed,
2278
      --  per the ARG meeting in Denver on 2011/11. However, there was no
2279
      --  consensus about what positive meaning this corner case should have,
2280
      --  and so it was decided to simply raise an exception. This does imply,
2281
      --  however, that it is not possible to use a partial iterator to specify
2282
      --  an empty sequence of items.
2283
 
2284
      if Start.Container = null then
2285
         raise Constraint_Error with
2286
           "Start position for iterator equals No_Element";
2287
      end if;
2288
 
2289
      if Start.Container /= V then
2290
         raise Program_Error with
2291
           "Start cursor of Iterate designates wrong vector";
2292
      end if;
2293
 
2294
      if Start.Index > V.Last then
2295
         raise Constraint_Error with
2296
           "Start position for iterator equals No_Element";
2297
      end if;
2298
 
2299
      --  The value of its Index component influences the behavior of the First
2300
      --  and Last selector functions of the iterator object. When the Index
2301
      --  component is not No_Index (as is the case here), it means that this
2302
      --  is a partial iteration, over a subset of the complete sequence of
2303
      --  items. The iterator object was constructed with a start expression,
2304
      --  indicating the position from which the iteration begins. Note that
2305
      --  the start position has the same value irrespective of whether this
2306
      --  is a forward or reverse iteration.
2307
 
2308
      return It : constant Iterator :=
2309
                    (Limited_Controlled with
2310
                       Container => V,
2311
                       Index     => Start.Index)
2312
      do
2313
         B := B + 1;
2314
      end return;
2315
   end Iterate;
2316
 
2317
   ----------
2318
   -- Last --
2319
   ----------
2320
 
2321
   function Last (Container : Vector) return Cursor is
2322
   begin
2323
      if Is_Empty (Container) then
2324
         return No_Element;
2325
      else
2326
         return (Container'Unrestricted_Access, Container.Last);
2327
      end if;
2328
   end Last;
2329
 
2330
   function Last (Object : Iterator) return Cursor is
2331
   begin
2332
      --  The value of the iterator object's Index component influences the
2333
      --  behavior of the Last (and First) selector function.
2334
 
2335
      --  When the Index component is No_Index, this means the iterator
2336
      --  object was constructed without a start expression, in which case the
2337
      --  (reverse) iteration starts from the (logical) beginning of the entire
2338
      --  sequence (corresponding to Container.Last, for a reverse iterator).
2339
 
2340
      --  Otherwise, this is iteration over a partial sequence of items.
2341
      --  When the Index component is not No_Index, the iterator object was
2342
      --  constructed with a start expression, that specifies the position
2343
      --  from which the (reverse) partial iteration begins.
2344
 
2345
      if Object.Index = No_Index then
2346
         return Last (Object.Container.all);
2347
      else
2348
         return Cursor'(Object.Container, Object.Index);
2349
      end if;
2350
   end Last;
2351
 
2352
   ------------------
2353
   -- Last_Element --
2354
   ------------------
2355
 
2356
   function Last_Element (Container : Vector) return Element_Type is
2357
   begin
2358
      if Container.Last = No_Index then
2359
         raise Constraint_Error with "Container is empty";
2360
      else
2361
         return Container.Elements.EA (Container.Last);
2362
      end if;
2363
   end Last_Element;
2364
 
2365
   ----------------
2366
   -- Last_Index --
2367
   ----------------
2368
 
2369
   function Last_Index (Container : Vector) return Extended_Index is
2370
   begin
2371
      return Container.Last;
2372
   end Last_Index;
2373
 
2374
   ------------
2375
   -- Length --
2376
   ------------
2377
 
2378
   function Length (Container : Vector) return Count_Type is
2379
      L : constant Index_Type'Base := Container.Last;
2380
      F : constant Index_Type := Index_Type'First;
2381
 
2382
   begin
2383
      --  The base range of the index type (Index_Type'Base) might not include
2384
      --  all values for length (Count_Type). Contrariwise, the index type
2385
      --  might include values outside the range of length.  Hence we use
2386
      --  whatever type is wider for intermediate values when calculating
2387
      --  length. Note that no matter what the index type is, the maximum
2388
      --  length to which a vector is allowed to grow is always the minimum
2389
      --  of Count_Type'Last and (IT'Last - IT'First + 1).
2390
 
2391
      --  For example, an Index_Type with range -127 .. 127 is only guaranteed
2392
      --  to have a base range of -128 .. 127, but the corresponding vector
2393
      --  would have lengths in the range 0 .. 255. In this case we would need
2394
      --  to use Count_Type'Base for intermediate values.
2395
 
2396
      --  Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2397
      --  vector would have a maximum length of 10, but the index values lie
2398
      --  outside the range of Count_Type (which is only 32 bits). In this
2399
      --  case we would need to use Index_Type'Base for intermediate values.
2400
 
2401
      if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2402
         return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2403
      else
2404
         return Count_Type (L - F + 1);
2405
      end if;
2406
   end Length;
2407
 
2408
   ----------
2409
   -- Move --
2410
   ----------
2411
 
2412
   procedure Move
2413
     (Target : in out Vector;
2414
      Source : in out Vector)
2415
   is
2416
   begin
2417
      if Target'Address = Source'Address then
2418
         return;
2419
      end if;
2420
 
2421
      if Target.Busy > 0 then
2422
         raise Program_Error with
2423
           "attempt to tamper with cursors (Target is busy)";
2424
      end if;
2425
 
2426
      if Source.Busy > 0 then
2427
         raise Program_Error with
2428
           "attempt to tamper with cursors (Source is busy)";
2429
      end if;
2430
 
2431
      declare
2432
         Target_Elements : constant Elements_Access := Target.Elements;
2433
      begin
2434
         Target.Elements := Source.Elements;
2435
         Source.Elements := Target_Elements;
2436
      end;
2437
 
2438
      Target.Last := Source.Last;
2439
      Source.Last := No_Index;
2440
   end Move;
2441
 
2442
   ----------
2443
   -- Next --
2444
   ----------
2445
 
2446
   function Next (Position : Cursor) return Cursor is
2447
   begin
2448
      if Position.Container = null then
2449
         return No_Element;
2450
      elsif Position.Index < Position.Container.Last then
2451
         return (Position.Container, Position.Index + 1);
2452
      else
2453
         return No_Element;
2454
      end if;
2455
   end Next;
2456
 
2457
   function Next (Object : Iterator; Position : Cursor) return Cursor is
2458
   begin
2459
      if Position.Container = null then
2460
         return No_Element;
2461
      end if;
2462
 
2463
      if Position.Container /= Object.Container then
2464
         raise Program_Error with
2465
           "Position cursor of Next designates wrong vector";
2466
      end if;
2467
 
2468
      return Next (Position);
2469
   end Next;
2470
 
2471
   procedure Next (Position : in out Cursor) is
2472
   begin
2473
      if Position.Container = null then
2474
         return;
2475
      elsif Position.Index < Position.Container.Last then
2476
         Position.Index := Position.Index + 1;
2477
      else
2478
         Position := No_Element;
2479
      end if;
2480
   end Next;
2481
 
2482
   -------------
2483
   -- Prepend --
2484
   -------------
2485
 
2486
   procedure Prepend (Container : in out Vector; New_Item : Vector) is
2487
   begin
2488
      Insert (Container, Index_Type'First, New_Item);
2489
   end Prepend;
2490
 
2491
   procedure Prepend
2492
     (Container : in out Vector;
2493
      New_Item  : Element_Type;
2494
      Count     : Count_Type := 1)
2495
   is
2496
   begin
2497
      Insert (Container,
2498
              Index_Type'First,
2499
              New_Item,
2500
              Count);
2501
   end Prepend;
2502
 
2503
   --------------
2504
   -- Previous --
2505
   --------------
2506
 
2507
   function Previous (Position : Cursor) return Cursor is
2508
   begin
2509
      if Position.Container = null then
2510
         return No_Element;
2511
      elsif Position.Index > Index_Type'First then
2512
         return (Position.Container, Position.Index - 1);
2513
      else
2514
         return No_Element;
2515
      end if;
2516
   end Previous;
2517
 
2518
   function Previous (Object : Iterator; Position : Cursor) return Cursor is
2519
   begin
2520
      if Position.Container = null then
2521
         return No_Element;
2522
      end if;
2523
 
2524
      if Position.Container /= Object.Container then
2525
         raise Program_Error with
2526
           "Position cursor of Previous designates wrong vector";
2527
      end if;
2528
 
2529
      return Previous (Position);
2530
   end Previous;
2531
 
2532
   procedure Previous (Position : in out Cursor) is
2533
   begin
2534
      if Position.Container = null then
2535
         return;
2536
      elsif Position.Index > Index_Type'First then
2537
         Position.Index := Position.Index - 1;
2538
      else
2539
         Position := No_Element;
2540
      end if;
2541
   end Previous;
2542
 
2543
   -------------------
2544
   -- Query_Element --
2545
   -------------------
2546
 
2547
   procedure Query_Element
2548
     (Container : Vector;
2549
      Index     : Index_Type;
2550
      Process   : not null access procedure (Element : Element_Type))
2551
   is
2552
      V : Vector renames Container'Unrestricted_Access.all;
2553
      B : Natural renames V.Busy;
2554
      L : Natural renames V.Lock;
2555
 
2556
   begin
2557
      if Index > Container.Last then
2558
         raise Constraint_Error with "Index is out of range";
2559
      end if;
2560
 
2561
      B := B + 1;
2562
      L := L + 1;
2563
 
2564
      begin
2565
         Process (V.Elements.EA (Index));
2566
      exception
2567
         when others =>
2568
            L := L - 1;
2569
            B := B - 1;
2570
            raise;
2571
      end;
2572
 
2573
      L := L - 1;
2574
      B := B - 1;
2575
   end Query_Element;
2576
 
2577
   procedure Query_Element
2578
     (Position : Cursor;
2579
      Process  : not null access procedure (Element : Element_Type))
2580
   is
2581
   begin
2582
      if Position.Container = null then
2583
         raise Constraint_Error with "Position cursor has no element";
2584
      end if;
2585
 
2586
      Query_Element (Position.Container.all, Position.Index, Process);
2587
   end Query_Element;
2588
 
2589
   ----------
2590
   -- Read --
2591
   ----------
2592
 
2593
   procedure Read
2594
     (Stream    : not null access Root_Stream_Type'Class;
2595
      Container : out Vector)
2596
   is
2597
      Length : Count_Type'Base;
2598
      Last   : Index_Type'Base := No_Index;
2599
 
2600
   begin
2601
      Clear (Container);
2602
 
2603
      Count_Type'Base'Read (Stream, Length);
2604
 
2605
      if Length > Capacity (Container) then
2606
         Reserve_Capacity (Container, Capacity => Length);
2607
      end if;
2608
 
2609
      for J in Count_Type range 1 .. Length loop
2610
         Last := Last + 1;
2611
         Element_Type'Read (Stream, Container.Elements.EA (Last));
2612
         Container.Last := Last;
2613
      end loop;
2614
   end Read;
2615
 
2616
   procedure Read
2617
     (Stream   : not null access Root_Stream_Type'Class;
2618
      Position : out Cursor)
2619
   is
2620
   begin
2621
      raise Program_Error with "attempt to stream vector cursor";
2622
   end Read;
2623
 
2624
   procedure Read
2625
     (Stream : not null access Root_Stream_Type'Class;
2626
      Item   : out Reference_Type)
2627
   is
2628
   begin
2629
      raise Program_Error with "attempt to stream reference";
2630
   end Read;
2631
 
2632
   procedure Read
2633
     (Stream : not null access Root_Stream_Type'Class;
2634
      Item   : out Constant_Reference_Type)
2635
   is
2636
   begin
2637
      raise Program_Error with "attempt to stream reference";
2638
   end Read;
2639
 
2640
   ---------------
2641
   -- Reference --
2642
   ---------------
2643
 
2644
   function Reference
2645
     (Container : aliased in out Vector;
2646
      Position  : Cursor) return Reference_Type
2647
   is
2648
   begin
2649
      if Position.Container = null then
2650
         raise Constraint_Error with "Position cursor has no element";
2651
      end if;
2652
 
2653
      if Position.Container /= Container'Unrestricted_Access then
2654
         raise Program_Error with "Position cursor denotes wrong container";
2655
      end if;
2656
 
2657
      if Position.Index > Position.Container.Last then
2658
         raise Constraint_Error with "Position cursor is out of range";
2659
      end if;
2660
 
2661
      declare
2662
         C : Vector renames Position.Container.all;
2663
         B : Natural renames C.Busy;
2664
         L : Natural renames C.Lock;
2665
      begin
2666
         return R : constant Reference_Type :=
2667
                      (Element =>
2668
                         Container.Elements.EA (Position.Index)'Access,
2669
                       Control => (Controlled with Position.Container))
2670
         do
2671
            B := B + 1;
2672
            L := L + 1;
2673
         end return;
2674
      end;
2675
   end Reference;
2676
 
2677
   function Reference
2678
     (Container : aliased in out Vector;
2679
      Index     : Index_Type) return Reference_Type
2680
   is
2681
   begin
2682
      if Index > Container.Last then
2683
         raise Constraint_Error with "Index is out of range";
2684
      else
2685
         declare
2686
            C : Vector renames Container'Unrestricted_Access.all;
2687
            B : Natural renames C.Busy;
2688
            L : Natural renames C.Lock;
2689
         begin
2690
            return R : constant Reference_Type :=
2691
                         (Element => Container.Elements.EA (Index)'Access,
2692
                          Control =>
2693
                            (Controlled with Container'Unrestricted_Access))
2694
            do
2695
               B := B + 1;
2696
               L := L + 1;
2697
            end return;
2698
         end;
2699
      end if;
2700
   end Reference;
2701
 
2702
   ---------------------
2703
   -- Replace_Element --
2704
   ---------------------
2705
 
2706
   procedure Replace_Element
2707
     (Container : in out Vector;
2708
      Index     : Index_Type;
2709
      New_Item  : Element_Type)
2710
   is
2711
   begin
2712
      if Index > Container.Last then
2713
         raise Constraint_Error with "Index is out of range";
2714
      end if;
2715
 
2716
      if Container.Lock > 0 then
2717
         raise Program_Error with
2718
           "attempt to tamper with elements (vector is locked)";
2719
      end if;
2720
 
2721
      Container.Elements.EA (Index) := New_Item;
2722
   end Replace_Element;
2723
 
2724
   procedure Replace_Element
2725
     (Container : in out Vector;
2726
      Position  : Cursor;
2727
      New_Item  : Element_Type)
2728
   is
2729
   begin
2730
      if Position.Container = null then
2731
         raise Constraint_Error with "Position cursor has no element";
2732
      end if;
2733
 
2734
      if Position.Container /= Container'Unrestricted_Access then
2735
         raise Program_Error with "Position cursor denotes wrong container";
2736
      end if;
2737
 
2738
      if Position.Index > Container.Last then
2739
         raise Constraint_Error with "Position cursor is out of range";
2740
      end if;
2741
 
2742
      if Container.Lock > 0 then
2743
         raise Program_Error with
2744
           "attempt to tamper with elements (vector is locked)";
2745
      end if;
2746
 
2747
      Container.Elements.EA (Position.Index) := New_Item;
2748
   end Replace_Element;
2749
 
2750
   ----------------------
2751
   -- Reserve_Capacity --
2752
   ----------------------
2753
 
2754
   procedure Reserve_Capacity
2755
     (Container : in out Vector;
2756
      Capacity  : Count_Type)
2757
   is
2758
      N : constant Count_Type := Length (Container);
2759
 
2760
      Index : Count_Type'Base;
2761
      Last  : Index_Type'Base;
2762
 
2763
   begin
2764
      --  Reserve_Capacity can be used to either expand the storage available
2765
      --  for elements (this would be its typical use, in anticipation of
2766
      --  future insertion), or to trim back storage. In the latter case,
2767
      --  storage can only be trimmed back to the limit of the container
2768
      --  length. Note that Reserve_Capacity neither deletes (active) elements
2769
      --  nor inserts elements; it only affects container capacity, never
2770
      --  container length.
2771
 
2772
      if Capacity = 0 then
2773
 
2774
         --  This is a request to trim back storage, to the minimum amount
2775
         --  possible given the current state of the container.
2776
 
2777
         if N = 0 then
2778
 
2779
            --  The container is empty, so in this unique case we can
2780
            --  deallocate the entire internal array. Note that an empty
2781
            --  container can never be busy, so there's no need to check the
2782
            --  tampering bits.
2783
 
2784
            declare
2785
               X : Elements_Access := Container.Elements;
2786
 
2787
            begin
2788
               --  First we remove the internal array from the container, to
2789
               --  handle the case when the deallocation raises an exception.
2790
 
2791
               Container.Elements := null;
2792
 
2793
               --  Container invariants have been restored, so it is now safe
2794
               --  to attempt to deallocate the internal array.
2795
 
2796
               Free (X);
2797
            end;
2798
 
2799
         elsif N < Container.Elements.EA'Length then
2800
 
2801
            --  The container is not empty, and the current length is less than
2802
            --  the current capacity, so there's storage available to trim. In
2803
            --  this case, we allocate a new internal array having a length
2804
            --  that exactly matches the number of items in the
2805
            --  container. (Reserve_Capacity does not delete active elements,
2806
            --  so this is the best we can do with respect to minimizing
2807
            --  storage).
2808
 
2809
            if Container.Busy > 0 then
2810
               raise Program_Error with
2811
                 "attempt to tamper with cursors (vector is busy)";
2812
            end if;
2813
 
2814
            declare
2815
               subtype Src_Index_Subtype is Index_Type'Base range
2816
                 Index_Type'First .. Container.Last;
2817
 
2818
               Src : Elements_Array renames
2819
                       Container.Elements.EA (Src_Index_Subtype);
2820
 
2821
               X : Elements_Access := Container.Elements;
2822
 
2823
            begin
2824
               --  Although we have isolated the old internal array that we're
2825
               --  going to deallocate, we don't deallocate it until we have
2826
               --  successfully allocated a new one. If there is an exception
2827
               --  during allocation (either because there is not enough
2828
               --  storage, or because initialization of the elements fails),
2829
               --  we let it propagate without causing any side-effect.
2830
 
2831
               Container.Elements := new Elements_Type'(Container.Last, Src);
2832
 
2833
               --  We have successfully allocated a new internal array (with a
2834
               --  smaller length than the old one, and containing a copy of
2835
               --  just the active elements in the container), so it is now
2836
               --  safe to attempt to deallocate the old array. The old array
2837
               --  has been isolated, and container invariants have been
2838
               --  restored, so if the deallocation fails (because finalization
2839
               --  of the elements fails), we simply let it propagate.
2840
 
2841
               Free (X);
2842
            end;
2843
         end if;
2844
 
2845
         return;
2846
      end if;
2847
 
2848
      --  Reserve_Capacity can be used to expand the storage available for
2849
      --  elements, but we do not let the capacity grow beyond the number of
2850
      --  values in Index_Type'Range. (Were it otherwise, there would be no way
2851
      --  to refer to the elements with an index value greater than
2852
      --  Index_Type'Last, so that storage would be wasted.) Here we compute
2853
      --  the Last index value of the new internal array, in a way that avoids
2854
      --  any possibility of overflow.
2855
 
2856
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2857
 
2858
         --  We perform a two-part test. First we determine whether the
2859
         --  computed Last value lies in the base range of the type, and then
2860
         --  determine whether it lies in the range of the index (sub)type.
2861
 
2862
         --  Last must satisfy this relation:
2863
         --    First + Length - 1 <= Last
2864
         --  We regroup terms:
2865
         --    First - 1 <= Last - Length
2866
         --  Which can rewrite as:
2867
         --    No_Index <= Last - Length
2868
 
2869
         if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
2870
            raise Constraint_Error with "Capacity is out of range";
2871
         end if;
2872
 
2873
         --  We now know that the computed value of Last is within the base
2874
         --  range of the type, so it is safe to compute its value:
2875
 
2876
         Last := No_Index + Index_Type'Base (Capacity);
2877
 
2878
         --  Finally we test whether the value is within the range of the
2879
         --  generic actual index subtype:
2880
 
2881
         if Last > Index_Type'Last then
2882
            raise Constraint_Error with "Capacity is out of range";
2883
         end if;
2884
 
2885
      elsif Index_Type'First <= 0 then
2886
 
2887
         --  Here we can compute Last directly, in the normal way. We know that
2888
         --  No_Index is less than 0, so there is no danger of overflow when
2889
         --  adding the (positive) value of Capacity.
2890
 
2891
         Index := Count_Type'Base (No_Index) + Capacity;  -- Last
2892
 
2893
         if Index > Count_Type'Base (Index_Type'Last) then
2894
            raise Constraint_Error with "Capacity is out of range";
2895
         end if;
2896
 
2897
         --  We know that the computed value (having type Count_Type) of Last
2898
         --  is within the range of the generic actual index subtype, so it is
2899
         --  safe to convert to Index_Type:
2900
 
2901
         Last := Index_Type'Base (Index);
2902
 
2903
      else
2904
         --  Here Index_Type'First (and Index_Type'Last) is positive, so we
2905
         --  must test the length indirectly (by working backwards from the
2906
         --  largest possible value of Last), in order to prevent overflow.
2907
 
2908
         Index := Count_Type'Base (Index_Type'Last) - Capacity;  -- No_Index
2909
 
2910
         if Index < Count_Type'Base (No_Index) then
2911
            raise Constraint_Error with "Capacity is out of range";
2912
         end if;
2913
 
2914
         --  We have determined that the value of Capacity would not create a
2915
         --  Last index value outside of the range of Index_Type, so we can now
2916
         --  safely compute its value.
2917
 
2918
         Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
2919
      end if;
2920
 
2921
      --  The requested capacity is non-zero, but we don't know yet whether
2922
      --  this is a request for expansion or contraction of storage.
2923
 
2924
      if Container.Elements = null then
2925
 
2926
         --  The container is empty (it doesn't even have an internal array),
2927
         --  so this represents a request to allocate (expand) storage having
2928
         --  the given capacity.
2929
 
2930
         Container.Elements := new Elements_Type (Last);
2931
         return;
2932
      end if;
2933
 
2934
      if Capacity <= N then
2935
 
2936
         --  This is a request to trim back storage, but only to the limit of
2937
         --  what's already in the container. (Reserve_Capacity never deletes
2938
         --  active elements, it only reclaims excess storage.)
2939
 
2940
         if N < Container.Elements.EA'Length then
2941
 
2942
            --  The container is not empty (because the requested capacity is
2943
            --  positive, and less than or equal to the container length), and
2944
            --  the current length is less than the current capacity, so
2945
            --  there's storage available to trim. In this case, we allocate a
2946
            --  new internal array having a length that exactly matches the
2947
            --  number of items in the container.
2948
 
2949
            if Container.Busy > 0 then
2950
               raise Program_Error with
2951
                 "attempt to tamper with cursors (vector is busy)";
2952
            end if;
2953
 
2954
            declare
2955
               subtype Src_Index_Subtype is Index_Type'Base range
2956
                 Index_Type'First .. Container.Last;
2957
 
2958
               Src : Elements_Array renames
2959
                       Container.Elements.EA (Src_Index_Subtype);
2960
 
2961
               X : Elements_Access := Container.Elements;
2962
 
2963
            begin
2964
               --  Although we have isolated the old internal array that we're
2965
               --  going to deallocate, we don't deallocate it until we have
2966
               --  successfully allocated a new one. If there is an exception
2967
               --  during allocation (either because there is not enough
2968
               --  storage, or because initialization of the elements fails),
2969
               --  we let it propagate without causing any side-effect.
2970
 
2971
               Container.Elements := new Elements_Type'(Container.Last, Src);
2972
 
2973
               --  We have successfully allocated a new internal array (with a
2974
               --  smaller length than the old one, and containing a copy of
2975
               --  just the active elements in the container), so it is now
2976
               --  safe to attempt to deallocate the old array. The old array
2977
               --  has been isolated, and container invariants have been
2978
               --  restored, so if the deallocation fails (because finalization
2979
               --  of the elements fails), we simply let it propagate.
2980
 
2981
               Free (X);
2982
            end;
2983
         end if;
2984
 
2985
         return;
2986
      end if;
2987
 
2988
      --  The requested capacity is larger than the container length (the
2989
      --  number of active elements). Whether this represents a request for
2990
      --  expansion or contraction of the current capacity depends on what the
2991
      --  current capacity is.
2992
 
2993
      if Capacity = Container.Elements.EA'Length then
2994
 
2995
         --  The requested capacity matches the existing capacity, so there's
2996
         --  nothing to do here. We treat this case as a no-op, and simply
2997
         --  return without checking the busy bit.
2998
 
2999
         return;
3000
      end if;
3001
 
3002
      --  There is a change in the capacity of a non-empty container, so a new
3003
      --  internal array will be allocated. (The length of the new internal
3004
      --  array could be less or greater than the old internal array. We know
3005
      --  only that the length of the new internal array is greater than the
3006
      --  number of active elements in the container.) We must check whether
3007
      --  the container is busy before doing anything else.
3008
 
3009
      if Container.Busy > 0 then
3010
         raise Program_Error with
3011
           "attempt to tamper with cursors (vector is busy)";
3012
      end if;
3013
 
3014
      --  We now allocate a new internal array, having a length different from
3015
      --  its current value.
3016
 
3017
      declare
3018
         E : Elements_Access := new Elements_Type (Last);
3019
 
3020
      begin
3021
         --  We have successfully allocated the new internal array. We first
3022
         --  attempt to copy the existing elements from the old internal array
3023
         --  ("src" elements) onto the new internal array ("tgt" elements).
3024
 
3025
         declare
3026
            subtype Index_Subtype is Index_Type'Base range
3027
              Index_Type'First .. Container.Last;
3028
 
3029
            Src : Elements_Array renames
3030
                    Container.Elements.EA (Index_Subtype);
3031
 
3032
            Tgt : Elements_Array renames E.EA (Index_Subtype);
3033
 
3034
         begin
3035
            Tgt := Src;
3036
 
3037
         exception
3038
            when others =>
3039
               Free (E);
3040
               raise;
3041
         end;
3042
 
3043
         --  We have successfully copied the existing elements onto the new
3044
         --  internal array, so now we can attempt to deallocate the old one.
3045
 
3046
         declare
3047
            X : Elements_Access := Container.Elements;
3048
 
3049
         begin
3050
            --  First we isolate the old internal array, and replace it in the
3051
            --  container with the new internal array.
3052
 
3053
            Container.Elements := E;
3054
 
3055
            --  Container invariants have been restored, so it is now safe to
3056
            --  attempt to deallocate the old internal array.
3057
 
3058
            Free (X);
3059
         end;
3060
      end;
3061
   end Reserve_Capacity;
3062
 
3063
   ----------------------
3064
   -- Reverse_Elements --
3065
   ----------------------
3066
 
3067
   procedure Reverse_Elements (Container : in out Vector) is
3068
   begin
3069
      if Container.Length <= 1 then
3070
         return;
3071
      end if;
3072
 
3073
      --  The exception behavior for the vector container must match that for
3074
      --  the list container, so we check for cursor tampering here (which will
3075
      --  catch more things) instead of for element tampering (which will catch
3076
      --  fewer things). It's true that the elements of this vector container
3077
      --  could be safely moved around while (say) an iteration is taking place
3078
      --  (iteration only increments the busy counter), and so technically
3079
      --  all we would need here is a test for element tampering (indicated
3080
      --  by the lock counter), that's simply an artifact of our array-based
3081
      --  implementation. Logically Reverse_Elements requires a check for
3082
      --  cursor tampering.
3083
 
3084
      if Container.Busy > 0 then
3085
         raise Program_Error with
3086
           "attempt to tamper with cursors (vector is busy)";
3087
      end if;
3088
 
3089
      declare
3090
         K : Index_Type;
3091
         J : Index_Type;
3092
         E : Elements_Type renames Container.Elements.all;
3093
 
3094
      begin
3095
         K := Index_Type'First;
3096
         J := Container.Last;
3097
         while K < J loop
3098
            declare
3099
               EK : constant Element_Type := E.EA (K);
3100
            begin
3101
               E.EA (K) := E.EA (J);
3102
               E.EA (J) := EK;
3103
            end;
3104
 
3105
            K := K + 1;
3106
            J := J - 1;
3107
         end loop;
3108
      end;
3109
   end Reverse_Elements;
3110
 
3111
   ------------------
3112
   -- Reverse_Find --
3113
   ------------------
3114
 
3115
   function Reverse_Find
3116
     (Container : Vector;
3117
      Item      : Element_Type;
3118
      Position  : Cursor := No_Element) return Cursor
3119
   is
3120
      Last : Index_Type'Base;
3121
 
3122
   begin
3123
      if Position.Container /= null
3124
        and then Position.Container /= Container'Unrestricted_Access
3125
      then
3126
         raise Program_Error with "Position cursor denotes wrong container";
3127
      end if;
3128
 
3129
      Last :=
3130
        (if Position.Container = null or else Position.Index > Container.Last
3131
         then Container.Last
3132
         else Position.Index);
3133
 
3134
      for Indx in reverse Index_Type'First .. Last loop
3135
         if Container.Elements.EA (Indx) = Item then
3136
            return (Container'Unrestricted_Access, Indx);
3137
         end if;
3138
      end loop;
3139
 
3140
      return No_Element;
3141
   end Reverse_Find;
3142
 
3143
   ------------------------
3144
   -- Reverse_Find_Index --
3145
   ------------------------
3146
 
3147
   function Reverse_Find_Index
3148
     (Container : Vector;
3149
      Item      : Element_Type;
3150
      Index     : Index_Type := Index_Type'Last) return Extended_Index
3151
   is
3152
      Last : constant Index_Type'Base :=
3153
               Index_Type'Min (Container.Last, Index);
3154
 
3155
   begin
3156
      for Indx in reverse Index_Type'First .. Last loop
3157
         if Container.Elements.EA (Indx) = Item then
3158
            return Indx;
3159
         end if;
3160
      end loop;
3161
 
3162
      return No_Index;
3163
   end Reverse_Find_Index;
3164
 
3165
   ---------------------
3166
   -- Reverse_Iterate --
3167
   ---------------------
3168
 
3169
   procedure Reverse_Iterate
3170
     (Container : Vector;
3171
      Process   : not null access procedure (Position : Cursor))
3172
   is
3173
      V : Vector renames Container'Unrestricted_Access.all;
3174
      B : Natural renames V.Busy;
3175
 
3176
   begin
3177
      B := B + 1;
3178
 
3179
      begin
3180
         for Indx in reverse Index_Type'First .. Container.Last loop
3181
            Process (Cursor'(Container'Unrestricted_Access, Indx));
3182
         end loop;
3183
      exception
3184
         when others =>
3185
            B := B - 1;
3186
            raise;
3187
      end;
3188
 
3189
      B := B - 1;
3190
   end Reverse_Iterate;
3191
 
3192
   ----------------
3193
   -- Set_Length --
3194
   ----------------
3195
 
3196
   procedure Set_Length (Container : in out Vector; Length : Count_Type) is
3197
      Count : constant Count_Type'Base := Container.Length - Length;
3198
 
3199
   begin
3200
      --  Set_Length allows the user to set the length explicitly, instead
3201
      --  of implicitly as a side-effect of deletion or insertion. If the
3202
      --  requested length is less then the current length, this is equivalent
3203
      --  to deleting items from the back end of the vector. If the requested
3204
      --  length is greater than the current length, then this is equivalent
3205
      --  to inserting "space" (nonce items) at the end.
3206
 
3207
      if Count >= 0 then
3208
         Container.Delete_Last (Count);
3209
 
3210
      elsif Container.Last >= Index_Type'Last then
3211
         raise Constraint_Error with "vector is already at its maximum length";
3212
 
3213
      else
3214
         Container.Insert_Space (Container.Last + 1, -Count);
3215
      end if;
3216
   end Set_Length;
3217
 
3218
   ----------
3219
   -- Swap --
3220
   ----------
3221
 
3222
   procedure Swap (Container : in out Vector; I, J : Index_Type) is
3223
   begin
3224
      if I > Container.Last then
3225
         raise Constraint_Error with "I index is out of range";
3226
      end if;
3227
 
3228
      if J > Container.Last then
3229
         raise Constraint_Error with "J index is out of range";
3230
      end if;
3231
 
3232
      if I = J then
3233
         return;
3234
      end if;
3235
 
3236
      if Container.Lock > 0 then
3237
         raise Program_Error with
3238
           "attempt to tamper with elements (vector is locked)";
3239
      end if;
3240
 
3241
      declare
3242
         EI_Copy : constant Element_Type := Container.Elements.EA (I);
3243
      begin
3244
         Container.Elements.EA (I) := Container.Elements.EA (J);
3245
         Container.Elements.EA (J) := EI_Copy;
3246
      end;
3247
   end Swap;
3248
 
3249
   procedure Swap (Container : in out Vector; I, J : Cursor) is
3250
   begin
3251
      if I.Container = null then
3252
         raise Constraint_Error with "I cursor has no element";
3253
      end if;
3254
 
3255
      if J.Container = null then
3256
         raise Constraint_Error with "J cursor has no element";
3257
      end if;
3258
 
3259
      if I.Container /= Container'Unrestricted_Access then
3260
         raise Program_Error with "I cursor denotes wrong container";
3261
      end if;
3262
 
3263
      if J.Container /= Container'Unrestricted_Access then
3264
         raise Program_Error with "J cursor denotes wrong container";
3265
      end if;
3266
 
3267
      Swap (Container, I.Index, J.Index);
3268
   end Swap;
3269
 
3270
   ---------------
3271
   -- To_Cursor --
3272
   ---------------
3273
 
3274
   function To_Cursor
3275
     (Container : Vector;
3276
      Index     : Extended_Index) return Cursor
3277
   is
3278
   begin
3279
      if Index not in Index_Type'First .. Container.Last then
3280
         return No_Element;
3281
      else
3282
         return (Container'Unrestricted_Access, Index);
3283
      end if;
3284
   end To_Cursor;
3285
 
3286
   --------------
3287
   -- To_Index --
3288
   --------------
3289
 
3290
   function To_Index (Position : Cursor) return Extended_Index is
3291
   begin
3292
      if Position.Container = null then
3293
         return No_Index;
3294
      end if;
3295
 
3296
      if Position.Index <= Position.Container.Last then
3297
         return Position.Index;
3298
      end if;
3299
 
3300
      return No_Index;
3301
   end To_Index;
3302
 
3303
   ---------------
3304
   -- To_Vector --
3305
   ---------------
3306
 
3307
   function To_Vector (Length : Count_Type) return Vector is
3308
      Index    : Count_Type'Base;
3309
      Last     : Index_Type'Base;
3310
      Elements : Elements_Access;
3311
 
3312
   begin
3313
      if Length = 0 then
3314
         return Empty_Vector;
3315
      end if;
3316
 
3317
      --  We create a vector object with a capacity that matches the specified
3318
      --  Length, but we do not allow the vector capacity (the length of the
3319
      --  internal array) to exceed the number of values in Index_Type'Range
3320
      --  (otherwise, there would be no way to refer to those components via an
3321
      --  index).  We must therefore check whether the specified Length would
3322
      --  create a Last index value greater than Index_Type'Last.
3323
 
3324
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3325
 
3326
         --  We perform a two-part test. First we determine whether the
3327
         --  computed Last value lies in the base range of the type, and then
3328
         --  determine whether it lies in the range of the index (sub)type.
3329
 
3330
         --  Last must satisfy this relation:
3331
         --    First + Length - 1 <= Last
3332
         --  We regroup terms:
3333
         --    First - 1 <= Last - Length
3334
         --  Which can rewrite as:
3335
         --    No_Index <= Last - Length
3336
 
3337
         if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3338
            raise Constraint_Error with "Length is out of range";
3339
         end if;
3340
 
3341
         --  We now know that the computed value of Last is within the base
3342
         --  range of the type, so it is safe to compute its value:
3343
 
3344
         Last := No_Index + Index_Type'Base (Length);
3345
 
3346
         --  Finally we test whether the value is within the range of the
3347
         --  generic actual index subtype:
3348
 
3349
         if Last > Index_Type'Last then
3350
            raise Constraint_Error with "Length is out of range";
3351
         end if;
3352
 
3353
      elsif Index_Type'First <= 0 then
3354
 
3355
         --  Here we can compute Last directly, in the normal way. We know that
3356
         --  No_Index is less than 0, so there is no danger of overflow when
3357
         --  adding the (positive) value of Length.
3358
 
3359
         Index := Count_Type'Base (No_Index) + Length;  -- Last
3360
 
3361
         if Index > Count_Type'Base (Index_Type'Last) then
3362
            raise Constraint_Error with "Length is out of range";
3363
         end if;
3364
 
3365
         --  We know that the computed value (having type Count_Type) of Last
3366
         --  is within the range of the generic actual index subtype, so it is
3367
         --  safe to convert to Index_Type:
3368
 
3369
         Last := Index_Type'Base (Index);
3370
 
3371
      else
3372
         --  Here Index_Type'First (and Index_Type'Last) is positive, so we
3373
         --  must test the length indirectly (by working backwards from the
3374
         --  largest possible value of Last), in order to prevent overflow.
3375
 
3376
         Index := Count_Type'Base (Index_Type'Last) - Length;  -- No_Index
3377
 
3378
         if Index < Count_Type'Base (No_Index) then
3379
            raise Constraint_Error with "Length is out of range";
3380
         end if;
3381
 
3382
         --  We have determined that the value of Length would not create a
3383
         --  Last index value outside of the range of Index_Type, so we can now
3384
         --  safely compute its value.
3385
 
3386
         Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3387
      end if;
3388
 
3389
      Elements := new Elements_Type (Last);
3390
 
3391
      return Vector'(Controlled with Elements, Last, 0, 0);
3392
   end To_Vector;
3393
 
3394
   function To_Vector
3395
     (New_Item : Element_Type;
3396
      Length   : Count_Type) return Vector
3397
   is
3398
      Index    : Count_Type'Base;
3399
      Last     : Index_Type'Base;
3400
      Elements : Elements_Access;
3401
 
3402
   begin
3403
      if Length = 0 then
3404
         return Empty_Vector;
3405
      end if;
3406
 
3407
      --  We create a vector object with a capacity that matches the specified
3408
      --  Length, but we do not allow the vector capacity (the length of the
3409
      --  internal array) to exceed the number of values in Index_Type'Range
3410
      --  (otherwise, there would be no way to refer to those components via an
3411
      --  index). We must therefore check whether the specified Length would
3412
      --  create a Last index value greater than Index_Type'Last.
3413
 
3414
      if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3415
 
3416
         --  We perform a two-part test. First we determine whether the
3417
         --  computed Last value lies in the base range of the type, and then
3418
         --  determine whether it lies in the range of the index (sub)type.
3419
 
3420
         --  Last must satisfy this relation:
3421
         --    First + Length - 1 <= Last
3422
         --  We regroup terms:
3423
         --    First - 1 <= Last - Length
3424
         --  Which can rewrite as:
3425
         --    No_Index <= Last - Length
3426
 
3427
         if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3428
            raise Constraint_Error with "Length is out of range";
3429
         end if;
3430
 
3431
         --  We now know that the computed value of Last is within the base
3432
         --  range of the type, so it is safe to compute its value:
3433
 
3434
         Last := No_Index + Index_Type'Base (Length);
3435
 
3436
         --  Finally we test whether the value is within the range of the
3437
         --  generic actual index subtype:
3438
 
3439
         if Last > Index_Type'Last then
3440
            raise Constraint_Error with "Length is out of range";
3441
         end if;
3442
 
3443
      elsif Index_Type'First <= 0 then
3444
 
3445
         --  Here we can compute Last directly, in the normal way. We know that
3446
         --  No_Index is less than 0, so there is no danger of overflow when
3447
         --  adding the (positive) value of Length.
3448
 
3449
         Index := Count_Type'Base (No_Index) + Length;  -- same value as V.Last
3450
 
3451
         if Index > Count_Type'Base (Index_Type'Last) then
3452
            raise Constraint_Error with "Length is out of range";
3453
         end if;
3454
 
3455
         --  We know that the computed value (having type Count_Type) of Last
3456
         --  is within the range of the generic actual index subtype, so it is
3457
         --  safe to convert to Index_Type:
3458
 
3459
         Last := Index_Type'Base (Index);
3460
 
3461
      else
3462
         --  Here Index_Type'First (and Index_Type'Last) is positive, so we
3463
         --  must test the length indirectly (by working backwards from the
3464
         --  largest possible value of Last), in order to prevent overflow.
3465
 
3466
         Index := Count_Type'Base (Index_Type'Last) - Length;  -- No_Index
3467
 
3468
         if Index < Count_Type'Base (No_Index) then
3469
            raise Constraint_Error with "Length is out of range";
3470
         end if;
3471
 
3472
         --  We have determined that the value of Length would not create a
3473
         --  Last index value outside of the range of Index_Type, so we can now
3474
         --  safely compute its value.
3475
 
3476
         Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3477
      end if;
3478
 
3479
      Elements := new Elements_Type'(Last, EA => (others => New_Item));
3480
 
3481
      return Vector'(Controlled with Elements, Last, 0, 0);
3482
   end To_Vector;
3483
 
3484
   --------------------
3485
   -- Update_Element --
3486
   --------------------
3487
 
3488
   procedure Update_Element
3489
     (Container : in out Vector;
3490
      Index     : Index_Type;
3491
      Process   : not null access procedure (Element : in out Element_Type))
3492
   is
3493
      B : Natural renames Container.Busy;
3494
      L : Natural renames Container.Lock;
3495
 
3496
   begin
3497
      if Index > Container.Last then
3498
         raise Constraint_Error with "Index is out of range";
3499
      end if;
3500
 
3501
      B := B + 1;
3502
      L := L + 1;
3503
 
3504
      begin
3505
         Process (Container.Elements.EA (Index));
3506
      exception
3507
         when others =>
3508
            L := L - 1;
3509
            B := B - 1;
3510
            raise;
3511
      end;
3512
 
3513
      L := L - 1;
3514
      B := B - 1;
3515
   end Update_Element;
3516
 
3517
   procedure Update_Element
3518
     (Container : in out Vector;
3519
      Position  : Cursor;
3520
      Process   : not null access procedure (Element : in out Element_Type))
3521
   is
3522
   begin
3523
      if Position.Container = null then
3524
         raise Constraint_Error with "Position cursor has no element";
3525
      elsif Position.Container /= Container'Unrestricted_Access then
3526
         raise Program_Error with "Position cursor denotes wrong container";
3527
      else
3528
         Update_Element (Container, Position.Index, Process);
3529
      end if;
3530
   end Update_Element;
3531
 
3532
   -----------
3533
   -- Write --
3534
   -----------
3535
 
3536
   procedure Write
3537
     (Stream    : not null access Root_Stream_Type'Class;
3538
      Container : Vector)
3539
   is
3540
   begin
3541
      Count_Type'Base'Write (Stream, Length (Container));
3542
 
3543
      for J in Index_Type'First .. Container.Last loop
3544
         Element_Type'Write (Stream, Container.Elements.EA (J));
3545
      end loop;
3546
   end Write;
3547
 
3548
   procedure Write
3549
     (Stream   : not null access Root_Stream_Type'Class;
3550
      Position : Cursor)
3551
   is
3552
   begin
3553
      raise Program_Error with "attempt to stream vector cursor";
3554
   end Write;
3555
 
3556
   procedure Write
3557
     (Stream : not null access Root_Stream_Type'Class;
3558
      Item   : Reference_Type)
3559
   is
3560
   begin
3561
      raise Program_Error with "attempt to stream reference";
3562
   end Write;
3563
 
3564
   procedure Write
3565
     (Stream : not null access Root_Stream_Type'Class;
3566
      Item   : Constant_Reference_Type)
3567
   is
3568
   begin
3569
      raise Program_Error with "attempt to stream reference";
3570
   end Write;
3571
 
3572
end Ada.Containers.Vectors;

powered by: WebSVN 2.1.0

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