OSDN Git Service

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