OSDN Git Service

2011-09-06 Ed Schonberg <schonberg@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-convec.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT LIBRARY COMPONENTS                          --
4 --                                                                          --
5 --                A D A . C O N T A I N E R S . V E C T O R S               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2004-2011, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17 --                                                                          --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception,   --
20 -- version 3.1, as published by the Free Software Foundation.               --
21 --                                                                          --
22 -- You should have received a copy of the GNU General Public License and    --
23 -- a copy of the GCC Runtime Library Exception along with this program;     --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25 -- <http://www.gnu.org/licenses/>.                                          --
26 --                                                                          --
27 -- This unit was originally developed by Matthew J Heaney.                  --
28 ------------------------------------------------------------------------------
29
30 with Ada.Containers.Generic_Array_Sort;
31 with Ada.Unchecked_Deallocation;
32
33 with System; use type System.Address;
34
35 package body Ada.Containers.Vectors is
36
37    procedure Free is
38      new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
39
40    type Iterator is new Vector_Iterator_Interfaces.Reversible_Iterator with
41    record
42       Container : Vector_Access;
43       Index     : Index_Type;
44    end record;
45
46    overriding function First (Object : Iterator) return Cursor;
47    overriding function Last  (Object : Iterator) return Cursor;
48    overriding function Next
49      (Object : Iterator;
50       Position : Cursor) return Cursor;
51    overriding function Previous
52      (Object   : Iterator;
53       Position : Cursor) return Cursor;
54
55    ---------
56    -- "&" --
57    ---------
58
59    function "&" (Left, Right : Vector) return Vector is
60       LN   : constant Count_Type := Length (Left);
61       RN   : constant Count_Type := Length (Right);
62       N    : Count_Type'Base;  -- length of result
63       J    : Count_Type'Base;  -- for computing intermediate index values
64       Last : Index_Type'Base;  -- Last index of result
65
66    begin
67       --  We decide that the capacity of the result is the sum of the lengths
68       --  of the vector parameters. We could decide to make it larger, but we
69       --  have no basis for knowing how much larger, so we just allocate the
70       --  minimum amount of storage.
71
72       --  Here we handle the easy cases first, when one of the vector
73       --  parameters is empty. (We say "easy" because there's nothing to
74       --  compute, that can potentially overflow.)
75
76       if LN = 0 then
77          if RN = 0 then
78             return Empty_Vector;
79          end if;
80
81          declare
82             RE : Elements_Array renames
83                    Right.Elements.EA (Index_Type'First .. Right.Last);
84
85             Elements : constant Elements_Access :=
86                          new Elements_Type'(Right.Last, RE);
87
88          begin
89             return (Controlled with Elements, Right.Last, 0, 0);
90          end;
91       end if;
92
93       if RN = 0 then
94          declare
95             LE : Elements_Array renames
96                    Left.Elements.EA (Index_Type'First .. Left.Last);
97
98             Elements : constant Elements_Access :=
99                          new Elements_Type'(Left.Last, LE);
100
101          begin
102             return (Controlled with Elements, Left.Last, 0, 0);
103          end;
104
105       end if;
106
107       --  Neither of the vector parameters is empty, so must compute the length
108       --  of the result vector and its last index. (This is the harder case,
109       --  because our computations must avoid overflow.)
110
111       --  There are two constraints we need to satisfy. The first constraint is
112       --  that a container cannot have more than Count_Type'Last elements, so
113       --  we must check the sum of the combined lengths. Note that we cannot
114       --  simply add the lengths, because of the possibility of overflow.
115
116       if LN > Count_Type'Last - RN then
117          raise Constraint_Error with "new length is out of range";
118       end if;
119
120       --  It is now safe compute the length of the new vector, without fear of
121       --  overflow.
122
123       N := LN + RN;
124
125       --  The second constraint is that the new Last index value cannot
126       --  exceed Index_Type'Last. We use the wider of Index_Type'Base and
127       --  Count_Type'Base as the type for intermediate values.
128
129       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
130
131          --  We perform a two-part test. First we determine whether the
132          --  computed Last value lies in the base range of the type, and then
133          --  determine whether it lies in the range of the index (sub)type.
134
135          --  Last must satisfy this relation:
136          --    First + Length - 1 <= Last
137          --  We regroup terms:
138          --    First - 1 <= Last - Length
139          --  Which can rewrite as:
140          --    No_Index <= Last - Length
141
142          if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
143             raise Constraint_Error with "new length is out of range";
144          end if;
145
146          --  We now know that the computed value of Last is within the base
147          --  range of the type, so it is safe to compute its value:
148
149          Last := No_Index + Index_Type'Base (N);
150
151          --  Finally we test whether the value is within the range of the
152          --  generic actual index subtype:
153
154          if Last > Index_Type'Last then
155             raise Constraint_Error with "new length is out of range";
156          end if;
157
158       elsif Index_Type'First <= 0 then
159
160          --  Here we can compute Last directly, in the normal way. We know that
161          --  No_Index is less than 0, so there is no danger of overflow when
162          --  adding the (positive) value of length.
163
164          J := Count_Type'Base (No_Index) + N;  -- Last
165
166          if J > Count_Type'Base (Index_Type'Last) then
167             raise Constraint_Error with "new length is out of range";
168          end if;
169
170          --  We know that the computed value (having type Count_Type) of Last
171          --  is within the range of the generic actual index subtype, so it is
172          --  safe to convert to Index_Type:
173
174          Last := Index_Type'Base (J);
175
176       else
177          --  Here Index_Type'First (and Index_Type'Last) is positive, so we
178          --  must test the length indirectly (by working backwards from the
179          --  largest possible value of Last), in order to prevent overflow.
180
181          J := Count_Type'Base (Index_Type'Last) - N;  -- No_Index
182
183          if J < Count_Type'Base (No_Index) then
184             raise Constraint_Error with "new length is out of range";
185          end if;
186
187          --  We have determined that the result length would not create a Last
188          --  index value outside of the range of Index_Type, so we can now
189          --  safely compute its value.
190
191          Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
192       end if;
193
194       declare
195          LE : Elements_Array renames
196                 Left.Elements.EA (Index_Type'First .. Left.Last);
197
198          RE : Elements_Array renames
199                 Right.Elements.EA (Index_Type'First .. Right.Last);
200
201          Elements : constant Elements_Access :=
202                       new Elements_Type'(Last, LE & RE);
203
204       begin
205          return (Controlled with Elements, Last, 0, 0);
206       end;
207    end "&";
208
209    function "&" (Left  : Vector; Right : Element_Type) return Vector is
210    begin
211       --  We decide that the capacity of the result is the sum of the lengths
212       --  of the parameters. We could decide to make it larger, but we have no
213       --  basis for knowing how much larger, so we just allocate the minimum
214       --  amount of storage.
215
216       --  Handle easy case first, when the vector parameter (Left) is empty
217
218       if Left.Is_Empty then
219          declare
220             Elements : constant Elements_Access :=
221                          new Elements_Type'
222                                (Last => Index_Type'First,
223                                 EA   => (others => Right));
224
225          begin
226             return (Controlled with Elements, Index_Type'First, 0, 0);
227          end;
228       end if;
229
230       --  The vector parameter is not empty, so we must compute the length of
231       --  the result vector and its last index, but in such a way that overflow
232       --  is avoided. We must satisfy two constraints: the new length cannot
233       --  exceed Count_Type'Last, and the new Last index cannot exceed
234       --  Index_Type'Last.
235
236       if Left.Length = Count_Type'Last then
237          raise Constraint_Error with "new length is out of range";
238       end if;
239
240       if Left.Last >= Index_Type'Last then
241          raise Constraint_Error with "new length is out of range";
242       end if;
243
244       declare
245          Last : constant Index_Type := Left.Last + 1;
246
247          LE : Elements_Array renames
248            Left.Elements.EA (Index_Type'First .. Left.Last);
249
250          Elements : constant Elements_Access :=
251                       new Elements_Type'(Last => Last, EA => LE & Right);
252
253       begin
254          return (Controlled with Elements, Last, 0, 0);
255       end;
256    end "&";
257
258    function "&" (Left  : Element_Type; Right : Vector) return Vector is
259    begin
260       --  We decide that the capacity of the result is the sum of the lengths
261       --  of the parameters. We could decide to make it larger, but we have no
262       --  basis for knowing how much larger, so we just allocate the minimum
263       --  amount of storage.
264
265       --  Handle easy case first, when the vector parameter (Right) is empty
266
267       if Right.Is_Empty then
268          declare
269             Elements : constant Elements_Access :=
270                          new Elements_Type'
271                                (Last => Index_Type'First,
272                                 EA   => (others => Left));
273
274          begin
275             return (Controlled with Elements, Index_Type'First, 0, 0);
276          end;
277       end if;
278
279       --  The vector parameter is not empty, so we must compute the length of
280       --  the result vector and its last index, but in such a way that overflow
281       --  is avoided. We must satisfy two constraints: the new length cannot
282       --  exceed Count_Type'Last, and the new Last index cannot exceed
283       --  Index_Type'Last.
284
285       if Right.Length = Count_Type'Last then
286          raise Constraint_Error with "new length is out of range";
287       end if;
288
289       if Right.Last >= Index_Type'Last then
290          raise Constraint_Error with "new length is out of range";
291       end if;
292
293       declare
294          Last : constant Index_Type := Right.Last + 1;
295
296          RE : Elements_Array renames
297                 Right.Elements.EA (Index_Type'First .. Right.Last);
298
299          Elements : constant Elements_Access :=
300                       new Elements_Type'
301                         (Last => Last,
302                          EA   => Left & RE);
303
304       begin
305          return (Controlled with Elements, Last, 0, 0);
306       end;
307    end "&";
308
309    function "&" (Left, Right : Element_Type) return Vector is
310    begin
311       --  We decide that the capacity of the result is the sum of the lengths
312       --  of the parameters. We could decide to make it larger, but we have no
313       --  basis for knowing how much larger, so we just allocate the minimum
314       --  amount of storage.
315
316       --  We must compute the length of the result vector and its last index,
317       --  but in such a way that overflow is avoided. We must satisfy two
318       --  constraints: the new length cannot exceed Count_Type'Last (here, we
319       --  know that that condition is satisfied), and the new Last index cannot
320       --  exceed Index_Type'Last.
321
322       if Index_Type'First >= Index_Type'Last then
323          raise Constraint_Error with "new length is out of range";
324       end if;
325
326       declare
327          Last : constant Index_Type := Index_Type'First + 1;
328
329          Elements : constant Elements_Access :=
330                       new Elements_Type'
331                             (Last => Last,
332                              EA   => (Left, Right));
333
334       begin
335          return (Controlled with Elements, Last, 0, 0);
336       end;
337    end "&";
338
339    ---------
340    -- "=" --
341    ---------
342
343    overriding function "=" (Left, Right : Vector) return Boolean is
344    begin
345       if Left'Address = Right'Address then
346          return True;
347       end if;
348
349       if Left.Last /= Right.Last then
350          return False;
351       end if;
352
353       for J in Index_Type range Index_Type'First .. Left.Last loop
354          if Left.Elements.EA (J) /= Right.Elements.EA (J) then
355             return False;
356          end if;
357       end loop;
358
359       return True;
360    end "=";
361
362    ------------
363    -- Adjust --
364    ------------
365
366    procedure Adjust (Container : in out Vector) is
367    begin
368       if Container.Last = No_Index then
369          Container.Elements := null;
370          return;
371       end if;
372
373       declare
374          L  : constant Index_Type := Container.Last;
375          EA : Elements_Array renames
376                 Container.Elements.EA (Index_Type'First .. L);
377
378       begin
379          Container.Elements := null;
380          Container.Busy := 0;
381          Container.Lock := 0;
382
383          --  Note: it may seem that the following assignment to Container.Last
384          --  is useless, since we assign it to L below. However this code is
385          --  used in case 'new Elements_Type' below raises an exception, to
386          --  keep Container in a consistent state.
387
388          Container.Last := No_Index;
389          Container.Elements := new Elements_Type'(L, EA);
390          Container.Last := L;
391       end;
392    end Adjust;
393
394    ------------
395    -- Append --
396    ------------
397
398    procedure Append (Container : in out Vector; New_Item : Vector) is
399    begin
400       if Is_Empty (New_Item) then
401          return;
402       end if;
403
404       if Container.Last = Index_Type'Last then
405          raise Constraint_Error with "vector is already at its maximum length";
406       end if;
407
408       Insert
409         (Container,
410          Container.Last + 1,
411          New_Item);
412    end Append;
413
414    procedure Append
415      (Container : in out Vector;
416       New_Item  : Element_Type;
417       Count     : Count_Type := 1)
418    is
419    begin
420       if Count = 0 then
421          return;
422       end if;
423
424       if Container.Last = Index_Type'Last then
425          raise Constraint_Error with "vector is already at its maximum length";
426       end if;
427
428       Insert
429         (Container,
430          Container.Last + 1,
431          New_Item,
432          Count);
433    end Append;
434
435    --------------
436    -- Capacity --
437    --------------
438
439    function Capacity (Container : Vector) return Count_Type is
440    begin
441       if Container.Elements = null then
442          return 0;
443       else
444          return Container.Elements.EA'Length;
445       end if;
446    end Capacity;
447
448    -----------
449    -- Clear --
450    -----------
451
452    procedure Clear (Container : in out Vector) is
453    begin
454       if Container.Busy > 0 then
455          raise Program_Error with
456            "attempt to tamper with cursors (vector is busy)";
457       else
458          Container.Last := No_Index;
459       end if;
460    end Clear;
461
462    --------------
463    -- Contains --
464    --------------
465
466    function Contains
467      (Container : Vector;
468       Item      : Element_Type) return Boolean
469    is
470    begin
471       return Find_Index (Container, Item) /= No_Index;
472    end Contains;
473
474    ------------
475    -- Delete --
476    ------------
477
478    procedure Delete
479      (Container : in out Vector;
480       Index     : Extended_Index;
481       Count     : Count_Type := 1)
482    is
483       Old_Last : constant Index_Type'Base := Container.Last;
484       New_Last : Index_Type'Base;
485       Count2   : Count_Type'Base;  -- count of items from Index to Old_Last
486       J        : Index_Type'Base;  -- first index of items that slide down
487
488    begin
489       --  Delete removes items from the vector, the number of which is the
490       --  minimum of the specified Count and the items (if any) that exist from
491       --  Index to Container.Last. There are no constraints on the specified
492       --  value of Count (it can be larger than what's available at this
493       --  position in the vector, for example), but there are constraints on
494       --  the allowed values of the Index.
495
496       --  As a precondition on the generic actual Index_Type, the base type
497       --  must include Index_Type'Pred (Index_Type'First); this is the value
498       --  that Container.Last assumes when the vector is empty. However, we do
499       --  not allow that as the value for Index when specifying which items
500       --  should be deleted, so we must manually check. (That the user is
501       --  allowed to specify the value at all here is a consequence of the
502       --  declaration of the Extended_Index subtype, which includes the values
503       --  in the base range that immediately precede and immediately follow the
504       --  values in the Index_Type.)
505
506       if Index < Index_Type'First then
507          raise Constraint_Error with "Index is out of range (too small)";
508       end if;
509
510       --  We do allow a value greater than Container.Last to be specified as
511       --  the Index, but only if it's immediately greater. This allows the
512       --  corner case of deleting no items from the back end of the vector to
513       --  be treated as a no-op. (It is assumed that specifying an index value
514       --  greater than Last + 1 indicates some deeper flaw in the caller's
515       --  algorithm, so that case is treated as a proper error.)
516
517       if Index > Old_Last then
518          if Index > Old_Last + 1 then
519             raise Constraint_Error with "Index is out of range (too large)";
520          end if;
521
522          return;
523       end if;
524
525       --  Here and elsewhere we treat deleting 0 items from the container as a
526       --  no-op, even when the container is busy, so we simply return.
527
528       if Count = 0 then
529          return;
530       end if;
531
532       --  The tampering bits exist to prevent an item from being deleted (or
533       --  otherwise harmfully manipulated) while it is being visited. Query,
534       --  Update, and Iterate increment the busy count on entry, and decrement
535       --  the count on exit. Delete checks the count to determine whether it is
536       --  being called while the associated callback procedure is executing.
537
538       if Container.Busy > 0 then
539          raise Program_Error with
540            "attempt to tamper with cursors (vector is busy)";
541       end if;
542
543       --  We first calculate what's available for deletion starting at
544       --  Index. Here and elsewhere we use the wider of Index_Type'Base and
545       --  Count_Type'Base as the type for intermediate values. (See function
546       --  Length for more information.)
547
548       if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
549          Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
550
551       else
552          Count2 := Count_Type'Base (Old_Last - Index + 1);
553       end if;
554
555       --  If more elements are requested (Count) for deletion than are
556       --  available (Count2) for deletion beginning at Index, then everything
557       --  from Index is deleted. There are no elements to slide down, and so
558       --  all we need to do is set the value of Container.Last.
559
560       if Count >= Count2 then
561          Container.Last := Index - 1;
562          return;
563       end if;
564
565       --  There are some elements aren't being deleted (the requested count was
566       --  less than the available count), so we must slide them down to
567       --  Index. We first calculate the index values of the respective array
568       --  slices, using the wider of Index_Type'Base and Count_Type'Base as the
569       --  type for intermediate calculations. For the elements that slide down,
570       --  index value New_Last is the last index value of their new home, and
571       --  index value J is the first index of their old home.
572
573       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
574          New_Last := Old_Last - Index_Type'Base (Count);
575          J := Index + Index_Type'Base (Count);
576
577       else
578          New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
579          J := Index_Type'Base (Count_Type'Base (Index) + Count);
580       end if;
581
582       --  The internal elements array isn't guaranteed to exist unless we have
583       --  elements, but we have that guarantee here because we know we have
584       --  elements to slide.  The array index values for each slice have
585       --  already been determined, so we just slide down to Index the elements
586       --  that weren't deleted.
587
588       declare
589          EA : Elements_Array renames Container.Elements.EA;
590
591       begin
592          EA (Index .. New_Last) := EA (J .. Old_Last);
593          Container.Last := New_Last;
594       end;
595    end Delete;
596
597    procedure Delete
598      (Container : in out Vector;
599       Position  : in out Cursor;
600       Count     : Count_Type := 1)
601    is
602       pragma Warnings (Off, Position);
603
604    begin
605       if Position.Container = null then
606          raise Constraint_Error with "Position cursor has no element";
607       end if;
608
609       if Position.Container /= Container'Unrestricted_Access then
610          raise Program_Error with "Position cursor denotes wrong container";
611       end if;
612
613       if Position.Index > Container.Last then
614          raise Program_Error with "Position index is out of range";
615       end if;
616
617       Delete (Container, Position.Index, Count);
618       Position := No_Element;
619    end Delete;
620
621    ------------------
622    -- Delete_First --
623    ------------------
624
625    procedure Delete_First
626      (Container : in out Vector;
627       Count     : Count_Type := 1)
628    is
629    begin
630       if Count = 0 then
631          return;
632       end if;
633
634       if Count >= Length (Container) then
635          Clear (Container);
636          return;
637       end if;
638
639       Delete (Container, Index_Type'First, Count);
640    end Delete_First;
641
642    -----------------
643    -- Delete_Last --
644    -----------------
645
646    procedure Delete_Last
647      (Container : in out Vector;
648       Count     : Count_Type := 1)
649    is
650    begin
651       --  It is not permitted to delete items while the container is busy (for
652       --  example, we're in the middle of a passive iteration). However, we
653       --  always treat deleting 0 items as a no-op, even when we're busy, so we
654       --  simply return without checking.
655
656       if Count = 0 then
657          return;
658       end if;
659
660       --  The tampering bits exist to prevent an item from being deleted (or
661       --  otherwise harmfully manipulated) while it is being visited. Query,
662       --  Update, and Iterate increment the busy count on entry, and decrement
663       --  the count on exit. Delete_Last checks the count to determine whether
664       --  it is being called while the associated callback procedure is
665       --  executing.
666
667       if Container.Busy > 0 then
668          raise Program_Error with
669            "attempt to tamper with cursors (vector is busy)";
670       end if;
671
672       --  There is no restriction on how large Count can be when deleting
673       --  items. If it is equal or greater than the current length, then this
674       --  is equivalent to clearing the vector. (In particular, there's no need
675       --  for us to actually calculate the new value for Last.)
676
677       --  If the requested count is less than the current length, then we must
678       --  calculate the new value for Last. For the type we use the widest of
679       --  Index_Type'Base and Count_Type'Base for the intermediate values of
680       --  our calculation.  (See the comments in Length for more information.)
681
682       if Count >= Container.Length then
683          Container.Last := No_Index;
684
685       elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
686          Container.Last := Container.Last - Index_Type'Base (Count);
687
688       else
689          Container.Last :=
690            Index_Type'Base (Count_Type'Base (Container.Last) - Count);
691       end if;
692    end Delete_Last;
693
694    -------------
695    -- Element --
696    -------------
697
698    function Element
699      (Container : Vector;
700       Index     : Index_Type) return Element_Type
701    is
702    begin
703       if Index > Container.Last then
704          raise Constraint_Error with "Index is out of range";
705       end if;
706
707       return Container.Elements.EA (Index);
708    end Element;
709
710    function Element (Position : Cursor) return Element_Type is
711    begin
712       if Position.Container = null then
713          raise Constraint_Error with "Position cursor has no element";
714       elsif Position.Index > Position.Container.Last then
715          raise Constraint_Error with "Position cursor is out of range";
716       else
717          return Position.Container.Elements.EA (Position.Index);
718       end if;
719    end Element;
720
721    --------------
722    -- Finalize --
723    --------------
724
725    procedure Finalize (Container : in out Vector) is
726       X : Elements_Access := Container.Elements;
727
728    begin
729       if Container.Busy > 0 then
730          raise Program_Error with
731            "attempt to tamper with cursors (vector is busy)";
732       end if;
733
734       Container.Elements := null;
735       Container.Last := No_Index;
736       Free (X);
737    end Finalize;
738
739    ----------
740    -- Find --
741    ----------
742
743    function Find
744      (Container : Vector;
745       Item      : Element_Type;
746       Position  : Cursor := No_Element) return Cursor
747    is
748    begin
749       if Position.Container /= null then
750          if Position.Container /= Container'Unrestricted_Access then
751             raise Program_Error with "Position cursor denotes wrong container";
752          end if;
753
754          if Position.Index > Container.Last then
755             raise Program_Error with "Position index is out of range";
756          end if;
757       end if;
758
759       for J in Position.Index .. Container.Last loop
760          if Container.Elements.EA (J) = Item then
761             return (Container'Unchecked_Access, J);
762          end if;
763       end loop;
764
765       return No_Element;
766    end Find;
767
768    ----------------
769    -- Find_Index --
770    ----------------
771
772    function Find_Index
773      (Container : Vector;
774       Item      : Element_Type;
775       Index     : Index_Type := Index_Type'First) return Extended_Index
776    is
777    begin
778       for Indx in Index .. Container.Last loop
779          if Container.Elements.EA (Indx) = Item then
780             return Indx;
781          end if;
782       end loop;
783
784       return No_Index;
785    end Find_Index;
786
787    -----------
788    -- First --
789    -----------
790
791    function First (Container : Vector) return Cursor is
792    begin
793       if Is_Empty (Container) then
794          return No_Element;
795       else
796          return (Container'Unchecked_Access, Index_Type'First);
797       end if;
798    end First;
799
800    function First (Object : Iterator) return Cursor is
801    begin
802       if Is_Empty (Object.Container.all) then
803          return No_Element;
804       else
805          return Cursor'(Object.Container, Index_Type'First);
806       end if;
807    end First;
808
809    -------------------
810    -- First_Element --
811    -------------------
812
813    function First_Element (Container : Vector) return Element_Type is
814    begin
815       if Container.Last = No_Index then
816          raise Constraint_Error with "Container is empty";
817       else
818          return Container.Elements.EA (Index_Type'First);
819       end if;
820    end First_Element;
821
822    -----------------
823    -- First_Index --
824    -----------------
825
826    function First_Index (Container : Vector) return Index_Type is
827       pragma Unreferenced (Container);
828    begin
829       return Index_Type'First;
830    end First_Index;
831
832    ---------------------
833    -- Generic_Sorting --
834    ---------------------
835
836    package body Generic_Sorting is
837
838       ---------------
839       -- Is_Sorted --
840       ---------------
841
842       function Is_Sorted (Container : Vector) return Boolean is
843       begin
844          if Container.Last <= Index_Type'First then
845             return True;
846          end if;
847
848          declare
849             EA : Elements_Array renames Container.Elements.EA;
850          begin
851             for J in Index_Type'First .. Container.Last - 1 loop
852                if EA (J + 1) < EA (J) then
853                   return False;
854                end if;
855             end loop;
856          end;
857
858          return True;
859       end Is_Sorted;
860
861       -----------
862       -- Merge --
863       -----------
864
865       procedure Merge (Target, Source : in out Vector) is
866          I : Index_Type'Base := Target.Last;
867          J : Index_Type'Base;
868
869       begin
870          if Target.Last < Index_Type'First then
871             Move (Target => Target, Source => Source);
872             return;
873          end if;
874
875          if Target'Address = Source'Address then
876             return;
877          end if;
878
879          if Source.Last < Index_Type'First then
880             return;
881          end if;
882
883          if Source.Busy > 0 then
884             raise Program_Error with
885               "attempt to tamper with cursors (vector is busy)";
886          end if;
887
888          Target.Set_Length (Length (Target) + Length (Source));
889
890          declare
891             TA : Elements_Array renames Target.Elements.EA;
892             SA : Elements_Array renames Source.Elements.EA;
893
894          begin
895             J := Target.Last;
896             while Source.Last >= Index_Type'First loop
897                pragma Assert (Source.Last <= Index_Type'First
898                                 or else not (SA (Source.Last) <
899                                              SA (Source.Last - 1)));
900
901                if I < Index_Type'First then
902                   TA (Index_Type'First .. J) :=
903                     SA (Index_Type'First .. Source.Last);
904
905                   Source.Last := No_Index;
906                   return;
907                end if;
908
909                pragma Assert (I <= Index_Type'First
910                                 or else not (TA (I) < TA (I - 1)));
911
912                if SA (Source.Last) < TA (I) then
913                   TA (J) := TA (I);
914                   I := I - 1;
915
916                else
917                   TA (J) := SA (Source.Last);
918                   Source.Last := Source.Last - 1;
919                end if;
920
921                J := J - 1;
922             end loop;
923          end;
924       end Merge;
925
926       ----------
927       -- Sort --
928       ----------
929
930       procedure Sort (Container : in out Vector)
931       is
932          procedure Sort is
933             new Generic_Array_Sort
934              (Index_Type   => Index_Type,
935               Element_Type => Element_Type,
936               Array_Type   => Elements_Array,
937               "<"          => "<");
938
939       begin
940          if Container.Last <= Index_Type'First then
941             return;
942          end if;
943
944          if Container.Lock > 0 then
945             raise Program_Error with
946               "attempt to tamper with elements (vector is locked)";
947          end if;
948
949          Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
950       end Sort;
951
952    end Generic_Sorting;
953
954    -----------------
955    -- Has_Element --
956    -----------------
957
958    function Has_Element (Position : Cursor) return Boolean is
959    begin
960       return Position /= No_Element;
961    end Has_Element;
962
963    ------------
964    -- Insert --
965    ------------
966
967    procedure Insert
968      (Container : in out Vector;
969       Before    : Extended_Index;
970       New_Item  : Element_Type;
971       Count     : Count_Type := 1)
972    is
973       Old_Length : constant Count_Type := Container.Length;
974
975       Max_Length : Count_Type'Base;  -- determined from range of Index_Type
976       New_Length : Count_Type'Base;  -- sum of current length and Count
977       New_Last   : Index_Type'Base;  -- last index of vector after insertion
978
979       Index : Index_Type'Base;  -- scratch for intermediate values
980       J     : Count_Type'Base;  -- scratch
981
982       New_Capacity : Count_Type'Base;  -- length of new, expanded array
983       Dst_Last     : Index_Type'Base;  -- last index of new, expanded array
984       Dst          : Elements_Access;  -- new, expanded internal array
985
986    begin
987       --  As a precondition on the generic actual Index_Type, the base type
988       --  must include Index_Type'Pred (Index_Type'First); this is the value
989       --  that Container.Last assumes when the vector is empty. However, we do
990       --  not allow that as the value for Index when specifying where the new
991       --  items should be inserted, so we must manually check. (That the user
992       --  is allowed to specify the value at all here is a consequence of the
993       --  declaration of the Extended_Index subtype, which includes the values
994       --  in the base range that immediately precede and immediately follow the
995       --  values in the Index_Type.)
996
997       if Before < Index_Type'First then
998          raise Constraint_Error with
999            "Before index is out of range (too small)";
1000       end if;
1001
1002       --  We do allow a value greater than Container.Last to be specified as
1003       --  the Index, but only if it's immediately greater. This allows for the
1004       --  case of appending items to the back end of the vector. (It is assumed
1005       --  that specifying an index value greater than Last + 1 indicates some
1006       --  deeper flaw in the caller's algorithm, so that case is treated as a
1007       --  proper error.)
1008
1009       if Before > Container.Last
1010         and then Before > Container.Last + 1
1011       then
1012          raise Constraint_Error with
1013            "Before index is out of range (too large)";
1014       end if;
1015
1016       --  We treat inserting 0 items into the container as a no-op, even when
1017       --  the container is busy, so we simply return.
1018
1019       if Count = 0 then
1020          return;
1021       end if;
1022
1023       --  There are two constraints we need to satisfy. The first constraint is
1024       --  that a container cannot have more than Count_Type'Last elements, so
1025       --  we must check the sum of the current length and the insertion
1026       --  count. Note that we cannot simply add these values, because of the
1027       --  possibility of overflow.
1028
1029       if Old_Length > Count_Type'Last - Count then
1030          raise Constraint_Error with "Count is out of range";
1031       end if;
1032
1033       --  It is now safe compute the length of the new vector, without fear of
1034       --  overflow.
1035
1036       New_Length := Old_Length + Count;
1037
1038       --  The second constraint is that the new Last index value cannot exceed
1039       --  Index_Type'Last. In each branch below, we calculate the maximum
1040       --  length (computed from the range of values in Index_Type), and then
1041       --  compare the new length to the maximum length. If the new length is
1042       --  acceptable, then we compute the new last index from that.
1043
1044       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1045
1046          --  We have to handle the case when there might be more values in the
1047          --  range of Index_Type than in the range of Count_Type.
1048
1049          if Index_Type'First <= 0 then
1050
1051             --  We know that No_Index (the same as Index_Type'First - 1) is
1052             --  less than 0, so it is safe to compute the following sum without
1053             --  fear of overflow.
1054
1055             Index := No_Index + Index_Type'Base (Count_Type'Last);
1056
1057             if Index <= Index_Type'Last then
1058
1059                --  We have determined that range of Index_Type has at least as
1060                --  many values as in Count_Type, so Count_Type'Last is the
1061                --  maximum number of items that are allowed.
1062
1063                Max_Length := Count_Type'Last;
1064
1065             else
1066                --  The range of Index_Type has fewer values than in Count_Type,
1067                --  so the maximum number of items is computed from the range of
1068                --  the Index_Type.
1069
1070                Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1071             end if;
1072
1073          else
1074             --  No_Index is equal or greater than 0, so we can safely compute
1075             --  the difference without fear of overflow (which we would have to
1076             --  worry about if No_Index were less than 0, but that case is
1077             --  handled above).
1078
1079             Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1080          end if;
1081
1082       elsif Index_Type'First <= 0 then
1083
1084          --  We know that No_Index (the same as Index_Type'First - 1) is less
1085          --  than 0, so it is safe to compute the following sum without fear of
1086          --  overflow.
1087
1088          J := Count_Type'Base (No_Index) + Count_Type'Last;
1089
1090          if J <= Count_Type'Base (Index_Type'Last) then
1091
1092             --  We have determined that range of Index_Type has at least as
1093             --  many values as in Count_Type, so Count_Type'Last is the maximum
1094             --  number of items that are allowed.
1095
1096             Max_Length := Count_Type'Last;
1097
1098          else
1099             --  The range of Index_Type has fewer values than Count_Type does,
1100             --  so the maximum number of items is computed from the range of
1101             --  the Index_Type.
1102
1103             Max_Length :=
1104               Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1105          end if;
1106
1107       else
1108          --  No_Index is equal or greater than 0, so we can safely compute the
1109          --  difference without fear of overflow (which we would have to worry
1110          --  about if No_Index were less than 0, but that case is handled
1111          --  above).
1112
1113          Max_Length :=
1114            Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1115       end if;
1116
1117       --  We have just computed the maximum length (number of items). We must
1118       --  now compare the requested length to the maximum length, as we do not
1119       --  allow a vector expand beyond the maximum (because that would create
1120       --  an internal array with a last index value greater than
1121       --  Index_Type'Last, with no way to index those elements).
1122
1123       if New_Length > Max_Length then
1124          raise Constraint_Error with "Count is out of range";
1125       end if;
1126
1127       --  New_Last is the last index value of the items in the container after
1128       --  insertion.  Use the wider of Index_Type'Base and Count_Type'Base to
1129       --  compute its value from the New_Length.
1130
1131       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1132          New_Last := No_Index + Index_Type'Base (New_Length);
1133
1134       else
1135          New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1136       end if;
1137
1138       if Container.Elements = null then
1139          pragma Assert (Container.Last = No_Index);
1140
1141          --  This is the simplest case, with which we must always begin: we're
1142          --  inserting items into an empty vector that hasn't allocated an
1143          --  internal array yet. Note that we don't need to check the busy bit
1144          --  here, because an empty container cannot be busy.
1145
1146          --  In order to preserve container invariants, we allocate the new
1147          --  internal array first, before setting the Last index value, in case
1148          --  the allocation fails (which can happen either because there is no
1149          --  storage available, or because element initialization fails).
1150
1151          Container.Elements := new Elements_Type'
1152                                      (Last => New_Last,
1153                                       EA   => (others => New_Item));
1154
1155          --  The allocation of the new, internal array succeeded, so it is now
1156          --  safe to update the Last index, restoring container invariants.
1157
1158          Container.Last := New_Last;
1159
1160          return;
1161       end if;
1162
1163       --  The tampering bits exist to prevent an item from being harmfully
1164       --  manipulated while it is being visited. Query, Update, and Iterate
1165       --  increment the busy count on entry, and decrement the count on
1166       --  exit. Insert checks the count to determine whether it is being called
1167       --  while the associated callback procedure is executing.
1168
1169       if Container.Busy > 0 then
1170          raise Program_Error with
1171            "attempt to tamper with cursors (vector is busy)";
1172       end if;
1173
1174       --  An internal array has already been allocated, so we must determine
1175       --  whether there is enough unused storage for the new items.
1176
1177       if New_Length <= Container.Elements.EA'Length then
1178
1179          --  In this case, we're inserting elements into a vector that has
1180          --  already allocated an internal array, and the existing array has
1181          --  enough unused storage for the new items.
1182
1183          declare
1184             EA : Elements_Array renames Container.Elements.EA;
1185
1186          begin
1187             if Before > Container.Last then
1188
1189                --  The new items are being appended to the vector, so no
1190                --  sliding of existing elements is required.
1191
1192                EA (Before .. New_Last) := (others => New_Item);
1193
1194             else
1195                --  The new items are being inserted before some existing
1196                --  elements, so we must slide the existing elements up to their
1197                --  new home. We use the wider of Index_Type'Base and
1198                --  Count_Type'Base as the type for intermediate index values.
1199
1200                if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1201                   Index := Before + Index_Type'Base (Count);
1202
1203                else
1204                   Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1205                end if;
1206
1207                EA (Index .. New_Last) := EA (Before .. Container.Last);
1208                EA (Before .. Index - 1) := (others => New_Item);
1209             end if;
1210          end;
1211
1212          Container.Last := New_Last;
1213          return;
1214       end if;
1215
1216       --  In this case, we're inserting elements into a vector that has already
1217       --  allocated an internal array, but the existing array does not have
1218       --  enough storage, so we must allocate a new, longer array. In order to
1219       --  guarantee that the amortized insertion cost is O(1), we always
1220       --  allocate an array whose length is some power-of-two factor of the
1221       --  current array length. (The new array cannot have a length less than
1222       --  the New_Length of the container, but its last index value cannot be
1223       --  greater than Index_Type'Last.)
1224
1225       New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1226       while New_Capacity < New_Length loop
1227          if New_Capacity > Count_Type'Last / 2 then
1228             New_Capacity := Count_Type'Last;
1229             exit;
1230          end if;
1231
1232          New_Capacity := 2 * New_Capacity;
1233       end loop;
1234
1235       if New_Capacity > Max_Length then
1236
1237          --  We have reached the limit of capacity, so no further expansion
1238          --  will occur. (This is not a problem, as there is never a need to
1239          --  have more capacity than the maximum container length.)
1240
1241          New_Capacity := Max_Length;
1242       end if;
1243
1244       --  We have computed the length of the new internal array (and this is
1245       --  what "vector capacity" means), so use that to compute its last index.
1246
1247       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1248          Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1249
1250       else
1251          Dst_Last :=
1252            Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1253       end if;
1254
1255       --  Now we allocate the new, longer internal array. If the allocation
1256       --  fails, we have not changed any container state, so no side-effect
1257       --  will occur as a result of propagating the exception.
1258
1259       Dst := new Elements_Type (Dst_Last);
1260
1261       --  We have our new internal array. All that needs to be done now is to
1262       --  copy the existing items (if any) from the old array (the "source"
1263       --  array, object SA below) to the new array (the "destination" array,
1264       --  object DA below), and then deallocate the old array.
1265
1266       declare
1267          SA : Elements_Array renames Container.Elements.EA; -- source
1268          DA : Elements_Array renames Dst.EA;                -- destination
1269
1270       begin
1271          DA (Index_Type'First .. Before - 1) :=
1272            SA (Index_Type'First .. Before - 1);
1273
1274          if Before > Container.Last then
1275             DA (Before .. New_Last) := (others => New_Item);
1276
1277          else
1278             --  The new items are being inserted before some existing elements,
1279             --  so we must slide the existing elements up to their new home.
1280
1281             if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1282                Index := Before + Index_Type'Base (Count);
1283
1284             else
1285                Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1286             end if;
1287
1288             DA (Before .. Index - 1) := (others => New_Item);
1289             DA (Index .. New_Last) := SA (Before .. Container.Last);
1290          end if;
1291
1292       exception
1293          when others =>
1294             Free (Dst);
1295             raise;
1296       end;
1297
1298       --  We have successfully copied the items onto the new array, so the
1299       --  final thing to do is deallocate the old array.
1300
1301       declare
1302          X : Elements_Access := Container.Elements;
1303       begin
1304          --  We first isolate the old internal array, removing it from the
1305          --  container and replacing it with the new internal array, before we
1306          --  deallocate the old array (which can fail if finalization of
1307          --  elements propagates an exception).
1308
1309          Container.Elements := Dst;
1310          Container.Last := New_Last;
1311
1312          --  The container invariants have been restored, so it is now safe to
1313          --  attempt to deallocate the old array.
1314
1315          Free (X);
1316       end;
1317    end Insert;
1318
1319    procedure Insert
1320      (Container : in out Vector;
1321       Before    : Extended_Index;
1322       New_Item  : Vector)
1323    is
1324       N : constant Count_Type := Length (New_Item);
1325       J : Index_Type'Base;
1326
1327    begin
1328       --  Use Insert_Space to create the "hole" (the destination slice) into
1329       --  which we copy the source items.
1330
1331       Insert_Space (Container, Before, Count => N);
1332
1333       if N = 0 then
1334
1335          --  There's nothing else to do here (vetting of parameters was
1336          --  performed already in Insert_Space), so we simply return.
1337
1338          return;
1339       end if;
1340
1341       --  We calculate the last index value of the destination slice using the
1342       --  wider of Index_Type'Base and count_Type'Base.
1343
1344       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1345          J := (Before - 1) + Index_Type'Base (N);
1346
1347       else
1348          J := Index_Type'Base (Count_Type'Base (Before - 1) + N);
1349       end if;
1350
1351       if Container'Address /= New_Item'Address then
1352
1353          --  This is the simple case.  New_Item denotes an object different
1354          --  from Container, so there's nothing special we need to do to copy
1355          --  the source items to their destination, because all of the source
1356          --  items are contiguous.
1357
1358          Container.Elements.EA (Before .. J) :=
1359            New_Item.Elements.EA (Index_Type'First .. New_Item.Last);
1360
1361          return;
1362       end if;
1363
1364       --  New_Item denotes the same object as Container, so an insertion has
1365       --  potentially split the source items. The destination is always the
1366       --  range [Before, J], but the source is [Index_Type'First, Before) and
1367       --  (J, Container.Last]. We perform the copy in two steps, using each of
1368       --  the two slices of the source items.
1369
1370       declare
1371          L : constant Index_Type'Base := Before - 1;
1372
1373          subtype Src_Index_Subtype is Index_Type'Base range
1374            Index_Type'First .. L;
1375
1376          Src : Elements_Array renames
1377            Container.Elements.EA (Src_Index_Subtype);
1378
1379          K : Index_Type'Base;
1380
1381       begin
1382          --  We first copy the source items that precede the space we
1383          --  inserted. Index value K is the last index of that portion
1384          --  destination that receives this slice of the source. (If Before
1385          --  equals Index_Type'First, then this first source slice will be
1386          --  empty, which is harmless.)
1387
1388          if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1389             K := L + Index_Type'Base (Src'Length);
1390
1391          else
1392             K := Index_Type'Base (Count_Type'Base (L) + Src'Length);
1393          end if;
1394
1395          Container.Elements.EA (Before .. K) := Src;
1396
1397          if Src'Length = N then
1398
1399             --  The new items were effectively appended to the container, so we
1400             --  have already copied all of the items that need to be copied.
1401             --  We return early here, even though the source slice below is
1402             --  empty (so the assignment would be harmless), because we want to
1403             --  avoid computing J + 1, which will overflow if J equals
1404             --  Index_Type'Base'Last.
1405
1406             return;
1407          end if;
1408       end;
1409
1410       declare
1411          --  Note that we want to avoid computing J + 1 here, in case J equals
1412          --  Index_Type'Base'Last. We prevent that by returning early above,
1413          --  immediately after copying the first slice of the source, and
1414          --  determining that this second slice of the source is empty.
1415
1416          F : constant Index_Type'Base := J + 1;
1417
1418          subtype Src_Index_Subtype is Index_Type'Base range
1419            F .. Container.Last;
1420
1421          Src : Elements_Array renames
1422            Container.Elements.EA (Src_Index_Subtype);
1423
1424          K : Index_Type'Base;
1425
1426       begin
1427          --  We next copy the source items that follow the space we
1428          --  inserted. Index value K is the first index of that portion of the
1429          --  destination that receives this slice of the source. (For the
1430          --  reasons given above, this slice is guaranteed to be non-empty.)
1431
1432          if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1433             K := F - Index_Type'Base (Src'Length);
1434
1435          else
1436             K := Index_Type'Base (Count_Type'Base (F) - Src'Length);
1437          end if;
1438
1439          Container.Elements.EA (K .. J) := Src;
1440       end;
1441    end Insert;
1442
1443    procedure Insert
1444      (Container : in out Vector;
1445       Before    : Cursor;
1446       New_Item  : Vector)
1447    is
1448       Index : Index_Type'Base;
1449
1450    begin
1451       if Before.Container /= null
1452         and then Before.Container /= Container'Unchecked_Access
1453       then
1454          raise Program_Error with "Before cursor denotes wrong container";
1455       end if;
1456
1457       if Is_Empty (New_Item) then
1458          return;
1459       end if;
1460
1461       if Before.Container = null
1462         or else Before.Index > Container.Last
1463       then
1464          if Container.Last = Index_Type'Last then
1465             raise Constraint_Error with
1466               "vector is already at its maximum length";
1467          end if;
1468
1469          Index := Container.Last + 1;
1470
1471       else
1472          Index := Before.Index;
1473       end if;
1474
1475       Insert (Container, Index, New_Item);
1476    end Insert;
1477
1478    procedure Insert
1479      (Container : in out Vector;
1480       Before    : Cursor;
1481       New_Item  : Vector;
1482       Position  : out Cursor)
1483    is
1484       Index : Index_Type'Base;
1485
1486    begin
1487       if Before.Container /= null
1488         and then Before.Container /= Container'Unchecked_Access
1489       then
1490          raise Program_Error with "Before cursor denotes wrong container";
1491       end if;
1492
1493       if Is_Empty (New_Item) then
1494          if Before.Container = null
1495            or else Before.Index > Container.Last
1496          then
1497             Position := No_Element;
1498          else
1499             Position := (Container'Unchecked_Access, Before.Index);
1500          end if;
1501
1502          return;
1503       end if;
1504
1505       if Before.Container = null
1506         or else Before.Index > Container.Last
1507       then
1508          if Container.Last = Index_Type'Last then
1509             raise Constraint_Error with
1510               "vector is already at its maximum length";
1511          end if;
1512
1513          Index := Container.Last + 1;
1514
1515       else
1516          Index := Before.Index;
1517       end if;
1518
1519       Insert (Container, Index, New_Item);
1520
1521       Position := Cursor'(Container'Unchecked_Access, Index);
1522    end Insert;
1523
1524    procedure Insert
1525      (Container : in out Vector;
1526       Before    : Cursor;
1527       New_Item  : Element_Type;
1528       Count     : Count_Type := 1)
1529    is
1530       Index : Index_Type'Base;
1531
1532    begin
1533       if Before.Container /= null
1534         and then Before.Container /= Container'Unchecked_Access
1535       then
1536          raise Program_Error with "Before cursor denotes wrong container";
1537       end if;
1538
1539       if Count = 0 then
1540          return;
1541       end if;
1542
1543       if Before.Container = null
1544         or else Before.Index > Container.Last
1545       then
1546          if Container.Last = Index_Type'Last then
1547             raise Constraint_Error with
1548               "vector is already at its maximum length";
1549          else
1550             Index := Container.Last + 1;
1551          end if;
1552
1553       else
1554          Index := Before.Index;
1555       end if;
1556
1557       Insert (Container, Index, New_Item, Count);
1558    end Insert;
1559
1560    procedure Insert
1561      (Container : in out Vector;
1562       Before    : Cursor;
1563       New_Item  : Element_Type;
1564       Position  : out Cursor;
1565       Count     : Count_Type := 1)
1566    is
1567       Index : Index_Type'Base;
1568
1569    begin
1570       if Before.Container /= null
1571         and then Before.Container /= Container'Unchecked_Access
1572       then
1573          raise Program_Error with "Before cursor denotes wrong container";
1574       end if;
1575
1576       if Count = 0 then
1577          if Before.Container = null
1578            or else Before.Index > Container.Last
1579          then
1580             Position := No_Element;
1581          else
1582             Position := (Container'Unchecked_Access, Before.Index);
1583          end if;
1584
1585          return;
1586       end if;
1587
1588       if Before.Container = null
1589         or else Before.Index > Container.Last
1590       then
1591          if Container.Last = Index_Type'Last then
1592             raise Constraint_Error with
1593               "vector is already at its maximum length";
1594          end if;
1595
1596          Index := Container.Last + 1;
1597
1598       else
1599          Index := Before.Index;
1600       end if;
1601
1602       Insert (Container, Index, New_Item, Count);
1603
1604       Position := Cursor'(Container'Unchecked_Access, Index);
1605    end Insert;
1606
1607    procedure Insert
1608      (Container : in out Vector;
1609       Before    : Extended_Index;
1610       Count     : Count_Type := 1)
1611    is
1612       New_Item : Element_Type;  -- Default-initialized value
1613       pragma Warnings (Off, New_Item);
1614
1615    begin
1616       Insert (Container, Before, New_Item, Count);
1617    end Insert;
1618
1619    procedure Insert
1620      (Container : in out Vector;
1621       Before    : Cursor;
1622       Position  : out Cursor;
1623       Count     : Count_Type := 1)
1624    is
1625       New_Item : Element_Type;  -- Default-initialized value
1626       pragma Warnings (Off, New_Item);
1627
1628    begin
1629       Insert (Container, Before, New_Item, Position, Count);
1630    end Insert;
1631
1632    ------------------
1633    -- Insert_Space --
1634    ------------------
1635
1636    procedure Insert_Space
1637      (Container : in out Vector;
1638       Before    : Extended_Index;
1639       Count     : Count_Type := 1)
1640    is
1641       Old_Length : constant Count_Type := Container.Length;
1642
1643       Max_Length : Count_Type'Base;  -- determined from range of Index_Type
1644       New_Length : Count_Type'Base;  -- sum of current length and Count
1645       New_Last   : Index_Type'Base;  -- last index of vector after insertion
1646
1647       Index : Index_Type'Base;  -- scratch for intermediate values
1648       J     : Count_Type'Base;  -- scratch
1649
1650       New_Capacity : Count_Type'Base;  -- length of new, expanded array
1651       Dst_Last     : Index_Type'Base;  -- last index of new, expanded array
1652       Dst          : Elements_Access;  -- new, expanded internal array
1653
1654    begin
1655       --  As a precondition on the generic actual Index_Type, the base type
1656       --  must include Index_Type'Pred (Index_Type'First); this is the value
1657       --  that Container.Last assumes when the vector is empty. However, we do
1658       --  not allow that as the value for Index when specifying where the new
1659       --  items should be inserted, so we must manually check. (That the user
1660       --  is allowed to specify the value at all here is a consequence of the
1661       --  declaration of the Extended_Index subtype, which includes the values
1662       --  in the base range that immediately precede and immediately follow the
1663       --  values in the Index_Type.)
1664
1665       if Before < Index_Type'First then
1666          raise Constraint_Error with
1667            "Before index is out of range (too small)";
1668       end if;
1669
1670       --  We do allow a value greater than Container.Last to be specified as
1671       --  the Index, but only if it's immediately greater. This allows for the
1672       --  case of appending items to the back end of the vector. (It is assumed
1673       --  that specifying an index value greater than Last + 1 indicates some
1674       --  deeper flaw in the caller's algorithm, so that case is treated as a
1675       --  proper error.)
1676
1677       if Before > Container.Last
1678         and then Before > Container.Last + 1
1679       then
1680          raise Constraint_Error with
1681            "Before index is out of range (too large)";
1682       end if;
1683
1684       --  We treat inserting 0 items into the container as a no-op, even when
1685       --  the container is busy, so we simply return.
1686
1687       if Count = 0 then
1688          return;
1689       end if;
1690
1691       --  There are two constraints we need to satisfy. The first constraint is
1692       --  that a container cannot have more than Count_Type'Last elements, so
1693       --  we must check the sum of the current length and the insertion
1694       --  count. Note that we cannot simply add these values, because of the
1695       --  possibility of overflow.
1696
1697       if Old_Length > Count_Type'Last - Count then
1698          raise Constraint_Error with "Count is out of range";
1699       end if;
1700
1701       --  It is now safe compute the length of the new vector, without fear of
1702       --  overflow.
1703
1704       New_Length := Old_Length + Count;
1705
1706       --  The second constraint is that the new Last index value cannot exceed
1707       --  Index_Type'Last. In each branch below, we calculate the maximum
1708       --  length (computed from the range of values in Index_Type), and then
1709       --  compare the new length to the maximum length. If the new length is
1710       --  acceptable, then we compute the new last index from that.
1711
1712       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1713
1714          --  We have to handle the case when there might be more values in the
1715          --  range of Index_Type than in the range of Count_Type.
1716
1717          if Index_Type'First <= 0 then
1718
1719             --  We know that No_Index (the same as Index_Type'First - 1) is
1720             --  less than 0, so it is safe to compute the following sum without
1721             --  fear of overflow.
1722
1723             Index := No_Index + Index_Type'Base (Count_Type'Last);
1724
1725             if Index <= Index_Type'Last then
1726
1727                --  We have determined that range of Index_Type has at least as
1728                --  many values as in Count_Type, so Count_Type'Last is the
1729                --  maximum number of items that are allowed.
1730
1731                Max_Length := Count_Type'Last;
1732
1733             else
1734                --  The range of Index_Type has fewer values than in Count_Type,
1735                --  so the maximum number of items is computed from the range of
1736                --  the Index_Type.
1737
1738                Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1739             end if;
1740
1741          else
1742             --  No_Index is equal or greater than 0, so we can safely compute
1743             --  the difference without fear of overflow (which we would have to
1744             --  worry about if No_Index were less than 0, but that case is
1745             --  handled above).
1746
1747             Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1748          end if;
1749
1750       elsif Index_Type'First <= 0 then
1751
1752          --  We know that No_Index (the same as Index_Type'First - 1) is less
1753          --  than 0, so it is safe to compute the following sum without fear of
1754          --  overflow.
1755
1756          J := Count_Type'Base (No_Index) + Count_Type'Last;
1757
1758          if J <= Count_Type'Base (Index_Type'Last) then
1759
1760             --  We have determined that range of Index_Type has at least as
1761             --  many values as in Count_Type, so Count_Type'Last is the maximum
1762             --  number of items that are allowed.
1763
1764             Max_Length := Count_Type'Last;
1765
1766          else
1767             --  The range of Index_Type has fewer values than Count_Type does,
1768             --  so the maximum number of items is computed from the range of
1769             --  the Index_Type.
1770
1771             Max_Length :=
1772               Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1773          end if;
1774
1775       else
1776          --  No_Index is equal or greater than 0, so we can safely compute the
1777          --  difference without fear of overflow (which we would have to worry
1778          --  about if No_Index were less than 0, but that case is handled
1779          --  above).
1780
1781          Max_Length :=
1782            Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1783       end if;
1784
1785       --  We have just computed the maximum length (number of items). We must
1786       --  now compare the requested length to the maximum length, as we do not
1787       --  allow a vector expand beyond the maximum (because that would create
1788       --  an internal array with a last index value greater than
1789       --  Index_Type'Last, with no way to index those elements).
1790
1791       if New_Length > Max_Length then
1792          raise Constraint_Error with "Count is out of range";
1793       end if;
1794
1795       --  New_Last is the last index value of the items in the container after
1796       --  insertion.  Use the wider of Index_Type'Base and Count_Type'Base to
1797       --  compute its value from the New_Length.
1798
1799       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1800          New_Last := No_Index + Index_Type'Base (New_Length);
1801
1802       else
1803          New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1804       end if;
1805
1806       if Container.Elements = null then
1807          pragma Assert (Container.Last = No_Index);
1808
1809          --  This is the simplest case, with which we must always begin: we're
1810          --  inserting items into an empty vector that hasn't allocated an
1811          --  internal array yet. Note that we don't need to check the busy bit
1812          --  here, because an empty container cannot be busy.
1813
1814          --  In order to preserve container invariants, we allocate the new
1815          --  internal array first, before setting the Last index value, in case
1816          --  the allocation fails (which can happen either because there is no
1817          --  storage available, or because default-valued element
1818          --  initialization fails).
1819
1820          Container.Elements := new Elements_Type (New_Last);
1821
1822          --  The allocation of the new, internal array succeeded, so it is now
1823          --  safe to update the Last index, restoring container invariants.
1824
1825          Container.Last := New_Last;
1826
1827          return;
1828       end if;
1829
1830       --  The tampering bits exist to prevent an item from being harmfully
1831       --  manipulated while it is being visited. Query, Update, and Iterate
1832       --  increment the busy count on entry, and decrement the count on
1833       --  exit. Insert checks the count to determine whether it is being called
1834       --  while the associated callback procedure is executing.
1835
1836       if Container.Busy > 0 then
1837          raise Program_Error with
1838            "attempt to tamper with cursors (vector is busy)";
1839       end if;
1840
1841       --  An internal array has already been allocated, so we must determine
1842       --  whether there is enough unused storage for the new items.
1843
1844       if New_Last <= Container.Elements.Last then
1845
1846          --  In this case, we're inserting space into a vector that has already
1847          --  allocated an internal array, and the existing array has enough
1848          --  unused storage for the new items.
1849
1850          declare
1851             EA : Elements_Array renames Container.Elements.EA;
1852
1853          begin
1854             if Before <= Container.Last then
1855
1856                --  The space is being inserted before some existing elements,
1857                --  so we must slide the existing elements up to their new
1858                --  home. We use the wider of Index_Type'Base and
1859                --  Count_Type'Base as the type for intermediate index values.
1860
1861                if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1862                   Index := Before + Index_Type'Base (Count);
1863
1864                else
1865                   Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1866                end if;
1867
1868                EA (Index .. New_Last) := EA (Before .. Container.Last);
1869             end if;
1870          end;
1871
1872          Container.Last := New_Last;
1873          return;
1874       end if;
1875
1876       --  In this case, we're inserting space into a vector that has already
1877       --  allocated an internal array, but the existing array does not have
1878       --  enough storage, so we must allocate a new, longer array. In order to
1879       --  guarantee that the amortized insertion cost is O(1), we always
1880       --  allocate an array whose length is some power-of-two factor of the
1881       --  current array length. (The new array cannot have a length less than
1882       --  the New_Length of the container, but its last index value cannot be
1883       --  greater than Index_Type'Last.)
1884
1885       New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1886       while New_Capacity < New_Length loop
1887          if New_Capacity > Count_Type'Last / 2 then
1888             New_Capacity := Count_Type'Last;
1889             exit;
1890          end if;
1891
1892          New_Capacity := 2 * New_Capacity;
1893       end loop;
1894
1895       if New_Capacity > Max_Length then
1896
1897          --  We have reached the limit of capacity, so no further expansion
1898          --  will occur. (This is not a problem, as there is never a need to
1899          --  have more capacity than the maximum container length.)
1900
1901          New_Capacity := Max_Length;
1902       end if;
1903
1904       --  We have computed the length of the new internal array (and this is
1905       --  what "vector capacity" means), so use that to compute its last index.
1906
1907       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1908          Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1909
1910       else
1911          Dst_Last :=
1912            Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1913       end if;
1914
1915       --  Now we allocate the new, longer internal array. If the allocation
1916       --  fails, we have not changed any container state, so no side-effect
1917       --  will occur as a result of propagating the exception.
1918
1919       Dst := new Elements_Type (Dst_Last);
1920
1921       --  We have our new internal array. All that needs to be done now is to
1922       --  copy the existing items (if any) from the old array (the "source"
1923       --  array, object SA below) to the new array (the "destination" array,
1924       --  object DA below), and then deallocate the old array.
1925
1926       declare
1927          SA : Elements_Array renames Container.Elements.EA;  -- source
1928          DA : Elements_Array renames Dst.EA;                 -- destination
1929
1930       begin
1931          DA (Index_Type'First .. Before - 1) :=
1932            SA (Index_Type'First .. Before - 1);
1933
1934          if Before <= Container.Last then
1935
1936             --  The space is being inserted before some existing elements, so
1937             --  we must slide the existing elements up to their new home.
1938
1939             if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1940                Index := Before + Index_Type'Base (Count);
1941
1942             else
1943                Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1944             end if;
1945
1946             DA (Index .. New_Last) := SA (Before .. Container.Last);
1947          end if;
1948
1949       exception
1950          when others =>
1951             Free (Dst);
1952             raise;
1953       end;
1954
1955       --  We have successfully copied the items onto the new array, so the
1956       --  final thing to do is restore invariants, and deallocate the old
1957       --  array.
1958
1959       declare
1960          X : Elements_Access := Container.Elements;
1961
1962       begin
1963          --  We first isolate the old internal array, removing it from the
1964          --  container and replacing it with the new internal array, before we
1965          --  deallocate the old array (which can fail if finalization of
1966          --  elements propagates an exception).
1967
1968          Container.Elements := Dst;
1969          Container.Last := New_Last;
1970
1971          --  The container invariants have been restored, so it is now safe to
1972          --  attempt to deallocate the old array.
1973
1974          Free (X);
1975       end;
1976    end Insert_Space;
1977
1978    procedure Insert_Space
1979      (Container : in out Vector;
1980       Before    : Cursor;
1981       Position  : out Cursor;
1982       Count     : Count_Type := 1)
1983    is
1984       Index : Index_Type'Base;
1985
1986    begin
1987       if Before.Container /= null
1988         and then Before.Container /= Container'Unchecked_Access
1989       then
1990          raise Program_Error with "Before cursor denotes wrong container";
1991       end if;
1992
1993       if Count = 0 then
1994          if Before.Container = null
1995            or else Before.Index > Container.Last
1996          then
1997             Position := No_Element;
1998          else
1999             Position := (Container'Unchecked_Access, Before.Index);
2000          end if;
2001
2002          return;
2003       end if;
2004
2005       if Before.Container = null
2006         or else Before.Index > Container.Last
2007       then
2008          if Container.Last = Index_Type'Last then
2009             raise Constraint_Error with
2010               "vector is already at its maximum length";
2011          else
2012             Index := Container.Last + 1;
2013          end if;
2014
2015       else
2016          Index := Before.Index;
2017       end if;
2018
2019       Insert_Space (Container, Index, Count => Count);
2020
2021       Position := Cursor'(Container'Unchecked_Access, Index);
2022    end Insert_Space;
2023
2024    --------------
2025    -- Is_Empty --
2026    --------------
2027
2028    function Is_Empty (Container : Vector) return Boolean is
2029    begin
2030       return Container.Last < Index_Type'First;
2031    end Is_Empty;
2032
2033    -------------
2034    -- Iterate --
2035    -------------
2036
2037    procedure Iterate
2038      (Container : Vector;
2039       Process   : not null access procedure (Position : Cursor))
2040    is
2041       V : Vector renames Container'Unrestricted_Access.all;
2042       B : Natural renames V.Busy;
2043
2044    begin
2045       B := B + 1;
2046
2047       begin
2048          for Indx in Index_Type'First .. Container.Last loop
2049             Process (Cursor'(Container'Unchecked_Access, Indx));
2050          end loop;
2051       exception
2052          when others =>
2053             B := B - 1;
2054             raise;
2055       end;
2056
2057       B := B - 1;
2058    end Iterate;
2059
2060    function Iterate
2061      (Container : Vector)
2062       return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2063    is
2064       It : constant Iterator := (Container'Unchecked_Access, Index_Type'First);
2065    begin
2066       return It;
2067    end Iterate;
2068
2069    function Iterate
2070      (Container : Vector;
2071       Start     : Cursor)
2072       return Vector_Iterator_Interfaces.Reversible_Iterator'class
2073    is
2074       It : constant Iterator := (Container'Unchecked_Access, Start.Index);
2075    begin
2076       return It;
2077    end Iterate;
2078
2079    ----------
2080    -- Last --
2081    ----------
2082
2083    function Last (Container : Vector) return Cursor is
2084    begin
2085       if Is_Empty (Container) then
2086          return No_Element;
2087       else
2088          return (Container'Unchecked_Access, Container.Last);
2089       end if;
2090    end Last;
2091
2092    function Last (Object : Iterator) return Cursor is
2093    begin
2094       if Is_Empty (Object.Container.all) then
2095          return No_Element;
2096       else
2097          return Cursor'(Object.Container, Object.Container.Last);
2098       end if;
2099    end Last;
2100
2101    ------------------
2102    -- Last_Element --
2103    ------------------
2104
2105    function Last_Element (Container : Vector) return Element_Type is
2106    begin
2107       if Container.Last = No_Index then
2108          raise Constraint_Error with "Container is empty";
2109       else
2110          return Container.Elements.EA (Container.Last);
2111       end if;
2112    end Last_Element;
2113
2114    ----------------
2115    -- Last_Index --
2116    ----------------
2117
2118    function Last_Index (Container : Vector) return Extended_Index is
2119    begin
2120       return Container.Last;
2121    end Last_Index;
2122
2123    ------------
2124    -- Length --
2125    ------------
2126
2127    function Length (Container : Vector) return Count_Type is
2128       L : constant Index_Type'Base := Container.Last;
2129       F : constant Index_Type := Index_Type'First;
2130
2131    begin
2132       --  The base range of the index type (Index_Type'Base) might not include
2133       --  all values for length (Count_Type). Contrariwise, the index type
2134       --  might include values outside the range of length.  Hence we use
2135       --  whatever type is wider for intermediate values when calculating
2136       --  length. Note that no matter what the index type is, the maximum
2137       --  length to which a vector is allowed to grow is always the minimum
2138       --  of Count_Type'Last and (IT'Last - IT'First + 1).
2139
2140       --  For example, an Index_Type with range -127 .. 127 is only guaranteed
2141       --  to have a base range of -128 .. 127, but the corresponding vector
2142       --  would have lengths in the range 0 .. 255. In this case we would need
2143       --  to use Count_Type'Base for intermediate values.
2144
2145       --  Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2146       --  vector would have a maximum length of 10, but the index values lie
2147       --  outside the range of Count_Type (which is only 32 bits). In this
2148       --  case we would need to use Index_Type'Base for intermediate values.
2149
2150       if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2151          return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2152       else
2153          return Count_Type (L - F + 1);
2154       end if;
2155    end Length;
2156
2157    ----------
2158    -- Move --
2159    ----------
2160
2161    procedure Move
2162      (Target : in out Vector;
2163       Source : in out Vector)
2164    is
2165    begin
2166       if Target'Address = Source'Address then
2167          return;
2168       end if;
2169
2170       if Target.Busy > 0 then
2171          raise Program_Error with
2172            "attempt to tamper with cursors (Target is busy)";
2173       end if;
2174
2175       if Source.Busy > 0 then
2176          raise Program_Error with
2177            "attempt to tamper with cursors (Source is busy)";
2178       end if;
2179
2180       declare
2181          Target_Elements : constant Elements_Access := Target.Elements;
2182       begin
2183          Target.Elements := Source.Elements;
2184          Source.Elements := Target_Elements;
2185       end;
2186
2187       Target.Last := Source.Last;
2188       Source.Last := No_Index;
2189    end Move;
2190
2191    ----------
2192    -- Next --
2193    ----------
2194
2195    function Next (Position : Cursor) return Cursor is
2196    begin
2197       if Position.Container = null then
2198          return No_Element;
2199       elsif Position.Index < Position.Container.Last then
2200          return (Position.Container, Position.Index + 1);
2201       else
2202          return No_Element;
2203       end if;
2204    end Next;
2205
2206    function Next (Object : Iterator; Position : Cursor) return Cursor is
2207    begin
2208       if Position.Index = Object.Container.Last then
2209          return  No_Element;
2210       else
2211          return (Object.Container, Position.Index + 1);
2212       end if;
2213    end Next;
2214
2215    ----------
2216    -- Next --
2217    ----------
2218
2219    procedure Next (Position : in out Cursor) is
2220    begin
2221       if Position.Container = null then
2222          return;
2223       end if;
2224
2225       if Position.Index < Position.Container.Last then
2226          Position.Index := Position.Index + 1;
2227       else
2228          Position := No_Element;
2229       end if;
2230    end Next;
2231
2232    -------------
2233    -- Prepend --
2234    -------------
2235
2236    procedure Prepend (Container : in out Vector; New_Item : Vector) is
2237    begin
2238       Insert (Container, Index_Type'First, New_Item);
2239    end Prepend;
2240
2241    procedure Prepend
2242      (Container : in out Vector;
2243       New_Item  : Element_Type;
2244       Count     : Count_Type := 1)
2245    is
2246    begin
2247       Insert (Container,
2248               Index_Type'First,
2249               New_Item,
2250               Count);
2251    end Prepend;
2252
2253    --------------
2254    -- Previous --
2255    --------------
2256
2257    procedure Previous (Position : in out Cursor) is
2258    begin
2259       if Position.Container = null then
2260          return;
2261       end if;
2262
2263       if Position.Index > Index_Type'First then
2264          Position.Index := Position.Index - 1;
2265       else
2266          Position := No_Element;
2267       end if;
2268    end Previous;
2269
2270    function Previous (Position : Cursor) return Cursor is
2271    begin
2272       if Position.Container = null then
2273          return No_Element;
2274       end if;
2275
2276       if Position.Index > Index_Type'First then
2277          return (Position.Container, Position.Index - 1);
2278       end if;
2279
2280       return No_Element;
2281    end Previous;
2282
2283    function Previous (Object : Iterator; Position : Cursor) return Cursor is
2284    begin
2285       if Position.Index > Index_Type'First then
2286          return (Object.Container, Position.Index - 1);
2287       else
2288          return No_Element;
2289       end if;
2290    end Previous;
2291
2292    -------------------
2293    -- Query_Element --
2294    -------------------
2295
2296    procedure Query_Element
2297      (Container : Vector;
2298       Index     : Index_Type;
2299       Process   : not null access procedure (Element : Element_Type))
2300    is
2301       V : Vector renames Container'Unrestricted_Access.all;
2302       B : Natural renames V.Busy;
2303       L : Natural renames V.Lock;
2304
2305    begin
2306       if Index > Container.Last then
2307          raise Constraint_Error with "Index is out of range";
2308       end if;
2309
2310       B := B + 1;
2311       L := L + 1;
2312
2313       begin
2314          Process (V.Elements.EA (Index));
2315       exception
2316          when others =>
2317             L := L - 1;
2318             B := B - 1;
2319             raise;
2320       end;
2321
2322       L := L - 1;
2323       B := B - 1;
2324    end Query_Element;
2325
2326    procedure Query_Element
2327      (Position : Cursor;
2328       Process  : not null access procedure (Element : Element_Type))
2329    is
2330    begin
2331       if Position.Container = null then
2332          raise Constraint_Error with "Position cursor has no element";
2333       end if;
2334
2335       Query_Element (Position.Container.all, Position.Index, Process);
2336    end Query_Element;
2337
2338    ----------
2339    -- Read --
2340    ----------
2341
2342    procedure Read
2343      (Stream    : not null access Root_Stream_Type'Class;
2344       Container : out Vector)
2345    is
2346       Length : Count_Type'Base;
2347       Last   : Index_Type'Base := No_Index;
2348
2349    begin
2350       Clear (Container);
2351
2352       Count_Type'Base'Read (Stream, Length);
2353
2354       if Length > Capacity (Container) then
2355          Reserve_Capacity (Container, Capacity => Length);
2356       end if;
2357
2358       for J in Count_Type range 1 .. Length loop
2359          Last := Last + 1;
2360          Element_Type'Read (Stream, Container.Elements.EA (Last));
2361          Container.Last := Last;
2362       end loop;
2363    end Read;
2364
2365    procedure Read
2366      (Stream   : not null access Root_Stream_Type'Class;
2367       Position : out Cursor)
2368    is
2369    begin
2370       raise Program_Error with "attempt to stream vector cursor";
2371    end Read;
2372
2373    procedure Read
2374      (Stream : not null access Root_Stream_Type'Class;
2375       Item   : out Reference_Type)
2376    is
2377    begin
2378       raise Program_Error with "attempt to stream reference";
2379    end Read;
2380
2381    procedure Read
2382      (Stream : not null access Root_Stream_Type'Class;
2383       Item   : out Constant_Reference_Type)
2384    is
2385    begin
2386       raise Program_Error with "attempt to stream reference";
2387    end Read;
2388
2389    ---------------
2390    -- Reference --
2391    ---------------
2392
2393    function Constant_Reference
2394      (Container : Vector;
2395       Position  : Cursor)    --  SHOULD BE ALIASED
2396       return Constant_Reference_Type
2397    is
2398    begin
2399       pragma Unreferenced (Container);
2400
2401       if Position.Container = null then
2402          raise Constraint_Error with "Position cursor has no element";
2403       end if;
2404
2405       if Position.Index > Position.Container.Last then
2406          raise Constraint_Error with "Position cursor is out of range";
2407       end if;
2408
2409       return
2410        (Element =>
2411           Position.Container.Elements.EA (Position.Index)'Access);
2412    end Constant_Reference;
2413
2414    function Constant_Reference
2415      (Container : Vector;
2416       Position  : Index_Type)
2417       return Constant_Reference_Type
2418    is
2419    begin
2420       if (Position) > Container.Last then
2421          raise Constraint_Error with "Index is out of range";
2422       else
2423          return (Element => Container.Elements.EA (Position)'Access);
2424       end if;
2425    end Constant_Reference;
2426
2427    function Reference (Container : Vector; Position : Cursor)
2428    return Reference_Type is
2429    begin
2430       pragma Unreferenced (Container);
2431
2432       if Position.Container = null then
2433          raise Constraint_Error with "Position cursor has no element";
2434       end if;
2435
2436       if Position.Index > Position.Container.Last then
2437          raise Constraint_Error with "Position cursor is out of range";
2438       end if;
2439
2440       return
2441         (Element => Position.Container.Elements.EA (Position.Index)'Access);
2442    end Reference;
2443
2444    function Reference (Container : Vector; Position : Index_Type)
2445    return Reference_Type is
2446    begin
2447       if Position > Container.Last then
2448          raise Constraint_Error with "Index is out of range";
2449       else
2450          return (Element => Container.Elements.EA (Position)'Access);
2451       end if;
2452    end Reference;
2453
2454    ---------------------
2455    -- Replace_Element --
2456    ---------------------
2457
2458    procedure Replace_Element
2459      (Container : in out Vector;
2460       Index     : Index_Type;
2461       New_Item  : Element_Type)
2462    is
2463    begin
2464       if Index > Container.Last then
2465          raise Constraint_Error with "Index is out of range";
2466       end if;
2467
2468       if Container.Lock > 0 then
2469          raise Program_Error with
2470            "attempt to tamper with elements (vector is locked)";
2471       end if;
2472
2473       Container.Elements.EA (Index) := New_Item;
2474    end Replace_Element;
2475
2476    procedure Replace_Element
2477      (Container : in out Vector;
2478       Position  : Cursor;
2479       New_Item  : Element_Type)
2480    is
2481    begin
2482       if Position.Container = null then
2483          raise Constraint_Error with "Position cursor has no element";
2484       end if;
2485
2486       if Position.Container /= Container'Unrestricted_Access then
2487          raise Program_Error with "Position cursor denotes wrong container";
2488       end if;
2489
2490       if Position.Index > Container.Last then
2491          raise Constraint_Error with "Position cursor is out of range";
2492       end if;
2493
2494       if Container.Lock > 0 then
2495          raise Program_Error with
2496            "attempt to tamper with elements (vector is locked)";
2497       end if;
2498
2499       Container.Elements.EA (Position.Index) := New_Item;
2500    end Replace_Element;
2501
2502    ----------------------
2503    -- Reserve_Capacity --
2504    ----------------------
2505
2506    procedure Reserve_Capacity
2507      (Container : in out Vector;
2508       Capacity  : Count_Type)
2509    is
2510       N : constant Count_Type := Length (Container);
2511
2512       Index : Count_Type'Base;
2513       Last  : Index_Type'Base;
2514
2515    begin
2516       --  Reserve_Capacity can be used to either expand the storage available
2517       --  for elements (this would be its typical use, in anticipation of
2518       --  future insertion), or to trim back storage. In the latter case,
2519       --  storage can only be trimmed back to the limit of the container
2520       --  length. Note that Reserve_Capacity neither deletes (active) elements
2521       --  nor inserts elements; it only affects container capacity, never
2522       --  container length.
2523
2524       if Capacity = 0 then
2525
2526          --  This is a request to trim back storage, to the minimum amount
2527          --  possible given the current state of the container.
2528
2529          if N = 0 then
2530
2531             --  The container is empty, so in this unique case we can
2532             --  deallocate the entire internal array. Note that an empty
2533             --  container can never be busy, so there's no need to check the
2534             --  tampering bits.
2535
2536             declare
2537                X : Elements_Access := Container.Elements;
2538
2539             begin
2540                --  First we remove the internal array from the container, to
2541                --  handle the case when the deallocation raises an exception.
2542
2543                Container.Elements := null;
2544
2545                --  Container invariants have been restored, so it is now safe
2546                --  to attempt to deallocate the internal array.
2547
2548                Free (X);
2549             end;
2550
2551          elsif N < Container.Elements.EA'Length then
2552
2553             --  The container is not empty, and the current length is less than
2554             --  the current capacity, so there's storage available to trim. In
2555             --  this case, we allocate a new internal array having a length
2556             --  that exactly matches the number of items in the
2557             --  container. (Reserve_Capacity does not delete active elements,
2558             --  so this is the best we can do with respect to minimizing
2559             --  storage).
2560
2561             if Container.Busy > 0 then
2562                raise Program_Error with
2563                  "attempt to tamper with cursors (vector is busy)";
2564             end if;
2565
2566             declare
2567                subtype Src_Index_Subtype is Index_Type'Base range
2568                  Index_Type'First .. Container.Last;
2569
2570                Src : Elements_Array renames
2571                        Container.Elements.EA (Src_Index_Subtype);
2572
2573                X : Elements_Access := Container.Elements;
2574
2575             begin
2576                --  Although we have isolated the old internal array that we're
2577                --  going to deallocate, we don't deallocate it until we have
2578                --  successfully allocated a new one. If there is an exception
2579                --  during allocation (either because there is not enough
2580                --  storage, or because initialization of the elements fails),
2581                --  we let it propagate without causing any side-effect.
2582
2583                Container.Elements := new Elements_Type'(Container.Last, Src);
2584
2585                --  We have successfully allocated a new internal array (with a
2586                --  smaller length than the old one, and containing a copy of
2587                --  just the active elements in the container), so it is now
2588                --  safe to attempt to deallocate the old array. The old array
2589                --  has been isolated, and container invariants have been
2590                --  restored, so if the deallocation fails (because finalization
2591                --  of the elements fails), we simply let it propagate.
2592
2593                Free (X);
2594             end;
2595          end if;
2596
2597          return;
2598       end if;
2599
2600       --  Reserve_Capacity can be used to expand the storage available for
2601       --  elements, but we do not let the capacity grow beyond the number of
2602       --  values in Index_Type'Range. (Were it otherwise, there would be no way
2603       --  to refer to the elements with an index value greater than
2604       --  Index_Type'Last, so that storage would be wasted.) Here we compute
2605       --  the Last index value of the new internal array, in a way that avoids
2606       --  any possibility of overflow.
2607
2608       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2609
2610          --  We perform a two-part test. First we determine whether the
2611          --  computed Last value lies in the base range of the type, and then
2612          --  determine whether it lies in the range of the index (sub)type.
2613
2614          --  Last must satisfy this relation:
2615          --    First + Length - 1 <= Last
2616          --  We regroup terms:
2617          --    First - 1 <= Last - Length
2618          --  Which can rewrite as:
2619          --    No_Index <= Last - Length
2620
2621          if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
2622             raise Constraint_Error with "Capacity is out of range";
2623          end if;
2624
2625          --  We now know that the computed value of Last is within the base
2626          --  range of the type, so it is safe to compute its value:
2627
2628          Last := No_Index + Index_Type'Base (Capacity);
2629
2630          --  Finally we test whether the value is within the range of the
2631          --  generic actual index subtype:
2632
2633          if Last > Index_Type'Last then
2634             raise Constraint_Error with "Capacity is out of range";
2635          end if;
2636
2637       elsif Index_Type'First <= 0 then
2638
2639          --  Here we can compute Last directly, in the normal way. We know that
2640          --  No_Index is less than 0, so there is no danger of overflow when
2641          --  adding the (positive) value of Capacity.
2642
2643          Index := Count_Type'Base (No_Index) + Capacity;  -- Last
2644
2645          if Index > Count_Type'Base (Index_Type'Last) then
2646             raise Constraint_Error with "Capacity is out of range";
2647          end if;
2648
2649          --  We know that the computed value (having type Count_Type) of Last
2650          --  is within the range of the generic actual index subtype, so it is
2651          --  safe to convert to Index_Type:
2652
2653          Last := Index_Type'Base (Index);
2654
2655       else
2656          --  Here Index_Type'First (and Index_Type'Last) is positive, so we
2657          --  must test the length indirectly (by working backwards from the
2658          --  largest possible value of Last), in order to prevent overflow.
2659
2660          Index := Count_Type'Base (Index_Type'Last) - Capacity;  -- No_Index
2661
2662          if Index < Count_Type'Base (No_Index) then
2663             raise Constraint_Error with "Capacity is out of range";
2664          end if;
2665
2666          --  We have determined that the value of Capacity would not create a
2667          --  Last index value outside of the range of Index_Type, so we can now
2668          --  safely compute its value.
2669
2670          Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
2671       end if;
2672
2673       --  The requested capacity is non-zero, but we don't know yet whether
2674       --  this is a request for expansion or contraction of storage.
2675
2676       if Container.Elements = null then
2677
2678          --  The container is empty (it doesn't even have an internal array),
2679          --  so this represents a request to allocate (expand) storage having
2680          --  the given capacity.
2681
2682          Container.Elements := new Elements_Type (Last);
2683          return;
2684       end if;
2685
2686       if Capacity <= N then
2687
2688          --  This is a request to trim back storage, but only to the limit of
2689          --  what's already in the container. (Reserve_Capacity never deletes
2690          --  active elements, it only reclaims excess storage.)
2691
2692          if N < Container.Elements.EA'Length then
2693
2694             --  The container is not empty (because the requested capacity is
2695             --  positive, and less than or equal to the container length), and
2696             --  the current length is less than the current capacity, so
2697             --  there's storage available to trim. In this case, we allocate a
2698             --  new internal array having a length that exactly matches the
2699             --  number of items in the container.
2700
2701             if Container.Busy > 0 then
2702                raise Program_Error with
2703                  "attempt to tamper with cursors (vector is busy)";
2704             end if;
2705
2706             declare
2707                subtype Src_Index_Subtype is Index_Type'Base range
2708                  Index_Type'First .. Container.Last;
2709
2710                Src : Elements_Array renames
2711                        Container.Elements.EA (Src_Index_Subtype);
2712
2713                X : Elements_Access := Container.Elements;
2714
2715             begin
2716                --  Although we have isolated the old internal array that we're
2717                --  going to deallocate, we don't deallocate it until we have
2718                --  successfully allocated a new one. If there is an exception
2719                --  during allocation (either because there is not enough
2720                --  storage, or because initialization of the elements fails),
2721                --  we let it propagate without causing any side-effect.
2722
2723                Container.Elements := new Elements_Type'(Container.Last, Src);
2724
2725                --  We have successfully allocated a new internal array (with a
2726                --  smaller length than the old one, and containing a copy of
2727                --  just the active elements in the container), so it is now
2728                --  safe to attempt to deallocate the old array. The old array
2729                --  has been isolated, and container invariants have been
2730                --  restored, so if the deallocation fails (because finalization
2731                --  of the elements fails), we simply let it propagate.
2732
2733                Free (X);
2734             end;
2735          end if;
2736
2737          return;
2738       end if;
2739
2740       --  The requested capacity is larger than the container length (the
2741       --  number of active elements). Whether this represents a request for
2742       --  expansion or contraction of the current capacity depends on what the
2743       --  current capacity is.
2744
2745       if Capacity = Container.Elements.EA'Length then
2746
2747          --  The requested capacity matches the existing capacity, so there's
2748          --  nothing to do here. We treat this case as a no-op, and simply
2749          --  return without checking the busy bit.
2750
2751          return;
2752       end if;
2753
2754       --  There is a change in the capacity of a non-empty container, so a new
2755       --  internal array will be allocated. (The length of the new internal
2756       --  array could be less or greater than the old internal array. We know
2757       --  only that the length of the new internal array is greater than the
2758       --  number of active elements in the container.) We must check whether
2759       --  the container is busy before doing anything else.
2760
2761       if Container.Busy > 0 then
2762          raise Program_Error with
2763            "attempt to tamper with cursors (vector is busy)";
2764       end if;
2765
2766       --  We now allocate a new internal array, having a length different from
2767       --  its current value.
2768
2769       declare
2770          E : Elements_Access := new Elements_Type (Last);
2771
2772       begin
2773          --  We have successfully allocated the new internal array. We first
2774          --  attempt to copy the existing elements from the old internal array
2775          --  ("src" elements) onto the new internal array ("tgt" elements).
2776
2777          declare
2778             subtype Index_Subtype is Index_Type'Base range
2779               Index_Type'First .. Container.Last;
2780
2781             Src : Elements_Array renames
2782                     Container.Elements.EA (Index_Subtype);
2783
2784             Tgt : Elements_Array renames E.EA (Index_Subtype);
2785
2786          begin
2787             Tgt := Src;
2788
2789          exception
2790             when others =>
2791                Free (E);
2792                raise;
2793          end;
2794
2795          --  We have successfully copied the existing elements onto the new
2796          --  internal array, so now we can attempt to deallocate the old one.
2797
2798          declare
2799             X : Elements_Access := Container.Elements;
2800
2801          begin
2802             --  First we isolate the old internal array, and replace it in the
2803             --  container with the new internal array.
2804
2805             Container.Elements := E;
2806
2807             --  Container invariants have been restored, so it is now safe to
2808             --  attempt to deallocate the old internal array.
2809
2810             Free (X);
2811          end;
2812       end;
2813    end Reserve_Capacity;
2814
2815    ----------------------
2816    -- Reverse_Elements --
2817    ----------------------
2818
2819    procedure Reverse_Elements (Container : in out Vector) is
2820    begin
2821       if Container.Length <= 1 then
2822          return;
2823       end if;
2824
2825       if Container.Lock > 0 then
2826          raise Program_Error with
2827            "attempt to tamper with elements (vector is locked)";
2828       end if;
2829
2830       declare
2831          I, J : Index_Type;
2832          E    : Elements_Type renames Container.Elements.all;
2833
2834       begin
2835          I := Index_Type'First;
2836          J := Container.Last;
2837          while I < J loop
2838             declare
2839                EI : constant Element_Type := E.EA (I);
2840
2841             begin
2842                E.EA (I) := E.EA (J);
2843                E.EA (J) := EI;
2844             end;
2845
2846             I := I + 1;
2847             J := J - 1;
2848          end loop;
2849       end;
2850    end Reverse_Elements;
2851
2852    ------------------
2853    -- Reverse_Find --
2854    ------------------
2855
2856    function Reverse_Find
2857      (Container : Vector;
2858       Item      : Element_Type;
2859       Position  : Cursor := No_Element) return Cursor
2860    is
2861       Last : Index_Type'Base;
2862
2863    begin
2864       if Position.Container /= null
2865         and then Position.Container /= Container'Unchecked_Access
2866       then
2867          raise Program_Error with "Position cursor denotes wrong container";
2868       end if;
2869
2870       Last :=
2871         (if Position.Container = null or else Position.Index > Container.Last
2872          then Container.Last
2873          else Position.Index);
2874
2875       for Indx in reverse Index_Type'First .. Last loop
2876          if Container.Elements.EA (Indx) = Item then
2877             return (Container'Unchecked_Access, Indx);
2878          end if;
2879       end loop;
2880
2881       return No_Element;
2882    end Reverse_Find;
2883
2884    ------------------------
2885    -- Reverse_Find_Index --
2886    ------------------------
2887
2888    function Reverse_Find_Index
2889      (Container : Vector;
2890       Item      : Element_Type;
2891       Index     : Index_Type := Index_Type'Last) return Extended_Index
2892    is
2893       Last : constant Index_Type'Base :=
2894                Index_Type'Min (Container.Last, Index);
2895
2896    begin
2897       for Indx in reverse Index_Type'First .. Last loop
2898          if Container.Elements.EA (Indx) = Item then
2899             return Indx;
2900          end if;
2901       end loop;
2902
2903       return No_Index;
2904    end Reverse_Find_Index;
2905
2906    ---------------------
2907    -- Reverse_Iterate --
2908    ---------------------
2909
2910    procedure Reverse_Iterate
2911      (Container : Vector;
2912       Process   : not null access procedure (Position : Cursor))
2913    is
2914       V : Vector renames Container'Unrestricted_Access.all;
2915       B : Natural renames V.Busy;
2916
2917    begin
2918       B := B + 1;
2919
2920       begin
2921          for Indx in reverse Index_Type'First .. Container.Last loop
2922             Process (Cursor'(Container'Unchecked_Access, Indx));
2923          end loop;
2924       exception
2925          when others =>
2926             B := B - 1;
2927             raise;
2928       end;
2929
2930       B := B - 1;
2931    end Reverse_Iterate;
2932
2933    ----------------
2934    -- Set_Length --
2935    ----------------
2936
2937    procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2938       Count : constant Count_Type'Base := Container.Length - Length;
2939
2940    begin
2941       --  Set_Length allows the user to set the length explicitly, instead of
2942       --  implicitly as a side-effect of deletion or insertion. If the
2943       --  requested length is less then the current length, this is equivalent
2944       --  to deleting items from the back end of the vector. If the requested
2945       --  length is greater than the current length, then this is equivalent to
2946       --  inserting "space" (nonce items) at the end.
2947
2948       if Count >= 0 then
2949          Container.Delete_Last (Count);
2950
2951       elsif Container.Last >= Index_Type'Last then
2952          raise Constraint_Error with "vector is already at its maximum length";
2953
2954       else
2955          Container.Insert_Space (Container.Last + 1, -Count);
2956       end if;
2957    end Set_Length;
2958
2959    ----------
2960    -- Swap --
2961    ----------
2962
2963    procedure Swap (Container : in out Vector; I, J : Index_Type) is
2964    begin
2965       if I > Container.Last then
2966          raise Constraint_Error with "I index is out of range";
2967       end if;
2968
2969       if J > Container.Last then
2970          raise Constraint_Error with "J index is out of range";
2971       end if;
2972
2973       if I = J then
2974          return;
2975       end if;
2976
2977       if Container.Lock > 0 then
2978          raise Program_Error with
2979            "attempt to tamper with elements (vector is locked)";
2980       end if;
2981
2982       declare
2983          EI_Copy : constant Element_Type := Container.Elements.EA (I);
2984       begin
2985          Container.Elements.EA (I) := Container.Elements.EA (J);
2986          Container.Elements.EA (J) := EI_Copy;
2987       end;
2988    end Swap;
2989
2990    procedure Swap (Container : in out Vector; I, J : Cursor) is
2991    begin
2992       if I.Container = null then
2993          raise Constraint_Error with "I cursor has no element";
2994       end if;
2995
2996       if J.Container = null then
2997          raise Constraint_Error with "J cursor has no element";
2998       end if;
2999
3000       if I.Container /= Container'Unrestricted_Access then
3001          raise Program_Error with "I cursor denotes wrong container";
3002       end if;
3003
3004       if J.Container /= Container'Unrestricted_Access then
3005          raise Program_Error with "J cursor denotes wrong container";
3006       end if;
3007
3008       Swap (Container, I.Index, J.Index);
3009    end Swap;
3010
3011    ---------------
3012    -- To_Cursor --
3013    ---------------
3014
3015    function To_Cursor
3016      (Container : Vector;
3017       Index     : Extended_Index) return Cursor
3018    is
3019    begin
3020       if Index not in Index_Type'First .. Container.Last then
3021          return No_Element;
3022       else
3023          return Cursor'(Container'Unchecked_Access, Index);
3024       end if;
3025    end To_Cursor;
3026
3027    --------------
3028    -- To_Index --
3029    --------------
3030
3031    function To_Index (Position : Cursor) return Extended_Index is
3032    begin
3033       if Position.Container = null then
3034          return No_Index;
3035       end if;
3036
3037       if Position.Index <= Position.Container.Last then
3038          return Position.Index;
3039       end if;
3040
3041       return No_Index;
3042    end To_Index;
3043
3044    ---------------
3045    -- To_Vector --
3046    ---------------
3047
3048    function To_Vector (Length : Count_Type) return Vector is
3049       Index    : Count_Type'Base;
3050       Last     : Index_Type'Base;
3051       Elements : Elements_Access;
3052
3053    begin
3054       if Length = 0 then
3055          return Empty_Vector;
3056       end if;
3057
3058       --  We create a vector object with a capacity that matches the specified
3059       --  Length, but we do not allow the vector capacity (the length of the
3060       --  internal array) to exceed the number of values in Index_Type'Range
3061       --  (otherwise, there would be no way to refer to those components via an
3062       --  index).  We must therefore check whether the specified Length would
3063       --  create a Last index value greater than Index_Type'Last.
3064
3065       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3066
3067          --  We perform a two-part test. First we determine whether the
3068          --  computed Last value lies in the base range of the type, and then
3069          --  determine whether it lies in the range of the index (sub)type.
3070
3071          --  Last must satisfy this relation:
3072          --    First + Length - 1 <= Last
3073          --  We regroup terms:
3074          --    First - 1 <= Last - Length
3075          --  Which can rewrite as:
3076          --    No_Index <= Last - Length
3077
3078          if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3079             raise Constraint_Error with "Length is out of range";
3080          end if;
3081
3082          --  We now know that the computed value of Last is within the base
3083          --  range of the type, so it is safe to compute its value:
3084
3085          Last := No_Index + Index_Type'Base (Length);
3086
3087          --  Finally we test whether the value is within the range of the
3088          --  generic actual index subtype:
3089
3090          if Last > Index_Type'Last then
3091             raise Constraint_Error with "Length is out of range";
3092          end if;
3093
3094       elsif Index_Type'First <= 0 then
3095
3096          --  Here we can compute Last directly, in the normal way. We know that
3097          --  No_Index is less than 0, so there is no danger of overflow when
3098          --  adding the (positive) value of Length.
3099
3100          Index := Count_Type'Base (No_Index) + Length;  -- Last
3101
3102          if Index > Count_Type'Base (Index_Type'Last) then
3103             raise Constraint_Error with "Length is out of range";
3104          end if;
3105
3106          --  We know that the computed value (having type Count_Type) of Last
3107          --  is within the range of the generic actual index subtype, so it is
3108          --  safe to convert to Index_Type:
3109
3110          Last := Index_Type'Base (Index);
3111
3112       else
3113          --  Here Index_Type'First (and Index_Type'Last) is positive, so we
3114          --  must test the length indirectly (by working backwards from the
3115          --  largest possible value of Last), in order to prevent overflow.
3116
3117          Index := Count_Type'Base (Index_Type'Last) - Length;  -- No_Index
3118
3119          if Index < Count_Type'Base (No_Index) then
3120             raise Constraint_Error with "Length is out of range";
3121          end if;
3122
3123          --  We have determined that the value of Length would not create a
3124          --  Last index value outside of the range of Index_Type, so we can now
3125          --  safely compute its value.
3126
3127          Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3128       end if;
3129
3130       Elements := new Elements_Type (Last);
3131
3132       return Vector'(Controlled with Elements, Last, 0, 0);
3133    end To_Vector;
3134
3135    function To_Vector
3136      (New_Item : Element_Type;
3137       Length   : Count_Type) return Vector
3138    is
3139       Index    : Count_Type'Base;
3140       Last     : Index_Type'Base;
3141       Elements : Elements_Access;
3142
3143    begin
3144       if Length = 0 then
3145          return Empty_Vector;
3146       end if;
3147
3148       --  We create a vector object with a capacity that matches the specified
3149       --  Length, but we do not allow the vector capacity (the length of the
3150       --  internal array) to exceed the number of values in Index_Type'Range
3151       --  (otherwise, there would be no way to refer to those components via an
3152       --  index). We must therefore check whether the specified Length would
3153       --  create a Last index value greater than Index_Type'Last.
3154
3155       if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3156
3157          --  We perform a two-part test. First we determine whether the
3158          --  computed Last value lies in the base range of the type, and then
3159          --  determine whether it lies in the range of the index (sub)type.
3160
3161          --  Last must satisfy this relation:
3162          --    First + Length - 1 <= Last
3163          --  We regroup terms:
3164          --    First - 1 <= Last - Length
3165          --  Which can rewrite as:
3166          --    No_Index <= Last - Length
3167
3168          if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3169             raise Constraint_Error with "Length is out of range";
3170          end if;
3171
3172          --  We now know that the computed value of Last is within the base
3173          --  range of the type, so it is safe to compute its value:
3174
3175          Last := No_Index + Index_Type'Base (Length);
3176
3177          --  Finally we test whether the value is within the range of the
3178          --  generic actual index subtype:
3179
3180          if Last > Index_Type'Last then
3181             raise Constraint_Error with "Length is out of range";
3182          end if;
3183
3184       elsif Index_Type'First <= 0 then
3185          --  Here we can compute Last directly, in the normal way. We know that
3186          --  No_Index is less than 0, so there is no danger of overflow when
3187          --  adding the (positive) value of Length.
3188
3189          Index := Count_Type'Base (No_Index) + Length;  -- same value as V.Last
3190
3191          if Index > Count_Type'Base (Index_Type'Last) then
3192             raise Constraint_Error with "Length is out of range";
3193          end if;
3194
3195          --  We know that the computed value (having type Count_Type) of Last
3196          --  is within the range of the generic actual index subtype, so it is
3197          --  safe to convert to Index_Type:
3198
3199          Last := Index_Type'Base (Index);
3200
3201       else
3202          --  Here Index_Type'First (and Index_Type'Last) is positive, so we
3203          --  must test the length indirectly (by working backwards from the
3204          --  largest possible value of Last), in order to prevent overflow.
3205
3206          Index := Count_Type'Base (Index_Type'Last) - Length;  -- No_Index
3207
3208          if Index < Count_Type'Base (No_Index) then
3209             raise Constraint_Error with "Length is out of range";
3210          end if;
3211
3212          --  We have determined that the value of Length would not create a
3213          --  Last index value outside of the range of Index_Type, so we can now
3214          --  safely compute its value.
3215
3216          Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3217       end if;
3218
3219       Elements := new Elements_Type'(Last, EA => (others => New_Item));
3220
3221       return Vector'(Controlled with Elements, Last, 0, 0);
3222    end To_Vector;
3223
3224    --------------------
3225    -- Update_Element --
3226    --------------------
3227
3228    procedure Update_Element
3229      (Container : in out Vector;
3230       Index     : Index_Type;
3231       Process   : not null access procedure (Element : in out Element_Type))
3232    is
3233       B : Natural renames Container.Busy;
3234       L : Natural renames Container.Lock;
3235
3236    begin
3237       if Index > Container.Last then
3238          raise Constraint_Error with "Index is out of range";
3239       end if;
3240
3241       B := B + 1;
3242       L := L + 1;
3243
3244       begin
3245          Process (Container.Elements.EA (Index));
3246       exception
3247          when others =>
3248             L := L - 1;
3249             B := B - 1;
3250             raise;
3251       end;
3252
3253       L := L - 1;
3254       B := B - 1;
3255    end Update_Element;
3256
3257    procedure Update_Element
3258      (Container : in out Vector;
3259       Position  : Cursor;
3260       Process   : not null access procedure (Element : in out Element_Type))
3261    is
3262    begin
3263       if Position.Container = null then
3264          raise Constraint_Error with "Position cursor has no element";
3265       end if;
3266
3267       if Position.Container /= Container'Unrestricted_Access then
3268          raise Program_Error with "Position cursor denotes wrong container";
3269       end if;
3270
3271       Update_Element (Container, Position.Index, Process);
3272    end Update_Element;
3273
3274    -----------
3275    -- Write --
3276    -----------
3277
3278    procedure Write
3279      (Stream    : not null access Root_Stream_Type'Class;
3280       Container : Vector)
3281    is
3282    begin
3283       Count_Type'Base'Write (Stream, Length (Container));
3284
3285       for J in Index_Type'First .. Container.Last loop
3286          Element_Type'Write (Stream, Container.Elements.EA (J));
3287       end loop;
3288    end Write;
3289
3290    procedure Write
3291      (Stream   : not null access Root_Stream_Type'Class;
3292       Position : Cursor)
3293    is
3294    begin
3295       raise Program_Error with "attempt to stream vector cursor";
3296    end Write;
3297
3298    procedure Write
3299      (Stream : not null access Root_Stream_Type'Class;
3300       Item   : Reference_Type)
3301    is
3302    begin
3303       raise Program_Error with "attempt to stream reference";
3304    end Write;
3305
3306    procedure Write
3307      (Stream : not null access Root_Stream_Type'Class;
3308       Item   : Constant_Reference_Type)
3309    is
3310    begin
3311       raise Program_Error with "attempt to stream reference";
3312    end Write;
3313
3314 end Ada.Containers.Vectors;