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
30with Ada.Containers.Generic_Array_Sort;
31with Ada.Finalization; use Ada.Finalization;
32
33with System; use type System.Address;
34
35package 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 than 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
2779end Ada.Containers.Bounded_Vectors;
2780