1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . I N D E F I N I T E _ V E C T O R S --
9 -- Copyright (C) 2004-2013, 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
.Indefinite_Vectors
is
38 new Ada
.Unchecked_Deallocation
(Elements_Type
, Elements_Access
);
41 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
47 function "&" (Left
, Right
: Vector
) return Vector
is
48 LN
: constant Count_Type
:= Length
(Left
);
49 RN
: constant Count_Type
:= Length
(Right
);
50 N
: Count_Type
'Base; -- length of result
51 J
: Count_Type
'Base; -- for computing intermediate values
52 Last
: Index_Type
'Base; -- Last index of result
55 -- We decide that the capacity of the result is the sum of the lengths
56 -- of the vector parameters. We could decide to make it larger, but we
57 -- have no basis for knowing how much larger, so we just allocate the
58 -- minimum amount of storage.
60 -- Here we handle the easy cases first, when one of the vector
61 -- parameters is empty. (We say "easy" because there's nothing to
62 -- compute, that can potentially overflow.)
70 RE
: Elements_Array
renames
71 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
73 Elements
: Elements_Access
:= new Elements_Type
(Right
.Last
);
76 -- Elements of an indefinite vector are allocated, so we cannot
77 -- use simple slice assignment to give a value to our result.
78 -- Hence we must walk the array of the Right vector, and copy
79 -- each source element individually.
81 for I
in Elements
.EA
'Range loop
83 if RE
(I
) /= null then
84 Elements
.EA
(I
) := new Element_Type
'(RE (I).all);
89 for J in Index_Type'First .. I - 1 loop
90 Free (Elements.EA (J));
98 return (Controlled with Elements, Right.Last, 0, 0);
104 LE : Elements_Array renames
105 Left.Elements.EA (Index_Type'First .. Left.Last);
107 Elements : Elements_Access := new Elements_Type (Left.Last);
110 -- Elements of an indefinite vector are allocated, so we cannot
111 -- use simple slice assignment to give a value to our result.
112 -- Hence we must walk the array of the Left vector, and copy
113 -- each source element individually.
115 for I in Elements.EA'Range loop
117 if LE (I) /= null then
118 Elements.EA (I) := new Element_Type'(LE
(I
).all);
123 for J
in Index_Type
'First .. I
- 1 loop
124 Free
(Elements
.EA
(J
));
132 return (Controlled
with Elements
, Left
.Last
, 0, 0);
136 -- Neither of the vector parameters is empty, so we must compute the
137 -- length of the result vector and its last index. (This is the harder
138 -- case, because our computations must avoid overflow.)
140 -- There are two constraints we need to satisfy. The first constraint is
141 -- that a container cannot have more than Count_Type'Last elements, so
142 -- we must check the sum of the combined lengths. Note that we cannot
143 -- simply add the lengths, because of the possibility of overflow.
145 if LN
> Count_Type
'Last - RN
then
146 raise Constraint_Error
with "new length is out of range";
149 -- It is now safe compute the length of the new vector.
153 -- The second constraint is that the new Last index value cannot
154 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
155 -- Count_Type'Base as the type for intermediate values.
157 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
159 -- We perform a two-part test. First we determine whether the
160 -- computed Last value lies in the base range of the type, and then
161 -- determine whether it lies in the range of the index (sub)type.
163 -- Last must satisfy this relation:
164 -- First + Length - 1 <= Last
166 -- First - 1 <= Last - Length
167 -- Which can rewrite as:
168 -- No_Index <= Last - Length
170 if Index_Type'Base'Last
- Index_Type
'Base (N
) < No_Index
then
171 raise Constraint_Error
with "new length is out of range";
174 -- We now know that the computed value of Last is within the base
175 -- range of the type, so it is safe to compute its value:
177 Last
:= No_Index
+ Index_Type
'Base (N
);
179 -- Finally we test whether the value is within the range of the
180 -- generic actual index subtype:
182 if Last
> Index_Type
'Last then
183 raise Constraint_Error
with "new length is out of range";
186 elsif Index_Type
'First <= 0 then
188 -- Here we can compute Last directly, in the normal way. We know that
189 -- No_Index is less than 0, so there is no danger of overflow when
190 -- adding the (positive) value of length.
192 J
:= Count_Type
'Base (No_Index
) + N
; -- Last
194 if J
> Count_Type
'Base (Index_Type
'Last) then
195 raise Constraint_Error
with "new length is out of range";
198 -- We know that the computed value (having type Count_Type) of Last
199 -- is within the range of the generic actual index subtype, so it is
200 -- safe to convert to Index_Type:
202 Last
:= Index_Type
'Base (J
);
205 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
206 -- must test the length indirectly (by working backwards from the
207 -- largest possible value of Last), in order to prevent overflow.
209 J
:= Count_Type
'Base (Index_Type
'Last) - N
; -- No_Index
211 if J
< Count_Type
'Base (No_Index
) then
212 raise Constraint_Error
with "new length is out of range";
215 -- We have determined that the result length would not create a Last
216 -- index value outside of the range of Index_Type, so we can now
217 -- safely compute its value.
219 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + N
);
223 LE
: Elements_Array
renames
224 Left
.Elements
.EA
(Index_Type
'First .. Left
.Last
);
225 RE
: Elements_Array
renames
226 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
228 Elements
: Elements_Access
:= new Elements_Type
(Last
);
230 I
: Index_Type
'Base := No_Index
;
233 -- Elements of an indefinite vector are allocated, so we cannot use
234 -- simple slice assignment to give a value to our result. Hence we
235 -- must walk the array of each vector parameter, and copy each source
236 -- element individually.
238 for LI
in LE
'Range loop
242 if LE
(LI
) /= null then
243 Elements
.EA
(I
) := new Element_Type
'(LE (LI).all);
248 for J in Index_Type'First .. I - 1 loop
249 Free (Elements.EA (J));
257 for RI in RE'Range loop
261 if RE (RI) /= null then
262 Elements.EA (I) := new Element_Type'(RE
(RI
).all);
267 for J
in Index_Type
'First .. I
- 1 loop
268 Free
(Elements
.EA
(J
));
276 return (Controlled
with Elements
, Last
, 0, 0);
280 function "&" (Left
: Vector
; Right
: Element_Type
) return Vector
is
282 -- We decide that the capacity of the result is the sum of the lengths
283 -- of the parameters. We could decide to make it larger, but we have no
284 -- basis for knowing how much larger, so we just allocate the minimum
285 -- amount of storage.
287 -- Here we handle the easy case first, when the vector parameter (Left)
290 if Left
.Is_Empty
then
292 Elements
: Elements_Access
:= new Elements_Type
(Index_Type
'First);
296 Elements
.EA
(Index_Type
'First) := new Element_Type
'(Right);
303 return (Controlled with Elements, Index_Type'First, 0, 0);
307 -- The vector parameter is not empty, so we must compute the length of
308 -- the result vector and its last index, but in such a way that overflow
309 -- is avoided. We must satisfy two constraints: the new length cannot
310 -- exceed Count_Type'Last, and the new Last index cannot exceed
313 if Left.Length = Count_Type'Last then
314 raise Constraint_Error with "new length is out of range";
317 if Left.Last >= Index_Type'Last then
318 raise Constraint_Error with "new length is out of range";
322 Last : constant Index_Type := Left.Last + 1;
324 LE : Elements_Array renames
325 Left.Elements.EA (Index_Type'First .. Left.Last);
327 Elements : Elements_Access := new Elements_Type (Last);
330 for I in LE'Range loop
332 if LE (I) /= null then
333 Elements.EA (I) := new Element_Type'(LE
(I
).all);
338 for J
in Index_Type
'First .. I
- 1 loop
339 Free
(Elements
.EA
(J
));
348 Elements
.EA
(Last
) := new Element_Type
'(Right);
352 for J in Index_Type'First .. Last - 1 loop
353 Free (Elements.EA (J));
360 return (Controlled with Elements, Last, 0, 0);
364 function "&" (Left : Element_Type; Right : Vector) return Vector is
366 -- We decide that the capacity of the result is the sum of the lengths
367 -- of the parameters. We could decide to make it larger, but we have no
368 -- basis for knowing how much larger, so we just allocate the minimum
369 -- amount of storage.
371 -- Here we handle the easy case first, when the vector parameter (Right)
374 if Right.Is_Empty then
376 Elements : Elements_Access := new Elements_Type (Index_Type'First);
380 Elements.EA (Index_Type'First) := new Element_Type'(Left
);
387 return (Controlled
with Elements
, Index_Type
'First, 0, 0);
391 -- The vector parameter is not empty, so we must compute the length of
392 -- the result vector and its last index, but in such a way that overflow
393 -- is avoided. We must satisfy two constraints: the new length cannot
394 -- exceed Count_Type'Last, and the new Last index cannot exceed
397 if Right
.Length
= Count_Type
'Last then
398 raise Constraint_Error
with "new length is out of range";
401 if Right
.Last
>= Index_Type
'Last then
402 raise Constraint_Error
with "new length is out of range";
406 Last
: constant Index_Type
:= Right
.Last
+ 1;
408 RE
: Elements_Array
renames
409 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
411 Elements
: Elements_Access
:= new Elements_Type
(Last
);
413 I
: Index_Type
'Base := Index_Type
'First;
417 Elements
.EA
(I
) := new Element_Type
'(Left);
424 for RI in RE'Range loop
428 if RE (RI) /= null then
429 Elements.EA (I) := new Element_Type'(RE
(RI
).all);
434 for J
in Index_Type
'First .. I
- 1 loop
435 Free
(Elements
.EA
(J
));
443 return (Controlled
with Elements
, Last
, 0, 0);
447 function "&" (Left
, Right
: Element_Type
) return Vector
is
449 -- We decide that the capacity of the result is the sum of the lengths
450 -- of the parameters. We could decide to make it larger, but we have no
451 -- basis for knowing how much larger, so we just allocate the minimum
452 -- amount of storage.
454 -- We must compute the length of the result vector and its last index,
455 -- but in such a way that overflow is avoided. We must satisfy two
456 -- constraints: the new length cannot exceed Count_Type'Last (here, we
457 -- know that that condition is satisfied), and the new Last index cannot
458 -- exceed Index_Type'Last.
460 if Index_Type
'First >= Index_Type
'Last then
461 raise Constraint_Error
with "new length is out of range";
465 Last
: constant Index_Type
:= Index_Type
'First + 1;
466 Elements
: Elements_Access
:= new Elements_Type
(Last
);
470 Elements
.EA
(Index_Type
'First) := new Element_Type
'(Left);
478 Elements.EA (Last) := new Element_Type'(Right
);
481 Free
(Elements
.EA
(Index_Type
'First));
486 return (Controlled
with Elements
, Last
, 0, 0);
494 overriding
function "=" (Left
, Right
: Vector
) return Boolean is
495 BL
: Natural renames Left
'Unrestricted_Access.Busy
;
496 LL
: Natural renames Left
'Unrestricted_Access.Lock
;
498 BR
: Natural renames Right
'Unrestricted_Access.Busy
;
499 LR
: Natural renames Right
'Unrestricted_Access.Lock
;
504 if Left
'Address = Right
'Address then
508 if Left
.Last
/= Right
.Last
then
512 -- Per AI05-0022, the container implementation is required to detect
513 -- element tampering by a generic actual subprogram.
522 for J
in Index_Type
'First .. Left
.Last
loop
523 if Left
.Elements
.EA
(J
) = null then
524 if Right
.Elements
.EA
(J
) /= null then
529 elsif Right
.Elements
.EA
(J
) = null then
533 elsif Left
.Elements
.EA
(J
).all /= Right
.Elements
.EA
(J
).all then
561 procedure Adjust
(Container
: in out Vector
) is
563 if Container
.Last
= No_Index
then
564 Container
.Elements
:= null;
569 L
: constant Index_Type
:= Container
.Last
;
570 E
: Elements_Array
renames
571 Container
.Elements
.EA
(Index_Type
'First .. L
);
574 Container
.Elements
:= null;
575 Container
.Last
:= No_Index
;
579 Container
.Elements
:= new Elements_Type
(L
);
581 for J
in E
'Range loop
582 if E
(J
) /= null then
583 Container
.Elements
.EA
(J
) := new Element_Type
'(E (J).all);
591 procedure Adjust (Control : in out Reference_Control_Type) is
593 if Control.Container /= null then
595 C : Vector renames Control.Container.all;
596 B : Natural renames C.Busy;
597 L : Natural renames C.Lock;
609 procedure Append (Container : in out Vector; New_Item : Vector) is
611 if Is_Empty (New_Item) then
613 elsif Container.Last = Index_Type'Last then
614 raise Constraint_Error with "vector is already at its maximum length";
616 Insert (Container, Container.Last + 1, New_Item);
621 (Container : in out Vector;
622 New_Item : Element_Type;
623 Count : Count_Type := 1)
628 elsif Container.Last = Index_Type'Last then
629 raise Constraint_Error with "vector is already at its maximum length";
631 Insert (Container, Container.Last + 1, New_Item, Count);
639 procedure Assign (Target : in out Vector; Source : Vector) is
641 if Target'Address = Source'Address then
645 Target.Append (Source);
653 function Capacity (Container : Vector) return Count_Type is
655 if Container.Elements = null then
658 return Container.Elements.EA'Length;
666 procedure Clear (Container : in out Vector) is
668 if Container.Busy > 0 then
669 raise Program_Error with
670 "attempt to tamper with cursors (vector is busy)";
673 while Container.Last >= Index_Type'First loop
675 X : Element_Access := Container.Elements.EA (Container.Last);
677 Container.Elements.EA (Container.Last) := null;
678 Container.Last := Container.Last - 1;
685 ------------------------
686 -- Constant_Reference --
687 ------------------------
689 function Constant_Reference
690 (Container : aliased Vector;
691 Position : Cursor) return Constant_Reference_Type
696 if Position.Container = null then
697 raise Constraint_Error with "Position cursor has no element";
700 if Position.Container /= Container'Unrestricted_Access then
701 raise Program_Error with "Position cursor denotes wrong container";
704 if Position.Index > Position.Container.Last then
705 raise Constraint_Error with "Position cursor is out of range";
708 E := Container.Elements.EA (Position.Index);
711 raise Constraint_Error with "element at Position is empty";
715 C : Vector renames Container'Unrestricted_Access.all;
716 B : Natural renames C.Busy;
717 L : Natural renames C.Lock;
719 return R : constant Constant_Reference_Type :=
720 (Element => E.all'Access,
721 Control => (Controlled with Container'Unrestricted_Access))
727 end Constant_Reference;
729 function Constant_Reference
730 (Container : aliased Vector;
731 Index : Index_Type) return Constant_Reference_Type
736 if Index > Container.Last then
737 raise Constraint_Error with "Index is out of range";
740 E := Container.Elements.EA (Index);
743 raise Constraint_Error with "element at Index is empty";
747 C : Vector renames Container'Unrestricted_Access.all;
748 B : Natural renames C.Busy;
749 L : Natural renames C.Lock;
751 return R : constant Constant_Reference_Type :=
752 (Element => E.all'Access,
753 Control => (Controlled with Container'Unrestricted_Access))
759 end Constant_Reference;
767 Item : Element_Type) return Boolean
770 return Find_Index (Container, Item) /= No_Index;
779 Capacity : Count_Type := 0) return Vector
787 elsif Capacity >= Source.Length then
792 with "Requested capacity is less than Source length";
795 return Target : Vector do
796 Target.Reserve_Capacity (C);
797 Target.Assign (Source);
806 (Container : in out Vector;
807 Index : Extended_Index;
808 Count : Count_Type := 1)
810 Old_Last : constant Index_Type'Base := Container.Last;
811 New_Last : Index_Type'Base;
812 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
813 J : Index_Type'Base; -- first index of items that slide down
816 -- Delete removes items from the vector, the number of which is the
817 -- minimum of the specified Count and the items (if any) that exist from
818 -- Index to Container.Last. There are no constraints on the specified
819 -- value of Count (it can be larger than what's available at this
820 -- position in the vector, for example), but there are constraints on
821 -- the allowed values of the Index.
823 -- As a precondition on the generic actual Index_Type, the base type
824 -- must include Index_Type'Pred (Index_Type'First); this is the value
825 -- that Container.Last assumes when the vector is empty. However, we do
826 -- not allow that as the value for Index when specifying which items
827 -- should be deleted, so we must manually check. (That the user is
828 -- allowed to specify the value at all here is a consequence of the
829 -- declaration of the Extended_Index subtype, which includes the values
830 -- in the base range that immediately precede and immediately follow the
831 -- values in the Index_Type.)
833 if Index < Index_Type'First then
834 raise Constraint_Error with "Index is out of range (too small)";
837 -- We do allow a value greater than Container.Last to be specified as
838 -- the Index, but only if it's immediately greater. This allows the
839 -- corner case of deleting no items from the back end of the vector to
840 -- be treated as a no-op. (It is assumed that specifying an index value
841 -- greater than Last + 1 indicates some deeper flaw in the caller's
842 -- algorithm, so that case is treated as a proper error.)
844 if Index > Old_Last then
845 if Index > Old_Last + 1 then
846 raise Constraint_Error with "Index is out of range (too large)";
852 -- Here and elsewhere we treat deleting 0 items from the container as a
853 -- no-op, even when the container is busy, so we simply return.
859 -- The internal elements array isn't guaranteed to exist unless we have
860 -- elements, so we handle that case here in order to avoid having to
861 -- check it later. (Note that an empty vector can never be busy, so
862 -- there's no semantic harm in returning early.)
864 if Container.Is_Empty then
868 -- The tampering bits exist to prevent an item from being deleted (or
869 -- otherwise harmfully manipulated) while it is being visited. Query,
870 -- Update, and Iterate increment the busy count on entry, and decrement
871 -- the count on exit. Delete checks the count to determine whether it is
872 -- being called while the associated callback procedure is executing.
874 if Container.Busy > 0 then
875 raise Program_Error with
876 "attempt to tamper with cursors (vector is busy)";
879 -- We first calculate what's available for deletion starting at
880 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
881 -- Count_Type'Base as the type for intermediate values. (See function
882 -- Length for more information.)
884 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
885 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
888 Count2 := Count_Type'Base (Old_Last - Index + 1);
891 -- If the number of elements requested (Count) for deletion is equal to
892 -- (or greater than) the number of elements available (Count2) for
893 -- deletion beginning at Index, then everything from Index to
894 -- Container.Last is deleted (this is equivalent to Delete_Last).
896 if Count >= Count2 then
897 -- Elements in an indefinite vector are allocated, so we must iterate
898 -- over the loop and deallocate elements one-at-a-time. We work from
899 -- back to front, deleting the last element during each pass, in
900 -- order to gracefully handle deallocation failures.
903 EA : Elements_Array renames Container.Elements.EA;
906 while Container.Last >= Index loop
908 K : constant Index_Type := Container.Last;
909 X : Element_Access := EA (K);
912 -- We first isolate the element we're deleting, removing it
913 -- from the vector before we attempt to deallocate it, in
914 -- case the deallocation fails.
917 Container.Last := K - 1;
919 -- Container invariants have been restored, so it is now
920 -- safe to attempt to deallocate the element.
930 -- There are some elements that aren't being deleted (the requested
931 -- count was less than the available count), so we must slide them down
932 -- to Index. We first calculate the index values of the respective array
933 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
934 -- type for intermediate calculations. For the elements that slide down,
935 -- index value New_Last is the last index value of their new home, and
936 -- index value J is the first index of their old home.
938 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
939 New_Last
:= Old_Last
- Index_Type
'Base (Count
);
940 J
:= Index
+ Index_Type
'Base (Count
);
942 New_Last
:= Index_Type
'Base (Count_Type
'Base (Old_Last
) - Count
);
943 J
:= Index_Type
'Base (Count_Type
'Base (Index
) + Count
);
946 -- The internal elements array isn't guaranteed to exist unless we have
947 -- elements, but we have that guarantee here because we know we have
948 -- elements to slide. The array index values for each slice have
949 -- already been determined, so what remains to be done is to first
950 -- deallocate the elements that are being deleted, and then slide down
951 -- to Index the elements that aren't being deleted.
954 EA
: Elements_Array
renames Container
.Elements
.EA
;
957 -- Before we can slide down the elements that aren't being deleted,
958 -- we need to deallocate the elements that are being deleted.
960 for K
in Index
.. J
- 1 loop
962 X
: Element_Access
:= EA
(K
);
965 -- First we remove the element we're about to deallocate from
966 -- the vector, in case the deallocation fails, in order to
967 -- preserve representation invariants.
971 -- The element has been removed from the vector, so it is now
972 -- safe to attempt to deallocate it.
978 EA
(Index
.. New_Last
) := EA
(J
.. Old_Last
);
979 Container
.Last
:= New_Last
;
984 (Container
: in out Vector
;
985 Position
: in out Cursor
;
986 Count
: Count_Type
:= 1)
988 pragma Warnings
(Off
, Position
);
991 if Position
.Container
= null then
992 raise Constraint_Error
with "Position cursor has no element";
994 elsif Position
.Container
/= Container
'Unrestricted_Access then
995 raise Program_Error
with "Position cursor denotes wrong container";
997 elsif Position
.Index
> Container
.Last
then
998 raise Program_Error
with "Position index is out of range";
1001 Delete
(Container
, Position
.Index
, Count
);
1002 Position
:= No_Element
;
1010 procedure Delete_First
1011 (Container
: in out Vector
;
1012 Count
: Count_Type
:= 1)
1018 elsif Count
>= Length
(Container
) then
1023 Delete
(Container
, Index_Type
'First, Count
);
1031 procedure Delete_Last
1032 (Container
: in out Vector
;
1033 Count
: Count_Type
:= 1)
1036 -- It is not permitted to delete items while the container is busy (for
1037 -- example, we're in the middle of a passive iteration). However, we
1038 -- always treat deleting 0 items as a no-op, even when we're busy, so we
1039 -- simply return without checking.
1045 -- We cannot simply subsume the empty case into the loop below (the loop
1046 -- would iterate 0 times), because we rename the internal array object
1047 -- (which is allocated), but an empty vector isn't guaranteed to have
1048 -- actually allocated an array. (Note that an empty vector can never be
1049 -- busy, so there's no semantic harm in returning early here.)
1051 if Container
.Is_Empty
then
1055 -- The tampering bits exist to prevent an item from being deleted (or
1056 -- otherwise harmfully manipulated) while it is being visited. Query,
1057 -- Update, and Iterate increment the busy count on entry, and decrement
1058 -- the count on exit. Delete_Last checks the count to determine whether
1059 -- it is being called while the associated callback procedure is
1062 if Container
.Busy
> 0 then
1063 raise Program_Error
with
1064 "attempt to tamper with cursors (vector is busy)";
1067 -- Elements in an indefinite vector are allocated, so we must iterate
1068 -- over the loop and deallocate elements one-at-a-time. We work from
1069 -- back to front, deleting the last element during each pass, in order
1070 -- to gracefully handle deallocation failures.
1073 E
: Elements_Array
renames Container
.Elements
.EA
;
1076 for Indx
in 1 .. Count_Type
'Min (Count
, Container
.Length
) loop
1078 J
: constant Index_Type
:= Container
.Last
;
1079 X
: Element_Access
:= E
(J
);
1082 -- Note that we first isolate the element we're deleting,
1083 -- removing it from the vector, before we actually deallocate
1084 -- it, in order to preserve representation invariants even if
1085 -- the deallocation fails.
1088 Container
.Last
:= J
- 1;
1090 -- Container invariants have been restored, so it is now safe
1091 -- to deallocate the element.
1104 (Container
: Vector
;
1105 Index
: Index_Type
) return Element_Type
1108 if Index
> Container
.Last
then
1109 raise Constraint_Error
with "Index is out of range";
1113 EA
: constant Element_Access
:= Container
.Elements
.EA
(Index
);
1116 raise Constraint_Error
with "element is empty";
1123 function Element
(Position
: Cursor
) return Element_Type
is
1125 if Position
.Container
= null then
1126 raise Constraint_Error
with "Position cursor has no element";
1129 if Position
.Index
> Position
.Container
.Last
then
1130 raise Constraint_Error
with "Position cursor is out of range";
1134 EA
: constant Element_Access
:=
1135 Position
.Container
.Elements
.EA
(Position
.Index
);
1138 raise Constraint_Error
with "element is empty";
1149 procedure Finalize
(Container
: in out Vector
) is
1151 Clear
(Container
); -- Checks busy-bit
1154 X
: Elements_Access
:= Container
.Elements
;
1156 Container
.Elements
:= null;
1161 procedure Finalize
(Object
: in out Iterator
) is
1162 B
: Natural renames Object
.Container
.Busy
;
1167 procedure Finalize
(Control
: in out Reference_Control_Type
) is
1169 if Control
.Container
/= null then
1171 C
: Vector
renames Control
.Container
.all;
1172 B
: Natural renames C
.Busy
;
1173 L
: Natural renames C
.Lock
;
1179 Control
.Container
:= null;
1188 (Container
: Vector
;
1189 Item
: Element_Type
;
1190 Position
: Cursor
:= No_Element
) return Cursor
1193 if Position
.Container
/= null then
1194 if Position
.Container
/= Container
'Unrestricted_Access then
1195 raise Program_Error
with "Position cursor denotes wrong container";
1198 if Position
.Index
> Container
.Last
then
1199 raise Program_Error
with "Position index is out of range";
1203 -- Per AI05-0022, the container implementation is required to detect
1204 -- element tampering by a generic actual subprogram.
1207 B
: Natural renames Container
'Unrestricted_Access.Busy
;
1208 L
: Natural renames Container
'Unrestricted_Access.Lock
;
1210 Result
: Index_Type
'Base;
1217 for J
in Position
.Index
.. Container
.Last
loop
1218 if Container
.Elements
.EA
(J
) /= null
1219 and then Container
.Elements
.EA
(J
).all = Item
1229 if Result
= No_Index
then
1232 return Cursor
'(Container'Unrestricted_Access, Result);
1248 (Container : Vector;
1249 Item : Element_Type;
1250 Index : Index_Type := Index_Type'First) return Extended_Index
1252 B : Natural renames Container'Unrestricted_Access.Busy;
1253 L : Natural renames Container'Unrestricted_Access.Lock;
1255 Result : Index_Type'Base;
1258 -- Per AI05-0022, the container implementation is required to detect
1259 -- element tampering by a generic actual subprogram.
1265 for Indx in Index .. Container.Last loop
1266 if Container.Elements.EA (Indx) /= null
1267 and then Container.Elements.EA (Indx).all = Item
1290 function First (Container : Vector) return Cursor is
1292 if Is_Empty (Container) then
1296 return (Container'Unrestricted_Access, Index_Type'First);
1299 function First (Object : Iterator) return Cursor is
1301 -- The value of the iterator object's Index component influences the
1302 -- behavior of the First (and Last) selector function.
1304 -- When the Index component is No_Index, this means the iterator
1305 -- object was constructed without a start expression, in which case the
1306 -- (forward) iteration starts from the (logical) beginning of the entire
1307 -- sequence of items (corresponding to Container.First, for a forward
1310 -- Otherwise, this is iteration over a partial sequence of items.
1311 -- When the Index component isn't No_Index, the iterator object was
1312 -- constructed with a start expression, that specifies the position
1313 -- from which the (forward) partial iteration begins.
1315 if Object.Index = No_Index then
1316 return First (Object.Container.all);
1318 return Cursor'(Object
.Container
, Object
.Index
);
1326 function First_Element
(Container
: Vector
) return Element_Type
is
1328 if Container
.Last
= No_Index
then
1329 raise Constraint_Error
with "Container is empty";
1333 EA
: constant Element_Access
:=
1334 Container
.Elements
.EA
(Index_Type
'First);
1337 raise Constraint_Error
with "first element is empty";
1348 function First_Index
(Container
: Vector
) return Index_Type
is
1349 pragma Unreferenced
(Container
);
1351 return Index_Type
'First;
1354 ---------------------
1355 -- Generic_Sorting --
1356 ---------------------
1358 package body Generic_Sorting
is
1360 -----------------------
1361 -- Local Subprograms --
1362 -----------------------
1364 function Is_Less
(L
, R
: Element_Access
) return Boolean;
1365 pragma Inline
(Is_Less
);
1371 function Is_Less
(L
, R
: Element_Access
) return Boolean is
1378 return L
.all < R
.all;
1386 function Is_Sorted
(Container
: Vector
) return Boolean is
1388 if Container
.Last
<= Index_Type
'First then
1392 -- Per AI05-0022, the container implementation is required to detect
1393 -- element tampering by a generic actual subprogram.
1396 E
: Elements_Array
renames Container
.Elements
.EA
;
1398 B
: Natural renames Container
'Unrestricted_Access.Busy
;
1399 L
: Natural renames Container
'Unrestricted_Access.Lock
;
1408 for I
in Index_Type
'First .. Container
.Last
- 1 loop
1409 if Is_Less
(E
(I
+ 1), E
(I
)) then
1432 procedure Merge
(Target
, Source
: in out Vector
) is
1433 I
, J
: Index_Type
'Base;
1436 -- The semantics of Merge changed slightly per AI05-0021. It was
1437 -- originally the case that if Target and Source denoted the same
1438 -- container object, then the GNAT implementation of Merge did
1439 -- nothing. However, it was argued that RM05 did not precisely
1440 -- specify the semantics for this corner case. The decision of the
1441 -- ARG was that if Target and Source denote the same non-empty
1442 -- container object, then Program_Error is raised.
1444 if Source
.Last
< Index_Type
'First then -- Source is empty
1448 if Target
'Address = Source
'Address then
1449 raise Program_Error
with
1450 "Target and Source denote same non-empty container";
1453 if Target
.Last
< Index_Type
'First then -- Target is empty
1454 Move
(Target
=> Target
, Source
=> Source
);
1458 if Source
.Busy
> 0 then
1459 raise Program_Error
with
1460 "attempt to tamper with cursors (vector is busy)";
1463 I
:= Target
.Last
; -- original value (before Set_Length)
1464 Target
.Set_Length
(Length
(Target
) + Length
(Source
));
1466 -- Per AI05-0022, the container implementation is required to detect
1467 -- element tampering by a generic actual subprogram.
1470 TA
: Elements_Array
renames Target
.Elements
.EA
;
1471 SA
: Elements_Array
renames Source
.Elements
.EA
;
1473 TB
: Natural renames Target
.Busy
;
1474 TL
: Natural renames Target
.Lock
;
1476 SB
: Natural renames Source
.Busy
;
1477 SL
: Natural renames Source
.Lock
;
1486 J
:= Target
.Last
; -- new value (after Set_Length)
1487 while Source
.Last
>= Index_Type
'First loop
1489 (Source
.Last
<= Index_Type
'First
1490 or else not (Is_Less
(SA
(Source
.Last
),
1491 SA
(Source
.Last
- 1))));
1493 if I
< Index_Type
'First then
1495 Src
: Elements_Array
renames
1496 SA
(Index_Type
'First .. Source
.Last
);
1498 TA
(Index_Type
'First .. J
) := Src
;
1499 Src
:= (others => null);
1502 Source
.Last
:= No_Index
;
1507 (I
<= Index_Type
'First
1508 or else not (Is_Less
(TA
(I
), TA
(I
- 1))));
1511 Src
: Element_Access
renames SA
(Source
.Last
);
1512 Tgt
: Element_Access
renames TA
(I
);
1515 if Is_Less
(Src
, Tgt
) then
1516 Target
.Elements
.EA
(J
) := Tgt
;
1521 Target
.Elements
.EA
(J
) := Src
;
1523 Source
.Last
:= Source
.Last
- 1;
1552 procedure Sort
(Container
: in out Vector
) is
1553 procedure Sort
is new Generic_Array_Sort
1554 (Index_Type
=> Index_Type
,
1555 Element_Type
=> Element_Access
,
1556 Array_Type
=> Elements_Array
,
1559 -- Start of processing for Sort
1562 if Container
.Last
<= Index_Type
'First then
1566 -- The exception behavior for the vector container must match that
1567 -- for the list container, so we check for cursor tampering here
1568 -- (which will catch more things) instead of for element tampering
1569 -- (which will catch fewer things). It's true that the elements of
1570 -- this vector container could be safely moved around while (say) an
1571 -- iteration is taking place (iteration only increments the busy
1572 -- counter), and so technically all we would need here is a test for
1573 -- element tampering (indicated by the lock counter), that's simply
1574 -- an artifact of our array-based implementation. Logically Sort
1575 -- requires a check for cursor tampering.
1577 if Container
.Busy
> 0 then
1578 raise Program_Error
with
1579 "attempt to tamper with cursors (vector is busy)";
1582 -- Per AI05-0022, the container implementation is required to detect
1583 -- element tampering by a generic actual subprogram.
1586 B
: Natural renames Container
.Busy
;
1587 L
: Natural renames Container
.Lock
;
1593 Sort
(Container
.Elements
.EA
(Index_Type
'First .. Container
.Last
));
1606 end Generic_Sorting
;
1612 function Has_Element
(Position
: Cursor
) return Boolean is
1614 if Position
.Container
= null then
1617 return Position
.Index
<= Position
.Container
.Last
;
1626 (Container
: in out Vector
;
1627 Before
: Extended_Index
;
1628 New_Item
: Element_Type
;
1629 Count
: Count_Type
:= 1)
1631 Old_Length
: constant Count_Type
:= Container
.Length
;
1633 Max_Length
: Count_Type
'Base; -- determined from range of Index_Type
1634 New_Length
: Count_Type
'Base; -- sum of current length and Count
1635 New_Last
: Index_Type
'Base; -- last index of vector after insertion
1637 Index
: Index_Type
'Base; -- scratch for intermediate values
1638 J
: Count_Type
'Base; -- scratch
1640 New_Capacity
: Count_Type
'Base; -- length of new, expanded array
1641 Dst_Last
: Index_Type
'Base; -- last index of new, expanded array
1642 Dst
: Elements_Access
; -- new, expanded internal array
1645 -- As a precondition on the generic actual Index_Type, the base type
1646 -- must include Index_Type'Pred (Index_Type'First); this is the value
1647 -- that Container.Last assumes when the vector is empty. However, we do
1648 -- not allow that as the value for Index when specifying where the new
1649 -- items should be inserted, so we must manually check. (That the user
1650 -- is allowed to specify the value at all here is a consequence of the
1651 -- declaration of the Extended_Index subtype, which includes the values
1652 -- in the base range that immediately precede and immediately follow the
1653 -- values in the Index_Type.)
1655 if Before
< Index_Type
'First then
1656 raise Constraint_Error
with
1657 "Before index is out of range (too small)";
1660 -- We do allow a value greater than Container.Last to be specified as
1661 -- the Index, but only if it's immediately greater. This allows for the
1662 -- case of appending items to the back end of the vector. (It is assumed
1663 -- that specifying an index value greater than Last + 1 indicates some
1664 -- deeper flaw in the caller's algorithm, so that case is treated as a
1667 if Before
> Container
.Last
1668 and then Before
> Container
.Last
+ 1
1670 raise Constraint_Error
with
1671 "Before index is out of range (too large)";
1674 -- We treat inserting 0 items into the container as a no-op, even when
1675 -- the container is busy, so we simply return.
1681 -- There are two constraints we need to satisfy. The first constraint is
1682 -- that a container cannot have more than Count_Type'Last elements, so
1683 -- we must check the sum of the current length and the insertion count.
1684 -- Note that we cannot simply add these values, because of the
1685 -- possibility of overflow.
1687 if Old_Length
> Count_Type
'Last - Count
then
1688 raise Constraint_Error
with "Count is out of range";
1691 -- It is now safe compute the length of the new vector, without fear of
1694 New_Length
:= Old_Length
+ Count
;
1696 -- The second constraint is that the new Last index value cannot exceed
1697 -- Index_Type'Last. In each branch below, we calculate the maximum
1698 -- length (computed from the range of values in Index_Type), and then
1699 -- compare the new length to the maximum length. If the new length is
1700 -- acceptable, then we compute the new last index from that.
1702 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1704 -- We have to handle the case when there might be more values in the
1705 -- range of Index_Type than in the range of Count_Type.
1707 if Index_Type'First <= 0 then
1709 -- We know that No_Index (the same as Index_Type'First - 1) is
1710 -- less than 0, so it is safe to compute the following sum without
1711 -- fear of overflow.
1713 Index := No_Index + Index_Type'Base (Count_Type'Last);
1715 if Index <= Index_Type'Last then
1717 -- We have determined that range of Index_Type has at least as
1718 -- many values as in Count_Type, so Count_Type'Last is the
1719 -- maximum number of items that are allowed.
1721 Max_Length := Count_Type'Last;
1724 -- The range of Index_Type has fewer values than in Count_Type,
1725 -- so the maximum number of items is computed from the range of
1728 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1732 -- No_Index is equal or greater than 0, so we can safely compute
1733 -- the difference without fear of overflow (which we would have to
1734 -- worry about if No_Index were less than 0, but that case is
1737 if Index_Type'Last - No_Index >=
1738 Count_Type'Pos (Count_Type'Last)
1740 -- We have determined that range of Index_Type has at least as
1741 -- many values as in Count_Type, so Count_Type'Last is the
1742 -- maximum number of items that are allowed.
1744 Max_Length := Count_Type'Last;
1747 -- The range of Index_Type has fewer values than in Count_Type,
1748 -- so the maximum number of items is computed from the range of
1751 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1755 elsif Index_Type'First <= 0 then
1757 -- We know that No_Index (the same as Index_Type'First - 1) is less
1758 -- than 0, so it is safe to compute the following sum without fear of
1761 J := Count_Type'Base (No_Index) + Count_Type'Last;
1763 if J <= Count_Type'Base (Index_Type'Last) then
1765 -- We have determined that range of Index_Type has at least as
1766 -- many values as in Count_Type, so Count_Type'Last is the maximum
1767 -- number of items that are allowed.
1769 Max_Length := Count_Type'Last;
1772 -- The range of Index_Type has fewer values than Count_Type does,
1773 -- so the maximum number of items is computed from the range of
1777 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1781 -- No_Index is equal or greater than 0, so we can safely compute the
1782 -- difference without fear of overflow (which we would have to worry
1783 -- about if No_Index were less than 0, but that case is handled
1787 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1790 -- We have just computed the maximum length (number of items). We must
1791 -- now compare the requested length to the maximum length, as we do not
1792 -- allow a vector expand beyond the maximum (because that would create
1793 -- an internal array with a last index value greater than
1794 -- Index_Type'Last, with no way to index those elements).
1796 if New_Length > Max_Length then
1797 raise Constraint_Error with "Count is out of range";
1800 -- New_Last is the last index value of the items in the container after
1801 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1802 -- compute its value from the New_Length.
1804 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1805 New_Last
:= No_Index
+ Index_Type
'Base (New_Length
);
1807 New_Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Length
);
1810 if Container
.Elements
= null then
1811 pragma Assert
(Container
.Last
= No_Index
);
1813 -- This is the simplest case, with which we must always begin: we're
1814 -- inserting items into an empty vector that hasn't allocated an
1815 -- internal array yet. Note that we don't need to check the busy bit
1816 -- here, because an empty container cannot be busy.
1818 -- In an indefinite vector, elements are allocated individually, and
1819 -- stored as access values on the internal array (the length of which
1820 -- represents the vector "capacity"), which is separately allocated.
1822 Container
.Elements
:= new Elements_Type
(New_Last
);
1824 -- The element backbone has been successfully allocated, so now we
1825 -- allocate the elements.
1827 for Idx
in Container
.Elements
.EA
'Range loop
1829 -- In order to preserve container invariants, we always attempt
1830 -- the element allocation first, before setting the Last index
1831 -- value, in case the allocation fails (either because there is no
1832 -- storage available, or because element initialization fails).
1835 -- The element allocator may need an accessibility check in the
1836 -- case actual type is class-wide or has access discriminants
1837 -- (see RM 4.8(10.1) and AI12-0035).
1839 pragma Unsuppress
(Accessibility_Check
);
1842 Container
.Elements
.EA
(Idx
) := new Element_Type
'(New_Item);
1845 -- The allocation of the element succeeded, so it is now safe to
1846 -- update the Last index, restoring container invariants.
1848 Container.Last := Idx;
1854 -- The tampering bits exist to prevent an item from being harmfully
1855 -- manipulated while it is being visited. Query, Update, and Iterate
1856 -- increment the busy count on entry, and decrement the count on
1857 -- exit. Insert checks the count to determine whether it is being called
1858 -- while the associated callback procedure is executing.
1860 if Container.Busy > 0 then
1861 raise Program_Error with
1862 "attempt to tamper with cursors (vector is busy)";
1865 if New_Length <= Container.Elements.EA'Length then
1867 -- In this case, we're inserting elements into a vector that has
1868 -- already allocated an internal array, and the existing array has
1869 -- enough unused storage for the new items.
1872 E : Elements_Array renames Container.Elements.EA;
1873 K : Index_Type'Base;
1876 if Before > Container.Last then
1878 -- The new items are being appended to the vector, so no
1879 -- sliding of existing elements is required.
1881 for Idx in Before .. New_Last loop
1883 -- In order to preserve container invariants, we always
1884 -- attempt the element allocation first, before setting the
1885 -- Last index value, in case the allocation fails (either
1886 -- because there is no storage available, or because element
1887 -- initialization fails).
1890 -- The element allocator may need an accessibility check
1891 -- in case the actual type is class-wide or has access
1892 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1894 pragma Unsuppress (Accessibility_Check);
1897 E (Idx) := new Element_Type'(New_Item
);
1900 -- The allocation of the element succeeded, so it is now
1901 -- safe to update the Last index, restoring container
1904 Container
.Last
:= Idx
;
1908 -- The new items are being inserted before some existing
1909 -- elements, so we must slide the existing elements up to their
1910 -- new home. We use the wider of Index_Type'Base and
1911 -- Count_Type'Base as the type for intermediate index values.
1913 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1914 Index := Before + Index_Type'Base (Count);
1916 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1919 -- The new items are being inserted in the middle of the array,
1920 -- in the range [Before, Index). Copy the existing elements to
1921 -- the end of the array, to make room for the new items.
1923 E (Index .. New_Last) := E (Before .. Container.Last);
1924 Container.Last := New_Last;
1926 -- We have copied the existing items up to the end of the
1927 -- array, to make room for the new items in the middle of
1928 -- the array. Now we actually allocate the new items.
1930 -- Note: initialize K outside loop to make it clear that
1931 -- K always has a value if the exception handler triggers.
1936 -- The element allocator may need an accessibility check in
1937 -- the case the actual type is class-wide or has access
1938 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1940 pragma Unsuppress (Accessibility_Check);
1943 while K < Index loop
1944 E (K) := new Element_Type'(New_Item
);
1951 -- Values in the range [Before, K) were successfully
1952 -- allocated, but values in the range [K, Index) are
1953 -- stale (these array positions contain copies of the
1954 -- old items, that did not get assigned a new item,
1955 -- because the allocation failed). We must finish what
1956 -- we started by clearing out all of the stale values,
1957 -- leaving a "hole" in the middle of the array.
1959 E
(K
.. Index
- 1) := (others => null);
1968 -- In this case, we're inserting elements into a vector that has already
1969 -- allocated an internal array, but the existing array does not have
1970 -- enough storage, so we must allocate a new, longer array. In order to
1971 -- guarantee that the amortized insertion cost is O(1), we always
1972 -- allocate an array whose length is some power-of-two factor of the
1973 -- current array length. (The new array cannot have a length less than
1974 -- the New_Length of the container, but its last index value cannot be
1975 -- greater than Index_Type'Last.)
1977 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
1978 while New_Capacity
< New_Length
loop
1979 if New_Capacity
> Count_Type
'Last / 2 then
1980 New_Capacity
:= Count_Type
'Last;
1984 New_Capacity
:= 2 * New_Capacity
;
1987 if New_Capacity
> Max_Length
then
1989 -- We have reached the limit of capacity, so no further expansion
1990 -- will occur. (This is not a problem, as there is never a need to
1991 -- have more capacity than the maximum container length.)
1993 New_Capacity
:= Max_Length
;
1996 -- We have computed the length of the new internal array (and this is
1997 -- what "vector capacity" means), so use that to compute its last index.
1999 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2000 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2003 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2006 -- Now we allocate the new, longer internal array. If the allocation
2007 -- fails, we have not changed any container state, so no side-effect
2008 -- will occur as a result of propagating the exception.
2010 Dst := new Elements_Type (Dst_Last);
2012 -- We have our new internal array. All that needs to be done now is to
2013 -- copy the existing items (if any) from the old array (the "source"
2014 -- array) to the new array (the "destination" array), and then
2015 -- deallocate the old array.
2018 Src : Elements_Access := Container.Elements;
2021 Dst.EA (Index_Type'First .. Before - 1) :=
2022 Src.EA (Index_Type'First .. Before - 1);
2024 if Before > Container.Last then
2026 -- The new items are being appended to the vector, so no
2027 -- sliding of existing elements is required.
2029 -- We have copied the elements from to the old source array to the
2030 -- new destination array, so we can now deallocate the old array.
2032 Container.Elements := Dst;
2035 -- Now we append the new items.
2037 for Idx in Before .. New_Last loop
2039 -- In order to preserve container invariants, we always attempt
2040 -- the element allocation first, before setting the Last index
2041 -- value, in case the allocation fails (either because there
2042 -- is no storage available, or because element initialization
2046 -- The element allocator may need an accessibility check in
2047 -- the case the actual type is class-wide or has access
2048 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2050 pragma Unsuppress (Accessibility_Check);
2053 Dst.EA (Idx) := new Element_Type'(New_Item
);
2056 -- The allocation of the element succeeded, so it is now safe
2057 -- to update the Last index, restoring container invariants.
2059 Container
.Last
:= Idx
;
2063 -- The new items are being inserted before some existing elements,
2064 -- so we must slide the existing elements up to their new home.
2066 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2067 Index := Before + Index_Type'Base (Count);
2069 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2072 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2074 -- We have copied the elements from to the old source array to the
2075 -- new destination array, so we can now deallocate the old array.
2077 Container.Elements := Dst;
2078 Container.Last := New_Last;
2081 -- The new array has a range in the middle containing null access
2082 -- values. Fill in that partition of the array with the new items.
2084 for Idx in Before .. Index - 1 loop
2086 -- Note that container invariants have already been satisfied
2087 -- (in particular, the Last index value of the vector has
2088 -- already been updated), so if this allocation fails we simply
2089 -- let it propagate.
2092 -- The element allocator may need an accessibility check in
2093 -- the case the actual type is class-wide or has access
2094 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2096 pragma Unsuppress (Accessibility_Check);
2099 Dst.EA (Idx) := new Element_Type'(New_Item
);
2107 (Container
: in out Vector
;
2108 Before
: Extended_Index
;
2111 N
: constant Count_Type
:= Length
(New_Item
);
2112 J
: Index_Type
'Base;
2115 -- Use Insert_Space to create the "hole" (the destination slice) into
2116 -- which we copy the source items.
2118 Insert_Space
(Container
, Before
, Count
=> N
);
2122 -- There's nothing else to do here (vetting of parameters was
2123 -- performed already in Insert_Space), so we simply return.
2128 if Container
'Address /= New_Item
'Address then
2130 -- This is the simple case. New_Item denotes an object different
2131 -- from Container, so there's nothing special we need to do to copy
2132 -- the source items to their destination, because all of the source
2133 -- items are contiguous.
2136 subtype Src_Index_Subtype
is Index_Type
'Base range
2137 Index_Type
'First .. New_Item
.Last
;
2139 Src
: Elements_Array
renames
2140 New_Item
.Elements
.EA
(Src_Index_Subtype
);
2142 Dst
: Elements_Array
renames Container
.Elements
.EA
;
2144 Dst_Index
: Index_Type
'Base;
2147 Dst_Index
:= Before
- 1;
2148 for Src_Index
in Src
'Range loop
2149 Dst_Index
:= Dst_Index
+ 1;
2151 if Src
(Src_Index
) /= null then
2152 Dst
(Dst_Index
) := new Element_Type
'(Src (Src_Index).all);
2160 -- New_Item denotes the same object as Container, so an insertion has
2161 -- potentially split the source items. The first source slice is
2162 -- [Index_Type'First, Before), and the second source slice is
2163 -- [J, Container.Last], where index value J is the first index of the
2164 -- second slice. (J gets computed below, but only after we have
2165 -- determined that the second source slice is non-empty.) The
2166 -- destination slice is always the range [Before, J). We perform the
2167 -- copy in two steps, using each of the two slices of the source items.
2170 L : constant Index_Type'Base := Before - 1;
2172 subtype Src_Index_Subtype is Index_Type'Base range
2173 Index_Type'First .. L;
2175 Src : Elements_Array renames
2176 Container.Elements.EA (Src_Index_Subtype);
2178 Dst : Elements_Array renames Container.Elements.EA;
2180 Dst_Index : Index_Type'Base;
2183 -- We first copy the source items that precede the space we
2184 -- inserted. (If Before equals Index_Type'First, then this first
2185 -- source slice will be empty, which is harmless.)
2187 Dst_Index := Before - 1;
2188 for Src_Index in Src'Range loop
2189 Dst_Index := Dst_Index + 1;
2191 if Src (Src_Index) /= null then
2192 Dst (Dst_Index) := new Element_Type'(Src
(Src_Index
).all);
2196 if Src
'Length = N
then
2198 -- The new items were effectively appended to the container, so we
2199 -- have already copied all of the items that need to be copied.
2200 -- We return early here, even though the source slice below is
2201 -- empty (so the assignment would be harmless), because we want to
2202 -- avoid computing J, which will overflow if J is greater than
2203 -- Index_Type'Base'Last.
2209 -- Index value J is the first index of the second source slice. (It is
2210 -- also 1 greater than the last index of the destination slice.) Note:
2211 -- avoid computing J if J is greater than Index_Type'Base'Last, in order
2212 -- to avoid overflow. Prevent that by returning early above, immediately
2213 -- after copying the first slice of the source, and determining that
2214 -- this second slice of the source is empty.
2216 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2217 J := Before + Index_Type'Base (N);
2219 J := Index_Type'Base (Count_Type'Base (Before) + N);
2223 subtype Src_Index_Subtype is Index_Type'Base range
2224 J .. Container.Last;
2226 Src : Elements_Array renames
2227 Container.Elements.EA (Src_Index_Subtype);
2229 Dst : Elements_Array renames Container.Elements.EA;
2231 Dst_Index : Index_Type'Base;
2234 -- We next copy the source items that follow the space we inserted.
2235 -- Index value Dst_Index is the first index of that portion of the
2236 -- destination that receives this slice of the source. (For the
2237 -- reasons given above, this slice is guaranteed to be non-empty.)
2239 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2240 Dst_Index
:= J
- Index_Type
'Base (Src
'Length);
2242 Dst_Index
:= Index_Type
'Base (Count_Type
'Base (J
) - Src
'Length);
2245 for Src_Index
in Src
'Range loop
2246 if Src
(Src_Index
) /= null then
2247 Dst
(Dst_Index
) := new Element_Type
'(Src (Src_Index).all);
2250 Dst_Index := Dst_Index + 1;
2256 (Container : in out Vector;
2260 Index : Index_Type'Base;
2263 if Before.Container /= null
2264 and then Before.Container /= Container'Unrestricted_Access
2266 raise Program_Error with "Before cursor denotes wrong container";
2269 if Is_Empty (New_Item) then
2273 if Before.Container = null or else Before.Index > Container.Last then
2274 if Container.Last = Index_Type'Last then
2275 raise Constraint_Error with
2276 "vector is already at its maximum length";
2279 Index := Container.Last + 1;
2282 Index := Before.Index;
2285 Insert (Container, Index, New_Item);
2289 (Container : in out Vector;
2292 Position : out Cursor)
2294 Index : Index_Type'Base;
2297 if Before.Container /= null
2298 and then Before.Container /=
2299 Vector_Access'(Container
'Unrestricted_Access)
2301 raise Program_Error
with "Before cursor denotes wrong container";
2304 if Is_Empty
(New_Item
) then
2305 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2306 Position
:= No_Element
;
2308 Position
:= (Container
'Unrestricted_Access, Before
.Index
);
2314 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2315 if Container
.Last
= Index_Type
'Last then
2316 raise Constraint_Error
with
2317 "vector is already at its maximum length";
2320 Index
:= Container
.Last
+ 1;
2323 Index
:= Before
.Index
;
2326 Insert
(Container
, Index
, New_Item
);
2328 Position
:= Cursor
'(Container'Unrestricted_Access, Index);
2332 (Container : in out Vector;
2334 New_Item : Element_Type;
2335 Count : Count_Type := 1)
2337 Index : Index_Type'Base;
2340 if Before.Container /= null
2341 and then Before.Container /= Container'Unrestricted_Access
2343 raise Program_Error with "Before cursor denotes wrong container";
2350 if Before.Container = null or else Before.Index > Container.Last then
2351 if Container.Last = Index_Type'Last then
2352 raise Constraint_Error with
2353 "vector is already at its maximum length";
2356 Index := Container.Last + 1;
2359 Index := Before.Index;
2362 Insert (Container, Index, New_Item, Count);
2366 (Container : in out Vector;
2368 New_Item : Element_Type;
2369 Position : out Cursor;
2370 Count : Count_Type := 1)
2372 Index : Index_Type'Base;
2375 if Before.Container /= null
2376 and then Before.Container /= Container'Unrestricted_Access
2378 raise Program_Error with "Before cursor denotes wrong container";
2382 if Before.Container = null
2383 or else Before.Index > Container.Last
2385 Position := No_Element;
2387 Position := (Container'Unrestricted_Access, Before.Index);
2393 if Before.Container = null or else Before.Index > Container.Last then
2394 if Container.Last = Index_Type'Last then
2395 raise Constraint_Error with
2396 "vector is already at its maximum length";
2399 Index := Container.Last + 1;
2402 Index := Before.Index;
2405 Insert (Container, Index, New_Item, Count);
2407 Position := (Container'Unrestricted_Access, Index);
2414 procedure Insert_Space
2415 (Container : in out Vector;
2416 Before : Extended_Index;
2417 Count : Count_Type := 1)
2419 Old_Length : constant Count_Type := Container.Length;
2421 Max_Length : Count_Type'Base; -- determined from range of Index_Type
2422 New_Length : Count_Type'Base; -- sum of current length and Count
2423 New_Last : Index_Type'Base; -- last index of vector after insertion
2425 Index : Index_Type'Base; -- scratch for intermediate values
2426 J : Count_Type'Base; -- scratch
2428 New_Capacity : Count_Type'Base; -- length of new, expanded array
2429 Dst_Last : Index_Type'Base; -- last index of new, expanded array
2430 Dst : Elements_Access; -- new, expanded internal array
2433 -- As a precondition on the generic actual Index_Type, the base type
2434 -- must include Index_Type'Pred (Index_Type'First); this is the value
2435 -- that Container.Last assumes when the vector is empty. However, we do
2436 -- not allow that as the value for Index when specifying where the new
2437 -- items should be inserted, so we must manually check. (That the user
2438 -- is allowed to specify the value at all here is a consequence of the
2439 -- declaration of the Extended_Index subtype, which includes the values
2440 -- in the base range that immediately precede and immediately follow the
2441 -- values in the Index_Type.)
2443 if Before < Index_Type'First then
2444 raise Constraint_Error with
2445 "Before index is out of range (too small)";
2448 -- We do allow a value greater than Container.Last to be specified as
2449 -- the Index, but only if it's immediately greater. This allows for the
2450 -- case of appending items to the back end of the vector. (It is assumed
2451 -- that specifying an index value greater than Last + 1 indicates some
2452 -- deeper flaw in the caller's algorithm, so that case is treated as a
2455 if Before > Container.Last and then Before > Container.Last + 1 then
2456 raise Constraint_Error with
2457 "Before index is out of range (too large)";
2460 -- We treat inserting 0 items into the container as a no-op, even when
2461 -- the container is busy, so we simply return.
2467 -- There are two constraints we need to satisfy. The first constraint is
2468 -- that a container cannot have more than Count_Type'Last elements, so
2469 -- we must check the sum of the current length and the insertion
2470 -- count. Note that we cannot simply add these values, because of the
2471 -- possibility of overflow.
2473 if Old_Length > Count_Type'Last - Count then
2474 raise Constraint_Error with "Count is out of range";
2477 -- It is now safe compute the length of the new vector, without fear of
2480 New_Length := Old_Length + Count;
2482 -- The second constraint is that the new Last index value cannot exceed
2483 -- Index_Type'Last. In each branch below, we calculate the maximum
2484 -- length (computed from the range of values in Index_Type), and then
2485 -- compare the new length to the maximum length. If the new length is
2486 -- acceptable, then we compute the new last index from that.
2488 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2489 -- We have to handle the case when there might be more values in the
2490 -- range of Index_Type than in the range of Count_Type.
2492 if Index_Type
'First <= 0 then
2494 -- We know that No_Index (the same as Index_Type'First - 1) is
2495 -- less than 0, so it is safe to compute the following sum without
2496 -- fear of overflow.
2498 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
2500 if Index
<= Index_Type
'Last then
2502 -- We have determined that range of Index_Type has at least as
2503 -- many values as in Count_Type, so Count_Type'Last is the
2504 -- maximum number of items that are allowed.
2506 Max_Length
:= Count_Type
'Last;
2509 -- The range of Index_Type has fewer values than in Count_Type,
2510 -- so the maximum number of items is computed from the range of
2513 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2517 -- No_Index is equal or greater than 0, so we can safely compute
2518 -- the difference without fear of overflow (which we would have to
2519 -- worry about if No_Index were less than 0, but that case is
2522 if Index_Type
'Last - No_Index
>=
2523 Count_Type
'Pos (Count_Type
'Last)
2525 -- We have determined that range of Index_Type has at least as
2526 -- many values as in Count_Type, so Count_Type'Last is the
2527 -- maximum number of items that are allowed.
2529 Max_Length
:= Count_Type
'Last;
2532 -- The range of Index_Type has fewer values than in Count_Type,
2533 -- so the maximum number of items is computed from the range of
2536 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2540 elsif Index_Type
'First <= 0 then
2542 -- We know that No_Index (the same as Index_Type'First - 1) is less
2543 -- than 0, so it is safe to compute the following sum without fear of
2546 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
2548 if J
<= Count_Type
'Base (Index_Type
'Last) then
2550 -- We have determined that range of Index_Type has at least as
2551 -- many values as in Count_Type, so Count_Type'Last is the maximum
2552 -- number of items that are allowed.
2554 Max_Length
:= Count_Type
'Last;
2557 -- The range of Index_Type has fewer values than Count_Type does,
2558 -- so the maximum number of items is computed from the range of
2562 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2566 -- No_Index is equal or greater than 0, so we can safely compute the
2567 -- difference without fear of overflow (which we would have to worry
2568 -- about if No_Index were less than 0, but that case is handled
2572 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2575 -- We have just computed the maximum length (number of items). We must
2576 -- now compare the requested length to the maximum length, as we do not
2577 -- allow a vector expand beyond the maximum (because that would create
2578 -- an internal array with a last index value greater than
2579 -- Index_Type'Last, with no way to index those elements).
2581 if New_Length
> Max_Length
then
2582 raise Constraint_Error
with "Count is out of range";
2585 -- New_Last is the last index value of the items in the container after
2586 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2587 -- compute its value from the New_Length.
2589 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2590 New_Last := No_Index + Index_Type'Base (New_Length);
2592 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2595 if Container.Elements = null then
2596 pragma Assert (Container.Last = No_Index);
2598 -- This is the simplest case, with which we must always begin: we're
2599 -- inserting items into an empty vector that hasn't allocated an
2600 -- internal array yet. Note that we don't need to check the busy bit
2601 -- here, because an empty container cannot be busy.
2603 -- In an indefinite vector, elements are allocated individually, and
2604 -- stored as access values on the internal array (the length of which
2605 -- represents the vector "capacity"), which is separately allocated.
2606 -- We have no elements here (because we're inserting "space"), so all
2607 -- we need to do is allocate the backbone.
2609 Container.Elements := new Elements_Type (New_Last);
2610 Container.Last := New_Last;
2615 -- The tampering bits exist to prevent an item from being harmfully
2616 -- manipulated while it is being visited. Query, Update, and Iterate
2617 -- increment the busy count on entry, and decrement the count on exit.
2618 -- Insert checks the count to determine whether it is being called while
2619 -- the associated callback procedure is executing.
2621 if Container.Busy > 0 then
2622 raise Program_Error with
2623 "attempt to tamper with cursors (vector is busy)";
2626 if New_Length <= Container.Elements.EA'Length then
2628 -- In this case, we are inserting elements into a vector that has
2629 -- already allocated an internal array, and the existing array has
2630 -- enough unused storage for the new items.
2633 E : Elements_Array renames Container.Elements.EA;
2636 if Before <= Container.Last then
2638 -- The new space is being inserted before some existing
2639 -- elements, so we must slide the existing elements up to
2640 -- their new home. We use the wider of Index_Type'Base and
2641 -- Count_Type'Base as the type for intermediate index values.
2643 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2644 Index
:= Before
+ Index_Type
'Base (Count
);
2646 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2649 E
(Index
.. New_Last
) := E
(Before
.. Container
.Last
);
2650 E
(Before
.. Index
- 1) := (others => null);
2654 Container
.Last
:= New_Last
;
2658 -- In this case, we're inserting elements into a vector that has already
2659 -- allocated an internal array, but the existing array does not have
2660 -- enough storage, so we must allocate a new, longer array. In order to
2661 -- guarantee that the amortized insertion cost is O(1), we always
2662 -- allocate an array whose length is some power-of-two factor of the
2663 -- current array length. (The new array cannot have a length less than
2664 -- the New_Length of the container, but its last index value cannot be
2665 -- greater than Index_Type'Last.)
2667 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
2668 while New_Capacity
< New_Length
loop
2669 if New_Capacity
> Count_Type
'Last / 2 then
2670 New_Capacity
:= Count_Type
'Last;
2674 New_Capacity
:= 2 * New_Capacity
;
2677 if New_Capacity
> Max_Length
then
2679 -- We have reached the limit of capacity, so no further expansion
2680 -- will occur. (This is not a problem, as there is never a need to
2681 -- have more capacity than the maximum container length.)
2683 New_Capacity
:= Max_Length
;
2686 -- We have computed the length of the new internal array (and this is
2687 -- what "vector capacity" means), so use that to compute its last index.
2689 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2690 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2693 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2696 -- Now we allocate the new, longer internal array. If the allocation
2697 -- fails, we have not changed any container state, so no side-effect
2698 -- will occur as a result of propagating the exception.
2700 Dst := new Elements_Type (Dst_Last);
2702 -- We have our new internal array. All that needs to be done now is to
2703 -- copy the existing items (if any) from the old array (the "source"
2704 -- array) to the new array (the "destination" array), and then
2705 -- deallocate the old array.
2708 Src : Elements_Access := Container.Elements;
2711 Dst.EA (Index_Type'First .. Before - 1) :=
2712 Src.EA (Index_Type'First .. Before - 1);
2714 if Before <= Container.Last then
2716 -- The new items are being inserted before some existing elements,
2717 -- so we must slide the existing elements up to their new home.
2719 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2720 Index
:= Before
+ Index_Type
'Base (Count
);
2722 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2725 Dst
.EA
(Index
.. New_Last
) := Src
.EA
(Before
.. Container
.Last
);
2728 -- We have copied the elements from to the old, source array to the
2729 -- new, destination array, so we can now restore invariants, and
2730 -- deallocate the old array.
2732 Container
.Elements
:= Dst
;
2733 Container
.Last
:= New_Last
;
2738 procedure Insert_Space
2739 (Container
: in out Vector
;
2741 Position
: out Cursor
;
2742 Count
: Count_Type
:= 1)
2744 Index
: Index_Type
'Base;
2747 if Before
.Container
/= null
2748 and then Before
.Container
/= Container
'Unrestricted_Access
2750 raise Program_Error
with "Before cursor denotes wrong container";
2754 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2755 Position
:= No_Element
;
2757 Position
:= (Container
'Unrestricted_Access, Before
.Index
);
2763 if Before
.Container
= null
2764 or else Before
.Index
> Container
.Last
2766 if Container
.Last
= Index_Type
'Last then
2767 raise Constraint_Error
with
2768 "vector is already at its maximum length";
2771 Index
:= Container
.Last
+ 1;
2774 Index
:= Before
.Index
;
2777 Insert_Space
(Container
, Index
, Count
);
2779 Position
:= Cursor
'(Container'Unrestricted_Access, Index);
2786 function Is_Empty (Container : Vector) return Boolean is
2788 return Container.Last < Index_Type'First;
2796 (Container : Vector;
2797 Process : not null access procedure (Position : Cursor))
2799 B : Natural renames Container'Unrestricted_Access.all.Busy;
2805 for Indx in Index_Type'First .. Container.Last loop
2806 Process (Cursor'(Container
'Unrestricted_Access, Indx
));
2817 function Iterate
(Container
: Vector
)
2818 return Vector_Iterator_Interfaces
.Reversible_Iterator
'Class
2820 V
: constant Vector_Access
:= Container
'Unrestricted_Access;
2821 B
: Natural renames V
.Busy
;
2824 -- The value of its Index component influences the behavior of the First
2825 -- and Last selector functions of the iterator object. When the Index
2826 -- component is No_Index (as is the case here), this means the iterator
2827 -- object was constructed without a start expression. This is a complete
2828 -- iterator, meaning that the iteration starts from the (logical)
2829 -- beginning of the sequence of items.
2831 -- Note: For a forward iterator, Container.First is the beginning, and
2832 -- for a reverse iterator, Container.Last is the beginning.
2834 return It
: constant Iterator
:=
2835 (Limited_Controlled
with
2844 (Container
: Vector
;
2846 return Vector_Iterator_Interfaces
.Reversible_Iterator
'Class
2848 V
: constant Vector_Access
:= Container
'Unrestricted_Access;
2849 B
: Natural renames V
.Busy
;
2852 -- It was formerly the case that when Start = No_Element, the partial
2853 -- iterator was defined to behave the same as for a complete iterator,
2854 -- and iterate over the entire sequence of items. However, those
2855 -- semantics were unintuitive and arguably error-prone (it is too easy
2856 -- to accidentally create an endless loop), and so they were changed,
2857 -- per the ARG meeting in Denver on 2011/11. However, there was no
2858 -- consensus about what positive meaning this corner case should have,
2859 -- and so it was decided to simply raise an exception. This does imply,
2860 -- however, that it is not possible to use a partial iterator to specify
2861 -- an empty sequence of items.
2863 if Start
.Container
= null then
2864 raise Constraint_Error
with
2865 "Start position for iterator equals No_Element";
2868 if Start
.Container
/= V
then
2869 raise Program_Error
with
2870 "Start cursor of Iterate designates wrong vector";
2873 if Start
.Index
> V
.Last
then
2874 raise Constraint_Error
with
2875 "Start position for iterator equals No_Element";
2878 -- The value of its Index component influences the behavior of the First
2879 -- and Last selector functions of the iterator object. When the Index
2880 -- component is not No_Index (as is the case here), it means that this
2881 -- is a partial iteration, over a subset of the complete sequence of
2882 -- items. The iterator object was constructed with a start expression,
2883 -- indicating the position from which the iteration begins. Note that
2884 -- the start position has the same value irrespective of whether this
2885 -- is a forward or reverse iteration.
2887 return It
: constant Iterator
:=
2888 (Limited_Controlled
with
2890 Index
=> Start
.Index
)
2900 function Last
(Container
: Vector
) return Cursor
is
2902 if Is_Empty
(Container
) then
2906 return (Container
'Unrestricted_Access, Container
.Last
);
2909 function Last
(Object
: Iterator
) return Cursor
is
2911 -- The value of the iterator object's Index component influences the
2912 -- behavior of the Last (and First) selector function.
2914 -- When the Index component is No_Index, this means the iterator
2915 -- object was constructed without a start expression, in which case the
2916 -- (reverse) iteration starts from the (logical) beginning of the entire
2917 -- sequence (corresponding to Container.Last, for a reverse iterator).
2919 -- Otherwise, this is iteration over a partial sequence of items.
2920 -- When the Index component is not No_Index, the iterator object was
2921 -- constructed with a start expression, that specifies the position
2922 -- from which the (reverse) partial iteration begins.
2924 if Object
.Index
= No_Index
then
2925 return Last
(Object
.Container
.all);
2927 return Cursor
'(Object.Container, Object.Index);
2935 function Last_Element (Container : Vector) return Element_Type is
2937 if Container.Last = No_Index then
2938 raise Constraint_Error with "Container is empty";
2942 EA : constant Element_Access :=
2943 Container.Elements.EA (Container.Last);
2946 raise Constraint_Error with "last element is empty";
2957 function Last_Index (Container : Vector) return Extended_Index is
2959 return Container.Last;
2966 function Length (Container : Vector) return Count_Type is
2967 L : constant Index_Type'Base := Container.Last;
2968 F : constant Index_Type := Index_Type'First;
2971 -- The base range of the index type (Index_Type'Base) might not include
2972 -- all values for length (Count_Type). Contrariwise, the index type
2973 -- might include values outside the range of length. Hence we use
2974 -- whatever type is wider for intermediate values when calculating
2975 -- length. Note that no matter what the index type is, the maximum
2976 -- length to which a vector is allowed to grow is always the minimum
2977 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2979 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2980 -- to have a base range of -128 .. 127, but the corresponding vector
2981 -- would have lengths in the range 0 .. 255. In this case we would need
2982 -- to use Count_Type'Base for intermediate values.
2984 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2985 -- vector would have a maximum length of 10, but the index values lie
2986 -- outside the range of Count_Type (which is only 32 bits). In this
2987 -- case we would need to use Index_Type'Base for intermediate values.
2989 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
2990 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2992 return Count_Type (L - F + 1);
3001 (Target : in out Vector;
3002 Source : in out Vector)
3005 if Target'Address = Source'Address then
3009 if Source.Busy > 0 then
3010 raise Program_Error with
3011 "attempt to tamper with cursors (Source is busy)";
3014 Clear (Target); -- Checks busy-bit
3017 Target_Elements : constant Elements_Access := Target.Elements;
3019 Target.Elements := Source.Elements;
3020 Source.Elements := Target_Elements;
3023 Target.Last := Source.Last;
3024 Source.Last := No_Index;
3031 function Next (Position : Cursor) return Cursor is
3033 if Position.Container = null then
3035 elsif Position.Index < Position.Container.Last then
3036 return (Position.Container, Position.Index + 1);
3042 function Next (Object : Iterator; Position : Cursor) return Cursor is
3044 if Position.Container = null then
3046 elsif Position.Container /= Object.Container then
3047 raise Program_Error with
3048 "Position cursor of Next designates wrong vector";
3050 return Next (Position);
3054 procedure Next (Position : in out Cursor) is
3056 if Position.Container = null then
3058 elsif Position.Index < Position.Container.Last then
3059 Position.Index := Position.Index + 1;
3061 Position := No_Element;
3069 procedure Prepend (Container : in out Vector; New_Item : Vector) is
3071 Insert (Container, Index_Type'First, New_Item);
3075 (Container : in out Vector;
3076 New_Item : Element_Type;
3077 Count : Count_Type := 1)
3080 Insert (Container, Index_Type'First, New_Item, Count);
3087 procedure Previous (Position : in out Cursor) is
3089 if Position.Container = null then
3091 elsif Position.Index > Index_Type'First then
3092 Position.Index := Position.Index - 1;
3094 Position := No_Element;
3098 function Previous (Position : Cursor) return Cursor is
3100 if Position.Container = null then
3102 elsif Position.Index > Index_Type'First then
3103 return (Position.Container, Position.Index - 1);
3109 function Previous (Object : Iterator; Position : Cursor) return Cursor is
3111 if Position.Container = null then
3113 elsif Position.Container /= Object.Container then
3114 raise Program_Error with
3115 "Position cursor of Previous designates wrong vector";
3117 return Previous (Position);
3125 procedure Query_Element
3126 (Container : Vector;
3128 Process : not null access procedure (Element : Element_Type))
3130 V : Vector renames Container'Unrestricted_Access.all;
3131 B : Natural renames V.Busy;
3132 L : Natural renames V.Lock;
3135 if Index > Container.Last then
3136 raise Constraint_Error with "Index is out of range";
3139 if V.Elements.EA (Index) = null then
3140 raise Constraint_Error with "element is null";
3147 Process (V.Elements.EA (Index).all);
3159 procedure Query_Element
3161 Process : not null access procedure (Element : Element_Type))
3164 if Position.Container = null then
3165 raise Constraint_Error with "Position cursor has no element";
3167 Query_Element (Position.Container.all, Position.Index, Process);
3176 (Stream : not null access Root_Stream_Type'Class;
3177 Container : out Vector)
3179 Length : Count_Type'Base;
3180 Last : Index_Type'Base := Index_Type'Pred (Index_Type'First);
3186 Count_Type'Base'Read
(Stream
, Length
);
3188 if Length
> Capacity
(Container
) then
3189 Reserve_Capacity
(Container
, Capacity
=> Length
);
3192 for J
in Count_Type
range 1 .. Length
loop
3195 Boolean'Read (Stream
, B
);
3198 Container
.Elements
.EA
(Last
) :=
3199 new Element_Type
'(Element_Type'Input (Stream));
3202 Container.Last := Last;
3207 (Stream : not null access Root_Stream_Type'Class;
3208 Position : out Cursor)
3211 raise Program_Error with "attempt to stream vector cursor";
3215 (Stream : not null access Root_Stream_Type'Class;
3216 Item : out Reference_Type)
3219 raise Program_Error with "attempt to stream reference";
3223 (Stream : not null access Root_Stream_Type'Class;
3224 Item : out Constant_Reference_Type)
3227 raise Program_Error with "attempt to stream reference";
3235 (Container : aliased in out Vector;
3236 Position : Cursor) return Reference_Type
3241 if Position.Container = null then
3242 raise Constraint_Error with "Position cursor has no element";
3245 if Position.Container /= Container'Unrestricted_Access then
3246 raise Program_Error with "Position cursor denotes wrong container";
3249 if Position.Index > Position.Container.Last then
3250 raise Constraint_Error with "Position cursor is out of range";
3253 E := Container.Elements.EA (Position.Index);
3256 raise Constraint_Error with "element at Position is empty";
3260 C : Vector renames Container'Unrestricted_Access.all;
3261 B : Natural renames C.Busy;
3262 L : Natural renames C.Lock;
3264 return R : constant Reference_Type :=
3265 (Element => E.all'Access,
3266 Control => (Controlled with Position.Container))
3275 (Container : aliased in out Vector;
3276 Index : Index_Type) return Reference_Type
3281 if Index > Container.Last then
3282 raise Constraint_Error with "Index is out of range";
3285 E := Container.Elements.EA (Index);
3288 raise Constraint_Error with "element at Index is empty";
3292 C : Vector renames Container'Unrestricted_Access.all;
3293 B : Natural renames C.Busy;
3294 L : Natural renames C.Lock;
3296 return R : constant Reference_Type :=
3297 (Element => E.all'Access,
3298 Control => (Controlled with Container'Unrestricted_Access))
3306 ---------------------
3307 -- Replace_Element --
3308 ---------------------
3310 procedure Replace_Element
3311 (Container : in out Vector;
3313 New_Item : Element_Type)
3316 if Index > Container.Last then
3317 raise Constraint_Error with "Index is out of range";
3320 if Container.Lock > 0 then
3321 raise Program_Error with
3322 "attempt to tamper with elements (vector is locked)";
3326 X : Element_Access := Container.Elements.EA (Index);
3328 -- The element allocator may need an accessibility check in the case
3329 -- where the actual type is class-wide or has access discriminants
3330 -- (see RM 4.8(10.1) and AI12-0035).
3332 pragma Unsuppress (Accessibility_Check);
3335 Container.Elements.EA (Index) := new Element_Type'(New_Item
);
3338 end Replace_Element
;
3340 procedure Replace_Element
3341 (Container
: in out Vector
;
3343 New_Item
: Element_Type
)
3346 if Position
.Container
= null then
3347 raise Constraint_Error
with "Position cursor has no element";
3350 if Position
.Container
/= Container
'Unrestricted_Access then
3351 raise Program_Error
with "Position cursor denotes wrong container";
3354 if Position
.Index
> Container
.Last
then
3355 raise Constraint_Error
with "Position cursor is out of range";
3358 if Container
.Lock
> 0 then
3359 raise Program_Error
with
3360 "attempt to tamper with elements (vector is locked)";
3364 X
: Element_Access
:= Container
.Elements
.EA
(Position
.Index
);
3366 -- The element allocator may need an accessibility check in the case
3367 -- where the actual type is class-wide or has access discriminants
3368 -- (see RM 4.8(10.1) and AI12-0035).
3370 pragma Unsuppress
(Accessibility_Check
);
3373 Container
.Elements
.EA
(Position
.Index
) := new Element_Type
'(New_Item);
3376 end Replace_Element;
3378 ----------------------
3379 -- Reserve_Capacity --
3380 ----------------------
3382 procedure Reserve_Capacity
3383 (Container : in out Vector;
3384 Capacity : Count_Type)
3386 N : constant Count_Type := Length (Container);
3388 Index : Count_Type'Base;
3389 Last : Index_Type'Base;
3392 -- Reserve_Capacity can be used to either expand the storage available
3393 -- for elements (this would be its typical use, in anticipation of
3394 -- future insertion), or to trim back storage. In the latter case,
3395 -- storage can only be trimmed back to the limit of the container
3396 -- length. Note that Reserve_Capacity neither deletes (active) elements
3397 -- nor inserts elements; it only affects container capacity, never
3398 -- container length.
3400 if Capacity = 0 then
3402 -- This is a request to trim back storage, to the minimum amount
3403 -- possible given the current state of the container.
3407 -- The container is empty, so in this unique case we can
3408 -- deallocate the entire internal array. Note that an empty
3409 -- container can never be busy, so there's no need to check the
3413 X : Elements_Access := Container.Elements;
3416 -- First we remove the internal array from the container, to
3417 -- handle the case when the deallocation raises an exception
3418 -- (although that's unlikely, since this is simply an array of
3419 -- access values, all of which are null).
3421 Container.Elements := null;
3423 -- Container invariants have been restored, so it is now safe
3424 -- to attempt to deallocate the internal array.
3429 elsif N < Container.Elements.EA'Length then
3431 -- The container is not empty, and the current length is less than
3432 -- the current capacity, so there's storage available to trim. In
3433 -- this case, we allocate a new internal array having a length
3434 -- that exactly matches the number of items in the
3435 -- container. (Reserve_Capacity does not delete active elements,
3436 -- so this is the best we can do with respect to minimizing
3439 if Container.Busy > 0 then
3440 raise Program_Error with
3441 "attempt to tamper with cursors (vector is busy)";
3445 subtype Array_Index_Subtype is Index_Type'Base range
3446 Index_Type'First .. Container.Last;
3448 Src : Elements_Array renames
3449 Container.Elements.EA (Array_Index_Subtype);
3451 X : Elements_Access := Container.Elements;
3454 -- Although we have isolated the old internal array that we're
3455 -- going to deallocate, we don't deallocate it until we have
3456 -- successfully allocated a new one. If there is an exception
3457 -- during allocation (because there is not enough storage), we
3458 -- let it propagate without causing any side-effect.
3460 Container.Elements := new Elements_Type'(Container
.Last
, Src
);
3462 -- We have successfully allocated a new internal array (with a
3463 -- smaller length than the old one, and containing a copy of
3464 -- just the active elements in the container), so we can
3465 -- deallocate the old array.
3474 -- Reserve_Capacity can be used to expand the storage available for
3475 -- elements, but we do not let the capacity grow beyond the number of
3476 -- values in Index_Type'Range. (Were it otherwise, there would be no way
3477 -- to refer to the elements with index values greater than
3478 -- Index_Type'Last, so that storage would be wasted.) Here we compute
3479 -- the Last index value of the new internal array, in a way that avoids
3480 -- any possibility of overflow.
3482 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3484 -- We perform a two-part test. First we determine whether the
3485 -- computed Last value lies in the base range of the type, and then
3486 -- determine whether it lies in the range of the index (sub)type.
3488 -- Last must satisfy this relation:
3489 -- First + Length - 1 <= Last
3490 -- We regroup terms:
3491 -- First - 1 <= Last - Length
3492 -- Which can rewrite as:
3493 -- No_Index <= Last - Length
3495 if Index_Type'Base'Last
- Index_Type
'Base (Capacity
) < No_Index
then
3496 raise Constraint_Error
with "Capacity is out of range";
3499 -- We now know that the computed value of Last is within the base
3500 -- range of the type, so it is safe to compute its value:
3502 Last
:= No_Index
+ Index_Type
'Base (Capacity
);
3504 -- Finally we test whether the value is within the range of the
3505 -- generic actual index subtype:
3507 if Last
> Index_Type
'Last then
3508 raise Constraint_Error
with "Capacity is out of range";
3511 elsif Index_Type
'First <= 0 then
3513 -- Here we can compute Last directly, in the normal way. We know that
3514 -- No_Index is less than 0, so there is no danger of overflow when
3515 -- adding the (positive) value of Capacity.
3517 Index
:= Count_Type
'Base (No_Index
) + Capacity
; -- Last
3519 if Index
> Count_Type
'Base (Index_Type
'Last) then
3520 raise Constraint_Error
with "Capacity is out of range";
3523 -- We know that the computed value (having type Count_Type) of Last
3524 -- is within the range of the generic actual index subtype, so it is
3525 -- safe to convert to Index_Type:
3527 Last
:= Index_Type
'Base (Index
);
3530 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3531 -- must test the length indirectly (by working backwards from the
3532 -- largest possible value of Last), in order to prevent overflow.
3534 Index
:= Count_Type
'Base (Index_Type
'Last) - Capacity
; -- No_Index
3536 if Index
< Count_Type
'Base (No_Index
) then
3537 raise Constraint_Error
with "Capacity is out of range";
3540 -- We have determined that the value of Capacity would not create a
3541 -- Last index value outside of the range of Index_Type, so we can now
3542 -- safely compute its value.
3544 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Capacity
);
3547 -- The requested capacity is non-zero, but we don't know yet whether
3548 -- this is a request for expansion or contraction of storage.
3550 if Container
.Elements
= null then
3552 -- The container is empty (it doesn't even have an internal array),
3553 -- so this represents a request to allocate storage having the given
3556 Container
.Elements
:= new Elements_Type
(Last
);
3560 if Capacity
<= N
then
3562 -- This is a request to trim back storage, but only to the limit of
3563 -- what's already in the container. (Reserve_Capacity never deletes
3564 -- active elements, it only reclaims excess storage.)
3566 if N
< Container
.Elements
.EA
'Length then
3568 -- The container is not empty (because the requested capacity is
3569 -- positive, and less than or equal to the container length), and
3570 -- the current length is less than the current capacity, so there
3571 -- is storage available to trim. In this case, we allocate a new
3572 -- internal array having a length that exactly matches the number
3573 -- of items in the container.
3575 if Container
.Busy
> 0 then
3576 raise Program_Error
with
3577 "attempt to tamper with cursors (vector is busy)";
3581 subtype Array_Index_Subtype
is Index_Type
'Base range
3582 Index_Type
'First .. Container
.Last
;
3584 Src
: Elements_Array
renames
3585 Container
.Elements
.EA
(Array_Index_Subtype
);
3587 X
: Elements_Access
:= Container
.Elements
;
3590 -- Although we have isolated the old internal array that we're
3591 -- going to deallocate, we don't deallocate it until we have
3592 -- successfully allocated a new one. If there is an exception
3593 -- during allocation (because there is not enough storage), we
3594 -- let it propagate without causing any side-effect.
3596 Container
.Elements
:= new Elements_Type
'(Container.Last, Src);
3598 -- We have successfully allocated a new internal array (with a
3599 -- smaller length than the old one, and containing a copy of
3600 -- just the active elements in the container), so it is now
3601 -- safe to deallocate the old array.
3610 -- The requested capacity is larger than the container length (the
3611 -- number of active elements). Whether this represents a request for
3612 -- expansion or contraction of the current capacity depends on what the
3613 -- current capacity is.
3615 if Capacity = Container.Elements.EA'Length then
3617 -- The requested capacity matches the existing capacity, so there's
3618 -- nothing to do here. We treat this case as a no-op, and simply
3619 -- return without checking the busy bit.
3624 -- There is a change in the capacity of a non-empty container, so a new
3625 -- internal array will be allocated. (The length of the new internal
3626 -- array could be less or greater than the old internal array. We know
3627 -- only that the length of the new internal array is greater than the
3628 -- number of active elements in the container.) We must check whether
3629 -- the container is busy before doing anything else.
3631 if Container.Busy > 0 then
3632 raise Program_Error with
3633 "attempt to tamper with cursors (vector is busy)";
3636 -- We now allocate a new internal array, having a length different from
3637 -- its current value.
3640 X : Elements_Access := Container.Elements;
3642 subtype Index_Subtype is Index_Type'Base range
3643 Index_Type'First .. Container.Last;
3646 -- We now allocate a new internal array, having a length different
3647 -- from its current value.
3649 Container.Elements := new Elements_Type (Last);
3651 -- We have successfully allocated the new internal array, so now we
3652 -- move the existing elements from the existing the old internal
3653 -- array onto the new one. Note that we're just copying access
3654 -- values, to this should not raise any exceptions.
3656 Container.Elements.EA (Index_Subtype) := X.EA (Index_Subtype);
3658 -- We have moved the elements from the old internal array, so now we
3659 -- can deallocate it.
3663 end Reserve_Capacity;
3665 ----------------------
3666 -- Reverse_Elements --
3667 ----------------------
3669 procedure Reverse_Elements (Container : in out Vector) is
3671 if Container.Length <= 1 then
3675 -- The exception behavior for the vector container must match that for
3676 -- the list container, so we check for cursor tampering here (which will
3677 -- catch more things) instead of for element tampering (which will catch
3678 -- fewer things). It's true that the elements of this vector container
3679 -- could be safely moved around while (say) an iteration is taking place
3680 -- (iteration only increments the busy counter), and so technically all
3681 -- we would need here is a test for element tampering (indicated by the
3682 -- lock counter), that's simply an artifact of our array-based
3683 -- implementation. Logically Reverse_Elements requires a check for
3684 -- cursor tampering.
3686 if Container.Busy > 0 then
3687 raise Program_Error with
3688 "attempt to tamper with cursors (vector is busy)";
3694 E : Elements_Array renames Container.Elements.EA;
3697 I := Index_Type'First;
3698 J := Container.Last;
3701 EI : constant Element_Access := E (I);
3712 end Reverse_Elements;
3718 function Reverse_Find
3719 (Container : Vector;
3720 Item : Element_Type;
3721 Position : Cursor := No_Element) return Cursor
3723 Last : Index_Type'Base;
3726 if Position.Container /= null
3727 and then Position.Container /= Container'Unrestricted_Access
3729 raise Program_Error with "Position cursor denotes wrong container";
3732 if Position.Container = null or else Position.Index > Container.Last then
3733 Last := Container.Last;
3735 Last := Position.Index;
3738 -- Per AI05-0022, the container implementation is required to detect
3739 -- element tampering by a generic actual subprogram.
3742 B : Natural renames Container'Unrestricted_Access.Busy;
3743 L : Natural renames Container'Unrestricted_Access.Lock;
3745 Result : Index_Type'Base;
3752 for Indx in reverse Index_Type'First .. Last loop
3753 if Container.Elements.EA (Indx) /= null
3754 and then Container.Elements.EA (Indx).all = Item
3764 if Result = No_Index then
3767 return Cursor'(Container
'Unrestricted_Access, Result
);
3778 ------------------------
3779 -- Reverse_Find_Index --
3780 ------------------------
3782 function Reverse_Find_Index
3783 (Container
: Vector
;
3784 Item
: Element_Type
;
3785 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
3787 B
: Natural renames Container
'Unrestricted_Access.Busy
;
3788 L
: Natural renames Container
'Unrestricted_Access.Lock
;
3790 Last
: constant Index_Type
'Base :=
3791 (if Index
> Container
.Last
then Container
.Last
else Index
);
3793 Result
: Index_Type
'Base;
3796 -- Per AI05-0022, the container implementation is required to detect
3797 -- element tampering by a generic actual subprogram.
3803 for Indx
in reverse Index_Type
'First .. Last
loop
3804 if Container
.Elements
.EA
(Indx
) /= null
3805 and then Container
.Elements
.EA
(Indx
).all = Item
3822 end Reverse_Find_Index
;
3824 ---------------------
3825 -- Reverse_Iterate --
3826 ---------------------
3828 procedure Reverse_Iterate
3829 (Container
: Vector
;
3830 Process
: not null access procedure (Position
: Cursor
))
3832 V
: Vector
renames Container
'Unrestricted_Access.all;
3833 B
: Natural renames V
.Busy
;
3839 for Indx
in reverse Index_Type
'First .. Container
.Last
loop
3840 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
3849 end Reverse_Iterate;
3855 procedure Set_Length
3856 (Container : in out Vector;
3857 Length : Count_Type)
3859 Count : constant Count_Type'Base := Container.Length - Length;
3862 -- Set_Length allows the user to set the length explicitly, instead of
3863 -- implicitly as a side-effect of deletion or insertion. If the
3864 -- requested length is less than the current length, this is equivalent
3865 -- to deleting items from the back end of the vector. If the requested
3866 -- length is greater than the current length, then this is equivalent to
3867 -- inserting "space" (nonce items) at the end.
3870 Container.Delete_Last (Count);
3872 elsif Container.Last >= Index_Type'Last then
3873 raise Constraint_Error with "vector is already at its maximum length";
3876 Container.Insert_Space (Container.Last + 1, -Count);
3885 (Container : in out Vector;
3889 if I > Container.Last then
3890 raise Constraint_Error with "I index is out of range";
3893 if J > Container.Last then
3894 raise Constraint_Error with "J index is out of range";
3901 if Container.Lock > 0 then
3902 raise Program_Error with
3903 "attempt to tamper with elements (vector is locked)";
3907 EI : Element_Access renames Container.Elements.EA (I);
3908 EJ : Element_Access renames Container.Elements.EA (J);
3910 EI_Copy : constant Element_Access := EI;
3919 (Container : in out Vector;
3923 if I.Container = null then
3924 raise Constraint_Error with "I cursor has no element";
3927 if J.Container = null then
3928 raise Constraint_Error with "J cursor has no element";
3931 if I.Container /= Container'Unrestricted_Access then
3932 raise Program_Error with "I cursor denotes wrong container";
3935 if J.Container /= Container'Unrestricted_Access then
3936 raise Program_Error with "J cursor denotes wrong container";
3939 Swap (Container, I.Index, J.Index);
3947 (Container : Vector;
3948 Index : Extended_Index) return Cursor
3951 if Index not in Index_Type'First .. Container.Last then
3955 return Cursor'(Container
'Unrestricted_Access, Index
);
3962 function To_Index
(Position
: Cursor
) return Extended_Index
is
3964 if Position
.Container
= null then
3966 elsif Position
.Index
<= Position
.Container
.Last
then
3967 return Position
.Index
;
3977 function To_Vector
(Length
: Count_Type
) return Vector
is
3978 Index
: Count_Type
'Base;
3979 Last
: Index_Type
'Base;
3980 Elements
: Elements_Access
;
3984 return Empty_Vector
;
3987 -- We create a vector object with a capacity that matches the specified
3988 -- Length, but we do not allow the vector capacity (the length of the
3989 -- internal array) to exceed the number of values in Index_Type'Range
3990 -- (otherwise, there would be no way to refer to those components via an
3991 -- index). We must therefore check whether the specified Length would
3992 -- create a Last index value greater than Index_Type'Last.
3994 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3996 -- We perform a two-part test. First we determine whether the
3997 -- computed Last value lies in the base range of the type, and then
3998 -- determine whether it lies in the range of the index (sub)type.
4000 -- Last must satisfy this relation:
4001 -- First + Length - 1 <= Last
4002 -- We regroup terms:
4003 -- First - 1 <= Last - Length
4004 -- Which can rewrite as:
4005 -- No_Index <= Last - Length
4007 if Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
then
4008 raise Constraint_Error
with "Length is out of range";
4011 -- We now know that the computed value of Last is within the base
4012 -- range of the type, so it is safe to compute its value:
4014 Last
:= No_Index
+ Index_Type
'Base (Length
);
4016 -- Finally we test whether the value is within the range of the
4017 -- generic actual index subtype:
4019 if Last
> Index_Type
'Last then
4020 raise Constraint_Error
with "Length is out of range";
4023 elsif Index_Type
'First <= 0 then
4025 -- Here we can compute Last directly, in the normal way. We know that
4026 -- No_Index is less than 0, so there is no danger of overflow when
4027 -- adding the (positive) value of Length.
4029 Index
:= Count_Type
'Base (No_Index
) + Length
; -- Last
4031 if Index
> Count_Type
'Base (Index_Type
'Last) then
4032 raise Constraint_Error
with "Length is out of range";
4035 -- We know that the computed value (having type Count_Type) of Last
4036 -- is within the range of the generic actual index subtype, so it is
4037 -- safe to convert to Index_Type:
4039 Last
:= Index_Type
'Base (Index
);
4042 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4043 -- must test the length indirectly (by working backwards from the
4044 -- largest possible value of Last), in order to prevent overflow.
4046 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
4048 if Index
< Count_Type
'Base (No_Index
) then
4049 raise Constraint_Error
with "Length is out of range";
4052 -- We have determined that the value of Length would not create a
4053 -- Last index value outside of the range of Index_Type, so we can now
4054 -- safely compute its value.
4056 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
4059 Elements
:= new Elements_Type
(Last
);
4061 return Vector
'(Controlled with Elements, Last, 0, 0);
4065 (New_Item : Element_Type;
4066 Length : Count_Type) return Vector
4068 Index : Count_Type'Base;
4069 Last : Index_Type'Base;
4070 Elements : Elements_Access;
4074 return Empty_Vector;
4077 -- We create a vector object with a capacity that matches the specified
4078 -- Length, but we do not allow the vector capacity (the length of the
4079 -- internal array) to exceed the number of values in Index_Type'Range
4080 -- (otherwise, there would be no way to refer to those components via an
4081 -- index). We must therefore check whether the specified Length would
4082 -- create a Last index value greater than Index_Type'Last.
4084 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
4086 -- We perform a two-part test. First we determine whether the
4087 -- computed Last value lies in the base range of the type, and then
4088 -- determine whether it lies in the range of the index (sub)type.
4090 -- Last must satisfy this relation:
4091 -- First + Length - 1 <= Last
4092 -- We regroup terms:
4093 -- First - 1 <= Last - Length
4094 -- Which can rewrite as:
4095 -- No_Index <= Last - Length
4097 if Index_Type
'Base'Last - Index_Type'Base (Length) < No_Index then
4098 raise Constraint_Error with "Length is out of range";
4101 -- We now know that the computed value of Last is within the base
4102 -- range of the type, so it is safe to compute its value:
4104 Last := No_Index + Index_Type'Base (Length);
4106 -- Finally we test whether the value is within the range of the
4107 -- generic actual index subtype:
4109 if Last > Index_Type'Last then
4110 raise Constraint_Error with "Length is out of range";
4113 elsif Index_Type'First <= 0 then
4115 -- Here we can compute Last directly, in the normal way. We know that
4116 -- No_Index is less than 0, so there is no danger of overflow when
4117 -- adding the (positive) value of Length.
4119 Index := Count_Type'Base (No_Index) + Length; -- Last
4121 if Index > Count_Type'Base (Index_Type'Last) then
4122 raise Constraint_Error with "Length is out of range";
4125 -- We know that the computed value (having type Count_Type) of Last
4126 -- is within the range of the generic actual index subtype, so it is
4127 -- safe to convert to Index_Type:
4129 Last := Index_Type'Base (Index);
4132 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4133 -- must test the length indirectly (by working backwards from the
4134 -- largest possible value of Last), in order to prevent overflow.
4136 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4138 if Index < Count_Type'Base (No_Index) then
4139 raise Constraint_Error with "Length is out of range";
4142 -- We have determined that the value of Length would not create a
4143 -- Last index value outside of the range of Index_Type, so we can now
4144 -- safely compute its value.
4146 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4149 Elements := new Elements_Type (Last);
4151 -- We use Last as the index of the loop used to populate the internal
4152 -- array with items. In general, we prefer to initialize the loop index
4153 -- immediately prior to entering the loop. However, Last is also used in
4154 -- the exception handler (to reclaim elements that have been allocated,
4155 -- before propagating the exception), and the initialization of Last
4156 -- after entering the block containing the handler confuses some static
4157 -- analysis tools, with respect to whether Last has been properly
4158 -- initialized when the handler executes. So here we initialize our loop
4159 -- variable earlier than we prefer, before entering the block, so there
4162 Last := Index_Type'First;
4165 -- The element allocator may need an accessibility check in the case
4166 -- where the actual type is class-wide or has access discriminants
4167 -- (see RM 4.8(10.1) and AI12-0035).
4169 pragma Unsuppress (Accessibility_Check);
4173 Elements.EA (Last) := new Element_Type'(New_Item
);
4174 exit when Last
= Elements
.Last
;
4180 for J
in Index_Type
'First .. Last
- 1 loop
4181 Free
(Elements
.EA
(J
));
4188 return (Controlled
with Elements
, Last
, 0, 0);
4191 --------------------
4192 -- Update_Element --
4193 --------------------
4195 procedure Update_Element
4196 (Container
: in out Vector
;
4198 Process
: not null access procedure (Element
: in out Element_Type
))
4200 B
: Natural renames Container
.Busy
;
4201 L
: Natural renames Container
.Lock
;
4204 if Index
> Container
.Last
then
4205 raise Constraint_Error
with "Index is out of range";
4208 if Container
.Elements
.EA
(Index
) = null then
4209 raise Constraint_Error
with "element is null";
4216 Process
(Container
.Elements
.EA
(Index
).all);
4228 procedure Update_Element
4229 (Container
: in out Vector
;
4231 Process
: not null access procedure (Element
: in out Element_Type
))
4234 if Position
.Container
= null then
4235 raise Constraint_Error
with "Position cursor has no element";
4237 elsif Position
.Container
/= Container
'Unrestricted_Access then
4238 raise Program_Error
with "Position cursor denotes wrong container";
4241 Update_Element
(Container
, Position
.Index
, Process
);
4250 (Stream
: not null access Root_Stream_Type
'Class;
4253 N
: constant Count_Type
:= Length
(Container
);
4256 Count_Type
'Base'Write (Stream, N);
4263 E : Elements_Array renames Container.Elements.EA;
4266 for Indx in Index_Type'First .. Container.Last loop
4267 if E (Indx) = null then
4268 Boolean'Write (Stream, False);
4270 Boolean'Write (Stream, True);
4271 Element_Type'Output (Stream, E (Indx).all);
4278 (Stream : not null access Root_Stream_Type'Class;
4282 raise Program_Error with "attempt to stream vector cursor";
4286 (Stream : not null access Root_Stream_Type'Class;
4287 Item : Reference_Type)
4290 raise Program_Error with "attempt to stream reference";
4294 (Stream : not null access Root_Stream_Type'Class;
4295 Item : Constant_Reference_Type)
4298 raise Program_Error with "attempt to stream reference";
4301 end Ada.Containers.Indefinite_Vectors;