OSDN Git Service

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