OSDN Git Service

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