OSDN Git Service

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