OSDN Git Service

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