OSDN Git Service

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