1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . V E C T O R S --
9 -- Copyright (C) 2004-2010, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Containers
.Generic_Array_Sort
;
31 with Ada
.Unchecked_Deallocation
;
33 with System
; use type System
.Address
;
35 package body Ada
.Containers
.Vectors
is
38 new Ada
.Unchecked_Deallocation
(Elements_Type
, Elements_Access
);
44 function "&" (Left
, Right
: Vector
) return Vector
is
45 LN
: constant Count_Type
:= Length
(Left
);
46 RN
: constant Count_Type
:= Length
(Right
);
47 N
: Count_Type
'Base; -- length of result
48 J
: Count_Type
'Base; -- for computing intermediate index values
49 Last
: Index_Type
'Base; -- Last index of result
52 -- We decide that the capacity of the result is the sum of the lengths
53 -- of the vector parameters. We could decide to make it larger, but we
54 -- have no basis for knowing how much larger, so we just allocate the
55 -- minimum amount of storage.
57 -- Here we handle the easy cases first, when one of the vector
58 -- parameters is empty. (We say "easy" because there's nothing to
59 -- compute, that can potentially overflow.)
67 RE
: Elements_Array
renames
68 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
70 Elements
: constant Elements_Access
:=
71 new Elements_Type
'(Right.Last, RE);
74 return (Controlled with Elements, Right.Last, 0, 0);
80 LE : Elements_Array renames
81 Left.Elements.EA (Index_Type'First .. Left.Last);
83 Elements : constant Elements_Access :=
84 new Elements_Type'(Left
.Last
, LE
);
87 return (Controlled
with Elements
, Left
.Last
, 0, 0);
92 -- Neither of the vector parameters is empty, so must compute the length
93 -- of the result vector and its last index. (This is the harder case,
94 -- because our computations must avoid overflow.)
96 -- There are two constraints we need to satisfy. The first constraint is
97 -- that a container cannot have more than Count_Type'Last elements, so
98 -- we must check the sum of the combined lengths. Note that we cannot
99 -- simply add the lengths, because of the possibilty of overflow.
101 if LN
> Count_Type
'Last - RN
then
102 raise Constraint_Error
with "new length is out of range";
105 -- It is now safe compute the length of the new vector, without fear of
110 -- The second constraint is that the new Last index value cannot
111 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
112 -- Count_Type'Base as the type for intermediate values.
114 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
115 -- We perform a two-part test. First we determine whether the
116 -- computed Last value lies in the base range of the type, and then
117 -- determine whether it lies in the range of the index (sub)type.
119 -- Last must satisfy this relation:
120 -- First + Length - 1 <= Last
122 -- First - 1 <= Last - Length
123 -- Which can rewrite as:
124 -- No_Index <= Last - Length
126 if Index_Type'Base'Last
- Index_Type
'Base (N
) < No_Index
then
127 raise Constraint_Error
with "new length is out of range";
130 -- We now know that the computed value of Last is within the base
131 -- range of the type, so it is safe to compute its value:
133 Last
:= No_Index
+ Index_Type
'Base (N
);
135 -- Finally we test whether the value is within the range of the
136 -- generic actual index subtype:
138 if Last
> Index_Type
'Last then
139 raise Constraint_Error
with "new length is out of range";
142 elsif Index_Type
'First <= 0 then
143 -- Here we can compute Last directly, in the normal way. We know that
144 -- No_Index is less than 0, so there is no danger of overflow when
145 -- adding the (positive) value of length.
147 J
:= Count_Type
'Base (No_Index
) + N
; -- Last
149 if J
> Count_Type
'Base (Index_Type
'Last) then
150 raise Constraint_Error
with "new length is out of range";
153 -- We know that the computed value (having type Count_Type) of Last
154 -- is within the range of the generic actual index subtype, so it is
155 -- safe to convert to Index_Type:
157 Last
:= Index_Type
'Base (J
);
160 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
161 -- must test the length indirectly (by working backwards from the
162 -- largest possible value of Last), in order to prevent overflow.
164 J
:= Count_Type
'Base (Index_Type
'Last) - N
; -- No_Index
166 if J
< Count_Type
'Base (No_Index
) then
167 raise Constraint_Error
with "new length is out of range";
170 -- We have determined that the result length would not create a Last
171 -- index value outside of the range of Index_Type, so we can now
172 -- safely compute its value.
174 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + N
);
178 LE
: Elements_Array
renames
179 Left
.Elements
.EA
(Index_Type
'First .. Left
.Last
);
181 RE
: Elements_Array
renames
182 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
184 Elements
: constant Elements_Access
:=
185 new Elements_Type
'(Last, LE & RE);
188 return (Controlled with Elements, Last, 0, 0);
192 function "&" (Left : Vector; Right : Element_Type) return Vector is
194 -- We decide that the capacity of the result is the sum of the lengths
195 -- of the parameters. We could decide to make it larger, but we have no
196 -- basis for knowing how much larger, so we just allocate the minimum
197 -- amount of storage.
199 -- Here we handle the easy case first, when the vector parameter (Left)
202 if Left.Is_Empty then
204 Elements : constant Elements_Access :=
206 (Last
=> Index_Type
'First,
207 EA
=> (others => Right
));
210 return (Controlled
with Elements
, Index_Type
'First, 0, 0);
214 -- The vector parameter is not empty, so we must compute the length of
215 -- the result vector and its last index, but in such a way that overflow
216 -- is avoided. We must satisfy two constraints: the new length cannot
217 -- exceed Count_Type'Last, and the new Last index cannot exceed
220 if Left
.Length
= Count_Type
'Last then
221 raise Constraint_Error
with "new length is out of range";
224 if Left
.Last
>= Index_Type
'Last then
225 raise Constraint_Error
with "new length is out of range";
229 Last
: constant Index_Type
:= Left
.Last
+ 1;
231 LE
: Elements_Array
renames
232 Left
.Elements
.EA
(Index_Type
'First .. Left
.Last
);
234 Elements
: constant Elements_Access
:=
240 return (Controlled with Elements, Last, 0, 0);
244 function "&" (Left : Element_Type; Right : Vector) return Vector is
246 -- We decide that the capacity of the result is the sum of the lengths
247 -- of the parameters. We could decide to make it larger, but we have no
248 -- basis for knowing how much larger, so we just allocate the minimum
249 -- amount of storage.
251 -- Here we handle the easy case first, when the vector parameter (Right)
254 if Right.Is_Empty then
256 Elements : constant Elements_Access :=
258 (Last
=> Index_Type
'First,
259 EA
=> (others => Left
));
262 return (Controlled
with Elements
, Index_Type
'First, 0, 0);
266 -- The vector parameter is not empty, so we must compute the length of
267 -- the result vector and its last index, but in such a way that overflow
268 -- is avoided. We must satisfy two constraints: the new length cannot
269 -- exceed Count_Type'Last, and the new Last index cannot exceed
272 if Right
.Length
= Count_Type
'Last then
273 raise Constraint_Error
with "new length is out of range";
276 if Right
.Last
>= Index_Type
'Last then
277 raise Constraint_Error
with "new length is out of range";
281 Last
: constant Index_Type
:= Right
.Last
+ 1;
283 RE
: Elements_Array
renames
284 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
286 Elements
: constant Elements_Access
:=
292 return (Controlled with Elements, Last, 0, 0);
296 function "&" (Left, Right : Element_Type) return Vector is
298 -- We decide that the capacity of the result is the sum of the lengths
299 -- of the parameters. We could decide to make it larger, but we have no
300 -- basis for knowing how much larger, so we just allocate the minimum
301 -- amount of storage.
303 -- We must compute the length of the result vector and its last index,
304 -- but in such a way that overflow is avoided. We must satisfy two
305 -- constraints: the new length cannot exceed Count_Type'Last (here, we
306 -- know that that condition is satisfied), and the new Last index cannot
307 -- exceed Index_Type'Last.
309 if Index_Type'First >= Index_Type'Last then
310 raise Constraint_Error with "new length is out of range";
314 Last : constant Index_Type := Index_Type'First + 1;
316 Elements : constant Elements_Access :=
319 EA
=> (Left
, Right
));
322 return (Controlled
with Elements
, Last
, 0, 0);
330 overriding
function "=" (Left
, Right
: Vector
) return Boolean is
332 if Left
'Address = Right
'Address then
336 if Left
.Last
/= Right
.Last
then
340 for J
in Index_Type
range Index_Type
'First .. Left
.Last
loop
341 if Left
.Elements
.EA
(J
) /= Right
.Elements
.EA
(J
) then
353 procedure Adjust
(Container
: in out Vector
) is
355 if Container
.Last
= No_Index
then
356 Container
.Elements
:= null;
361 L
: constant Index_Type
:= Container
.Last
;
362 EA
: Elements_Array
renames
363 Container
.Elements
.EA
(Index_Type
'First .. L
);
366 Container
.Elements
:= null;
370 -- Note: it may seem that the following assignment to Container.Last
371 -- is useless, since we assign it to L below. However this code is
372 -- used in case 'new Elements_Type' below raises an exception, to
373 -- keep Container in a consistent state.
375 Container
.Last
:= No_Index
;
376 Container
.Elements
:= new Elements_Type
'(L, EA);
385 procedure Append (Container : in out Vector; New_Item : Vector) is
387 if Is_Empty (New_Item) then
391 if Container.Last = Index_Type'Last then
392 raise Constraint_Error with "vector is already at its maximum length";
402 (Container : in out Vector;
403 New_Item : Element_Type;
404 Count : Count_Type := 1)
411 if Container.Last = Index_Type'Last then
412 raise Constraint_Error with "vector is already at its maximum length";
426 function Capacity (Container : Vector) return Count_Type is
428 if Container.Elements = null then
432 return Container.Elements.EA'Length;
439 procedure Clear (Container : in out Vector) is
441 if Container.Busy > 0 then
442 raise Program_Error with
443 "attempt to tamper with elements (vector is busy)";
446 Container.Last := No_Index;
455 Item : Element_Type) return Boolean
458 return Find_Index (Container, Item) /= No_Index;
466 (Container : in out Vector;
467 Index : Extended_Index;
468 Count : Count_Type := 1)
470 Old_Last : constant Index_Type'Base := Container.Last;
471 New_Last : Index_Type'Base;
472 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
473 J : Index_Type'Base; -- first index of items that slide down
476 -- Delete removes items from the vector, the number of which is the
477 -- minimum of the specified Count and the items (if any) that exist from
478 -- Index to Container.Last. There are no constraints on the specified
479 -- value of Count (it can be larger than what's available at this
480 -- position in the vector, for example), but there are constraints on
481 -- the allowed values of the Index.
483 -- As a precondition on the generic actual Index_Type, the base type
484 -- must include Index_Type'Pred (Index_Type'First); this is the value
485 -- that Container.Last assumes when the vector is empty. However, we do
486 -- not allow that as the value for Index when specifying which items
487 -- should be deleted, so we must manually check. (That the user is
488 -- allowed to specify the value at all here is a consequence of the
489 -- declaration of the Extended_Index subtype, which includes the values
490 -- in the base range that immediately precede and immediately follow the
491 -- values in the Index_Type.)
493 if Index < Index_Type'First then
494 raise Constraint_Error with "Index is out of range (too small)";
497 -- We do allow a value greater than Container.Last to be specified as
498 -- the Index, but only if it's immediately greater. This allows the
499 -- corner case of deleting no items from the back end of the vector to
500 -- be treated as a no-op. (It is assumed that specifying an index value
501 -- greater than Last + 1 indicates some deeper flaw in the caller's
502 -- algorithm, so that case is treated as a proper error.)
504 if Index > Old_Last then
505 if Index > Old_Last + 1 then
506 raise Constraint_Error with "Index is out of range (too large)";
512 -- Here and elsewhere we treat deleting 0 items from the container as a
513 -- no-op, even when the container is busy, so we simply return.
519 -- The tampering bits exist to prevent an item from being deleted (or
520 -- otherwise harmfully manipulated) while it is being visited. Query,
521 -- Update, and Iterate increment the busy count on entry, and decrement
522 -- the count on exit. Delete checks the count to determine whether it is
523 -- being called while the associated callback procedure is executing.
525 if Container.Busy > 0 then
526 raise Program_Error with
527 "attempt to tamper with elements (vector is busy)";
530 -- We first calculate what's available for deletion starting at
531 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
532 -- Count_Type'Base as the type for intermediate values. (See function
533 -- Length for more information.)
535 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
536 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
539 Count2 := Count_Type'Base (Old_Last - Index + 1);
542 -- If more elements are requested (Count) for deletion than are
543 -- available (Count2) for deletion beginning at Index, then everything
544 -- from Index is deleted. There are no elements to slide down, and so
545 -- all we need to do is set the value of Container.Last.
547 if Count >= Count2 then
548 Container.Last := Index - 1;
552 -- There are some elements aren't being deleted (the requested count was
553 -- less than the available count), so we must slide them down to
554 -- Index. We first calculate the index values of the respective array
555 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
556 -- type for intermediate calculations. For the elements that slide down,
557 -- index value New_Last is the last index value of their new home, and
558 -- index value J is the first index of their old home.
560 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
561 New_Last
:= Old_Last
- Index_Type
'Base (Count
);
562 J
:= Index
+ Index_Type
'Base (Count
);
565 New_Last
:= Index_Type
'Base (Count_Type
'Base (Old_Last
) - Count
);
566 J
:= Index_Type
'Base (Count_Type
'Base (Index
) + Count
);
569 -- The internal elements array isn't guaranteed to exist unless we have
570 -- elements, but we have that guarantee here because we know we have
571 -- elements to slide. The array index values for each slice have
572 -- already been determined, so we just slide down to Index the elements
573 -- that weren't deleted.
576 EA
: Elements_Array
renames Container
.Elements
.EA
;
579 EA
(Index
.. New_Last
) := EA
(J
.. Old_Last
);
580 Container
.Last
:= New_Last
;
585 (Container
: in out Vector
;
586 Position
: in out Cursor
;
587 Count
: Count_Type
:= 1)
589 pragma Warnings
(Off
, Position
);
592 if Position
.Container
= null then
593 raise Constraint_Error
with "Position cursor has no element";
596 if Position
.Container
/= Container
'Unrestricted_Access then
597 raise Program_Error
with "Position cursor denotes wrong container";
600 if Position
.Index
> Container
.Last
then
601 raise Program_Error
with "Position index is out of range";
604 Delete
(Container
, Position
.Index
, Count
);
605 Position
:= No_Element
;
612 procedure Delete_First
613 (Container
: in out Vector
;
614 Count
: Count_Type
:= 1)
621 if Count
>= Length
(Container
) then
626 Delete
(Container
, Index_Type
'First, Count
);
633 procedure Delete_Last
634 (Container
: in out Vector
;
635 Count
: Count_Type
:= 1)
638 -- It is not permitted to delete items while the container is busy (for
639 -- example, we're in the middle of a passive iteration). However, we
640 -- always treat deleting 0 items as a no-op, even when we're busy, so we
641 -- simply return without checking.
647 -- The tampering bits exist to prevent an item from being deleted (or
648 -- otherwise harmfully manipulated) while it is being visited. Query,
649 -- Update, and Iterate increment the busy count on entry, and decrement
650 -- the count on exit. Delete_Last checks the count to determine whether
651 -- it is being called while the associated callback procedure is
654 if Container
.Busy
> 0 then
655 raise Program_Error
with
656 "attempt to tamper with elements (vector is busy)";
659 -- There is no restriction on how large Count can be when deleting
660 -- items. If it is equal or greater than the current length, then this
661 -- is equivalent to clearing the vector. (In particular, there's no need
662 -- for us to actually calculate the new value for Last.)
664 -- If the requested count is less than the current length, then we must
665 -- calculate the new value for Last. For the type we use the widest of
666 -- Index_Type'Base and Count_Type'Base for the intermediate values of
667 -- our calculation. (See the comments in Length for more information.)
669 if Count
>= Container
.Length
then
670 Container
.Last
:= No_Index
;
672 elsif Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
673 Container.Last := Container.Last - Index_Type'Base (Count);
677 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
687 Index : Index_Type) return Element_Type
690 if Index > Container.Last then
691 raise Constraint_Error with "Index is out of range";
694 return Container.Elements.EA (Index);
697 function Element (Position : Cursor) return Element_Type is
699 if Position.Container = null then
700 raise Constraint_Error with "Position cursor has no element";
703 if Position.Index > Position.Container.Last then
704 raise Constraint_Error with "Position cursor is out of range";
707 return Position.Container.Elements.EA (Position.Index);
714 procedure Finalize (Container : in out Vector) is
715 X : Elements_Access := Container.Elements;
718 if Container.Busy > 0 then
719 raise Program_Error with
720 "attempt to tamper with elements (vector is busy)";
723 Container.Elements := null;
724 Container.Last := No_Index;
735 Position : Cursor := No_Element) return Cursor
738 if Position.Container /= null then
739 if Position.Container /= Container'Unrestricted_Access then
740 raise Program_Error with "Position cursor denotes wrong container";
743 if Position.Index > Container.Last then
744 raise Program_Error with "Position index is out of range";
748 for J in Position.Index .. Container.Last loop
749 if Container.Elements.EA (J) = Item then
750 return (Container'Unchecked_Access, J);
764 Index : Index_Type := Index_Type'First) return Extended_Index
767 for Indx in Index .. Container.Last loop
768 if Container.Elements.EA (Indx) = Item then
780 function First (Container : Vector) return Cursor is
782 if Is_Empty (Container) then
786 return (Container'Unchecked_Access, Index_Type'First);
793 function First_Element (Container : Vector) return Element_Type is
795 if Container.Last = No_Index then
796 raise Constraint_Error with "Container is empty";
799 return Container.Elements.EA (Index_Type'First);
806 function First_Index (Container : Vector) return Index_Type is
807 pragma Unreferenced (Container);
809 return Index_Type'First;
812 ---------------------
813 -- Generic_Sorting --
814 ---------------------
816 package body Generic_Sorting is
822 function Is_Sorted (Container : Vector) return Boolean is
824 if Container.Last <= Index_Type'First then
829 EA : Elements_Array renames Container.Elements.EA;
831 for I in Index_Type'First .. Container.Last - 1 loop
832 if EA (I + 1) < EA (I) then
845 procedure Merge (Target, Source : in out Vector) is
846 I : Index_Type'Base := Target.Last;
850 if Target.Last < Index_Type'First then
851 Move (Target => Target, Source => Source);
855 if Target'Address = Source'Address then
859 if Source.Last < Index_Type'First then
863 if Source.Busy > 0 then
864 raise Program_Error with
865 "attempt to tamper with elements (vector is busy)";
868 Target.Set_Length (Length (Target) + Length (Source));
871 TA : Elements_Array renames Target.Elements.EA;
872 SA : Elements_Array renames Source.Elements.EA;
876 while Source.Last >= Index_Type'First loop
877 pragma Assert (Source.Last <= Index_Type'First
878 or else not (SA (Source.Last) <
879 SA (Source.Last - 1)));
881 if I < Index_Type'First then
882 TA (Index_Type'First .. J) :=
883 SA (Index_Type'First .. Source.Last);
885 Source.Last := No_Index;
889 pragma Assert (I <= Index_Type'First
890 or else not (TA (I) < TA (I - 1)));
892 if SA (Source.Last) < TA (I) then
897 TA (J) := SA (Source.Last);
898 Source.Last := Source.Last - 1;
910 procedure Sort (Container : in out Vector)
913 new Generic_Array_Sort
914 (Index_Type => Index_Type,
915 Element_Type => Element_Type,
916 Array_Type => Elements_Array,
920 if Container.Last <= Index_Type'First then
924 if Container.Lock > 0 then
925 raise Program_Error with
926 "attempt to tamper with cursors (vector is locked)";
929 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
938 function Has_Element (Position : Cursor) return Boolean is
940 if Position.Container = null then
944 return Position.Index <= Position.Container.Last;
952 (Container : in out Vector;
953 Before : Extended_Index;
954 New_Item : Element_Type;
955 Count : Count_Type := 1)
957 Old_Length : constant Count_Type := Container.Length;
959 Max_Length : Count_Type'Base; -- determined from range of Index_Type
960 New_Length : Count_Type'Base; -- sum of current length and Count
961 New_Last : Index_Type'Base; -- last index of vector after insertion
963 Index : Index_Type'Base; -- scratch for intermediate values
964 J : Count_Type'Base; -- scratch
966 New_Capacity : Count_Type'Base; -- length of new, expanded array
967 Dst_Last : Index_Type'Base; -- last index of new, expanded array
968 Dst : Elements_Access; -- new, expanded internal array
971 -- As a precondition on the generic actual Index_Type, the base type
972 -- must include Index_Type'Pred (Index_Type'First); this is the value
973 -- that Container.Last assumes when the vector is empty. However, we do
974 -- not allow that as the value for Index when specifying where the new
975 -- items should be inserted, so we must manually check. (That the user
976 -- is allowed to specify the value at all here is a consequence of the
977 -- declaration of the Extended_Index subtype, which includes the values
978 -- in the base range that immediately precede and immediately follow the
979 -- values in the Index_Type.)
981 if Before < Index_Type'First then
982 raise Constraint_Error with
983 "Before index is out of range (too small)";
986 -- We do allow a value greater than Container.Last to be specified as
987 -- the Index, but only if it's immediately greater. This allows for the
988 -- case of appending items to the back end of the vector. (It is assumed
989 -- that specifying an index value greater than Last + 1 indicates some
990 -- deeper flaw in the caller's algorithm, so that case is treated as a
993 if Before > Container.Last
994 and then Before > Container.Last + 1
996 raise Constraint_Error with
997 "Before index is out of range (too large)";
1000 -- We treat inserting 0 items into the container as a no-op, even when
1001 -- the container is busy, so we simply return.
1007 -- There are two constraints we need to satisfy. The first constraint is
1008 -- that a container cannot have more than Count_Type'Last elements, so
1009 -- we must check the sum of the current length and the insertion
1010 -- count. Note that we cannot simply add these values, because of the
1011 -- possibilty of overflow.
1013 if Old_Length > Count_Type'Last - Count then
1014 raise Constraint_Error with "Count is out of range";
1017 -- It is now safe compute the length of the new vector, without fear of
1020 New_Length := Old_Length + Count;
1022 -- The second constraint is that the new Last index value cannot exceed
1023 -- Index_Type'Last. In each branch below, we calculate the maximum
1024 -- length (computed from the range of values in Index_Type), and then
1025 -- compare the new length to the maximum length. If the new length is
1026 -- acceptable, then we compute the new last index from that.
1028 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1029 -- We have to handle the case when there might be more values in the
1030 -- range of Index_Type than in the range of Count_Type.
1032 if Index_Type
'First <= 0 then
1033 -- We know that No_Index (the same as Index_Type'First - 1) is
1034 -- less than 0, so it is safe to compute the following sum without
1035 -- fear of overflow.
1037 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1039 if Index
<= Index_Type
'Last then
1040 -- We have determined that range of Index_Type has at least as
1041 -- many values as in Count_Type, so Count_Type'Last is the
1042 -- maximum number of items that are allowed.
1044 Max_Length
:= Count_Type
'Last;
1047 -- The range of Index_Type has fewer values than in Count_Type,
1048 -- so the maximum number of items is computed from the range of
1051 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1055 -- No_Index is equal or greater than 0, so we can safely compute
1056 -- the difference without fear of overflow (which we would have to
1057 -- worry about if No_Index were less than 0, but that case is
1060 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1063 elsif Index_Type
'First <= 0 then
1064 -- We know that No_Index (the same as Index_Type'First - 1) is less
1065 -- than 0, so it is safe to compute the following sum without fear of
1068 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
1070 if J
<= Count_Type
'Base (Index_Type
'Last) then
1071 -- We have determined that range of Index_Type has at least as
1072 -- many values as in Count_Type, so Count_Type'Last is the maximum
1073 -- number of items that are allowed.
1075 Max_Length
:= Count_Type
'Last;
1078 -- The range of Index_Type has fewer values than Count_Type does,
1079 -- so the maximum number of items is computed from the range of
1083 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1087 -- No_Index is equal or greater than 0, so we can safely compute the
1088 -- difference without fear of overflow (which we would have to worry
1089 -- about if No_Index were less than 0, but that case is handled
1093 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1096 -- We have just computed the maximum length (number of items). We must
1097 -- now compare the requested length to the maximum length, as we do not
1098 -- allow a vector expand beyond the maximum (because that would create
1099 -- an internal array with a last index value greater than
1100 -- Index_Type'Last, with no way to index those elements).
1102 if New_Length
> Max_Length
then
1103 raise Constraint_Error
with "Count is out of range";
1106 -- New_Last is the last index value of the items in the container after
1107 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1108 -- compute its value from the New_Length.
1110 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1111 New_Last := No_Index + Index_Type'Base (New_Length);
1114 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1117 if Container.Elements = null then
1118 pragma Assert (Container.Last = No_Index);
1120 -- This is the simplest case, with which we must always begin: we're
1121 -- inserting items into an empty vector that hasn't allocated an
1122 -- internal array yet. Note that we don't need to check the busy bit
1123 -- here, because an empty container cannot be busy.
1125 -- In order to preserve container invariants, we allocate the new
1126 -- internal array first, before setting the Last index value, in case
1127 -- the allocation fails (which can happen either because there is no
1128 -- storage available, or because element initialization fails).
1130 Container.Elements := new Elements_Type'
1132 EA
=> (others => New_Item
));
1134 -- The allocation of the new, internal array succeeded, so it is now
1135 -- safe to update the Last index, restoring container invariants.
1137 Container
.Last
:= New_Last
;
1142 -- The tampering bits exist to prevent an item from being harmfully
1143 -- manipulated while it is being visited. Query, Update, and Iterate
1144 -- increment the busy count on entry, and decrement the count on
1145 -- exit. Insert checks the count to determine whether it is being called
1146 -- while the associated callback procedure is executing.
1148 if Container
.Busy
> 0 then
1149 raise Program_Error
with
1150 "attempt to tamper with elements (vector is busy)";
1153 -- An internal array has already been allocated, so we must determine
1154 -- whether there is enough unused storage for the new items.
1156 if New_Length
<= Container
.Elements
.EA
'Length then
1157 -- In this case, we're inserting elements into a vector that has
1158 -- already allocated an internal array, and the existing array has
1159 -- enough unused storage for the new items.
1162 EA
: Elements_Array
renames Container
.Elements
.EA
;
1165 if Before
> Container
.Last
then
1166 -- The new items are being appended to the vector, so no
1167 -- sliding of existing elements is required.
1169 EA
(Before
.. New_Last
) := (others => New_Item
);
1172 -- The new items are being inserted before some existing
1173 -- elements, so we must slide the existing elements up to their
1174 -- new home. We use the wider of Index_Type'Base and
1175 -- Count_Type'Base as the type for intermediate index values.
1177 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1178 Index := Before + Index_Type'Base (Count);
1181 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1184 EA (Index .. New_Last) := EA (Before .. Container.Last);
1185 EA (Before .. Index - 1) := (others => New_Item);
1189 Container.Last := New_Last;
1193 -- In this case, we're inserting elements into a vector that has already
1194 -- allocated an internal array, but the existing array does not have
1195 -- enough storage, so we must allocate a new, longer array. In order to
1196 -- guarantee that the amortized insertion cost is O(1), we always
1197 -- allocate an array whose length is some power-of-two factor of the
1198 -- current array length. (The new array cannot have a length less than
1199 -- the New_Length of the container, but its last index value cannot be
1200 -- greater than Index_Type'Last.)
1202 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1203 while New_Capacity < New_Length loop
1204 if New_Capacity > Count_Type'Last / 2 then
1205 New_Capacity := Count_Type'Last;
1209 New_Capacity := 2 * New_Capacity;
1212 if New_Capacity > Max_Length then
1213 -- We have reached the limit of capacity, so no further expansion
1214 -- will occur. (This is not a problem, as there is never a need to
1215 -- have more capacity than the maximum container length.)
1217 New_Capacity := Max_Length;
1220 -- We have computed the length of the new internal array (and this is
1221 -- what "vector capacity" means), so use that to compute its last index.
1223 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1224 Dst_Last
:= No_Index
+ Index_Type
'Base (New_Capacity
);
1228 Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Capacity
);
1231 -- Now we allocate the new, longer internal array. If the allocation
1232 -- fails, we have not changed any container state, so no side-effect
1233 -- will occur as a result of propagating the exception.
1235 Dst
:= new Elements_Type
(Dst_Last
);
1237 -- We have our new internal array. All that needs to be done now is to
1238 -- copy the existing items (if any) from the old array (the "source"
1239 -- array, object SA below) to the new array (the "destination" array,
1240 -- object DA below), and then deallocate the old array.
1243 SA
: Elements_Array
renames Container
.Elements
.EA
; -- source
1244 DA
: Elements_Array
renames Dst
.EA
; -- destination
1247 DA
(Index_Type
'First .. Before
- 1) :=
1248 SA
(Index_Type
'First .. Before
- 1);
1250 if Before
> Container
.Last
then
1251 DA
(Before
.. New_Last
) := (others => New_Item
);
1254 -- The new items are being inserted before some existing elements,
1255 -- so we must slide the existing elements up to their new home.
1257 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1258 Index := Before + Index_Type'Base (Count);
1261 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1264 DA (Before .. Index - 1) := (others => New_Item);
1265 DA (Index .. New_Last) := SA (Before .. Container.Last);
1273 -- We have successfully copied the items onto the new array, so the
1274 -- final thing to do is deallocate the old array.
1277 X : Elements_Access := Container.Elements;
1279 -- We first isolate the old internal array, removing it from the
1280 -- container and replacing it with the new internal array, before we
1281 -- deallocate the old array (which can fail if finalization of
1282 -- elements propagates an exception).
1284 Container.Elements := Dst;
1285 Container.Last := New_Last;
1287 -- The container invariants have been restored, so it is now safe to
1288 -- attempt to deallocate the old array.
1295 (Container : in out Vector;
1296 Before : Extended_Index;
1299 N : constant Count_Type := Length (New_Item);
1300 J : Index_Type'Base;
1303 -- Use Insert_Space to create the "hole" (the destination slice) into
1304 -- which we copy the source items.
1306 Insert_Space (Container, Before, Count => N);
1309 -- There's nothing else to do here (vetting of parameters was
1310 -- performed already in Insert_Space), so we simply return.
1315 -- We calculate the last index value of the destination slice using the
1316 -- wider of Index_Type'Base and count_Type'Base.
1318 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1319 J
:= (Before
- 1) + Index_Type
'Base (N
);
1322 J
:= Index_Type
'Base (Count_Type
'Base (Before
- 1) + N
);
1325 if Container
'Address /= New_Item
'Address then
1326 -- This is the simple case. New_Item denotes an object different
1327 -- from Container, so there's nothing special we need to do to copy
1328 -- the source items to their destination, because all of the source
1329 -- items are contiguous.
1331 Container
.Elements
.EA
(Before
.. J
) :=
1332 New_Item
.Elements
.EA
(Index_Type
'First .. New_Item
.Last
);
1337 -- New_Item denotes the same object as Container, so an insertion has
1338 -- potentially split the source items. The destination is always the
1339 -- range [Before, J], but the source is [Index_Type'First, Before) and
1340 -- (J, Container.Last]. We perform the copy in two steps, using each of
1341 -- the two slices of the source items.
1344 L
: constant Index_Type
'Base := Before
- 1;
1346 subtype Src_Index_Subtype
is Index_Type
'Base range
1347 Index_Type
'First .. L
;
1349 Src
: Elements_Array
renames
1350 Container
.Elements
.EA
(Src_Index_Subtype
);
1352 K
: Index_Type
'Base;
1355 -- We first copy the source items that precede the space we
1356 -- inserted. Index value K is the last index of that portion
1357 -- destination that receives this slice of the source. (If Before
1358 -- equals Index_Type'First, then this first source slice will be
1359 -- empty, which is harmless.)
1361 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1362 K := L + Index_Type'Base (Src'Length);
1365 K := Index_Type'Base (Count_Type'Base (L) + Src'Length);
1368 Container.Elements.EA (Before .. K) := Src;
1370 if Src'Length = N then
1371 -- The new items were effectively appended to the container, so we
1372 -- have already copied all of the items that need to be copied.
1373 -- We return early here, even though the source slice below is
1374 -- empty (so the assignment would be harmless), because we want to
1375 -- avoid computing J + 1, which will overflow if J equals
1376 -- Index_Type'Base'Last
.
1383 -- Note that we want to avoid computing J + 1 here, in case J equals
1384 -- Index_Type'Base'Last. We prevent that by returning early above,
1385 -- immediately after copying the first slice of the source, and
1386 -- determining that this second slice of the source is empty.
1388 F
: constant Index_Type
'Base := J
+ 1;
1390 subtype Src_Index_Subtype
is Index_Type
'Base range
1391 F
.. Container
.Last
;
1393 Src
: Elements_Array
renames
1394 Container
.Elements
.EA
(Src_Index_Subtype
);
1396 K
: Index_Type
'Base;
1399 -- We next copy the source items that follow the space we
1400 -- inserted. Index value K is the first index of that portion of the
1401 -- destination that receives this slice of the source. (For the
1402 -- reasons given above, this slice is guaranteed to be non-empty.)
1404 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1405 K := F - Index_Type'Base (Src'Length);
1408 K := Index_Type'Base (Count_Type'Base (F) - Src'Length);
1411 Container.Elements.EA (K .. J) := Src;
1416 (Container : in out Vector;
1420 Index : Index_Type'Base;
1423 if Before.Container /= null
1424 and then Before.Container /= Container'Unchecked_Access
1426 raise Program_Error with "Before cursor denotes wrong container";
1429 if Is_Empty (New_Item) then
1433 if Before.Container = null
1434 or else Before.Index > Container.Last
1436 if Container.Last = Index_Type'Last then
1437 raise Constraint_Error with
1438 "vector is already at its maximum length";
1441 Index := Container.Last + 1;
1444 Index := Before.Index;
1447 Insert (Container, Index, New_Item);
1451 (Container : in out Vector;
1454 Position : out Cursor)
1456 Index : Index_Type'Base;
1459 if Before.Container /= null
1460 and then Before.Container /= Container'Unchecked_Access
1462 raise Program_Error with "Before cursor denotes wrong container";
1465 if Is_Empty (New_Item) then
1466 if Before.Container = null
1467 or else Before.Index > Container.Last
1469 Position := No_Element;
1471 Position := (Container'Unchecked_Access, Before.Index);
1477 if Before.Container = null
1478 or else Before.Index > Container.Last
1480 if Container.Last = Index_Type'Last then
1481 raise Constraint_Error with
1482 "vector is already at its maximum length";
1485 Index := Container.Last + 1;
1488 Index := Before.Index;
1491 Insert (Container, Index, New_Item);
1493 Position := Cursor'(Container
'Unchecked_Access, Index
);
1497 (Container
: in out Vector
;
1499 New_Item
: Element_Type
;
1500 Count
: Count_Type
:= 1)
1502 Index
: Index_Type
'Base;
1505 if Before
.Container
/= null
1506 and then Before
.Container
/= Container
'Unchecked_Access
1508 raise Program_Error
with "Before cursor denotes wrong container";
1515 if Before
.Container
= null
1516 or else Before
.Index
> Container
.Last
1518 if Container
.Last
= Index_Type
'Last then
1519 raise Constraint_Error
with
1520 "vector is already at its maximum length";
1523 Index
:= Container
.Last
+ 1;
1526 Index
:= Before
.Index
;
1529 Insert
(Container
, Index
, New_Item
, Count
);
1533 (Container
: in out Vector
;
1535 New_Item
: Element_Type
;
1536 Position
: out Cursor
;
1537 Count
: Count_Type
:= 1)
1539 Index
: Index_Type
'Base;
1542 if Before
.Container
/= null
1543 and then Before
.Container
/= Container
'Unchecked_Access
1545 raise Program_Error
with "Before cursor denotes wrong container";
1549 if Before
.Container
= null
1550 or else Before
.Index
> Container
.Last
1552 Position
:= No_Element
;
1554 Position
:= (Container
'Unchecked_Access, Before
.Index
);
1560 if Before
.Container
= null
1561 or else Before
.Index
> Container
.Last
1563 if Container
.Last
= Index_Type
'Last then
1564 raise Constraint_Error
with
1565 "vector is already at its maximum length";
1568 Index
:= Container
.Last
+ 1;
1571 Index
:= Before
.Index
;
1574 Insert
(Container
, Index
, New_Item
, Count
);
1576 Position
:= Cursor
'(Container'Unchecked_Access, Index);
1580 (Container : in out Vector;
1581 Before : Extended_Index;
1582 Count : Count_Type := 1)
1584 New_Item : Element_Type; -- Default-initialized value
1585 pragma Warnings (Off, New_Item);
1588 Insert (Container, Before, New_Item, Count);
1592 (Container : in out Vector;
1594 Position : out Cursor;
1595 Count : Count_Type := 1)
1597 New_Item : Element_Type; -- Default-initialized value
1598 pragma Warnings (Off, New_Item);
1601 Insert (Container, Before, New_Item, Position, Count);
1608 procedure Insert_Space
1609 (Container : in out Vector;
1610 Before : Extended_Index;
1611 Count : Count_Type := 1)
1613 Old_Length : constant Count_Type := Container.Length;
1615 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1616 New_Length : Count_Type'Base; -- sum of current length and Count
1617 New_Last : Index_Type'Base; -- last index of vector after insertion
1619 Index : Index_Type'Base; -- scratch for intermediate values
1620 J : Count_Type'Base; -- scratch
1622 New_Capacity : Count_Type'Base; -- length of new, expanded array
1623 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1624 Dst : Elements_Access; -- new, expanded internal array
1627 -- As a precondition on the generic actual Index_Type, the base type
1628 -- must include Index_Type'Pred (Index_Type'First); this is the value
1629 -- that Container.Last assumes when the vector is empty. However, we do
1630 -- not allow that as the value for Index when specifying where the new
1631 -- items should be inserted, so we must manually check. (That the user
1632 -- is allowed to specify the value at all here is a consequence of the
1633 -- declaration of the Extended_Index subtype, which includes the values
1634 -- in the base range that immediately precede and immediately follow the
1635 -- values in the Index_Type.)
1637 if Before < Index_Type'First then
1638 raise Constraint_Error with
1639 "Before index is out of range (too small)";
1642 -- We do allow a value greater than Container.Last to be specified as
1643 -- the Index, but only if it's immediately greater. This allows for the
1644 -- case of appending items to the back end of the vector. (It is assumed
1645 -- that specifying an index value greater than Last + 1 indicates some
1646 -- deeper flaw in the caller's algorithm, so that case is treated as a
1649 if Before > Container.Last
1650 and then Before > Container.Last + 1
1652 raise Constraint_Error with
1653 "Before index is out of range (too large)";
1656 -- We treat inserting 0 items into the container as a no-op, even when
1657 -- the container is busy, so we simply return.
1663 -- There are two constraints we need to satisfy. The first constraint is
1664 -- that a container cannot have more than Count_Type'Last elements, so
1665 -- we must check the sum of the current length and the insertion
1666 -- count. Note that we cannot simply add these values, because of the
1667 -- possibilty of overflow.
1669 if Old_Length > Count_Type'Last - Count then
1670 raise Constraint_Error with "Count is out of range";
1673 -- It is now safe compute the length of the new vector, without fear of
1676 New_Length := Old_Length + Count;
1678 -- The second constraint is that the new Last index value cannot exceed
1679 -- Index_Type'Last. In each branch below, we calculate the maximum
1680 -- length (computed from the range of values in Index_Type), and then
1681 -- compare the new length to the maximum length. If the new length is
1682 -- acceptable, then we compute the new last index from that.
1684 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1685 -- We have to handle the case when there might be more values in the
1686 -- range of Index_Type than in the range of Count_Type.
1688 if Index_Type
'First <= 0 then
1689 -- We know that No_Index (the same as Index_Type'First - 1) is
1690 -- less than 0, so it is safe to compute the following sum without
1691 -- fear of overflow.
1693 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1695 if Index
<= Index_Type
'Last then
1696 -- We have determined that range of Index_Type has at least as
1697 -- many values as in Count_Type, so Count_Type'Last is the
1698 -- maximum number of items that are allowed.
1700 Max_Length
:= Count_Type
'Last;
1703 -- The range of Index_Type has fewer values than in Count_Type,
1704 -- so the maximum number of items is computed from the range of
1707 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1711 -- No_Index is equal or greater than 0, so we can safely compute
1712 -- the difference without fear of overflow (which we would have to
1713 -- worry about if No_Index were less than 0, but that case is
1716 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1719 elsif Index_Type
'First <= 0 then
1720 -- We know that No_Index (the same as Index_Type'First - 1) is less
1721 -- than 0, so it is safe to compute the following sum without fear of
1724 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
1726 if J
<= Count_Type
'Base (Index_Type
'Last) then
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 maximum
1729 -- number of items that are allowed.
1731 Max_Length
:= Count_Type
'Last;
1734 -- The range of Index_Type has fewer values than Count_Type does,
1735 -- so the maximum number of items is computed from the range of
1739 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1743 -- No_Index is equal or greater than 0, so we can safely compute the
1744 -- difference without fear of overflow (which we would have to worry
1745 -- about if No_Index were less than 0, but that case is handled
1749 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1752 -- We have just computed the maximum length (number of items). We must
1753 -- now compare the requested length to the maximum length, as we do not
1754 -- allow a vector expand beyond the maximum (because that would create
1755 -- an internal array with a last index value greater than
1756 -- Index_Type'Last, with no way to index those elements).
1758 if New_Length
> Max_Length
then
1759 raise Constraint_Error
with "Count is out of range";
1762 -- New_Last is the last index value of the items in the container after
1763 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1764 -- compute its value from the New_Length.
1766 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1767 New_Last := No_Index + Index_Type'Base (New_Length);
1770 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1773 if Container.Elements = null then
1774 pragma Assert (Container.Last = No_Index);
1776 -- This is the simplest case, with which we must always begin: we're
1777 -- inserting items into an empty vector that hasn't allocated an
1778 -- internal array yet. Note that we don't need to check the busy bit
1779 -- here, because an empty container cannot be busy.
1781 -- In order to preserve container invariants, we allocate the new
1782 -- internal array first, before setting the Last index value, in case
1783 -- the allocation fails (which can happen either because there is no
1784 -- storage available, or because default-valued element
1785 -- initialization fails).
1787 Container.Elements := new Elements_Type (New_Last);
1789 -- The allocation of the new, internal array succeeded, so it is now
1790 -- safe to update the Last index, restoring container invariants.
1792 Container.Last := New_Last;
1797 -- The tampering bits exist to prevent an item from being harmfully
1798 -- manipulated while it is being visited. Query, Update, and Iterate
1799 -- increment the busy count on entry, and decrement the count on
1800 -- exit. Insert checks the count to determine whether it is being called
1801 -- while the associated callback procedure is executing.
1803 if Container.Busy > 0 then
1804 raise Program_Error with
1805 "attempt to tamper with elements (vector is busy)";
1808 -- An internal array has already been allocated, so we must determine
1809 -- whether there is enough unused storage for the new items.
1811 if New_Last <= Container.Elements.Last then
1812 -- In this case, we're inserting space into a vector that has already
1813 -- allocated an internal array, and the existing array has enough
1814 -- unused storage for the new items.
1817 EA : Elements_Array renames Container.Elements.EA;
1820 if Before <= Container.Last then
1821 -- The space is being inserted before some existing elements,
1822 -- so we must slide the existing elements up to their new
1823 -- home. We use the wider of Index_Type'Base and
1824 -- Count_Type'Base as the type for intermediate index values.
1826 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1827 Index
:= Before
+ Index_Type
'Base (Count
);
1830 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
1833 EA
(Index
.. New_Last
) := EA
(Before
.. Container
.Last
);
1837 Container
.Last
:= New_Last
;
1841 -- In this case, we're inserting space into a vector that has already
1842 -- allocated an internal array, but the existing array does not have
1843 -- enough storage, so we must allocate a new, longer array. In order to
1844 -- guarantee that the amortized insertion cost is O(1), we always
1845 -- allocate an array whose length is some power-of-two factor of the
1846 -- current array length. (The new array cannot have a length less than
1847 -- the New_Length of the container, but its last index value cannot be
1848 -- greater than Index_Type'Last.)
1850 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
1851 while New_Capacity
< New_Length
loop
1852 if New_Capacity
> Count_Type
'Last / 2 then
1853 New_Capacity
:= Count_Type
'Last;
1857 New_Capacity
:= 2 * New_Capacity
;
1860 if New_Capacity
> Max_Length
then
1861 -- We have reached the limit of capacity, so no further expansion
1862 -- will occur. (This is not a problem, as there is never a need to
1863 -- have more capacity than the maximum container length.)
1865 New_Capacity
:= Max_Length
;
1868 -- We have computed the length of the new internal array (and this is
1869 -- what "vector capacity" means), so use that to compute its last index.
1871 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1872 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1876 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1879 -- Now we allocate the new, longer internal array. If the allocation
1880 -- fails, we have not changed any container state, so no side-effect
1881 -- will occur as a result of propagating the exception.
1883 Dst := new Elements_Type (Dst_Last);
1885 -- We have our new internal array. All that needs to be done now is to
1886 -- copy the existing items (if any) from the old array (the "source"
1887 -- array, object SA below) to the new array (the "destination" array,
1888 -- object DA below), and then deallocate the old array.
1891 SA : Elements_Array renames Container.Elements.EA; -- source
1892 DA : Elements_Array renames Dst.EA; -- destination
1895 DA (Index_Type'First .. Before - 1) :=
1896 SA (Index_Type'First .. Before - 1);
1898 if Before <= Container.Last then
1899 -- The space is being inserted before some existing elements, so
1900 -- we must slide the existing elements up to their new home.
1902 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1903 Index
:= Before
+ Index_Type
'Base (Count
);
1906 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
1909 DA
(Index
.. New_Last
) := SA
(Before
.. Container
.Last
);
1917 -- We have successfully copied the items onto the new array, so the
1918 -- final thing to do is restore invariants, and deallocate the old
1922 X
: Elements_Access
:= Container
.Elements
;
1924 -- We first isolate the old internal array, removing it from the
1925 -- container and replacing it with the new internal array, before we
1926 -- deallocate the old array (which can fail if finalization of
1927 -- elements propagates an exception).
1929 Container
.Elements
:= Dst
;
1930 Container
.Last
:= New_Last
;
1932 -- The container invariants have been restored, so it is now safe to
1933 -- attempt to deallocate the old array.
1939 procedure Insert_Space
1940 (Container
: in out Vector
;
1942 Position
: out Cursor
;
1943 Count
: Count_Type
:= 1)
1945 Index
: Index_Type
'Base;
1948 if Before
.Container
/= null
1949 and then Before
.Container
/= Container
'Unchecked_Access
1951 raise Program_Error
with "Before cursor denotes wrong container";
1955 if Before
.Container
= null
1956 or else Before
.Index
> Container
.Last
1958 Position
:= No_Element
;
1960 Position
:= (Container
'Unchecked_Access, Before
.Index
);
1966 if Before
.Container
= null
1967 or else Before
.Index
> Container
.Last
1969 if Container
.Last
= Index_Type
'Last then
1970 raise Constraint_Error
with
1971 "vector is already at its maximum length";
1974 Index
:= Container
.Last
+ 1;
1977 Index
:= Before
.Index
;
1980 Insert_Space
(Container
, Index
, Count
=> Count
);
1982 Position
:= Cursor
'(Container'Unchecked_Access, Index);
1989 function Is_Empty (Container : Vector) return Boolean is
1991 return Container.Last < Index_Type'First;
1999 (Container : Vector;
2000 Process : not null access procedure (Position : Cursor))
2002 V : Vector renames Container'Unrestricted_Access.all;
2003 B : Natural renames V.Busy;
2009 for Indx in Index_Type'First .. Container.Last loop
2010 Process (Cursor'(Container
'Unchecked_Access, Indx
));
2025 function Last
(Container
: Vector
) return Cursor
is
2027 if Is_Empty
(Container
) then
2031 return (Container
'Unchecked_Access, Container
.Last
);
2038 function Last_Element
(Container
: Vector
) return Element_Type
is
2040 if Container
.Last
= No_Index
then
2041 raise Constraint_Error
with "Container is empty";
2044 return Container
.Elements
.EA
(Container
.Last
);
2051 function Last_Index
(Container
: Vector
) return Extended_Index
is
2053 return Container
.Last
;
2060 function Length
(Container
: Vector
) return Count_Type
is
2061 L
: constant Index_Type
'Base := Container
.Last
;
2062 F
: constant Index_Type
:= Index_Type
'First;
2065 -- The base range of the index type (Index_Type'Base) might not include
2066 -- all values for length (Count_Type). Contrariwise, the index type
2067 -- might include values outside the range of length. Hence we use
2068 -- whatever type is wider for intermediate values when calculating
2069 -- length. Note that no matter what the index type is, the maximum
2070 -- length to which a vector is allowed to grow is always the minimum
2071 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2073 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2074 -- to have a base range of -128 .. 127, but the corresponding vector
2075 -- would have lengths in the range 0 .. 255. In this case we would need
2076 -- to use Count_Type'Base for intermediate values.
2078 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2079 -- vector would have a maximum length of 10, but the index values lie
2080 -- outside the range of Count_Type (which is only 32 bits). In this
2081 -- case we would need to use Index_Type'Base for intermediate values.
2083 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
2084 return Count_Type
'Base (L
) - Count_Type
'Base (F
) + 1;
2086 return Count_Type
(L
- F
+ 1);
2095 (Target
: in out Vector
;
2096 Source
: in out Vector
)
2099 if Target
'Address = Source
'Address then
2103 if Target
.Busy
> 0 then
2104 raise Program_Error
with
2105 "attempt to tamper with elements (Target is busy)";
2108 if Source
.Busy
> 0 then
2109 raise Program_Error
with
2110 "attempt to tamper with elements (Source is busy)";
2114 Target_Elements
: constant Elements_Access
:= Target
.Elements
;
2116 Target
.Elements
:= Source
.Elements
;
2117 Source
.Elements
:= Target_Elements
;
2120 Target
.Last
:= Source
.Last
;
2121 Source
.Last
:= No_Index
;
2128 function Next
(Position
: Cursor
) return Cursor
is
2130 if Position
.Container
= null then
2134 if Position
.Index
< Position
.Container
.Last
then
2135 return (Position
.Container
, Position
.Index
+ 1);
2145 procedure Next
(Position
: in out Cursor
) is
2147 if Position
.Container
= null then
2151 if Position
.Index
< Position
.Container
.Last
then
2152 Position
.Index
:= Position
.Index
+ 1;
2154 Position
:= No_Element
;
2162 procedure Prepend
(Container
: in out Vector
; New_Item
: Vector
) is
2164 Insert
(Container
, Index_Type
'First, New_Item
);
2168 (Container
: in out Vector
;
2169 New_Item
: Element_Type
;
2170 Count
: Count_Type
:= 1)
2183 procedure Previous
(Position
: in out Cursor
) is
2185 if Position
.Container
= null then
2189 if Position
.Index
> Index_Type
'First then
2190 Position
.Index
:= Position
.Index
- 1;
2192 Position
:= No_Element
;
2196 function Previous
(Position
: Cursor
) return Cursor
is
2198 if Position
.Container
= null then
2202 if Position
.Index
> Index_Type
'First then
2203 return (Position
.Container
, Position
.Index
- 1);
2213 procedure Query_Element
2214 (Container
: Vector
;
2216 Process
: not null access procedure (Element
: Element_Type
))
2218 V
: Vector
renames Container
'Unrestricted_Access.all;
2219 B
: Natural renames V
.Busy
;
2220 L
: Natural renames V
.Lock
;
2223 if Index
> Container
.Last
then
2224 raise Constraint_Error
with "Index is out of range";
2231 Process
(V
.Elements
.EA
(Index
));
2243 procedure Query_Element
2245 Process
: not null access procedure (Element
: Element_Type
))
2248 if Position
.Container
= null then
2249 raise Constraint_Error
with "Position cursor has no element";
2252 Query_Element
(Position
.Container
.all, Position
.Index
, Process
);
2260 (Stream
: not null access Root_Stream_Type
'Class;
2261 Container
: out Vector
)
2263 Length
: Count_Type
'Base;
2264 Last
: Index_Type
'Base := No_Index
;
2269 Count_Type
'Base'Read (Stream, Length);
2271 if Length > Capacity (Container) then
2272 Reserve_Capacity (Container, Capacity => Length);
2275 for J in Count_Type range 1 .. Length loop
2277 Element_Type'Read (Stream, Container.Elements.EA (Last));
2278 Container.Last := Last;
2283 (Stream : not null access Root_Stream_Type'Class;
2284 Position : out Cursor)
2287 raise Program_Error with "attempt to stream vector cursor";
2290 ---------------------
2291 -- Replace_Element --
2292 ---------------------
2294 procedure Replace_Element
2295 (Container : in out Vector;
2297 New_Item : Element_Type)
2300 if Index > Container.Last then
2301 raise Constraint_Error with "Index is out of range";
2304 if Container.Lock > 0 then
2305 raise Program_Error with
2306 "attempt to tamper with cursors (vector is locked)";
2309 Container.Elements.EA (Index) := New_Item;
2310 end Replace_Element;
2312 procedure Replace_Element
2313 (Container : in out Vector;
2315 New_Item : Element_Type)
2318 if Position.Container = null then
2319 raise Constraint_Error with "Position cursor has no element";
2322 if Position.Container /= Container'Unrestricted_Access then
2323 raise Program_Error with "Position cursor denotes wrong container";
2326 if Position.Index > Container.Last then
2327 raise Constraint_Error with "Position cursor is out of range";
2330 if Container.Lock > 0 then
2331 raise Program_Error with
2332 "attempt to tamper with cursors (vector is locked)";
2335 Container.Elements.EA (Position.Index) := New_Item;
2336 end Replace_Element;
2338 ----------------------
2339 -- Reserve_Capacity --
2340 ----------------------
2342 procedure Reserve_Capacity
2343 (Container : in out Vector;
2344 Capacity : Count_Type)
2346 N : constant Count_Type := Length (Container);
2348 Index : Count_Type'Base;
2349 Last : Index_Type'Base;
2352 -- Reserve_Capacity can be used to either expand the storage available
2353 -- for elements (this would be its typical use, in anticipation of
2354 -- future insertion), or to trim back storage. In the latter case,
2355 -- storage can only be trimmed back to the limit of the container
2356 -- length. Note that Reserve_Capacity neither deletes (active) elements
2357 -- nor inserts elements; it only affects container capacity, never
2358 -- container length.
2360 if Capacity = 0 then
2361 -- This is a request to trim back storage, to the minimum amount
2362 -- possible given the current state of the container.
2365 -- The container is empty, so in this unique case we can
2366 -- deallocate the entire internal array. Note that an empty
2367 -- container can never be busy, so there's no need to check the
2371 X : Elements_Access := Container.Elements;
2373 -- First we remove the internal array from the container, to
2374 -- handle the case when the deallocation raises an exception.
2376 Container.Elements := null;
2378 -- Container invariants have been restored, so it is now safe
2379 -- to attempt to deallocate the internal array.
2384 elsif N < Container.Elements.EA'Length then
2385 -- The container is not empty, and the current length is less than
2386 -- the current capacity, so there's storage available to trim. In
2387 -- this case, we allocate a new internal array having a length
2388 -- that exactly matches the number of items in the
2389 -- container. (Reserve_Capacity does not delete active elements,
2390 -- so this is the best we can do with respect to minimizing
2393 if Container.Busy > 0 then
2394 raise Program_Error with
2395 "attempt to tamper with elements (vector is busy)";
2399 subtype Src_Index_Subtype is Index_Type'Base range
2400 Index_Type'First .. Container.Last;
2402 Src : Elements_Array renames
2403 Container.Elements.EA (Src_Index_Subtype);
2405 X : Elements_Access := Container.Elements;
2408 -- Although we have isolated the old internal array that we're
2409 -- going to deallocate, we don't deallocate it until we have
2410 -- successfully allocated a new one. If there is an exception
2411 -- during allocation (either because there is not enough
2412 -- storage, or because initialization of the elements fails),
2413 -- we let it propagate without causing any side-effect.
2415 Container.Elements := new Elements_Type'(Container
.Last
, Src
);
2417 -- We have succesfully allocated a new internal array (with a
2418 -- smaller length than the old one, and containing a copy of
2419 -- just the active elements in the container), so it is now
2420 -- safe to attempt to deallocate the old array. The old array
2421 -- has been isolated, and container invariants have been
2422 -- restored, so if the deallocation fails (because finalization
2423 -- of the elements fails), we simply let it propagate.
2432 -- Reserve_Capacity can be used to expand the storage available for
2433 -- elements, but we do not let the capacity grow beyond the number of
2434 -- values in Index_Type'Range. (Were it otherwise, there would be no way
2435 -- to refer to the elements with an index value greater than
2436 -- Index_Type'Last, so that storage would be wasted.) Here we compute
2437 -- the Last index value of the new internal array, in a way that avoids
2438 -- any possibility of overflow.
2440 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2441 -- We perform a two-part test. First we determine whether the
2442 -- computed Last value lies in the base range of the type, and then
2443 -- determine whether it lies in the range of the index (sub)type.
2445 -- Last must satisfy this relation:
2446 -- First + Length - 1 <= Last
2447 -- We regroup terms:
2448 -- First - 1 <= Last - Length
2449 -- Which can rewrite as:
2450 -- No_Index <= Last - Length
2452 if Index_Type'Base'Last
- Index_Type
'Base (Capacity
) < No_Index
then
2453 raise Constraint_Error
with "Capacity is out of range";
2456 -- We now know that the computed value of Last is within the base
2457 -- range of the type, so it is safe to compute its value:
2459 Last
:= No_Index
+ Index_Type
'Base (Capacity
);
2461 -- Finally we test whether the value is within the range of the
2462 -- generic actual index subtype:
2464 if Last
> Index_Type
'Last then
2465 raise Constraint_Error
with "Capacity is out of range";
2468 elsif Index_Type
'First <= 0 then
2469 -- Here we can compute Last directly, in the normal way. We know that
2470 -- No_Index is less than 0, so there is no danger of overflow when
2471 -- adding the (positive) value of Capacity.
2473 Index
:= Count_Type
'Base (No_Index
) + Capacity
; -- Last
2475 if Index
> Count_Type
'Base (Index_Type
'Last) then
2476 raise Constraint_Error
with "Capacity is out of range";
2479 -- We know that the computed value (having type Count_Type) of Last
2480 -- is within the range of the generic actual index subtype, so it is
2481 -- safe to convert to Index_Type:
2483 Last
:= Index_Type
'Base (Index
);
2486 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2487 -- must test the length indirectly (by working backwards from the
2488 -- largest possible value of Last), in order to prevent overflow.
2490 Index
:= Count_Type
'Base (Index_Type
'Last) - Capacity
; -- No_Index
2492 if Index
< Count_Type
'Base (No_Index
) then
2493 raise Constraint_Error
with "Capacity is out of range";
2496 -- We have determined that the value of Capacity would not create a
2497 -- Last index value outside of the range of Index_Type, so we can now
2498 -- safely compute its value.
2500 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Capacity
);
2503 -- The requested capacity is non-zero, but we don't know yet whether
2504 -- this is a request for expansion or contraction of storage.
2506 if Container
.Elements
= null then
2507 -- The container is empty (it doesn't even have an internal array),
2508 -- so this represents a request to allocate (expand) storage having
2509 -- the given capacity.
2511 Container
.Elements
:= new Elements_Type
(Last
);
2515 if Capacity
<= N
then
2516 -- This is a request to trim back storage, but only to the limit of
2517 -- what's already in the container. (Reserve_Capacity never deletes
2518 -- active elements, it only reclaims excess storage.)
2520 if N
< Container
.Elements
.EA
'Length then
2521 -- The container is not empty (because the requested capacity is
2522 -- positive, and less than or equal to the container length), and
2523 -- the current length is less than the current capacity, so
2524 -- there's storage available to trim. In this case, we allocate a
2525 -- new internal array having a length that exactly matches the
2526 -- number of items in the container.
2528 if Container
.Busy
> 0 then
2529 raise Program_Error
with
2530 "attempt to tamper with elements (vector is busy)";
2534 subtype Src_Index_Subtype
is Index_Type
'Base range
2535 Index_Type
'First .. Container
.Last
;
2537 Src
: Elements_Array
renames
2538 Container
.Elements
.EA
(Src_Index_Subtype
);
2540 X
: Elements_Access
:= Container
.Elements
;
2543 -- Although we have isolated the old internal array that we're
2544 -- going to deallocate, we don't deallocate it until we have
2545 -- successfully allocated a new one. If there is an exception
2546 -- during allocation (either because there is not enough
2547 -- storage, or because initialization of the elements fails),
2548 -- we let it propagate without causing any side-effect.
2550 Container
.Elements
:= new Elements_Type
'(Container.Last, Src);
2552 -- We have succesfully allocated a new internal array (with a
2553 -- smaller length than the old one, and containing a copy of
2554 -- just the active elements in the container), so it is now
2555 -- safe to attempt to deallocate the old array. The old array
2556 -- has been isolated, and container invariants have been
2557 -- restored, so if the deallocation fails (because finalization
2558 -- of the elements fails), we simply let it propagate.
2567 -- The requested capacity is larger than the container length (the
2568 -- number of active elements). Whether this represents a request for
2569 -- expansion or contraction of the current capacity depends on what the
2570 -- current capacity is.
2572 if Capacity = Container.Elements.EA'Length then
2573 -- The requested capacity matches the existing capacity, so there's
2574 -- nothing to do here. We treat this case as a no-op, and simply
2575 -- return without checking the busy bit.
2580 -- There is a change in the capacity of a non-empty container, so a new
2581 -- internal array will be allocated. (The length of the new internal
2582 -- array could be less or greater than the old internal array. We know
2583 -- only that the length of the new internal array is greater than the
2584 -- number of active elements in the container.) We must check whether
2585 -- the container is busy before doing anything else.
2587 if Container.Busy > 0 then
2588 raise Program_Error with
2589 "attempt to tamper with elements (vector is busy)";
2592 -- We now allocate a new internal array, having a length different from
2593 -- its current value.
2596 E : Elements_Access := new Elements_Type (Last);
2599 -- We have successfully allocated the new internal array. We first
2600 -- attempt to copy the existing elements from the old internal array
2601 -- ("src" elements) onto the new internal array ("tgt" elements).
2604 subtype Index_Subtype is Index_Type'Base range
2605 Index_Type'First .. Container.Last;
2607 Src : Elements_Array renames
2608 Container.Elements.EA (Index_Subtype);
2610 Tgt : Elements_Array renames E.EA (Index_Subtype);
2621 -- We have successfully copied the existing elements onto the new
2622 -- internal array, so now we can attempt to deallocate the old one.
2625 X : Elements_Access := Container.Elements;
2627 -- First we isolate the old internal array, and replace it in the
2628 -- container with the new internal array.
2630 Container.Elements := E;
2632 -- Container invariants have been restored, so it is now safe to
2633 -- attempt to deallocate the old internal array.
2638 end Reserve_Capacity;
2640 ----------------------
2641 -- Reverse_Elements --
2642 ----------------------
2644 procedure Reverse_Elements (Container : in out Vector) is
2646 if Container.Length <= 1 then
2650 if Container.Lock > 0 then
2651 raise Program_Error with
2652 "attempt to tamper with cursors (vector is locked)";
2657 E : Elements_Type renames Container.Elements.all;
2660 I := Index_Type'First;
2661 J := Container.Last;
2664 EI : constant Element_Type := E.EA (I);
2667 E.EA (I) := E.EA (J);
2675 end Reverse_Elements;
2681 function Reverse_Find
2682 (Container : Vector;
2683 Item : Element_Type;
2684 Position : Cursor := No_Element) return Cursor
2686 Last : Index_Type'Base;
2689 if Position.Container /= null
2690 and then Position.Container /= Container'Unchecked_Access
2692 raise Program_Error with "Position cursor denotes wrong container";
2696 (if Position.Container = null or else Position.Index > Container.Last
2698 else Position.Index);
2700 for Indx in reverse Index_Type'First .. Last loop
2701 if Container.Elements.EA (Indx) = Item then
2702 return (Container'Unchecked_Access, Indx);
2709 ------------------------
2710 -- Reverse_Find_Index --
2711 ------------------------
2713 function Reverse_Find_Index
2714 (Container : Vector;
2715 Item : Element_Type;
2716 Index : Index_Type := Index_Type'Last) return Extended_Index
2718 Last : constant Index_Type'Base :=
2719 Index_Type'Min (Container.Last, Index);
2722 for Indx in reverse Index_Type'First .. Last loop
2723 if Container.Elements.EA (Indx) = Item then
2729 end Reverse_Find_Index;
2731 ---------------------
2732 -- Reverse_Iterate --
2733 ---------------------
2735 procedure Reverse_Iterate
2736 (Container : Vector;
2737 Process : not null access procedure (Position : Cursor))
2739 V : Vector renames Container'Unrestricted_Access.all;
2740 B : Natural renames V.Busy;
2746 for Indx in reverse Index_Type'First .. Container.Last loop
2747 Process (Cursor'(Container
'Unchecked_Access, Indx
));
2756 end Reverse_Iterate
;
2762 procedure Set_Length
(Container
: in out Vector
; Length
: Count_Type
) is
2763 Count
: constant Count_Type
'Base := Container
.Length
- Length
;
2766 -- Set_Length allows the user to set the length explicitly, instead of
2767 -- implicitly as a side-effect of deletion or insertion. If the
2768 -- requested length is less then the current length, this is equivalent
2769 -- to deleting items from the back end of the vector. If the requested
2770 -- length is greater than the current length, then this is equivalent to
2771 -- inserting "space" (nonce items) at the end.
2774 Container
.Delete_Last
(Count
);
2776 elsif Container
.Last
>= Index_Type
'Last then
2777 raise Constraint_Error
with "vector is already at its maximum length";
2780 Container
.Insert_Space
(Container
.Last
+ 1, -Count
);
2788 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
2790 if I
> Container
.Last
then
2791 raise Constraint_Error
with "I index is out of range";
2794 if J
> Container
.Last
then
2795 raise Constraint_Error
with "J index is out of range";
2802 if Container
.Lock
> 0 then
2803 raise Program_Error
with
2804 "attempt to tamper with cursors (vector is locked)";
2808 EI_Copy
: constant Element_Type
:= Container
.Elements
.EA
(I
);
2810 Container
.Elements
.EA
(I
) := Container
.Elements
.EA
(J
);
2811 Container
.Elements
.EA
(J
) := EI_Copy
;
2815 procedure Swap
(Container
: in out Vector
; I
, J
: Cursor
) is
2817 if I
.Container
= null then
2818 raise Constraint_Error
with "I cursor has no element";
2821 if J
.Container
= null then
2822 raise Constraint_Error
with "J cursor has no element";
2825 if I
.Container
/= Container
'Unrestricted_Access then
2826 raise Program_Error
with "I cursor denotes wrong container";
2829 if J
.Container
/= Container
'Unrestricted_Access then
2830 raise Program_Error
with "J cursor denotes wrong container";
2833 Swap
(Container
, I
.Index
, J
.Index
);
2841 (Container
: Vector
;
2842 Index
: Extended_Index
) return Cursor
2845 if Index
not in Index_Type
'First .. Container
.Last
then
2849 return Cursor
'(Container'Unchecked_Access, Index);
2856 function To_Index (Position : Cursor) return Extended_Index is
2858 if Position.Container = null then
2862 if Position.Index <= Position.Container.Last then
2863 return Position.Index;
2873 function To_Vector (Length : Count_Type) return Vector is
2874 Index : Count_Type'Base;
2875 Last : Index_Type'Base;
2876 Elements : Elements_Access;
2880 return Empty_Vector;
2883 -- We create a vector object with a capacity that matches the specified
2884 -- Length, but we do not allow the vector capacity (the length of the
2885 -- internal array) to exceed the number of values in Index_Type'Range
2886 -- (otherwise, there would be no way to refer to those components via an
2887 -- index). We must therefore check whether the specified Length would
2888 -- create a Last index value greater than Index_Type'Last.
2890 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2891 -- We perform a two-part test. First we determine whether the
2892 -- computed Last value lies in the base range of the type, and then
2893 -- determine whether it lies in the range of the index (sub)type.
2895 -- Last must satisfy this relation:
2896 -- First + Length - 1 <= Last
2897 -- We regroup terms:
2898 -- First - 1 <= Last - Length
2899 -- Which can rewrite as:
2900 -- No_Index <= Last - Length
2902 if Index_Type
'Base'Last - Index_Type'Base (Length) < No_Index then
2903 raise Constraint_Error with "Length is out of range";
2906 -- We now know that the computed value of Last is within the base
2907 -- range of the type, so it is safe to compute its value:
2909 Last := No_Index + Index_Type'Base (Length);
2911 -- Finally we test whether the value is within the range of the
2912 -- generic actual index subtype:
2914 if Last > Index_Type'Last then
2915 raise Constraint_Error with "Length is out of range";
2918 elsif Index_Type'First <= 0 then
2919 -- Here we can compute Last directly, in the normal way. We know that
2920 -- No_Index is less than 0, so there is no danger of overflow when
2921 -- adding the (positive) value of Length.
2923 Index := Count_Type'Base (No_Index) + Length; -- Last
2925 if Index > Count_Type'Base (Index_Type'Last) then
2926 raise Constraint_Error with "Length is out of range";
2929 -- We know that the computed value (having type Count_Type) of Last
2930 -- is within the range of the generic actual index subtype, so it is
2931 -- safe to convert to Index_Type:
2933 Last := Index_Type'Base (Index);
2936 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2937 -- must test the length indirectly (by working backwards from the
2938 -- largest possible value of Last), in order to prevent overflow.
2940 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2942 if Index < Count_Type'Base (No_Index) then
2943 raise Constraint_Error with "Length is out of range";
2946 -- We have determined that the value of Length would not create a
2947 -- Last index value outside of the range of Index_Type, so we can now
2948 -- safely compute its value.
2950 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2953 Elements := new Elements_Type (Last);
2955 return Vector'(Controlled
with Elements
, Last
, 0, 0);
2959 (New_Item
: Element_Type
;
2960 Length
: Count_Type
) return Vector
2962 Index
: Count_Type
'Base;
2963 Last
: Index_Type
'Base;
2964 Elements
: Elements_Access
;
2968 return Empty_Vector
;
2971 -- We create a vector object with a capacity that matches the specified
2972 -- Length, but we do not allow the vector capacity (the length of the
2973 -- internal array) to exceed the number of values in Index_Type'Range
2974 -- (otherwise, there would be no way to refer to those components via an
2975 -- index). We must therefore check whether the specified Length would
2976 -- create a Last index value greater than Index_Type'Last.
2978 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2979 -- We perform a two-part test. First we determine whether the
2980 -- computed Last value lies in the base range of the type, and then
2981 -- determine whether it lies in the range of the index (sub)type.
2983 -- Last must satisfy this relation:
2984 -- First + Length - 1 <= Last
2985 -- We regroup terms:
2986 -- First - 1 <= Last - Length
2987 -- Which can rewrite as:
2988 -- No_Index <= Last - Length
2990 if Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
then
2991 raise Constraint_Error
with "Length is out of range";
2994 -- We now know that the computed value of Last is within the base
2995 -- range of the type, so it is safe to compute its value:
2997 Last
:= No_Index
+ Index_Type
'Base (Length
);
2999 -- Finally we test whether the value is within the range of the
3000 -- generic actual index subtype:
3002 if Last
> Index_Type
'Last then
3003 raise Constraint_Error
with "Length is out of range";
3006 elsif Index_Type
'First <= 0 then
3007 -- Here we can compute Last directly, in the normal way. We know that
3008 -- No_Index is less than 0, so there is no danger of overflow when
3009 -- adding the (positive) value of Length.
3011 Index
:= Count_Type
'Base (No_Index
) + Length
; -- same value as V.Last
3013 if Index
> Count_Type
'Base (Index_Type
'Last) then
3014 raise Constraint_Error
with "Length is out of range";
3017 -- We know that the computed value (having type Count_Type) of Last
3018 -- is within the range of the generic actual index subtype, so it is
3019 -- safe to convert to Index_Type:
3021 Last
:= Index_Type
'Base (Index
);
3024 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3025 -- must test the length indirectly (by working backwards from the
3026 -- largest possible value of Last), in order to prevent overflow.
3028 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
3030 if Index
< Count_Type
'Base (No_Index
) then
3031 raise Constraint_Error
with "Length is out of range";
3034 -- We have determined that the value of Length would not create a
3035 -- Last index value outside of the range of Index_Type, so we can now
3036 -- safely compute its value.
3038 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
3041 Elements
:= new Elements_Type
'(Last, EA => (others => New_Item));
3043 return Vector'(Controlled
with Elements
, Last
, 0, 0);
3046 --------------------
3047 -- Update_Element --
3048 --------------------
3050 procedure Update_Element
3051 (Container
: in out Vector
;
3053 Process
: not null access procedure (Element
: in out Element_Type
))
3055 B
: Natural renames Container
.Busy
;
3056 L
: Natural renames Container
.Lock
;
3059 if Index
> Container
.Last
then
3060 raise Constraint_Error
with "Index is out of range";
3067 Process
(Container
.Elements
.EA
(Index
));
3079 procedure Update_Element
3080 (Container
: in out Vector
;
3082 Process
: not null access procedure (Element
: in out Element_Type
))
3085 if Position
.Container
= null then
3086 raise Constraint_Error
with "Position cursor has no element";
3089 if Position
.Container
/= Container
'Unrestricted_Access then
3090 raise Program_Error
with "Position cursor denotes wrong container";
3093 Update_Element
(Container
, Position
.Index
, Process
);
3101 (Stream
: not null access Root_Stream_Type
'Class;
3105 Count_Type
'Base'Write (Stream, Length (Container));
3107 for J in Index_Type'First .. Container.Last loop
3108 Element_Type'Write (Stream, Container.Elements.EA (J));
3113 (Stream : not null access Root_Stream_Type'Class;
3117 raise Program_Error with "attempt to stream vector cursor";
3120 end Ada.Containers.Vectors;