OSDN Git Service

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