OSDN Git Service

2012-01-10 Richard Guenther <rguenther@suse.de>
[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-2011, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17 --                                                                          --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception,   --
20 -- version 3.1, as published by the Free Software Foundation.               --
21 --                                                                          --
22 -- You should have received a copy of the GNU General Public License and    --
23 -- a copy of the GCC Runtime Library Exception along with this program;     --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25 -- <http://www.gnu.org/licenses/>.                                          --
26 --                                                                          --
27 -- This unit was originally developed by Matthew J Heaney.                  --
28 ------------------------------------------------------------------------------
29
30 with Ada.Containers.Generic_Array_Sort;
31 with Ada.Unchecked_Deallocation;
32
33 with System; use type System.Address;
34
35 package body Ada.Containers.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
1400          procedure Sort is new Generic_Array_Sort
1401            (Index_Type   => Index_Type,
1402             Element_Type => Element_Access,
1403             Array_Type   => Elements_Array,
1404             "<"          => Is_Less);
1405
1406       --  Start of processing for Sort
1407
1408       begin
1409          if Container.Last <= Index_Type'First then
1410             return;
1411          end if;
1412
1413          if Container.Lock > 0 then
1414             raise Program_Error with
1415               "attempt to tamper with elements (vector is locked)";
1416          end if;
1417
1418          Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1419       end Sort;
1420
1421    end Generic_Sorting;
1422
1423    -----------------
1424    -- Has_Element --
1425    -----------------
1426
1427    function Has_Element (Position : Cursor) return Boolean is
1428    begin
1429       if Position.Container = null then
1430          return False;
1431       end if;
1432
1433       return Position.Index <= Position.Container.Last;
1434    end Has_Element;
1435
1436    ------------
1437    -- Insert --
1438    ------------
1439
1440    procedure Insert
1441      (Container : in out Vector;
1442       Before    : Extended_Index;
1443       New_Item  : Element_Type;
1444       Count     : Count_Type := 1)
1445    is
1446       Old_Length : constant Count_Type := Container.Length;
1447
1448       Max_Length : Count_Type'Base;  -- determined from range of Index_Type
1449       New_Length : Count_Type'Base;  -- sum of current length and Count
1450       New_Last   : Index_Type'Base;  -- last index of vector after insertion
1451
1452       Index : Index_Type'Base;  -- scratch for intermediate values
1453       J     : Count_Type'Base;  -- scratch
1454
1455       New_Capacity : Count_Type'Base;  -- length of new, expanded array
1456       Dst_Last     : Index_Type'Base;  -- last index of new, expanded array
1457       Dst          : Elements_Access;  -- new, expanded internal array
1458
1459    begin
1460       --  As a precondition on the generic actual Index_Type, the base type
1461       --  must include Index_Type'Pred (Index_Type'First); this is the value
1462       --  that Container.Last assumes when the vector is empty. However, we do
1463       --  not allow that as the value for Index when specifying where the new
1464       --  items should be inserted, so we must manually check. (That the user
1465       --  is allowed to specify the value at all here is a consequence of the
1466       --  declaration of the Extended_Index subtype, which includes the values
1467       --  in the base range that immediately precede and immediately follow the
1468       --  values in the Index_Type.)
1469
1470       if Before < Index_Type'First then
1471          raise Constraint_Error with
1472            "Before index is out of range (too small)";
1473       end if;
1474
1475       --  We do allow a value greater than Container.Last to be specified as
1476       --  the Index, but only if it's immediately greater. This allows for the
1477       --  case of appending items to the back end of the vector. (It is assumed
1478       --  that specifying an index value greater than Last + 1 indicates some
1479       --  deeper flaw in the caller's algorithm, so that case is treated as a
1480       --  proper error.)
1481
1482       if Before > Container.Last
1483         and then Before > Container.Last + 1
1484       then
1485          raise Constraint_Error with
1486            "Before index is out of range (too large)";
1487       end if;
1488
1489       --  We treat inserting 0 items into the container as a no-op, even when
1490       --  the container is busy, so we simply return.
1491
1492       if Count = 0 then
1493          return;
1494       end if;
1495
1496       --  There are two constraints we need to satisfy. The first constraint is
1497       --  that a container cannot have more than Count_Type'Last elements, so
1498       --  we must check the sum of the current length and the insertion count.
1499       --  Note that we cannot simply add these values, because of the
1500       --  possibility of overflow.
1501
1502       if Old_Length > Count_Type'Last - Count then
1503          raise Constraint_Error with "Count is out of range";
1504       end if;
1505
1506       --  It is now safe compute the length of the new vector, without fear of
1507       --  overflow.
1508
1509       New_Length := Old_Length + Count;
1510
1511       --  The second constraint is that the new Last index value cannot exceed
1512       --  Index_Type'Last. In each branch below, we calculate the maximum
1513       --  length (computed from the range of values in Index_Type), and then
1514       --  compare the new length to the maximum length. If the new length is
1515       --  acceptable, then we compute the new last index from that.
1516
1517       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1518
1519          --  We have to handle the case when there might be more values in the
1520          --  range of Index_Type than in the range of Count_Type.
1521
1522          if Index_Type'First <= 0 then
1523
1524             --  We know that No_Index (the same as Index_Type'First - 1) is
1525             --  less than 0, so it is safe to compute the following sum without
1526             --  fear of overflow.
1527
1528             Index := No_Index + Index_Type'Base (Count_Type'Last);
1529
1530             if Index <= Index_Type'Last then
1531
1532                --  We have determined that range of Index_Type has at least as
1533                --  many values as in Count_Type, so Count_Type'Last is the
1534                --  maximum number of items that are allowed.
1535
1536                Max_Length := Count_Type'Last;
1537
1538             else
1539                --  The range of Index_Type has fewer values than in Count_Type,
1540                --  so the maximum number of items is computed from the range of
1541                --  the Index_Type.
1542
1543                Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1544             end if;
1545
1546          else
1547             --  No_Index is equal or greater than 0, so we can safely compute
1548             --  the difference without fear of overflow (which we would have to
1549             --  worry about if No_Index were less than 0, but that case is
1550             --  handled above).
1551
1552             Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1553          end if;
1554
1555       elsif Index_Type'First <= 0 then
1556
1557          --  We know that No_Index (the same as Index_Type'First - 1) is less
1558          --  than 0, so it is safe to compute the following sum without fear of
1559          --  overflow.
1560
1561          J := Count_Type'Base (No_Index) + Count_Type'Last;
1562
1563          if J <= Count_Type'Base (Index_Type'Last) then
1564
1565             --  We have determined that range of Index_Type has at least as
1566             --  many values as in Count_Type, so Count_Type'Last is the maximum
1567             --  number of items that are allowed.
1568
1569             Max_Length := Count_Type'Last;
1570
1571          else
1572             --  The range of Index_Type has fewer values than Count_Type does,
1573             --  so the maximum number of items is computed from the range of
1574             --  the Index_Type.
1575
1576             Max_Length :=
1577               Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1578          end if;
1579
1580       else
1581          --  No_Index is equal or greater than 0, so we can safely compute the
1582          --  difference without fear of overflow (which we would have to worry
1583          --  about if No_Index were less than 0, but that case is handled
1584          --  above).
1585
1586          Max_Length :=
1587            Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1588       end if;
1589
1590       --  We have just computed the maximum length (number of items). We must
1591       --  now compare the requested length to the maximum length, as we do not
1592       --  allow a vector expand beyond the maximum (because that would create
1593       --  an internal array with a last index value greater than
1594       --  Index_Type'Last, with no way to index those elements).
1595
1596       if New_Length > Max_Length then
1597          raise Constraint_Error with "Count is out of range";
1598       end if;
1599
1600       --  New_Last is the last index value of the items in the container after
1601       --  insertion.  Use the wider of Index_Type'Base and Count_Type'Base to
1602       --  compute its value from the New_Length.
1603
1604       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1605          New_Last := No_Index + Index_Type'Base (New_Length);
1606
1607       else
1608          New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1609       end if;
1610
1611       if Container.Elements = null then
1612          pragma Assert (Container.Last = No_Index);
1613
1614          --  This is the simplest case, with which we must always begin: we're
1615          --  inserting items into an empty vector that hasn't allocated an
1616          --  internal array yet. Note that we don't need to check the busy bit
1617          --  here, because an empty container cannot be busy.
1618
1619          --  In an indefinite vector, elements are allocated individually, and
1620          --  stored as access values on the internal array (the length of which
1621          --  represents the vector "capacity"), which is separately allocated.
1622
1623          Container.Elements := new Elements_Type (New_Last);
1624
1625          --  The element backbone has been successfully allocated, so now we
1626          --  allocate the elements.
1627
1628          for Idx in Container.Elements.EA'Range loop
1629
1630             --  In order to preserve container invariants, we always attempt
1631             --  the element allocation first, before setting the Last index
1632             --  value, in case the allocation fails (either because there is no
1633             --  storage available, or because element initialization fails).
1634
1635             Container.Elements.EA (Idx) := new Element_Type'(New_Item);
1636
1637             --  The allocation of the element succeeded, so it is now safe to
1638             --  update the Last index, restoring container invariants.
1639
1640             Container.Last := Idx;
1641          end loop;
1642
1643          return;
1644       end if;
1645
1646       --  The tampering bits exist to prevent an item from being harmfully
1647       --  manipulated while it is being visited. Query, Update, and Iterate
1648       --  increment the busy count on entry, and decrement the count on
1649       --  exit. Insert checks the count to determine whether it is being called
1650       --  while the associated callback procedure is executing.
1651
1652       if Container.Busy > 0 then
1653          raise Program_Error with
1654            "attempt to tamper with cursors (vector is busy)";
1655       end if;
1656
1657       if New_Length <= Container.Elements.EA'Length then
1658
1659          --  In this case, we're inserting elements into a vector that has
1660          --  already allocated an internal array, and the existing array has
1661          --  enough unused storage for the new items.
1662
1663          declare
1664             E : Elements_Array renames Container.Elements.EA;
1665             K : Index_Type'Base;
1666
1667          begin
1668             if Before > Container.Last then
1669
1670                --  The new items are being appended to the vector, so no
1671                --  sliding of existing elements is required.
1672
1673                for Idx in Before .. New_Last loop
1674
1675                   --  In order to preserve container invariants, we always
1676                   --  attempt the element allocation first, before setting the
1677                   --  Last index value, in case the allocation fails (either
1678                   --  because there is no storage available, or because element
1679                   --  initialization fails).
1680
1681                   E (Idx) := new Element_Type'(New_Item);
1682
1683                   --  The allocation of the element succeeded, so it is now
1684                   --  safe to update the Last index, restoring container
1685                   --  invariants.
1686
1687                   Container.Last := Idx;
1688                end loop;
1689
1690             else
1691                --  The new items are being inserted before some existing
1692                --  elements, so we must slide the existing elements up to their
1693                --  new home. We use the wider of Index_Type'Base and
1694                --  Count_Type'Base as the type for intermediate index values.
1695
1696                if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1697                   Index := Before + Index_Type'Base (Count);
1698                else
1699                   Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1700                end if;
1701
1702                --  The new items are being inserted in the middle of the array,
1703                --  in the range [Before, Index). Copy the existing elements to
1704                --  the end of the array, to make room for the new items.
1705
1706                E (Index .. New_Last) := E (Before .. Container.Last);
1707                Container.Last := New_Last;
1708
1709                --  We have copied the existing items up to the end of the
1710                --  array, to make room for the new items in the middle of
1711                --  the array.  Now we actually allocate the new items.
1712
1713                --  Note: initialize K outside loop to make it clear that
1714                --  K always has a value if the exception handler triggers.
1715
1716                K := Before;
1717                begin
1718                   while K < Index loop
1719                      E (K) := new Element_Type'(New_Item);
1720                      K := K + 1;
1721                   end loop;
1722
1723                exception
1724                   when others =>
1725
1726                      --  Values in the range [Before, K) were successfully
1727                      --  allocated, but values in the range [K, Index) are
1728                      --  stale (these array positions contain copies of the
1729                      --  old items, that did not get assigned a new item,
1730                      --  because the allocation failed). We must finish what
1731                      --  we started by clearing out all of the stale values,
1732                      --  leaving a "hole" in the middle of the array.
1733
1734                      E (K .. Index - 1) := (others => null);
1735                      raise;
1736                end;
1737             end if;
1738          end;
1739
1740          return;
1741       end if;
1742
1743       --  In this case, we're inserting elements into a vector that has already
1744       --  allocated an internal array, but the existing array does not have
1745       --  enough storage, so we must allocate a new, longer array. In order to
1746       --  guarantee that the amortized insertion cost is O(1), we always
1747       --  allocate an array whose length is some power-of-two factor of the
1748       --  current array length. (The new array cannot have a length less than
1749       --  the New_Length of the container, but its last index value cannot be
1750       --  greater than Index_Type'Last.)
1751
1752       New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1753       while New_Capacity < New_Length loop
1754          if New_Capacity > Count_Type'Last / 2 then
1755             New_Capacity := Count_Type'Last;
1756             exit;
1757          end if;
1758
1759          New_Capacity := 2 * New_Capacity;
1760       end loop;
1761
1762       if New_Capacity > Max_Length then
1763
1764          --  We have reached the limit of capacity, so no further expansion
1765          --  will occur. (This is not a problem, as there is never a need to
1766          --  have more capacity than the maximum container length.)
1767
1768          New_Capacity := Max_Length;
1769       end if;
1770
1771       --  We have computed the length of the new internal array (and this is
1772       --  what "vector capacity" means), so use that to compute its last index.
1773
1774       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1775          Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1776
1777       else
1778          Dst_Last :=
1779            Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1780       end if;
1781
1782       --  Now we allocate the new, longer internal array. If the allocation
1783       --  fails, we have not changed any container state, so no side-effect
1784       --  will occur as a result of propagating the exception.
1785
1786       Dst := new Elements_Type (Dst_Last);
1787
1788       --  We have our new internal array. All that needs to be done now is to
1789       --  copy the existing items (if any) from the old array (the "source"
1790       --  array) to the new array (the "destination" array), and then
1791       --  deallocate the old array.
1792
1793       declare
1794          Src : Elements_Access := Container.Elements;
1795
1796       begin
1797          Dst.EA (Index_Type'First .. Before - 1) :=
1798            Src.EA (Index_Type'First .. Before - 1);
1799
1800          if Before > Container.Last then
1801
1802             --  The new items are being appended to the vector, so no
1803             --  sliding of existing elements is required.
1804
1805             --  We have copied the elements from to the old, source array to
1806             --  the new, destination array, so we can now deallocate the old
1807             --  array.
1808
1809             Container.Elements := Dst;
1810             Free (Src);
1811
1812             --  Now we append the new items.
1813
1814             for Idx in Before .. New_Last loop
1815
1816                --  In order to preserve container invariants, we always
1817                --  attempt the element allocation first, before setting the
1818                --  Last index value, in case the allocation fails (either
1819                --  because there is no storage available, or because element
1820                --  initialization fails).
1821
1822                Dst.EA (Idx) := new Element_Type'(New_Item);
1823
1824                --  The allocation of the element succeeded, so it is now safe
1825                --  to update the Last index, restoring container invariants.
1826
1827                Container.Last := Idx;
1828             end loop;
1829
1830          else
1831             --  The new items are being inserted before some existing elements,
1832             --  so we must slide the existing elements up to their new home.
1833
1834             if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1835                Index := Before + Index_Type'Base (Count);
1836
1837             else
1838                Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1839             end if;
1840
1841             Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
1842
1843             --  We have copied the elements from to the old, source array to
1844             --  the new, destination array, so we can now deallocate the old
1845             --  array.
1846
1847             Container.Elements := Dst;
1848             Container.Last := New_Last;
1849             Free (Src);
1850
1851             --  The new array has a range in the middle containing null access
1852             --  values. We now fill in that partition of the array with the new
1853             --  items.
1854
1855             for Idx in Before .. Index - 1 loop
1856
1857                --  Note that container invariants have already been satisfied
1858                --  (in particular, the Last index value of the vector has
1859                --  already been updated), so if this allocation fails we simply
1860                --  let it propagate.
1861
1862                Dst.EA (Idx) := new Element_Type'(New_Item);
1863             end loop;
1864          end if;
1865       end;
1866    end Insert;
1867
1868    procedure Insert
1869      (Container : in out Vector;
1870       Before    : Extended_Index;
1871       New_Item  : Vector)
1872    is
1873       N : constant Count_Type := Length (New_Item);
1874       J : Index_Type'Base;
1875
1876    begin
1877       --  Use Insert_Space to create the "hole" (the destination slice) into
1878       --  which we copy the source items.
1879
1880       Insert_Space (Container, Before, Count => N);
1881
1882       if N = 0 then
1883
1884          --  There's nothing else to do here (vetting of parameters was
1885          --  performed already in Insert_Space), so we simply return.
1886
1887          return;
1888       end if;
1889
1890       if Container'Address /= New_Item'Address then
1891
1892          --  This is the simple case.  New_Item denotes an object different
1893          --  from Container, so there's nothing special we need to do to copy
1894          --  the source items to their destination, because all of the source
1895          --  items are contiguous.
1896
1897          declare
1898             subtype Src_Index_Subtype is Index_Type'Base range
1899               Index_Type'First .. New_Item.Last;
1900
1901             Src : Elements_Array renames
1902                     New_Item.Elements.EA (Src_Index_Subtype);
1903
1904             Dst : Elements_Array renames Container.Elements.EA;
1905
1906             Dst_Index : Index_Type'Base;
1907
1908          begin
1909             Dst_Index := Before - 1;
1910             for Src_Index in Src'Range loop
1911                Dst_Index := Dst_Index + 1;
1912
1913                if Src (Src_Index) /= null then
1914                   Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1915                end if;
1916             end loop;
1917          end;
1918
1919          return;
1920       end if;
1921
1922       --  New_Item denotes the same object as Container, so an insertion has
1923       --  potentially split the source items.  The first source slice is
1924       --  [Index_Type'First, Before), and the second source slice is
1925       --  [J, Container.Last], where index value J is the first index of the
1926       --  second slice. (J gets computed below, but only after we have
1927       --  determined that the second source slice is non-empty.) The
1928       --  destination slice is always the range [Before, J). We perform the
1929       --  copy in two steps, using each of the two slices of the source items.
1930
1931       declare
1932          L : constant Index_Type'Base := Before - 1;
1933
1934          subtype Src_Index_Subtype is Index_Type'Base range
1935            Index_Type'First .. L;
1936
1937          Src : Elements_Array renames
1938                  Container.Elements.EA (Src_Index_Subtype);
1939
1940          Dst : Elements_Array renames Container.Elements.EA;
1941
1942          Dst_Index : Index_Type'Base;
1943
1944       begin
1945          --  We first copy the source items that precede the space we
1946          --  inserted. (If Before equals Index_Type'First, then this first
1947          --  source slice will be empty, which is harmless.)
1948
1949          Dst_Index := Before - 1;
1950          for Src_Index in Src'Range loop
1951             Dst_Index := Dst_Index + 1;
1952
1953             if Src (Src_Index) /= null then
1954                Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1955             end if;
1956          end loop;
1957
1958          if Src'Length = N then
1959
1960             --  The new items were effectively appended to the container, so we
1961             --  have already copied all of the items that need to be copied.
1962             --  We return early here, even though the source slice below is
1963             --  empty (so the assignment would be harmless), because we want to
1964             --  avoid computing J, which will overflow if J is greater than
1965             --  Index_Type'Base'Last.
1966
1967             return;
1968          end if;
1969       end;
1970
1971       --  Index value J is the first index of the second source slice. (It is
1972       --  also 1 greater than the last index of the destination slice.) Note:
1973       --  avoid computing J if J is greater than Index_Type'Base'Last, in order
1974       --  to avoid overflow. Prevent that by returning early above, immediately
1975       --  after copying the first slice of the source, and determining that
1976       --  this second slice of the source is empty.
1977
1978       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1979          J := Before + Index_Type'Base (N);
1980
1981       else
1982          J := Index_Type'Base (Count_Type'Base (Before) + N);
1983       end if;
1984
1985       declare
1986          subtype Src_Index_Subtype is Index_Type'Base range
1987            J .. Container.Last;
1988
1989          Src : Elements_Array renames
1990                  Container.Elements.EA (Src_Index_Subtype);
1991
1992          Dst : Elements_Array renames Container.Elements.EA;
1993
1994          Dst_Index : Index_Type'Base;
1995
1996       begin
1997          --  We next copy the source items that follow the space we inserted.
1998          --  Index value Dst_Index is the first index of that portion of the
1999          --  destination that receives this slice of the source. (For the
2000          --  reasons given above, this slice is guaranteed to be non-empty.)
2001
2002          if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2003             Dst_Index := J - Index_Type'Base (Src'Length);
2004
2005          else
2006             Dst_Index := Index_Type'Base (Count_Type'Base (J) - Src'Length);
2007          end if;
2008
2009          for Src_Index in Src'Range loop
2010             if Src (Src_Index) /= null then
2011                Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2012             end if;
2013
2014             Dst_Index := Dst_Index + 1;
2015          end loop;
2016       end;
2017    end Insert;
2018
2019    procedure Insert
2020      (Container : in out Vector;
2021       Before    : Cursor;
2022       New_Item  : Vector)
2023    is
2024       Index : Index_Type'Base;
2025
2026    begin
2027       if Before.Container /= null
2028         and then Before.Container /= Container'Unrestricted_Access
2029       then
2030          raise Program_Error with "Before cursor denotes wrong container";
2031       end if;
2032
2033       if Is_Empty (New_Item) then
2034          return;
2035       end if;
2036
2037       if Before.Container = null
2038         or else Before.Index > Container.Last
2039       then
2040          if Container.Last = Index_Type'Last then
2041             raise Constraint_Error with
2042               "vector is already at its maximum length";
2043          end if;
2044
2045          Index := Container.Last + 1;
2046
2047       else
2048          Index := Before.Index;
2049       end if;
2050
2051       Insert (Container, Index, New_Item);
2052    end Insert;
2053
2054    procedure Insert
2055      (Container : in out Vector;
2056       Before    : Cursor;
2057       New_Item  : Vector;
2058       Position  : out Cursor)
2059    is
2060       Index : Index_Type'Base;
2061
2062    begin
2063       if Before.Container /= null
2064         and then Before.Container /=
2065                    Vector_Access'(Container'Unrestricted_Access)
2066       then
2067          raise Program_Error with "Before cursor denotes wrong container";
2068       end if;
2069
2070       if Is_Empty (New_Item) then
2071          if Before.Container = null
2072            or else Before.Index > Container.Last
2073          then
2074             Position := No_Element;
2075          else
2076             Position := (Container'Unrestricted_Access, Before.Index);
2077          end if;
2078
2079          return;
2080       end if;
2081
2082       if Before.Container = null
2083         or else Before.Index > Container.Last
2084       then
2085          if Container.Last = Index_Type'Last then
2086             raise Constraint_Error with
2087               "vector is already at its maximum length";
2088          end if;
2089
2090          Index := Container.Last + 1;
2091
2092       else
2093          Index := Before.Index;
2094       end if;
2095
2096       Insert (Container, Index, New_Item);
2097
2098       Position := Cursor'(Container'Unrestricted_Access, Index);
2099    end Insert;
2100
2101    procedure Insert
2102      (Container : in out Vector;
2103       Before    : Cursor;
2104       New_Item  : Element_Type;
2105       Count     : Count_Type := 1)
2106    is
2107       Index : Index_Type'Base;
2108
2109    begin
2110       if Before.Container /= null
2111         and then Before.Container /= Container'Unrestricted_Access
2112       then
2113          raise Program_Error with "Before cursor denotes wrong container";
2114       end if;
2115
2116       if Count = 0 then
2117          return;
2118       end if;
2119
2120       if Before.Container = null
2121         or else Before.Index > Container.Last
2122       then
2123          if Container.Last = Index_Type'Last then
2124             raise Constraint_Error with
2125               "vector is already at its maximum length";
2126          end if;
2127
2128          Index := Container.Last + 1;
2129
2130       else
2131          Index := Before.Index;
2132       end if;
2133
2134       Insert (Container, Index, New_Item, Count);
2135    end Insert;
2136
2137    procedure Insert
2138      (Container : in out Vector;
2139       Before    : Cursor;
2140       New_Item  : Element_Type;
2141       Position  : out Cursor;
2142       Count     : Count_Type := 1)
2143    is
2144       Index : Index_Type'Base;
2145
2146    begin
2147       if Before.Container /= null
2148         and then Before.Container /= Container'Unrestricted_Access
2149       then
2150          raise Program_Error with "Before cursor denotes wrong container";
2151       end if;
2152
2153       if Count = 0 then
2154          if Before.Container = null
2155            or else Before.Index > Container.Last
2156          then
2157             Position := No_Element;
2158          else
2159             Position := (Container'Unrestricted_Access, Before.Index);
2160          end if;
2161
2162          return;
2163       end if;
2164
2165       if Before.Container = null
2166         or else Before.Index > Container.Last
2167       then
2168          if Container.Last = Index_Type'Last then
2169             raise Constraint_Error with
2170               "vector is already at its maximum length";
2171          end if;
2172
2173          Index := Container.Last + 1;
2174
2175       else
2176          Index := Before.Index;
2177       end if;
2178
2179       Insert (Container, Index, New_Item, Count);
2180
2181       Position := (Container'Unrestricted_Access, Index);
2182    end Insert;
2183
2184    ------------------
2185    -- Insert_Space --
2186    ------------------
2187
2188    procedure Insert_Space
2189      (Container : in out Vector;
2190       Before    : Extended_Index;
2191       Count     : Count_Type := 1)
2192    is
2193       Old_Length : constant Count_Type := Container.Length;
2194
2195       Max_Length : Count_Type'Base;  -- determined from range of Index_Type
2196       New_Length : Count_Type'Base;  -- sum of current length and Count
2197       New_Last   : Index_Type'Base;  -- last index of vector after insertion
2198
2199       Index : Index_Type'Base;  -- scratch for intermediate values
2200       J     : Count_Type'Base;  -- scratch
2201
2202       New_Capacity : Count_Type'Base;  -- length of new, expanded array
2203       Dst_Last     : Index_Type'Base;  -- last index of new, expanded array
2204       Dst          : Elements_Access;  -- new, expanded internal array
2205
2206    begin
2207       --  As a precondition on the generic actual Index_Type, the base type
2208       --  must include Index_Type'Pred (Index_Type'First); this is the value
2209       --  that Container.Last assumes when the vector is empty. However, we do
2210       --  not allow that as the value for Index when specifying where the new
2211       --  items should be inserted, so we must manually check. (That the user
2212       --  is allowed to specify the value at all here is a consequence of the
2213       --  declaration of the Extended_Index subtype, which includes the values
2214       --  in the base range that immediately precede and immediately follow the
2215       --  values in the Index_Type.)
2216
2217       if Before < Index_Type'First then
2218          raise Constraint_Error with
2219            "Before index is out of range (too small)";
2220       end if;
2221
2222       --  We do allow a value greater than Container.Last to be specified as
2223       --  the Index, but only if it's immediately greater. This allows for the
2224       --  case of appending items to the back end of the vector. (It is assumed
2225       --  that specifying an index value greater than Last + 1 indicates some
2226       --  deeper flaw in the caller's algorithm, so that case is treated as a
2227       --  proper error.)
2228
2229       if Before > Container.Last
2230         and then Before > Container.Last + 1
2231       then
2232          raise Constraint_Error with
2233            "Before index is out of range (too large)";
2234       end if;
2235
2236       --  We treat inserting 0 items into the container as a no-op, even when
2237       --  the container is busy, so we simply return.
2238
2239       if Count = 0 then
2240          return;
2241       end if;
2242
2243       --  There are two constraints we need to satisfy. The first constraint is
2244       --  that a container cannot have more than Count_Type'Last elements, so
2245       --  we must check the sum of the current length and the insertion
2246       --  count. Note that we cannot simply add these values, because of the
2247       --  possibility of overflow.
2248
2249       if Old_Length > Count_Type'Last - Count then
2250          raise Constraint_Error with "Count is out of range";
2251       end if;
2252
2253       --  It is now safe compute the length of the new vector, without fear of
2254       --  overflow.
2255
2256       New_Length := Old_Length + Count;
2257
2258       --  The second constraint is that the new Last index value cannot exceed
2259       --  Index_Type'Last. In each branch below, we calculate the maximum
2260       --  length (computed from the range of values in Index_Type), and then
2261       --  compare the new length to the maximum length. If the new length is
2262       --  acceptable, then we compute the new last index from that.
2263
2264       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2265          --  We have to handle the case when there might be more values in the
2266          --  range of Index_Type than in the range of Count_Type.
2267
2268          if Index_Type'First <= 0 then
2269
2270             --  We know that No_Index (the same as Index_Type'First - 1) is
2271             --  less than 0, so it is safe to compute the following sum without
2272             --  fear of overflow.
2273
2274             Index := No_Index + Index_Type'Base (Count_Type'Last);
2275
2276             if Index <= Index_Type'Last then
2277
2278                --  We have determined that range of Index_Type has at least as
2279                --  many values as in Count_Type, so Count_Type'Last is the
2280                --  maximum number of items that are allowed.
2281
2282                Max_Length := Count_Type'Last;
2283
2284             else
2285                --  The range of Index_Type has fewer values than in Count_Type,
2286                --  so the maximum number of items is computed from the range of
2287                --  the Index_Type.
2288
2289                Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2290             end if;
2291
2292          else
2293             --  No_Index is equal or greater than 0, so we can safely compute
2294             --  the difference without fear of overflow (which we would have to
2295             --  worry about if No_Index were less than 0, but that case is
2296             --  handled above).
2297
2298             Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2299          end if;
2300
2301       elsif Index_Type'First <= 0 then
2302
2303          --  We know that No_Index (the same as Index_Type'First - 1) is less
2304          --  than 0, so it is safe to compute the following sum without fear of
2305          --  overflow.
2306
2307          J := Count_Type'Base (No_Index) + Count_Type'Last;
2308
2309          if J <= Count_Type'Base (Index_Type'Last) then
2310
2311             --  We have determined that range of Index_Type has at least as
2312             --  many values as in Count_Type, so Count_Type'Last is the maximum
2313             --  number of items that are allowed.
2314
2315             Max_Length := Count_Type'Last;
2316
2317          else
2318             --  The range of Index_Type has fewer values than Count_Type does,
2319             --  so the maximum number of items is computed from the range of
2320             --  the Index_Type.
2321
2322             Max_Length :=
2323               Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2324          end if;
2325
2326       else
2327          --  No_Index is equal or greater than 0, so we can safely compute the
2328          --  difference without fear of overflow (which we would have to worry
2329          --  about if No_Index were less than 0, but that case is handled
2330          --  above).
2331
2332          Max_Length :=
2333            Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2334       end if;
2335
2336       --  We have just computed the maximum length (number of items). We must
2337       --  now compare the requested length to the maximum length, as we do not
2338       --  allow a vector expand beyond the maximum (because that would create
2339       --  an internal array with a last index value greater than
2340       --  Index_Type'Last, with no way to index those elements).
2341
2342       if New_Length > Max_Length then
2343          raise Constraint_Error with "Count is out of range";
2344       end if;
2345
2346       --  New_Last is the last index value of the items in the container after
2347       --  insertion.  Use the wider of Index_Type'Base and Count_Type'Base to
2348       --  compute its value from the New_Length.
2349
2350       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2351          New_Last := No_Index + Index_Type'Base (New_Length);
2352
2353       else
2354          New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2355       end if;
2356
2357       if Container.Elements = null then
2358          pragma Assert (Container.Last = No_Index);
2359
2360          --  This is the simplest case, with which we must always begin: we're
2361          --  inserting items into an empty vector that hasn't allocated an
2362          --  internal array yet. Note that we don't need to check the busy bit
2363          --  here, because an empty container cannot be busy.
2364
2365          --  In an indefinite vector, elements are allocated individually, and
2366          --  stored as access values on the internal array (the length of which
2367          --  represents the vector "capacity"), which is separately allocated.
2368          --  We have no elements here (because we're inserting "space"), so all
2369          --  we need to do is allocate the backbone.
2370
2371          Container.Elements := new Elements_Type (New_Last);
2372          Container.Last := New_Last;
2373
2374          return;
2375       end if;
2376
2377       --  The tampering bits exist to prevent an item from being harmfully
2378       --  manipulated while it is being visited. Query, Update, and Iterate
2379       --  increment the busy count on entry, and decrement the count on exit.
2380       --  Insert checks the count to determine whether it is being called while
2381       --  the associated callback procedure is executing.
2382
2383       if Container.Busy > 0 then
2384          raise Program_Error with
2385            "attempt to tamper with cursors (vector is busy)";
2386       end if;
2387
2388       if New_Length <= Container.Elements.EA'Length then
2389          --  In this case, we're inserting elements into a vector that has
2390          --  already allocated an internal array, and the existing array has
2391          --  enough unused storage for the new items.
2392
2393          declare
2394             E : Elements_Array renames Container.Elements.EA;
2395
2396          begin
2397             if Before <= Container.Last then
2398
2399                --  The new space is being inserted before some existing
2400                --  elements, so we must slide the existing elements up to their
2401                --  new home. We use the wider of Index_Type'Base and
2402                --  Count_Type'Base as the type for intermediate index values.
2403
2404                if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2405                   Index := Before + Index_Type'Base (Count);
2406
2407                else
2408                   Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2409                end if;
2410
2411                E (Index .. New_Last) := E (Before .. Container.Last);
2412                E (Before .. Index - 1) := (others => null);
2413             end if;
2414          end;
2415
2416          Container.Last := New_Last;
2417          return;
2418       end if;
2419
2420       --  In this case, we're inserting elements into a vector that has already
2421       --  allocated an internal array, but the existing array does not have
2422       --  enough storage, so we must allocate a new, longer array. In order to
2423       --  guarantee that the amortized insertion cost is O(1), we always
2424       --  allocate an array whose length is some power-of-two factor of the
2425       --  current array length. (The new array cannot have a length less than
2426       --  the New_Length of the container, but its last index value cannot be
2427       --  greater than Index_Type'Last.)
2428
2429       New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
2430       while New_Capacity < New_Length loop
2431          if New_Capacity > Count_Type'Last / 2 then
2432             New_Capacity := Count_Type'Last;
2433             exit;
2434          end if;
2435
2436          New_Capacity := 2 * New_Capacity;
2437       end loop;
2438
2439       if New_Capacity > Max_Length then
2440
2441          --  We have reached the limit of capacity, so no further expansion
2442          --  will occur. (This is not a problem, as there is never a need to
2443          --  have more capacity than the maximum container length.)
2444
2445          New_Capacity := Max_Length;
2446       end if;
2447
2448       --  We have computed the length of the new internal array (and this is
2449       --  what "vector capacity" means), so use that to compute its last index.
2450
2451       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2452          Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2453
2454       else
2455          Dst_Last :=
2456            Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2457       end if;
2458
2459       --  Now we allocate the new, longer internal array. If the allocation
2460       --  fails, we have not changed any container state, so no side-effect
2461       --  will occur as a result of propagating the exception.
2462
2463       Dst := new Elements_Type (Dst_Last);
2464
2465       --  We have our new internal array. All that needs to be done now is to
2466       --  copy the existing items (if any) from the old array (the "source"
2467       --  array) to the new array (the "destination" array), and then
2468       --  deallocate the old array.
2469
2470       declare
2471          Src : Elements_Access := Container.Elements;
2472
2473       begin
2474          Dst.EA (Index_Type'First .. Before - 1) :=
2475            Src.EA (Index_Type'First .. Before - 1);
2476
2477          if Before <= Container.Last then
2478
2479             --  The new items are being inserted before some existing elements,
2480             --  so we must slide the existing elements up to their new home.
2481
2482             if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2483                Index := Before + Index_Type'Base (Count);
2484
2485             else
2486                Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2487             end if;
2488
2489             Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2490          end if;
2491
2492          --  We have copied the elements from to the old, source array to the
2493          --  new, destination array, so we can now restore invariants, and
2494          --  deallocate the old array.
2495
2496          Container.Elements := Dst;
2497          Container.Last := New_Last;
2498          Free (Src);
2499       end;
2500    end Insert_Space;
2501
2502    procedure Insert_Space
2503      (Container : in out Vector;
2504       Before    : Cursor;
2505       Position  : out Cursor;
2506       Count     : Count_Type := 1)
2507    is
2508       Index : Index_Type'Base;
2509
2510    begin
2511       if Before.Container /= null
2512         and then Before.Container /= Container'Unrestricted_Access
2513       then
2514          raise Program_Error with "Before cursor denotes wrong container";
2515       end if;
2516
2517       if Count = 0 then
2518          if Before.Container = null
2519            or else Before.Index > Container.Last
2520          then
2521             Position := No_Element;
2522          else
2523             Position := (Container'Unrestricted_Access, Before.Index);
2524          end if;
2525
2526          return;
2527       end if;
2528
2529       if Before.Container = null
2530         or else Before.Index > Container.Last
2531       then
2532          if Container.Last = Index_Type'Last then
2533             raise Constraint_Error with
2534               "vector is already at its maximum length";
2535          end if;
2536
2537          Index := Container.Last + 1;
2538
2539       else
2540          Index := Before.Index;
2541       end if;
2542
2543       Insert_Space (Container, Index, Count);
2544
2545       Position := Cursor'(Container'Unrestricted_Access, Index);
2546    end Insert_Space;
2547
2548    --------------
2549    -- Is_Empty --
2550    --------------
2551
2552    function Is_Empty (Container : Vector) return Boolean is
2553    begin
2554       return Container.Last < Index_Type'First;
2555    end Is_Empty;
2556
2557    -------------
2558    -- Iterate --
2559    -------------
2560
2561    procedure Iterate
2562      (Container : Vector;
2563       Process   : not null access procedure (Position : Cursor))
2564    is
2565       B : Natural renames Container'Unrestricted_Access.all.Busy;
2566
2567    begin
2568       B := B + 1;
2569
2570       begin
2571          for Indx in Index_Type'First .. Container.Last loop
2572             Process (Cursor'(Container'Unrestricted_Access, Indx));
2573          end loop;
2574       exception
2575          when others =>
2576             B := B - 1;
2577             raise;
2578       end;
2579
2580       B := B - 1;
2581    end Iterate;
2582
2583    function Iterate (Container : Vector)
2584       return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2585    is
2586       V : constant Vector_Access := Container'Unrestricted_Access;
2587       B : Natural renames V.Busy;
2588
2589    begin
2590       --  The value of its Index component influences the behavior of the First
2591       --  and Last selector functions of the iterator object. When the Index
2592       --  component is No_Index (as is the case here), this means the iterator
2593       --  object was constructed without a start expression. This is a complete
2594       --  iterator, meaning that the iteration starts from the (logical)
2595       --  beginning of the sequence of items.
2596
2597       --  Note: For a forward iterator, Container.First is the beginning, and
2598       --  for a reverse iterator, Container.Last is the beginning.
2599
2600       return It : constant Iterator :=
2601                     (Limited_Controlled with
2602                        Container => V,
2603                        Index     => No_Index)
2604       do
2605          B := B + 1;
2606       end return;
2607    end Iterate;
2608
2609    function Iterate
2610      (Container : Vector;
2611       Start     : Cursor)
2612       return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2613    is
2614       V : constant Vector_Access := Container'Unrestricted_Access;
2615       B : Natural renames V.Busy;
2616
2617    begin
2618       --  It was formerly the case that when Start = No_Element, the partial
2619       --  iterator was defined to behave the same as for a complete iterator,
2620       --  and iterate over the entire sequence of items. However, those
2621       --  semantics were unintuitive and arguably error-prone (it is too easy
2622       --  to accidentally create an endless loop), and so they were changed,
2623       --  per the ARG meeting in Denver on 2011/11. However, there was no
2624       --  consensus about what positive meaning this corner case should have,
2625       --  and so it was decided to simply raise an exception. This does imply,
2626       --  however, that it is not possible to use a partial iterator to specify
2627       --  an empty sequence of items.
2628
2629       if Start.Container = null then
2630          raise Constraint_Error with
2631            "Start position for iterator equals No_Element";
2632       end if;
2633
2634       if Start.Container /= V then
2635          raise Program_Error with
2636            "Start cursor of Iterate designates wrong vector";
2637       end if;
2638
2639       if Start.Index > V.Last then
2640          raise Constraint_Error with
2641            "Start position for iterator equals No_Element";
2642       end if;
2643
2644       --  The value of its Index component influences the behavior of the First
2645       --  and Last selector functions of the iterator object. When the Index
2646       --  component is not No_Index (as is the case here), it means that this
2647       --  is a partial iteration, over a subset of the complete sequence of
2648       --  items. The iterator object was constructed with a start expression,
2649       --  indicating the position from which the iteration begins. Note that
2650       --  the start position has the same value irrespective of whether this
2651       --  is a forward or reverse iteration.
2652
2653       return It : constant Iterator :=
2654                     (Limited_Controlled with
2655                        Container => V,
2656                        Index     => Start.Index)
2657       do
2658          B := B + 1;
2659       end return;
2660    end Iterate;
2661
2662    ----------
2663    -- Last --
2664    ----------
2665
2666    function Last (Container : Vector) return Cursor is
2667    begin
2668       if Is_Empty (Container) then
2669          return No_Element;
2670       end if;
2671
2672       return (Container'Unrestricted_Access, Container.Last);
2673    end Last;
2674
2675    function Last (Object : Iterator) return Cursor is
2676    begin
2677       --  The value of the iterator object's Index component influences the
2678       --  behavior of the Last (and First) selector function.
2679
2680       --  When the Index component is No_Index, this means the iterator
2681       --  object was constructed without a start expression, in which case the
2682       --  (reverse) iteration starts from the (logical) beginning of the entire
2683       --  sequence (corresponding to Container.Last, for a reverse iterator).
2684
2685       --  Otherwise, this is iteration over a partial sequence of items.
2686       --  When the Index component is not No_Index, the iterator object was
2687       --  constructed with a start expression, that specifies the position
2688       --  from which the (reverse) partial iteration begins.
2689
2690       if Object.Index = No_Index then
2691          return Last (Object.Container.all);
2692       else
2693          return Cursor'(Object.Container, Object.Index);
2694       end if;
2695    end Last;
2696
2697    -----------------
2698    -- Last_Element --
2699    ------------------
2700
2701    function Last_Element (Container : Vector) return Element_Type is
2702    begin
2703       if Container.Last = No_Index then
2704          raise Constraint_Error with "Container is empty";
2705       end if;
2706
2707       declare
2708          EA : constant Element_Access :=
2709                 Container.Elements.EA (Container.Last);
2710
2711       begin
2712          if EA = null then
2713             raise Constraint_Error with "last element is empty";
2714          end if;
2715
2716          return EA.all;
2717       end;
2718    end Last_Element;
2719
2720    ----------------
2721    -- Last_Index --
2722    ----------------
2723
2724    function Last_Index (Container : Vector) return Extended_Index is
2725    begin
2726       return Container.Last;
2727    end Last_Index;
2728
2729    ------------
2730    -- Length --
2731    ------------
2732
2733    function Length (Container : Vector) return Count_Type is
2734       L : constant Index_Type'Base := Container.Last;
2735       F : constant Index_Type := Index_Type'First;
2736
2737    begin
2738       --  The base range of the index type (Index_Type'Base) might not include
2739       --  all values for length (Count_Type). Contrariwise, the index type
2740       --  might include values outside the range of length.  Hence we use
2741       --  whatever type is wider for intermediate values when calculating
2742       --  length. Note that no matter what the index type is, the maximum
2743       --  length to which a vector is allowed to grow is always the minimum
2744       --  of Count_Type'Last and (IT'Last - IT'First + 1).
2745
2746       --  For example, an Index_Type with range -127 .. 127 is only guaranteed
2747       --  to have a base range of -128 .. 127, but the corresponding vector
2748       --  would have lengths in the range 0 .. 255. In this case we would need
2749       --  to use Count_Type'Base for intermediate values.
2750
2751       --  Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2752       --  vector would have a maximum length of 10, but the index values lie
2753       --  outside the range of Count_Type (which is only 32 bits). In this
2754       --  case we would need to use Index_Type'Base for intermediate values.
2755
2756       if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2757          return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2758       else
2759          return Count_Type (L - F + 1);
2760       end if;
2761    end Length;
2762
2763    ----------
2764    -- Move --
2765    ----------
2766
2767    procedure Move
2768      (Target : in out Vector;
2769       Source : in out Vector)
2770    is
2771    begin
2772       if Target'Address = Source'Address then
2773          return;
2774       end if;
2775
2776       if Source.Busy > 0 then
2777          raise Program_Error with
2778            "attempt to tamper with cursors (Source is busy)";
2779       end if;
2780
2781       Clear (Target);  --  Checks busy-bit
2782
2783       declare
2784          Target_Elements : constant Elements_Access := Target.Elements;
2785       begin
2786          Target.Elements := Source.Elements;
2787          Source.Elements := Target_Elements;
2788       end;
2789
2790       Target.Last := Source.Last;
2791       Source.Last := No_Index;
2792    end Move;
2793
2794    ----------
2795    -- Next --
2796    ----------
2797
2798    function Next (Position : Cursor) return Cursor is
2799    begin
2800       if Position.Container = null then
2801          return No_Element;
2802       end if;
2803
2804       if Position.Index < Position.Container.Last then
2805          return (Position.Container, Position.Index + 1);
2806       end if;
2807
2808       return No_Element;
2809    end Next;
2810
2811    function Next (Object : Iterator; Position : Cursor) return Cursor is
2812    begin
2813       if Position.Container = null then
2814          return No_Element;
2815       end if;
2816
2817       if Position.Container /= Object.Container then
2818          raise Program_Error with
2819            "Position cursor of Next designates wrong vector";
2820       end if;
2821
2822       return Next (Position);
2823    end Next;
2824
2825    procedure Next (Position : in out Cursor) is
2826    begin
2827       if Position.Container = null then
2828          return;
2829       end if;
2830
2831       if Position.Index < Position.Container.Last then
2832          Position.Index := Position.Index + 1;
2833       else
2834          Position := No_Element;
2835       end if;
2836    end Next;
2837
2838    -------------
2839    -- Prepend --
2840    -------------
2841
2842    procedure Prepend (Container : in out Vector; New_Item : Vector) is
2843    begin
2844       Insert (Container, Index_Type'First, New_Item);
2845    end Prepend;
2846
2847    procedure Prepend
2848      (Container : in out Vector;
2849       New_Item  : Element_Type;
2850       Count     : Count_Type := 1)
2851    is
2852    begin
2853       Insert (Container,
2854               Index_Type'First,
2855               New_Item,
2856               Count);
2857    end Prepend;
2858
2859    --------------
2860    -- Previous --
2861    --------------
2862
2863    procedure Previous (Position : in out Cursor) is
2864    begin
2865       if Position.Container = null then
2866          return;
2867       end if;
2868
2869       if Position.Index > Index_Type'First then
2870          Position.Index := Position.Index - 1;
2871       else
2872          Position := No_Element;
2873       end if;
2874    end Previous;
2875
2876    function Previous (Position : Cursor) return Cursor is
2877    begin
2878       if Position.Container = null then
2879          return No_Element;
2880       end if;
2881
2882       if Position.Index > Index_Type'First then
2883          return (Position.Container, Position.Index - 1);
2884       end if;
2885
2886       return No_Element;
2887    end Previous;
2888
2889    function Previous (Object : Iterator; Position : Cursor) return Cursor is
2890    begin
2891       if Position.Container = null then
2892          return No_Element;
2893       end if;
2894
2895       if Position.Container /= Object.Container then
2896          raise Program_Error with
2897            "Position cursor of Previous designates wrong vector";
2898       end if;
2899
2900       return Previous (Position);
2901    end Previous;
2902
2903    -------------------
2904    -- Query_Element --
2905    -------------------
2906
2907    procedure Query_Element
2908      (Container : Vector;
2909       Index     : Index_Type;
2910       Process   : not null access procedure (Element : Element_Type))
2911    is
2912       V : Vector renames Container'Unrestricted_Access.all;
2913       B : Natural renames V.Busy;
2914       L : Natural renames V.Lock;
2915
2916    begin
2917       if Index > Container.Last then
2918          raise Constraint_Error with "Index is out of range";
2919       end if;
2920
2921       if V.Elements.EA (Index) = null then
2922          raise Constraint_Error with "element is null";
2923       end if;
2924
2925       B := B + 1;
2926       L := L + 1;
2927
2928       begin
2929          Process (V.Elements.EA (Index).all);
2930       exception
2931          when others =>
2932             L := L - 1;
2933             B := B - 1;
2934             raise;
2935       end;
2936
2937       L := L - 1;
2938       B := B - 1;
2939    end Query_Element;
2940
2941    procedure Query_Element
2942      (Position : Cursor;
2943       Process  : not null access procedure (Element : Element_Type))
2944    is
2945    begin
2946       if Position.Container = null then
2947          raise Constraint_Error with "Position cursor has no element";
2948       end if;
2949
2950       Query_Element (Position.Container.all, Position.Index, Process);
2951    end Query_Element;
2952
2953    ----------
2954    -- Read --
2955    ----------
2956
2957    procedure Read
2958      (Stream    : not null access Root_Stream_Type'Class;
2959       Container : out Vector)
2960    is
2961       Length : Count_Type'Base;
2962       Last   : Index_Type'Base := Index_Type'Pred (Index_Type'First);
2963
2964       B : Boolean;
2965
2966    begin
2967       Clear (Container);
2968
2969       Count_Type'Base'Read (Stream, Length);
2970
2971       if Length > Capacity (Container) then
2972          Reserve_Capacity (Container, Capacity => Length);
2973       end if;
2974
2975       for J in Count_Type range 1 .. Length loop
2976          Last := Last + 1;
2977
2978          Boolean'Read (Stream, B);
2979
2980          if B then
2981             Container.Elements.EA (Last) :=
2982               new Element_Type'(Element_Type'Input (Stream));
2983          end if;
2984
2985          Container.Last := Last;
2986       end loop;
2987    end Read;
2988
2989    procedure Read
2990      (Stream   : not null access Root_Stream_Type'Class;
2991       Position : out Cursor)
2992    is
2993    begin
2994       raise Program_Error with "attempt to stream vector cursor";
2995    end Read;
2996
2997    procedure Read
2998      (Stream : not null access Root_Stream_Type'Class;
2999       Item   : out Reference_Type)
3000    is
3001    begin
3002       raise Program_Error with "attempt to stream reference";
3003    end Read;
3004
3005    procedure Read
3006      (Stream : not null access Root_Stream_Type'Class;
3007       Item   : out Constant_Reference_Type)
3008    is
3009    begin
3010       raise Program_Error with "attempt to stream reference";
3011    end Read;
3012
3013    ---------------
3014    -- Reference --
3015    ---------------
3016
3017    function Reference
3018      (Container : aliased in out Vector;
3019       Position  : Cursor) return Reference_Type
3020    is
3021       E : Element_Access;
3022
3023    begin
3024       if Position.Container = null then
3025          raise Constraint_Error with "Position cursor has no element";
3026       end if;
3027
3028       if Position.Container /= Container'Unrestricted_Access then
3029          raise Program_Error with "Position cursor denotes wrong container";
3030       end if;
3031
3032       if Position.Index > Position.Container.Last then
3033          raise Constraint_Error with "Position cursor is out of range";
3034       end if;
3035
3036       E := Container.Elements.EA (Position.Index);
3037
3038       if E = null then
3039          raise Constraint_Error with "element at Position is empty";
3040       end if;
3041
3042       return (Element => E.all'Access);
3043    end Reference;
3044
3045    function Reference
3046      (Container : aliased in out Vector;
3047       Index     : Index_Type) return Reference_Type
3048    is
3049       E : Element_Access;
3050
3051    begin
3052       if Index > Container.Last then
3053          raise Constraint_Error with "Index is out of range";
3054       end if;
3055
3056       E := Container.Elements.EA (Index);
3057
3058       if E = null then
3059          raise Constraint_Error with "element at Index is empty";
3060       end if;
3061
3062       return (Element => E.all'Access);
3063    end Reference;
3064
3065    ---------------------
3066    -- Replace_Element --
3067    ---------------------
3068
3069    procedure Replace_Element
3070      (Container : in out Vector;
3071       Index     : Index_Type;
3072       New_Item  : Element_Type)
3073    is
3074    begin
3075       if Index > Container.Last then
3076          raise Constraint_Error with "Index is out of range";
3077       end if;
3078
3079       if Container.Lock > 0 then
3080          raise Program_Error with
3081            "attempt to tamper with elements (vector is locked)";
3082       end if;
3083
3084       declare
3085          X : Element_Access := Container.Elements.EA (Index);
3086       begin
3087          Container.Elements.EA (Index) := new Element_Type'(New_Item);
3088          Free (X);
3089       end;
3090    end Replace_Element;
3091
3092    procedure Replace_Element
3093      (Container : in out Vector;
3094       Position  : Cursor;
3095       New_Item  : Element_Type)
3096    is
3097    begin
3098       if Position.Container = null then
3099          raise Constraint_Error with "Position cursor has no element";
3100       end if;
3101
3102       if Position.Container /= Container'Unrestricted_Access then
3103          raise Program_Error with "Position cursor denotes wrong container";
3104       end if;
3105
3106       if Position.Index > Container.Last then
3107          raise Constraint_Error with "Position cursor is out of range";
3108       end if;
3109
3110       if Container.Lock > 0 then
3111          raise Program_Error with
3112            "attempt to tamper with elements (vector is locked)";
3113       end if;
3114
3115       declare
3116          X : Element_Access := Container.Elements.EA (Position.Index);
3117       begin
3118          Container.Elements.EA (Position.Index) := new Element_Type'(New_Item);
3119          Free (X);
3120       end;
3121    end Replace_Element;
3122
3123    ----------------------
3124    -- Reserve_Capacity --
3125    ----------------------
3126
3127    procedure Reserve_Capacity
3128      (Container : in out Vector;
3129       Capacity  : Count_Type)
3130    is
3131       N : constant Count_Type := Length (Container);
3132
3133       Index : Count_Type'Base;
3134       Last  : Index_Type'Base;
3135
3136    begin
3137       --  Reserve_Capacity can be used to either expand the storage available
3138       --  for elements (this would be its typical use, in anticipation of
3139       --  future insertion), or to trim back storage. In the latter case,
3140       --  storage can only be trimmed back to the limit of the container
3141       --  length. Note that Reserve_Capacity neither deletes (active) elements
3142       --  nor inserts elements; it only affects container capacity, never
3143       --  container length.
3144
3145       if Capacity = 0 then
3146
3147          --  This is a request to trim back storage, to the minimum amount
3148          --  possible given the current state of the container.
3149
3150          if N = 0 then
3151
3152             --  The container is empty, so in this unique case we can
3153             --  deallocate the entire internal array. Note that an empty
3154             --  container can never be busy, so there's no need to check the
3155             --  tampering bits.
3156
3157             declare
3158                X : Elements_Access := Container.Elements;
3159
3160             begin
3161                --  First we remove the internal array from the container, to
3162                --  handle the case when the deallocation raises an exception
3163                --  (although that's unlikely, since this is simply an array of
3164                --  access values, all of which are null).
3165
3166                Container.Elements := null;
3167
3168                --  Container invariants have been restored, so it is now safe
3169                --  to attempt to deallocate the internal array.
3170
3171                Free (X);
3172             end;
3173
3174          elsif N < Container.Elements.EA'Length then
3175
3176             --  The container is not empty, and the current length is less than
3177             --  the current capacity, so there's storage available to trim. In
3178             --  this case, we allocate a new internal array having a length
3179             --  that exactly matches the number of items in the
3180             --  container. (Reserve_Capacity does not delete active elements,
3181             --  so this is the best we can do with respect to minimizing
3182             --  storage).
3183
3184             if Container.Busy > 0 then
3185                raise Program_Error with
3186                  "attempt to tamper with cursors (vector is busy)";
3187             end if;
3188
3189             declare
3190                subtype Array_Index_Subtype is Index_Type'Base range
3191                  Index_Type'First .. Container.Last;
3192
3193                Src : Elements_Array renames
3194                        Container.Elements.EA (Array_Index_Subtype);
3195
3196                X : Elements_Access := Container.Elements;
3197
3198             begin
3199                --  Although we have isolated the old internal array that we're
3200                --  going to deallocate, we don't deallocate it until we have
3201                --  successfully allocated a new one. If there is an exception
3202                --  during allocation (because there is not enough storage), we
3203                --  let it propagate without causing any side-effect.
3204
3205                Container.Elements := new Elements_Type'(Container.Last, Src);
3206
3207                --  We have successfully allocated a new internal array (with a
3208                --  smaller length than the old one, and containing a copy of
3209                --  just the active elements in the container), so we can
3210                --  deallocate the old array.
3211
3212                Free (X);
3213             end;
3214          end if;
3215
3216          return;
3217       end if;
3218
3219       --  Reserve_Capacity can be used to expand the storage available for
3220       --  elements, but we do not let the capacity grow beyond the number of
3221       --  values in Index_Type'Range. (Were it otherwise, there would be no way
3222       --  to refer to the elements with index values greater than
3223       --  Index_Type'Last, so that storage would be wasted.) Here we compute
3224       --  the Last index value of the new internal array, in a way that avoids
3225       --  any possibility of overflow.
3226
3227       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3228
3229          --  We perform a two-part test. First we determine whether the
3230          --  computed Last value lies in the base range of the type, and then
3231          --  determine whether it lies in the range of the index (sub)type.
3232
3233          --  Last must satisfy this relation:
3234          --    First + Length - 1 <= Last
3235          --  We regroup terms:
3236          --    First - 1 <= Last - Length
3237          --  Which can rewrite as:
3238          --    No_Index <= Last - Length
3239
3240          if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
3241             raise Constraint_Error with "Capacity is out of range";
3242          end if;
3243
3244          --  We now know that the computed value of Last is within the base
3245          --  range of the type, so it is safe to compute its value:
3246
3247          Last := No_Index + Index_Type'Base (Capacity);
3248
3249          --  Finally we test whether the value is within the range of the
3250          --  generic actual index subtype:
3251
3252          if Last > Index_Type'Last then
3253             raise Constraint_Error with "Capacity is out of range";
3254          end if;
3255
3256       elsif Index_Type'First <= 0 then
3257
3258          --  Here we can compute Last directly, in the normal way. We know that
3259          --  No_Index is less than 0, so there is no danger of overflow when
3260          --  adding the (positive) value of Capacity.
3261
3262          Index := Count_Type'Base (No_Index) + Capacity;  -- Last
3263
3264          if Index > Count_Type'Base (Index_Type'Last) then
3265             raise Constraint_Error with "Capacity is out of range";
3266          end if;
3267
3268          --  We know that the computed value (having type Count_Type) of Last
3269          --  is within the range of the generic actual index subtype, so it is
3270          --  safe to convert to Index_Type:
3271
3272          Last := Index_Type'Base (Index);
3273
3274       else
3275          --  Here Index_Type'First (and Index_Type'Last) is positive, so we
3276          --  must test the length indirectly (by working backwards from the
3277          --  largest possible value of Last), in order to prevent overflow.
3278
3279          Index := Count_Type'Base (Index_Type'Last) - Capacity;  -- No_Index
3280
3281          if Index < Count_Type'Base (No_Index) then
3282             raise Constraint_Error with "Capacity is out of range";
3283          end if;
3284
3285          --  We have determined that the value of Capacity would not create a
3286          --  Last index value outside of the range of Index_Type, so we can now
3287          --  safely compute its value.
3288
3289          Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
3290       end if;
3291
3292       --  The requested capacity is non-zero, but we don't know yet whether
3293       --  this is a request for expansion or contraction of storage.
3294
3295       if Container.Elements = null then
3296
3297          --  The container is empty (it doesn't even have an internal array),
3298          --  so this represents a request to allocate storage having the given
3299          --  capacity.
3300
3301          Container.Elements := new Elements_Type (Last);
3302          return;
3303       end if;
3304
3305       if Capacity <= N then
3306
3307          --  This is a request to trim back storage, but only to the limit of
3308          --  what's already in the container. (Reserve_Capacity never deletes
3309          --  active elements, it only reclaims excess storage.)
3310
3311          if N < Container.Elements.EA'Length then
3312
3313             --  The container is not empty (because the requested capacity is
3314             --  positive, and less than or equal to the container length), and
3315             --  the current length is less than the current capacity, so there
3316             --  is storage available to trim. In this case, we allocate a new
3317             --  internal array having a length that exactly matches the number
3318             --  of items in the container.
3319
3320             if Container.Busy > 0 then
3321                raise Program_Error with
3322                  "attempt to tamper with cursors (vector is busy)";
3323             end if;
3324
3325             declare
3326                subtype Array_Index_Subtype is Index_Type'Base range
3327                  Index_Type'First .. Container.Last;
3328
3329                Src : Elements_Array renames
3330                        Container.Elements.EA (Array_Index_Subtype);
3331
3332                X : Elements_Access := Container.Elements;
3333
3334             begin
3335                --  Although we have isolated the old internal array that we're
3336                --  going to deallocate, we don't deallocate it until we have
3337                --  successfully allocated a new one. If there is an exception
3338                --  during allocation (because there is not enough storage), we
3339                --  let it propagate without causing any side-effect.
3340
3341                Container.Elements := new Elements_Type'(Container.Last, Src);
3342
3343                --  We have successfully allocated a new internal array (with a
3344                --  smaller length than the old one, and containing a copy of
3345                --  just the active elements in the container), so it is now
3346                --  safe to deallocate the old array.
3347
3348                Free (X);
3349             end;
3350          end if;
3351
3352          return;
3353       end if;
3354
3355       --  The requested capacity is larger than the container length (the
3356       --  number of active elements). Whether this represents a request for
3357       --  expansion or contraction of the current capacity depends on what the
3358       --  current capacity is.
3359
3360       if Capacity = Container.Elements.EA'Length then
3361
3362          --  The requested capacity matches the existing capacity, so there's
3363          --  nothing to do here. We treat this case as a no-op, and simply
3364          --  return without checking the busy bit.
3365
3366          return;
3367       end if;
3368
3369       --  There is a change in the capacity of a non-empty container, so a new
3370       --  internal array will be allocated. (The length of the new internal
3371       --  array could be less or greater than the old internal array. We know
3372       --  only that the length of the new internal array is greater than the
3373       --  number of active elements in the container.) We must check whether
3374       --  the container is busy before doing anything else.
3375
3376       if Container.Busy > 0 then
3377          raise Program_Error with
3378            "attempt to tamper with cursors (vector is busy)";
3379       end if;
3380
3381       --  We now allocate a new internal array, having a length different from
3382       --  its current value.
3383
3384       declare
3385          X : Elements_Access := Container.Elements;
3386
3387          subtype Index_Subtype is Index_Type'Base range
3388            Index_Type'First .. Container.Last;
3389
3390       begin
3391          --  We now allocate a new internal array, having a length different
3392          --  from its current value.
3393
3394          Container.Elements := new Elements_Type (Last);
3395
3396          --  We have successfully allocated the new internal array, so now we
3397          --  move the existing elements from the existing the old internal
3398          --  array onto the new one. Note that we're just copying access
3399          --  values, to this should not raise any exceptions.
3400
3401          Container.Elements.EA (Index_Subtype) := X.EA (Index_Subtype);
3402
3403          --  We have moved the elements from the old internal array, so now we
3404          --  can deallocate it.
3405
3406          Free (X);
3407       end;
3408    end Reserve_Capacity;
3409
3410    ----------------------
3411    -- Reverse_Elements --
3412    ----------------------
3413
3414    procedure Reverse_Elements (Container : in out Vector) is
3415    begin
3416       if Container.Length <= 1 then
3417          return;
3418       end if;
3419
3420       if Container.Lock > 0 then
3421          raise Program_Error with
3422            "attempt to tamper with elements (vector is locked)";
3423       end if;
3424
3425       declare
3426          I : Index_Type;
3427          J : Index_Type;
3428          E : Elements_Array renames Container.Elements.EA;
3429
3430       begin
3431          I := Index_Type'First;
3432          J := Container.Last;
3433          while I < J loop
3434             declare
3435                EI : constant Element_Access := E (I);
3436
3437             begin
3438                E (I) := E (J);
3439                E (J) := EI;
3440             end;
3441
3442             I := I + 1;
3443             J := J - 1;
3444          end loop;
3445       end;
3446    end Reverse_Elements;
3447
3448    ------------------
3449    -- Reverse_Find --
3450    ------------------
3451
3452    function Reverse_Find
3453      (Container : Vector;
3454       Item      : Element_Type;
3455       Position  : Cursor := No_Element) return Cursor
3456    is
3457       Last : Index_Type'Base;
3458
3459    begin
3460       if Position.Container /= null
3461         and then Position.Container /= Container'Unrestricted_Access
3462       then
3463          raise Program_Error with "Position cursor denotes wrong container";
3464       end if;
3465
3466       if Position.Container = null
3467         or else Position.Index > Container.Last
3468       then
3469          Last := Container.Last;
3470       else
3471          Last := Position.Index;
3472       end if;
3473
3474       for Indx in reverse Index_Type'First .. Last loop
3475          if Container.Elements.EA (Indx) /= null
3476            and then Container.Elements.EA (Indx).all = Item
3477          then
3478             return (Container'Unrestricted_Access, Indx);
3479          end if;
3480       end loop;
3481
3482       return No_Element;
3483    end Reverse_Find;
3484
3485    ------------------------
3486    -- Reverse_Find_Index --
3487    ------------------------
3488
3489    function Reverse_Find_Index
3490      (Container : Vector;
3491       Item      : Element_Type;
3492       Index     : Index_Type := Index_Type'Last) return Extended_Index
3493    is
3494       Last : constant Index_Type'Base :=
3495                (if Index > Container.Last then Container.Last else Index);
3496    begin
3497       for Indx in reverse Index_Type'First .. Last loop
3498          if Container.Elements.EA (Indx) /= null
3499            and then Container.Elements.EA (Indx).all = Item
3500          then
3501             return Indx;
3502          end if;
3503       end loop;
3504
3505       return No_Index;
3506    end Reverse_Find_Index;
3507
3508    ---------------------
3509    -- Reverse_Iterate --
3510    ---------------------
3511
3512    procedure Reverse_Iterate
3513      (Container : Vector;
3514       Process   : not null access procedure (Position : Cursor))
3515    is
3516       V : Vector renames Container'Unrestricted_Access.all;
3517       B : Natural renames V.Busy;
3518
3519    begin
3520       B := B + 1;
3521
3522       begin
3523          for Indx in reverse Index_Type'First .. Container.Last loop
3524             Process (Cursor'(Container'Unrestricted_Access, Indx));
3525          end loop;
3526       exception
3527          when others =>
3528             B := B - 1;
3529             raise;
3530       end;
3531
3532       B := B - 1;
3533    end Reverse_Iterate;
3534
3535    ----------------
3536    -- Set_Length --
3537    ----------------
3538
3539    procedure Set_Length
3540      (Container : in out Vector;
3541       Length    : Count_Type)
3542    is
3543       Count : constant Count_Type'Base := Container.Length - Length;
3544
3545    begin
3546       --  Set_Length allows the user to set the length explicitly, instead of
3547       --  implicitly as a side-effect of deletion or insertion. If the
3548       --  requested length is less than the current length, this is equivalent
3549       --  to deleting items from the back end of the vector. If the requested
3550       --  length is greater than the current length, then this is equivalent to
3551       --  inserting "space" (nonce items) at the end.
3552
3553       if Count >= 0 then
3554          Container.Delete_Last (Count);
3555
3556       elsif Container.Last >= Index_Type'Last then
3557          raise Constraint_Error with "vector is already at its maximum length";
3558
3559       else
3560          Container.Insert_Space (Container.Last + 1, -Count);
3561       end if;
3562    end Set_Length;
3563
3564    ----------
3565    -- Swap --
3566    ----------
3567
3568    procedure Swap
3569      (Container : in out Vector;
3570       I, J      : Index_Type)
3571    is
3572    begin
3573       if I > Container.Last then
3574          raise Constraint_Error with "I index is out of range";
3575       end if;
3576
3577       if J > Container.Last then
3578          raise Constraint_Error with "J index is out of range";
3579       end if;
3580
3581       if I = J then
3582          return;
3583       end if;
3584
3585       if Container.Lock > 0 then
3586          raise Program_Error with
3587            "attempt to tamper with elements (vector is locked)";
3588       end if;
3589
3590       declare
3591          EI : Element_Access renames Container.Elements.EA (I);
3592          EJ : Element_Access renames Container.Elements.EA (J);
3593
3594          EI_Copy : constant Element_Access := EI;
3595
3596       begin
3597          EI := EJ;
3598          EJ := EI_Copy;
3599       end;
3600    end Swap;
3601
3602    procedure Swap
3603      (Container : in out Vector;
3604       I, J      : Cursor)
3605    is
3606    begin
3607       if I.Container = null then
3608          raise Constraint_Error with "I cursor has no element";
3609       end if;
3610
3611       if J.Container = null then
3612          raise Constraint_Error with "J cursor has no element";
3613       end if;
3614
3615       if I.Container /= Container'Unrestricted_Access then
3616          raise Program_Error with "I cursor denotes wrong container";
3617       end if;
3618
3619       if J.Container /= Container'Unrestricted_Access then
3620          raise Program_Error with "J cursor denotes wrong container";
3621       end if;
3622
3623       Swap (Container, I.Index, J.Index);
3624    end Swap;
3625
3626    ---------------
3627    -- To_Cursor --
3628    ---------------
3629
3630    function To_Cursor
3631      (Container : Vector;
3632       Index     : Extended_Index) return Cursor
3633    is
3634    begin
3635       if Index not in Index_Type'First .. Container.Last then
3636          return No_Element;
3637       end if;
3638
3639       return Cursor'(Container'Unrestricted_Access, Index);
3640    end To_Cursor;
3641
3642    --------------
3643    -- To_Index --
3644    --------------
3645
3646    function To_Index (Position : Cursor) return Extended_Index is
3647    begin
3648       if Position.Container = null then
3649          return No_Index;
3650       end if;
3651
3652       if Position.Index <= Position.Container.Last then
3653          return Position.Index;
3654       end if;
3655
3656       return No_Index;
3657    end To_Index;
3658
3659    ---------------
3660    -- To_Vector --
3661    ---------------
3662
3663    function To_Vector (Length : Count_Type) return Vector is
3664       Index    : Count_Type'Base;
3665       Last     : Index_Type'Base;
3666       Elements : Elements_Access;
3667
3668    begin
3669       if Length = 0 then
3670          return Empty_Vector;
3671       end if;
3672
3673       --  We create a vector object with a capacity that matches the specified
3674       --  Length, but we do not allow the vector capacity (the length of the
3675       --  internal array) to exceed the number of values in Index_Type'Range
3676       --  (otherwise, there would be no way to refer to those components via an
3677       --  index).  We must therefore check whether the specified Length would
3678       --  create a Last index value greater than Index_Type'Last.
3679
3680       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3681
3682          --  We perform a two-part test. First we determine whether the
3683          --  computed Last value lies in the base range of the type, and then
3684          --  determine whether it lies in the range of the index (sub)type.
3685
3686          --  Last must satisfy this relation:
3687          --    First + Length - 1 <= Last
3688          --  We regroup terms:
3689          --    First - 1 <= Last - Length
3690          --  Which can rewrite as:
3691          --    No_Index <= Last - Length
3692
3693          if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3694             raise Constraint_Error with "Length is out of range";
3695          end if;
3696
3697          --  We now know that the computed value of Last is within the base
3698          --  range of the type, so it is safe to compute its value:
3699
3700          Last := No_Index + Index_Type'Base (Length);
3701
3702          --  Finally we test whether the value is within the range of the
3703          --  generic actual index subtype:
3704
3705          if Last > Index_Type'Last then
3706             raise Constraint_Error with "Length is out of range";
3707          end if;
3708
3709       elsif Index_Type'First <= 0 then
3710
3711          --  Here we can compute Last directly, in the normal way. We know that
3712          --  No_Index is less than 0, so there is no danger of overflow when
3713          --  adding the (positive) value of Length.
3714
3715          Index := Count_Type'Base (No_Index) + Length;  -- Last
3716
3717          if Index > Count_Type'Base (Index_Type'Last) then
3718             raise Constraint_Error with "Length is out of range";
3719          end if;
3720
3721          --  We know that the computed value (having type Count_Type) of Last
3722          --  is within the range of the generic actual index subtype, so it is
3723          --  safe to convert to Index_Type:
3724
3725          Last := Index_Type'Base (Index);
3726
3727       else
3728          --  Here Index_Type'First (and Index_Type'Last) is positive, so we
3729          --  must test the length indirectly (by working backwards from the
3730          --  largest possible value of Last), in order to prevent overflow.
3731
3732          Index := Count_Type'Base (Index_Type'Last) - Length;  -- No_Index
3733
3734          if Index < Count_Type'Base (No_Index) then
3735             raise Constraint_Error with "Length is out of range";
3736          end if;
3737
3738          --  We have determined that the value of Length would not create a
3739          --  Last index value outside of the range of Index_Type, so we can now
3740          --  safely compute its value.
3741
3742          Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3743       end if;
3744
3745       Elements := new Elements_Type (Last);
3746
3747       return Vector'(Controlled with Elements, Last, 0, 0);
3748    end To_Vector;
3749
3750    function To_Vector
3751      (New_Item : Element_Type;
3752       Length   : Count_Type) return Vector
3753    is
3754       Index    : Count_Type'Base;
3755       Last     : Index_Type'Base;
3756       Elements : Elements_Access;
3757
3758    begin
3759       if Length = 0 then
3760          return Empty_Vector;
3761       end if;
3762
3763       --  We create a vector object with a capacity that matches the specified
3764       --  Length, but we do not allow the vector capacity (the length of the
3765       --  internal array) to exceed the number of values in Index_Type'Range
3766       --  (otherwise, there would be no way to refer to those components via an
3767       --  index). We must therefore check whether the specified Length would
3768       --  create a Last index value greater than Index_Type'Last.
3769
3770       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3771
3772          --  We perform a two-part test. First we determine whether the
3773          --  computed Last value lies in the base range of the type, and then
3774          --  determine whether it lies in the range of the index (sub)type.
3775
3776          --  Last must satisfy this relation:
3777          --    First + Length - 1 <= Last
3778          --  We regroup terms:
3779          --    First - 1 <= Last - Length
3780          --  Which can rewrite as:
3781          --    No_Index <= Last - Length
3782
3783          if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3784             raise Constraint_Error with "Length is out of range";
3785          end if;
3786
3787          --  We now know that the computed value of Last is within the base
3788          --  range of the type, so it is safe to compute its value:
3789
3790          Last := No_Index + Index_Type'Base (Length);
3791
3792          --  Finally we test whether the value is within the range of the
3793          --  generic actual index subtype:
3794
3795          if Last > Index_Type'Last then
3796             raise Constraint_Error with "Length is out of range";
3797          end if;
3798
3799       elsif Index_Type'First <= 0 then
3800
3801          --  Here we can compute Last directly, in the normal way. We know that
3802          --  No_Index is less than 0, so there is no danger of overflow when
3803          --  adding the (positive) value of Length.
3804
3805          Index := Count_Type'Base (No_Index) + Length;  -- Last
3806
3807          if Index > Count_Type'Base (Index_Type'Last) then
3808             raise Constraint_Error with "Length is out of range";
3809          end if;
3810
3811          --  We know that the computed value (having type Count_Type) of Last
3812          --  is within the range of the generic actual index subtype, so it is
3813          --  safe to convert to Index_Type:
3814
3815          Last := Index_Type'Base (Index);
3816
3817       else
3818          --  Here Index_Type'First (and Index_Type'Last) is positive, so we
3819          --  must test the length indirectly (by working backwards from the
3820          --  largest possible value of Last), in order to prevent overflow.
3821
3822          Index := Count_Type'Base (Index_Type'Last) - Length;  -- No_Index
3823
3824          if Index < Count_Type'Base (No_Index) then
3825             raise Constraint_Error with "Length is out of range";
3826          end if;
3827
3828          --  We have determined that the value of Length would not create a
3829          --  Last index value outside of the range of Index_Type, so we can now
3830          --  safely compute its value.
3831
3832          Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3833       end if;
3834
3835       Elements := new Elements_Type (Last);
3836
3837       --  We use Last as the index of the loop used to populate the internal
3838       --  array with items. In general, we prefer to initialize the loop index
3839       --  immediately prior to entering the loop. However, Last is also used in
3840       --  the exception handler (to reclaim elements that have been allocated,
3841       --  before propagating the exception), and the initialization of Last
3842       --  after entering the block containing the handler confuses some static
3843       --  analysis tools, with respect to whether Last has been properly
3844       --  initialized when the handler executes. So here we initialize our loop
3845       --  variable earlier than we prefer, before entering the block, so there
3846       --  is no ambiguity.
3847
3848       Last := Index_Type'First;
3849
3850       begin
3851          loop
3852             Elements.EA (Last) := new Element_Type'(New_Item);
3853             exit when Last = Elements.Last;
3854             Last := Last + 1;
3855          end loop;
3856
3857       exception
3858          when others =>
3859             for J in Index_Type'First .. Last - 1 loop
3860                Free (Elements.EA (J));
3861             end loop;
3862
3863             Free (Elements);
3864             raise;
3865       end;
3866
3867       return (Controlled with Elements, Last, 0, 0);
3868    end To_Vector;
3869
3870    --------------------
3871    -- Update_Element --
3872    --------------------
3873
3874    procedure Update_Element
3875      (Container : in out Vector;
3876       Index     : Index_Type;
3877       Process   : not null access procedure (Element : in out Element_Type))
3878    is
3879       B : Natural renames Container.Busy;
3880       L : Natural renames Container.Lock;
3881
3882    begin
3883       if Index > Container.Last then
3884          raise Constraint_Error with "Index is out of range";
3885       end if;
3886
3887       if Container.Elements.EA (Index) = null then
3888          raise Constraint_Error with "element is null";
3889       end if;
3890
3891       B := B + 1;
3892       L := L + 1;
3893
3894       begin
3895          Process (Container.Elements.EA (Index).all);
3896       exception
3897          when others =>
3898             L := L - 1;
3899             B := B - 1;
3900             raise;
3901       end;
3902
3903       L := L - 1;
3904       B := B - 1;
3905    end Update_Element;
3906
3907    procedure Update_Element
3908      (Container : in out Vector;
3909       Position  : Cursor;
3910       Process   : not null access procedure (Element : in out Element_Type))
3911    is
3912    begin
3913       if Position.Container = null then
3914          raise Constraint_Error with "Position cursor has no element";
3915       end if;
3916
3917       if Position.Container /= Container'Unrestricted_Access then
3918          raise Program_Error with "Position cursor denotes wrong container";
3919       end if;
3920
3921       Update_Element (Container, Position.Index, Process);
3922    end Update_Element;
3923
3924    -----------
3925    -- Write --
3926    -----------
3927
3928    procedure Write
3929      (Stream    : not null access Root_Stream_Type'Class;
3930       Container : Vector)
3931    is
3932       N : constant Count_Type := Length (Container);
3933
3934    begin
3935       Count_Type'Base'Write (Stream, N);
3936
3937       if N = 0 then
3938          return;
3939       end if;
3940
3941       declare
3942          E : Elements_Array renames Container.Elements.EA;
3943
3944       begin
3945          for Indx in Index_Type'First .. Container.Last loop
3946             if E (Indx) = null then
3947                Boolean'Write (Stream, False);
3948             else
3949                Boolean'Write (Stream, True);
3950                Element_Type'Output (Stream, E (Indx).all);
3951             end if;
3952          end loop;
3953       end;
3954    end Write;
3955
3956    procedure Write
3957      (Stream   : not null access Root_Stream_Type'Class;
3958       Position : Cursor)
3959    is
3960    begin
3961       raise Program_Error with "attempt to stream vector cursor";
3962    end Write;
3963
3964    procedure Write
3965      (Stream : not null access Root_Stream_Type'Class;
3966       Item   : Reference_Type)
3967    is
3968    begin
3969       raise Program_Error with "attempt to stream reference";
3970    end Write;
3971
3972    procedure Write
3973      (Stream : not null access Root_Stream_Type'Class;
3974       Item   : Constant_Reference_Type)
3975    is
3976    begin
3977       raise Program_Error with "attempt to stream reference";
3978    end Write;
3979
3980 end Ada.Containers.Indefinite_Vectors;