OSDN Git Service

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