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
562 procedure Adjust
(Container
: in out Vector
) is
564 if Container
.Last
= No_Index
then
565 Container
.Elements
:= null;
570 L
: constant Index_Type
:= Container
.Last
;
571 E
: Elements_Array
renames
572 Container
.Elements
.EA
(Index_Type
'First .. L
);
575 Container
.Elements
:= null;
576 Container
.Last
:= No_Index
;
580 Container
.Elements
:= new Elements_Type
(L
);
582 for J
in E
'Range loop
583 if E
(J
) /= null then
584 Container
.Elements
.EA
(J
) := new Element_Type
'(E (J).all);
592 procedure Adjust (Control : in out Reference_Control_Type) is
594 if Control.Container /= null then
596 C : Vector renames Control.Container.all;
597 B : Natural renames C.Busy;
598 L : Natural renames C.Lock;
610 procedure Append (Container : in out Vector; New_Item : Vector) is
612 if Is_Empty (New_Item) then
614 elsif Container.Last = Index_Type'Last then
615 raise Constraint_Error with "vector is already at its maximum length";
617 Insert (Container, Container.Last + 1, New_Item);
622 (Container : in out Vector;
623 New_Item : Element_Type;
624 Count : Count_Type := 1)
629 elsif Container.Last = Index_Type'Last then
630 raise Constraint_Error with "vector is already at its maximum length";
632 Insert (Container, Container.Last + 1, New_Item, Count);
640 procedure Assign (Target : in out Vector; Source : Vector) is
642 if Target'Address = Source'Address then
646 Target.Append (Source);
654 function Capacity (Container : Vector) return Count_Type is
656 if Container.Elements = null then
659 return Container.Elements.EA'Length;
667 procedure Clear (Container : in out Vector) is
669 if Container.Busy > 0 then
670 raise Program_Error with
671 "attempt to tamper with cursors (vector is busy)";
674 while Container.Last >= Index_Type'First loop
676 X : Element_Access := Container.Elements.EA (Container.Last);
678 Container.Elements.EA (Container.Last) := null;
679 Container.Last := Container.Last - 1;
686 ------------------------
687 -- Constant_Reference --
688 ------------------------
690 function Constant_Reference
691 (Container : aliased Vector;
692 Position : Cursor) return Constant_Reference_Type
697 if Position.Container = null then
698 raise Constraint_Error with "Position cursor has no element";
701 if Position.Container /= Container'Unrestricted_Access then
702 raise Program_Error with "Position cursor denotes wrong container";
705 if Position.Index > Position.Container.Last then
706 raise Constraint_Error with "Position cursor is out of range";
709 E := Container.Elements.EA (Position.Index);
712 raise Constraint_Error with "element at Position is empty";
716 C : Vector renames Container'Unrestricted_Access.all;
717 B : Natural renames C.Busy;
718 L : Natural renames C.Lock;
720 return R : constant Constant_Reference_Type :=
721 (Element => E.all'Access,
722 Control => (Controlled with Container'Unrestricted_Access))
728 end Constant_Reference;
730 function Constant_Reference
731 (Container : aliased Vector;
732 Index : Index_Type) return Constant_Reference_Type
737 if Index > Container.Last then
738 raise Constraint_Error with "Index is out of range";
741 E := Container.Elements.EA (Index);
744 raise Constraint_Error with "element at Index is empty";
748 C : Vector renames Container'Unrestricted_Access.all;
749 B : Natural renames C.Busy;
750 L : Natural renames C.Lock;
752 return R : constant Constant_Reference_Type :=
753 (Element => E.all'Access,
754 Control => (Controlled with Container'Unrestricted_Access))
760 end Constant_Reference;
768 Item : Element_Type) return Boolean
771 return Find_Index (Container, Item) /= No_Index;
780 Capacity : Count_Type := 0) return Vector
788 elsif Capacity >= Source.Length then
793 with "Requested capacity is less than Source length";
796 return Target : Vector do
797 Target.Reserve_Capacity (C);
798 Target.Assign (Source);
807 (Container : in out Vector;
808 Index : Extended_Index;
809 Count : Count_Type := 1)
811 Old_Last : constant Index_Type'Base := Container.Last;
812 New_Last : Index_Type'Base;
813 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
814 J : Index_Type'Base; -- first index of items that slide down
817 -- Delete removes items from the vector, the number of which is the
818 -- minimum of the specified Count and the items (if any) that exist from
819 -- Index to Container.Last. There are no constraints on the specified
820 -- value of Count (it can be larger than what's available at this
821 -- position in the vector, for example), but there are constraints on
822 -- the allowed values of the Index.
824 -- As a precondition on the generic actual Index_Type, the base type
825 -- must include Index_Type'Pred (Index_Type'First); this is the value
826 -- that Container.Last assumes when the vector is empty. However, we do
827 -- not allow that as the value for Index when specifying which items
828 -- should be deleted, so we must manually check. (That the user is
829 -- allowed to specify the value at all here is a consequence of the
830 -- declaration of the Extended_Index subtype, which includes the values
831 -- in the base range that immediately precede and immediately follow the
832 -- values in the Index_Type.)
834 if Index < Index_Type'First then
835 raise Constraint_Error with "Index is out of range (too small)";
838 -- We do allow a value greater than Container.Last to be specified as
839 -- the Index, but only if it's immediately greater. This allows the
840 -- corner case of deleting no items from the back end of the vector to
841 -- be treated as a no-op. (It is assumed that specifying an index value
842 -- greater than Last + 1 indicates some deeper flaw in the caller's
843 -- algorithm, so that case is treated as a proper error.)
845 if Index > Old_Last then
846 if Index > Old_Last + 1 then
847 raise Constraint_Error with "Index is out of range (too large)";
853 -- Here and elsewhere we treat deleting 0 items from the container as a
854 -- no-op, even when the container is busy, so we simply return.
860 -- The internal elements array isn't guaranteed to exist unless we have
861 -- elements, so we handle that case here in order to avoid having to
862 -- check it later. (Note that an empty vector can never be busy, so
863 -- there's no semantic harm in returning early.)
865 if Container.Is_Empty then
869 -- The tampering bits exist to prevent an item from being deleted (or
870 -- otherwise harmfully manipulated) while it is being visited. Query,
871 -- Update, and Iterate increment the busy count on entry, and decrement
872 -- the count on exit. Delete checks the count to determine whether it is
873 -- being called while the associated callback procedure is executing.
875 if Container.Busy > 0 then
876 raise Program_Error with
877 "attempt to tamper with cursors (vector is busy)";
880 -- We first calculate what's available for deletion starting at
881 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
882 -- Count_Type'Base as the type for intermediate values. (See function
883 -- Length for more information.)
885 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
886 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
889 Count2 := Count_Type'Base (Old_Last - Index + 1);
892 -- If the number of elements requested (Count) for deletion is equal to
893 -- (or greater than) the number of elements available (Count2) for
894 -- deletion beginning at Index, then everything from Index to
895 -- Container.Last is deleted (this is equivalent to Delete_Last).
897 if Count >= Count2 then
898 -- Elements in an indefinite vector are allocated, so we must iterate
899 -- over the loop and deallocate elements one-at-a-time. We work from
900 -- back to front, deleting the last element during each pass, in
901 -- order to gracefully handle deallocation failures.
904 EA : Elements_Array renames Container.Elements.EA;
907 while Container.Last >= Index loop
909 K : constant Index_Type := Container.Last;
910 X : Element_Access := EA (K);
913 -- We first isolate the element we're deleting, removing it
914 -- from the vector before we attempt to deallocate it, in
915 -- case the deallocation fails.
918 Container.Last := K - 1;
920 -- Container invariants have been restored, so it is now
921 -- safe to attempt to deallocate the element.
931 -- There are some elements that aren't being deleted (the requested
932 -- count was less than the available count), so we must slide them down
933 -- to Index. We first calculate the index values of the respective array
934 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
935 -- type for intermediate calculations. For the elements that slide down,
936 -- index value New_Last is the last index value of their new home, and
937 -- index value J is the first index of their old home.
939 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
940 New_Last
:= Old_Last
- Index_Type
'Base (Count
);
941 J
:= Index
+ Index_Type
'Base (Count
);
943 New_Last
:= Index_Type
'Base (Count_Type
'Base (Old_Last
) - Count
);
944 J
:= Index_Type
'Base (Count_Type
'Base (Index
) + Count
);
947 -- The internal elements array isn't guaranteed to exist unless we have
948 -- elements, but we have that guarantee here because we know we have
949 -- elements to slide. The array index values for each slice have
950 -- already been determined, so what remains to be done is to first
951 -- deallocate the elements that are being deleted, and then slide down
952 -- to Index the elements that aren't being deleted.
955 EA
: Elements_Array
renames Container
.Elements
.EA
;
958 -- Before we can slide down the elements that aren't being deleted,
959 -- we need to deallocate the elements that are being deleted.
961 for K
in Index
.. J
- 1 loop
963 X
: Element_Access
:= EA
(K
);
966 -- First we remove the element we're about to deallocate from
967 -- the vector, in case the deallocation fails, in order to
968 -- preserve representation invariants.
972 -- The element has been removed from the vector, so it is now
973 -- safe to attempt to deallocate it.
979 EA
(Index
.. New_Last
) := EA
(J
.. Old_Last
);
980 Container
.Last
:= New_Last
;
985 (Container
: in out Vector
;
986 Position
: in out Cursor
;
987 Count
: Count_Type
:= 1)
989 pragma Warnings
(Off
, Position
);
992 if Position
.Container
= null then
993 raise Constraint_Error
with "Position cursor has no element";
995 elsif Position
.Container
/= Container
'Unrestricted_Access then
996 raise Program_Error
with "Position cursor denotes wrong container";
998 elsif Position
.Index
> Container
.Last
then
999 raise Program_Error
with "Position index is out of range";
1002 Delete
(Container
, Position
.Index
, Count
);
1003 Position
:= No_Element
;
1011 procedure Delete_First
1012 (Container
: in out Vector
;
1013 Count
: Count_Type
:= 1)
1019 elsif Count
>= Length
(Container
) then
1024 Delete
(Container
, Index_Type
'First, Count
);
1032 procedure Delete_Last
1033 (Container
: in out Vector
;
1034 Count
: Count_Type
:= 1)
1037 -- It is not permitted to delete items while the container is busy (for
1038 -- example, we're in the middle of a passive iteration). However, we
1039 -- always treat deleting 0 items as a no-op, even when we're busy, so we
1040 -- simply return without checking.
1046 -- We cannot simply subsume the empty case into the loop below (the loop
1047 -- would iterate 0 times), because we rename the internal array object
1048 -- (which is allocated), but an empty vector isn't guaranteed to have
1049 -- actually allocated an array. (Note that an empty vector can never be
1050 -- busy, so there's no semantic harm in returning early here.)
1052 if Container
.Is_Empty
then
1056 -- The tampering bits exist to prevent an item from being deleted (or
1057 -- otherwise harmfully manipulated) while it is being visited. Query,
1058 -- Update, and Iterate increment the busy count on entry, and decrement
1059 -- the count on exit. Delete_Last checks the count to determine whether
1060 -- it is being called while the associated callback procedure is
1063 if Container
.Busy
> 0 then
1064 raise Program_Error
with
1065 "attempt to tamper with cursors (vector is busy)";
1068 -- Elements in an indefinite vector are allocated, so we must iterate
1069 -- over the loop and deallocate elements one-at-a-time. We work from
1070 -- back to front, deleting the last element during each pass, in order
1071 -- to gracefully handle deallocation failures.
1074 E
: Elements_Array
renames Container
.Elements
.EA
;
1077 for Indx
in 1 .. Count_Type
'Min (Count
, Container
.Length
) loop
1079 J
: constant Index_Type
:= Container
.Last
;
1080 X
: Element_Access
:= E
(J
);
1083 -- Note that we first isolate the element we're deleting,
1084 -- removing it from the vector, before we actually deallocate
1085 -- it, in order to preserve representation invariants even if
1086 -- the deallocation fails.
1089 Container
.Last
:= J
- 1;
1091 -- Container invariants have been restored, so it is now safe
1092 -- to deallocate the element.
1105 (Container
: Vector
;
1106 Index
: Index_Type
) return Element_Type
1109 if Index
> Container
.Last
then
1110 raise Constraint_Error
with "Index is out of range";
1114 EA
: constant Element_Access
:= Container
.Elements
.EA
(Index
);
1117 raise Constraint_Error
with "element is empty";
1124 function Element
(Position
: Cursor
) return Element_Type
is
1126 if Position
.Container
= null then
1127 raise Constraint_Error
with "Position cursor has no element";
1130 if Position
.Index
> Position
.Container
.Last
then
1131 raise Constraint_Error
with "Position cursor is out of range";
1135 EA
: constant Element_Access
:=
1136 Position
.Container
.Elements
.EA
(Position
.Index
);
1139 raise Constraint_Error
with "element is empty";
1150 procedure Finalize
(Container
: in out Vector
) is
1152 Clear
(Container
); -- Checks busy-bit
1155 X
: Elements_Access
:= Container
.Elements
;
1157 Container
.Elements
:= null;
1162 procedure Finalize
(Object
: in out Iterator
) is
1163 B
: Natural renames Object
.Container
.Busy
;
1168 procedure Finalize
(Control
: in out Reference_Control_Type
) is
1170 if Control
.Container
/= null then
1172 C
: Vector
renames Control
.Container
.all;
1173 B
: Natural renames C
.Busy
;
1174 L
: Natural renames C
.Lock
;
1180 Control
.Container
:= null;
1189 (Container
: Vector
;
1190 Item
: Element_Type
;
1191 Position
: Cursor
:= No_Element
) return Cursor
1194 if Position
.Container
/= null then
1195 if Position
.Container
/= Container
'Unrestricted_Access then
1196 raise Program_Error
with "Position cursor denotes wrong container";
1199 if Position
.Index
> Container
.Last
then
1200 raise Program_Error
with "Position index is out of range";
1204 -- Per AI05-0022, the container implementation is required to detect
1205 -- element tampering by a generic actual subprogram.
1208 B
: Natural renames Container
'Unrestricted_Access.Busy
;
1209 L
: Natural renames Container
'Unrestricted_Access.Lock
;
1211 Result
: Index_Type
'Base;
1218 for J
in Position
.Index
.. Container
.Last
loop
1219 if Container
.Elements
.EA
(J
) /= null
1220 and then Container
.Elements
.EA
(J
).all = Item
1230 if Result
= No_Index
then
1233 return Cursor
'(Container'Unrestricted_Access, Result);
1249 (Container : Vector;
1250 Item : Element_Type;
1251 Index : Index_Type := Index_Type'First) return Extended_Index
1253 B : Natural renames Container'Unrestricted_Access.Busy;
1254 L : Natural renames Container'Unrestricted_Access.Lock;
1256 Result : Index_Type'Base;
1259 -- Per AI05-0022, the container implementation is required to detect
1260 -- element tampering by a generic actual subprogram.
1266 for Indx in Index .. Container.Last loop
1267 if Container.Elements.EA (Indx) /= null
1268 and then Container.Elements.EA (Indx).all = Item
1292 function First (Container : Vector) return Cursor is
1294 if Is_Empty (Container) then
1298 return (Container'Unrestricted_Access, Index_Type'First);
1301 function First (Object : Iterator) return Cursor is
1303 -- The value of the iterator object's Index component influences the
1304 -- behavior of the First (and Last) selector function.
1306 -- When the Index component is No_Index, this means the iterator
1307 -- object was constructed without a start expression, in which case the
1308 -- (forward) iteration starts from the (logical) beginning of the entire
1309 -- sequence of items (corresponding to Container.First, for a forward
1312 -- Otherwise, this is iteration over a partial sequence of items.
1313 -- When the Index component isn't No_Index, the iterator object was
1314 -- constructed with a start expression, that specifies the position
1315 -- from which the (forward) partial iteration begins.
1317 if Object.Index = No_Index then
1318 return First (Object.Container.all);
1320 return Cursor'(Object
.Container
, Object
.Index
);
1328 function First_Element
(Container
: Vector
) return Element_Type
is
1330 if Container
.Last
= No_Index
then
1331 raise Constraint_Error
with "Container is empty";
1335 EA
: constant Element_Access
:=
1336 Container
.Elements
.EA
(Index_Type
'First);
1339 raise Constraint_Error
with "first element is empty";
1350 function First_Index
(Container
: Vector
) return Index_Type
is
1351 pragma Unreferenced
(Container
);
1353 return Index_Type
'First;
1356 ---------------------
1357 -- Generic_Sorting --
1358 ---------------------
1360 package body Generic_Sorting
is
1362 -----------------------
1363 -- Local Subprograms --
1364 -----------------------
1366 function Is_Less
(L
, R
: Element_Access
) return Boolean;
1367 pragma Inline
(Is_Less
);
1373 function Is_Less
(L
, R
: Element_Access
) return Boolean is
1380 return L
.all < R
.all;
1388 function Is_Sorted
(Container
: Vector
) return Boolean is
1390 if Container
.Last
<= Index_Type
'First then
1394 -- Per AI05-0022, the container implementation is required to detect
1395 -- element tampering by a generic actual subprogram.
1398 E
: Elements_Array
renames Container
.Elements
.EA
;
1400 B
: Natural renames Container
'Unrestricted_Access.Busy
;
1401 L
: Natural renames Container
'Unrestricted_Access.Lock
;
1410 for I
in Index_Type
'First .. Container
.Last
- 1 loop
1411 if Is_Less
(E
(I
+ 1), E
(I
)) then
1435 procedure Merge
(Target
, Source
: in out Vector
) is
1436 I
, J
: Index_Type
'Base;
1439 -- The semantics of Merge changed slightly per AI05-0021. It was
1440 -- originally the case that if Target and Source denoted the same
1441 -- container object, then the GNAT implementation of Merge did
1442 -- nothing. However, it was argued that RM05 did not precisely
1443 -- specify the semantics for this corner case. The decision of the
1444 -- ARG was that if Target and Source denote the same non-empty
1445 -- container object, then Program_Error is raised.
1447 if Source
.Last
< Index_Type
'First then -- Source is empty
1451 if Target
'Address = Source
'Address then
1452 raise Program_Error
with
1453 "Target and Source denote same non-empty container";
1456 if Target
.Last
< Index_Type
'First then -- Target is empty
1457 Move
(Target
=> Target
, Source
=> Source
);
1461 if Source
.Busy
> 0 then
1462 raise Program_Error
with
1463 "attempt to tamper with cursors (vector is busy)";
1466 I
:= Target
.Last
; -- original value (before Set_Length)
1467 Target
.Set_Length
(Length
(Target
) + Length
(Source
));
1469 -- Per AI05-0022, the container implementation is required to detect
1470 -- element tampering by a generic actual subprogram.
1473 TA
: Elements_Array
renames Target
.Elements
.EA
;
1474 SA
: Elements_Array
renames Source
.Elements
.EA
;
1476 TB
: Natural renames Target
.Busy
;
1477 TL
: Natural renames Target
.Lock
;
1479 SB
: Natural renames Source
.Busy
;
1480 SL
: Natural renames Source
.Lock
;
1489 J
:= Target
.Last
; -- new value (after Set_Length)
1490 while Source
.Last
>= Index_Type
'First loop
1492 (Source
.Last
<= Index_Type
'First
1493 or else not (Is_Less
(SA
(Source
.Last
),
1494 SA
(Source
.Last
- 1))));
1496 if I
< Index_Type
'First then
1498 Src
: Elements_Array
renames
1499 SA
(Index_Type
'First .. Source
.Last
);
1501 TA
(Index_Type
'First .. J
) := Src
;
1502 Src
:= (others => null);
1505 Source
.Last
:= No_Index
;
1510 (I
<= Index_Type
'First
1511 or else not (Is_Less
(TA
(I
), TA
(I
- 1))));
1514 Src
: Element_Access
renames SA
(Source
.Last
);
1515 Tgt
: Element_Access
renames TA
(I
);
1518 if Is_Less
(Src
, Tgt
) then
1519 Target
.Elements
.EA
(J
) := Tgt
;
1524 Target
.Elements
.EA
(J
) := Src
;
1526 Source
.Last
:= Source
.Last
- 1;
1555 procedure Sort
(Container
: in out Vector
) is
1556 procedure Sort
is new Generic_Array_Sort
1557 (Index_Type
=> Index_Type
,
1558 Element_Type
=> Element_Access
,
1559 Array_Type
=> Elements_Array
,
1562 -- Start of processing for Sort
1565 if Container
.Last
<= Index_Type
'First then
1569 -- The exception behavior for the vector container must match that
1570 -- for the list container, so we check for cursor tampering here
1571 -- (which will catch more things) instead of for element tampering
1572 -- (which will catch fewer things). It's true that the elements of
1573 -- this vector container could be safely moved around while (say) an
1574 -- iteration is taking place (iteration only increments the busy
1575 -- counter), and so technically all we would need here is a test for
1576 -- element tampering (indicated by the lock counter), that's simply
1577 -- an artifact of our array-based implementation. Logically Sort
1578 -- requires a check for cursor tampering.
1580 if Container
.Busy
> 0 then
1581 raise Program_Error
with
1582 "attempt to tamper with cursors (vector is busy)";
1585 -- Per AI05-0022, the container implementation is required to detect
1586 -- element tampering by a generic actual subprogram.
1589 B
: Natural renames Container
.Busy
;
1590 L
: Natural renames Container
.Lock
;
1596 Sort
(Container
.Elements
.EA
(Index_Type
'First .. Container
.Last
));
1610 end Generic_Sorting
;
1616 function Has_Element
(Position
: Cursor
) return Boolean is
1618 if Position
.Container
= null then
1621 return Position
.Index
<= Position
.Container
.Last
;
1630 (Container
: in out Vector
;
1631 Before
: Extended_Index
;
1632 New_Item
: Element_Type
;
1633 Count
: Count_Type
:= 1)
1635 Old_Length
: constant Count_Type
:= Container
.Length
;
1637 Max_Length
: Count_Type
'Base; -- determined from range of Index_Type
1638 New_Length
: Count_Type
'Base; -- sum of current length and Count
1639 New_Last
: Index_Type
'Base; -- last index of vector after insertion
1641 Index
: Index_Type
'Base; -- scratch for intermediate values
1642 J
: Count_Type
'Base; -- scratch
1644 New_Capacity
: Count_Type
'Base; -- length of new, expanded array
1645 Dst_Last
: Index_Type
'Base; -- last index of new, expanded array
1646 Dst
: Elements_Access
; -- new, expanded internal array
1649 -- As a precondition on the generic actual Index_Type, the base type
1650 -- must include Index_Type'Pred (Index_Type'First); this is the value
1651 -- that Container.Last assumes when the vector is empty. However, we do
1652 -- not allow that as the value for Index when specifying where the new
1653 -- items should be inserted, so we must manually check. (That the user
1654 -- is allowed to specify the value at all here is a consequence of the
1655 -- declaration of the Extended_Index subtype, which includes the values
1656 -- in the base range that immediately precede and immediately follow the
1657 -- values in the Index_Type.)
1659 if Before
< Index_Type
'First then
1660 raise Constraint_Error
with
1661 "Before index is out of range (too small)";
1664 -- We do allow a value greater than Container.Last to be specified as
1665 -- the Index, but only if it's immediately greater. This allows for the
1666 -- case of appending items to the back end of the vector. (It is assumed
1667 -- that specifying an index value greater than Last + 1 indicates some
1668 -- deeper flaw in the caller's algorithm, so that case is treated as a
1671 if Before
> Container
.Last
1672 and then Before
> Container
.Last
+ 1
1674 raise Constraint_Error
with
1675 "Before index is out of range (too large)";
1678 -- We treat inserting 0 items into the container as a no-op, even when
1679 -- the container is busy, so we simply return.
1685 -- There are two constraints we need to satisfy. The first constraint is
1686 -- that a container cannot have more than Count_Type'Last elements, so
1687 -- we must check the sum of the current length and the insertion count.
1688 -- Note that we cannot simply add these values, because of the
1689 -- possibility of overflow.
1691 if Old_Length
> Count_Type
'Last - Count
then
1692 raise Constraint_Error
with "Count is out of range";
1695 -- It is now safe compute the length of the new vector, without fear of
1698 New_Length
:= Old_Length
+ Count
;
1700 -- The second constraint is that the new Last index value cannot exceed
1701 -- Index_Type'Last. In each branch below, we calculate the maximum
1702 -- length (computed from the range of values in Index_Type), and then
1703 -- compare the new length to the maximum length. If the new length is
1704 -- acceptable, then we compute the new last index from that.
1706 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1708 -- We have to handle the case when there might be more values in the
1709 -- range of Index_Type than in the range of Count_Type.
1711 if Index_Type'First <= 0 then
1713 -- We know that No_Index (the same as Index_Type'First - 1) is
1714 -- less than 0, so it is safe to compute the following sum without
1715 -- fear of overflow.
1717 Index := No_Index + Index_Type'Base (Count_Type'Last);
1719 if Index <= Index_Type'Last then
1721 -- We have determined that range of Index_Type has at least as
1722 -- many values as in Count_Type, so Count_Type'Last is the
1723 -- maximum number of items that are allowed.
1725 Max_Length := Count_Type'Last;
1728 -- The range of Index_Type has fewer values than in Count_Type,
1729 -- so the maximum number of items is computed from the range of
1732 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1736 -- No_Index is equal or greater than 0, so we can safely compute
1737 -- the difference without fear of overflow (which we would have to
1738 -- worry about if No_Index were less than 0, but that case is
1741 if Index_Type'Last - No_Index >=
1742 Count_Type'Pos (Count_Type'Last)
1744 -- We have determined that range of Index_Type has at least as
1745 -- many values as in Count_Type, so Count_Type'Last is the
1746 -- maximum number of items that are allowed.
1748 Max_Length := Count_Type'Last;
1751 -- The range of Index_Type has fewer values than in Count_Type,
1752 -- so the maximum number of items is computed from the range of
1755 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1759 elsif Index_Type'First <= 0 then
1761 -- We know that No_Index (the same as Index_Type'First - 1) is less
1762 -- than 0, so it is safe to compute the following sum without fear of
1765 J := Count_Type'Base (No_Index) + Count_Type'Last;
1767 if J <= Count_Type'Base (Index_Type'Last) then
1769 -- We have determined that range of Index_Type has at least as
1770 -- many values as in Count_Type, so Count_Type'Last is the maximum
1771 -- number of items that are allowed.
1773 Max_Length := Count_Type'Last;
1776 -- The range of Index_Type has fewer values than Count_Type does,
1777 -- so the maximum number of items is computed from the range of
1781 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1785 -- No_Index is equal or greater than 0, so we can safely compute the
1786 -- difference without fear of overflow (which we would have to worry
1787 -- about if No_Index were less than 0, but that case is handled
1791 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1794 -- We have just computed the maximum length (number of items). We must
1795 -- now compare the requested length to the maximum length, as we do not
1796 -- allow a vector expand beyond the maximum (because that would create
1797 -- an internal array with a last index value greater than
1798 -- Index_Type'Last, with no way to index those elements).
1800 if New_Length > Max_Length then
1801 raise Constraint_Error with "Count is out of range";
1804 -- New_Last is the last index value of the items in the container after
1805 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1806 -- compute its value from the New_Length.
1808 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1809 New_Last
:= No_Index
+ Index_Type
'Base (New_Length
);
1811 New_Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Length
);
1814 if Container
.Elements
= null then
1815 pragma Assert
(Container
.Last
= No_Index
);
1817 -- This is the simplest case, with which we must always begin: we're
1818 -- inserting items into an empty vector that hasn't allocated an
1819 -- internal array yet. Note that we don't need to check the busy bit
1820 -- here, because an empty container cannot be busy.
1822 -- In an indefinite vector, elements are allocated individually, and
1823 -- stored as access values on the internal array (the length of which
1824 -- represents the vector "capacity"), which is separately allocated.
1826 Container
.Elements
:= new Elements_Type
(New_Last
);
1828 -- The element backbone has been successfully allocated, so now we
1829 -- allocate the elements.
1831 for Idx
in Container
.Elements
.EA
'Range loop
1833 -- In order to preserve container invariants, we always attempt
1834 -- the element allocation first, before setting the Last index
1835 -- value, in case the allocation fails (either because there is no
1836 -- storage available, or because element initialization fails).
1839 -- The element allocator may need an accessibility check in the
1840 -- case actual type is class-wide or has access discriminants
1841 -- (see RM 4.8(10.1) and AI12-0035).
1843 pragma Unsuppress
(Accessibility_Check
);
1846 Container
.Elements
.EA
(Idx
) := new Element_Type
'(New_Item);
1849 -- The allocation of the element succeeded, so it is now safe to
1850 -- update the Last index, restoring container invariants.
1852 Container.Last := Idx;
1858 -- The tampering bits exist to prevent an item from being harmfully
1859 -- manipulated while it is being visited. Query, Update, and Iterate
1860 -- increment the busy count on entry, and decrement the count on
1861 -- exit. Insert checks the count to determine whether it is being called
1862 -- while the associated callback procedure is executing.
1864 if Container.Busy > 0 then
1865 raise Program_Error with
1866 "attempt to tamper with cursors (vector is busy)";
1869 if New_Length <= Container.Elements.EA'Length then
1871 -- In this case, we're inserting elements into a vector that has
1872 -- already allocated an internal array, and the existing array has
1873 -- enough unused storage for the new items.
1876 E : Elements_Array renames Container.Elements.EA;
1877 K : Index_Type'Base;
1880 if Before > Container.Last then
1882 -- The new items are being appended to the vector, so no
1883 -- sliding of existing elements is required.
1885 for Idx in Before .. New_Last loop
1887 -- In order to preserve container invariants, we always
1888 -- attempt the element allocation first, before setting the
1889 -- Last index value, in case the allocation fails (either
1890 -- because there is no storage available, or because element
1891 -- initialization fails).
1894 -- The element allocator may need an accessibility check
1895 -- in case the actual type is class-wide or has access
1896 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1898 pragma Unsuppress (Accessibility_Check);
1901 E (Idx) := new Element_Type'(New_Item
);
1904 -- The allocation of the element succeeded, so it is now
1905 -- safe to update the Last index, restoring container
1908 Container
.Last
:= Idx
;
1912 -- The new items are being inserted before some existing
1913 -- elements, so we must slide the existing elements up to their
1914 -- new home. We use the wider of Index_Type'Base and
1915 -- Count_Type'Base as the type for intermediate index values.
1917 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1918 Index := Before + Index_Type'Base (Count);
1920 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1923 -- The new items are being inserted in the middle of the array,
1924 -- in the range [Before, Index). Copy the existing elements to
1925 -- the end of the array, to make room for the new items.
1927 E (Index .. New_Last) := E (Before .. Container.Last);
1928 Container.Last := New_Last;
1930 -- We have copied the existing items up to the end of the
1931 -- array, to make room for the new items in the middle of
1932 -- the array. Now we actually allocate the new items.
1934 -- Note: initialize K outside loop to make it clear that
1935 -- K always has a value if the exception handler triggers.
1940 -- The element allocator may need an accessibility check in
1941 -- the case the actual type is class-wide or has access
1942 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1944 pragma Unsuppress (Accessibility_Check);
1947 while K < Index loop
1948 E (K) := new Element_Type'(New_Item
);
1955 -- Values in the range [Before, K) were successfully
1956 -- allocated, but values in the range [K, Index) are
1957 -- stale (these array positions contain copies of the
1958 -- old items, that did not get assigned a new item,
1959 -- because the allocation failed). We must finish what
1960 -- we started by clearing out all of the stale values,
1961 -- leaving a "hole" in the middle of the array.
1963 E
(K
.. Index
- 1) := (others => null);
1972 -- In this case, we're inserting elements into a vector that has already
1973 -- allocated an internal array, but the existing array does not have
1974 -- enough storage, so we must allocate a new, longer array. In order to
1975 -- guarantee that the amortized insertion cost is O(1), we always
1976 -- allocate an array whose length is some power-of-two factor of the
1977 -- current array length. (The new array cannot have a length less than
1978 -- the New_Length of the container, but its last index value cannot be
1979 -- greater than Index_Type'Last.)
1981 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
1982 while New_Capacity
< New_Length
loop
1983 if New_Capacity
> Count_Type
'Last / 2 then
1984 New_Capacity
:= Count_Type
'Last;
1988 New_Capacity
:= 2 * New_Capacity
;
1991 if New_Capacity
> Max_Length
then
1993 -- We have reached the limit of capacity, so no further expansion
1994 -- will occur. (This is not a problem, as there is never a need to
1995 -- have more capacity than the maximum container length.)
1997 New_Capacity
:= Max_Length
;
2000 -- We have computed the length of the new internal array (and this is
2001 -- what "vector capacity" means), so use that to compute its last index.
2003 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2004 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2007 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2010 -- Now we allocate the new, longer internal array. If the allocation
2011 -- fails, we have not changed any container state, so no side-effect
2012 -- will occur as a result of propagating the exception.
2014 Dst := new Elements_Type (Dst_Last);
2016 -- We have our new internal array. All that needs to be done now is to
2017 -- copy the existing items (if any) from the old array (the "source"
2018 -- array) to the new array (the "destination" array), and then
2019 -- deallocate the old array.
2022 Src : Elements_Access := Container.Elements;
2025 Dst.EA (Index_Type'First .. Before - 1) :=
2026 Src.EA (Index_Type'First .. Before - 1);
2028 if Before > Container.Last then
2030 -- The new items are being appended to the vector, so no
2031 -- sliding of existing elements is required.
2033 -- We have copied the elements from to the old source array to the
2034 -- new destination array, so we can now deallocate the old array.
2036 Container.Elements := Dst;
2039 -- Now we append the new items.
2041 for Idx in Before .. New_Last loop
2043 -- In order to preserve container invariants, we always attempt
2044 -- the element allocation first, before setting the Last index
2045 -- value, in case the allocation fails (either because there
2046 -- is no storage available, or because element initialization
2050 -- The element allocator may need an accessibility check in
2051 -- the case the actual type is class-wide or has access
2052 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2054 pragma Unsuppress (Accessibility_Check);
2057 Dst.EA (Idx) := new Element_Type'(New_Item
);
2060 -- The allocation of the element succeeded, so it is now safe
2061 -- to update the Last index, restoring container invariants.
2063 Container
.Last
:= Idx
;
2067 -- The new items are being inserted before some existing elements,
2068 -- so we must slide the existing elements up to their new home.
2070 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2071 Index := Before + Index_Type'Base (Count);
2073 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2076 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2078 -- We have copied the elements from to the old source array to the
2079 -- new destination array, so we can now deallocate the old array.
2081 Container.Elements := Dst;
2082 Container.Last := New_Last;
2085 -- The new array has a range in the middle containing null access
2086 -- values. Fill in that partition of the array with the new items.
2088 for Idx in Before .. Index - 1 loop
2090 -- Note that container invariants have already been satisfied
2091 -- (in particular, the Last index value of the vector has
2092 -- already been updated), so if this allocation fails we simply
2093 -- let it propagate.
2096 -- The element allocator may need an accessibility check in
2097 -- the case the actual type is class-wide or has access
2098 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2100 pragma Unsuppress (Accessibility_Check);
2103 Dst.EA (Idx) := new Element_Type'(New_Item
);
2111 (Container
: in out Vector
;
2112 Before
: Extended_Index
;
2115 N
: constant Count_Type
:= Length
(New_Item
);
2116 J
: Index_Type
'Base;
2119 -- Use Insert_Space to create the "hole" (the destination slice) into
2120 -- which we copy the source items.
2122 Insert_Space
(Container
, Before
, Count
=> N
);
2126 -- There's nothing else to do here (vetting of parameters was
2127 -- performed already in Insert_Space), so we simply return.
2132 if Container
'Address /= New_Item
'Address then
2134 -- This is the simple case. New_Item denotes an object different
2135 -- from Container, so there's nothing special we need to do to copy
2136 -- the source items to their destination, because all of the source
2137 -- items are contiguous.
2140 subtype Src_Index_Subtype
is Index_Type
'Base range
2141 Index_Type
'First .. New_Item
.Last
;
2143 Src
: Elements_Array
renames
2144 New_Item
.Elements
.EA
(Src_Index_Subtype
);
2146 Dst
: Elements_Array
renames Container
.Elements
.EA
;
2148 Dst_Index
: Index_Type
'Base;
2151 Dst_Index
:= Before
- 1;
2152 for Src_Index
in Src
'Range loop
2153 Dst_Index
:= Dst_Index
+ 1;
2155 if Src
(Src_Index
) /= null then
2156 Dst
(Dst_Index
) := new Element_Type
'(Src (Src_Index).all);
2164 -- New_Item denotes the same object as Container, so an insertion has
2165 -- potentially split the source items. The first source slice is
2166 -- [Index_Type'First, Before), and the second source slice is
2167 -- [J, Container.Last], where index value J is the first index of the
2168 -- second slice. (J gets computed below, but only after we have
2169 -- determined that the second source slice is non-empty.) The
2170 -- destination slice is always the range [Before, J). We perform the
2171 -- copy in two steps, using each of the two slices of the source items.
2174 L : constant Index_Type'Base := Before - 1;
2176 subtype Src_Index_Subtype is Index_Type'Base range
2177 Index_Type'First .. L;
2179 Src : Elements_Array renames
2180 Container.Elements.EA (Src_Index_Subtype);
2182 Dst : Elements_Array renames Container.Elements.EA;
2184 Dst_Index : Index_Type'Base;
2187 -- We first copy the source items that precede the space we
2188 -- inserted. (If Before equals Index_Type'First, then this first
2189 -- source slice will be empty, which is harmless.)
2191 Dst_Index := Before - 1;
2192 for Src_Index in Src'Range loop
2193 Dst_Index := Dst_Index + 1;
2195 if Src (Src_Index) /= null then
2196 Dst (Dst_Index) := new Element_Type'(Src
(Src_Index
).all);
2200 if Src
'Length = N
then
2202 -- The new items were effectively appended to the container, so we
2203 -- have already copied all of the items that need to be copied.
2204 -- We return early here, even though the source slice below is
2205 -- empty (so the assignment would be harmless), because we want to
2206 -- avoid computing J, which will overflow if J is greater than
2207 -- Index_Type'Base'Last.
2213 -- Index value J is the first index of the second source slice. (It is
2214 -- also 1 greater than the last index of the destination slice.) Note:
2215 -- avoid computing J if J is greater than Index_Type'Base'Last, in order
2216 -- to avoid overflow. Prevent that by returning early above, immediately
2217 -- after copying the first slice of the source, and determining that
2218 -- this second slice of the source is empty.
2220 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2221 J := Before + Index_Type'Base (N);
2223 J := Index_Type'Base (Count_Type'Base (Before) + N);
2227 subtype Src_Index_Subtype is Index_Type'Base range
2228 J .. Container.Last;
2230 Src : Elements_Array renames
2231 Container.Elements.EA (Src_Index_Subtype);
2233 Dst : Elements_Array renames Container.Elements.EA;
2235 Dst_Index : Index_Type'Base;
2238 -- We next copy the source items that follow the space we inserted.
2239 -- Index value Dst_Index is the first index of that portion of the
2240 -- destination that receives this slice of the source. (For the
2241 -- reasons given above, this slice is guaranteed to be non-empty.)
2243 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2244 Dst_Index
:= J
- Index_Type
'Base (Src
'Length);
2246 Dst_Index
:= Index_Type
'Base (Count_Type
'Base (J
) - Src
'Length);
2249 for Src_Index
in Src
'Range loop
2250 if Src
(Src_Index
) /= null then
2251 Dst
(Dst_Index
) := new Element_Type
'(Src (Src_Index).all);
2254 Dst_Index := Dst_Index + 1;
2260 (Container : in out Vector;
2264 Index : Index_Type'Base;
2267 if Before.Container /= null
2268 and then Before.Container /= Container'Unrestricted_Access
2270 raise Program_Error with "Before cursor denotes wrong container";
2273 if Is_Empty (New_Item) then
2277 if Before.Container = null or else Before.Index > Container.Last then
2278 if Container.Last = Index_Type'Last then
2279 raise Constraint_Error with
2280 "vector is already at its maximum length";
2283 Index := Container.Last + 1;
2286 Index := Before.Index;
2289 Insert (Container, Index, New_Item);
2293 (Container : in out Vector;
2296 Position : out Cursor)
2298 Index : Index_Type'Base;
2301 if Before.Container /= null
2302 and then Before.Container /=
2303 Vector_Access'(Container
'Unrestricted_Access)
2305 raise Program_Error
with "Before cursor denotes wrong container";
2308 if Is_Empty
(New_Item
) then
2309 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2310 Position
:= No_Element
;
2312 Position
:= (Container
'Unrestricted_Access, Before
.Index
);
2318 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2319 if Container
.Last
= Index_Type
'Last then
2320 raise Constraint_Error
with
2321 "vector is already at its maximum length";
2324 Index
:= Container
.Last
+ 1;
2327 Index
:= Before
.Index
;
2330 Insert
(Container
, Index
, New_Item
);
2332 Position
:= Cursor
'(Container'Unrestricted_Access, Index);
2336 (Container : in out Vector;
2338 New_Item : Element_Type;
2339 Count : Count_Type := 1)
2341 Index : Index_Type'Base;
2344 if Before.Container /= null
2345 and then Before.Container /= Container'Unrestricted_Access
2347 raise Program_Error with "Before cursor denotes wrong container";
2354 if Before.Container = null or else Before.Index > Container.Last then
2355 if Container.Last = Index_Type'Last then
2356 raise Constraint_Error with
2357 "vector is already at its maximum length";
2360 Index := Container.Last + 1;
2363 Index := Before.Index;
2366 Insert (Container, Index, New_Item, Count);
2370 (Container : in out Vector;
2372 New_Item : Element_Type;
2373 Position : out Cursor;
2374 Count : Count_Type := 1)
2376 Index : Index_Type'Base;
2379 if Before.Container /= null
2380 and then Before.Container /= Container'Unrestricted_Access
2382 raise Program_Error with "Before cursor denotes wrong container";
2386 if Before.Container = null
2387 or else Before.Index > Container.Last
2389 Position := No_Element;
2391 Position := (Container'Unrestricted_Access, Before.Index);
2397 if Before.Container = null or else Before.Index > Container.Last then
2398 if Container.Last = Index_Type'Last then
2399 raise Constraint_Error with
2400 "vector is already at its maximum length";
2403 Index := Container.Last + 1;
2406 Index := Before.Index;
2409 Insert (Container, Index, New_Item, Count);
2411 Position := (Container'Unrestricted_Access, Index);
2418 procedure Insert_Space
2419 (Container : in out Vector;
2420 Before : Extended_Index;
2421 Count : Count_Type := 1)
2423 Old_Length : constant Count_Type := Container.Length;
2425 Max_Length : Count_Type'Base; -- determined from range of Index_Type
2426 New_Length : Count_Type'Base; -- sum of current length and Count
2427 New_Last : Index_Type'Base; -- last index of vector after insertion
2429 Index : Index_Type'Base; -- scratch for intermediate values
2430 J : Count_Type'Base; -- scratch
2432 New_Capacity : Count_Type'Base; -- length of new, expanded array
2433 Dst_Last : Index_Type'Base; -- last index of new, expanded array
2434 Dst : Elements_Access; -- new, expanded internal array
2437 -- As a precondition on the generic actual Index_Type, the base type
2438 -- must include Index_Type'Pred (Index_Type'First); this is the value
2439 -- that Container.Last assumes when the vector is empty. However, we do
2440 -- not allow that as the value for Index when specifying where the new
2441 -- items should be inserted, so we must manually check. (That the user
2442 -- is allowed to specify the value at all here is a consequence of the
2443 -- declaration of the Extended_Index subtype, which includes the values
2444 -- in the base range that immediately precede and immediately follow the
2445 -- values in the Index_Type.)
2447 if Before < Index_Type'First then
2448 raise Constraint_Error with
2449 "Before index is out of range (too small)";
2452 -- We do allow a value greater than Container.Last to be specified as
2453 -- the Index, but only if it's immediately greater. This allows for the
2454 -- case of appending items to the back end of the vector. (It is assumed
2455 -- that specifying an index value greater than Last + 1 indicates some
2456 -- deeper flaw in the caller's algorithm, so that case is treated as a
2459 if Before > Container.Last and then Before > Container.Last + 1 then
2460 raise Constraint_Error with
2461 "Before index is out of range (too large)";
2464 -- We treat inserting 0 items into the container as a no-op, even when
2465 -- the container is busy, so we simply return.
2471 -- There are two constraints we need to satisfy. The first constraint is
2472 -- that a container cannot have more than Count_Type'Last elements, so
2473 -- we must check the sum of the current length and the insertion
2474 -- count. Note that we cannot simply add these values, because of the
2475 -- possibility of overflow.
2477 if Old_Length > Count_Type'Last - Count then
2478 raise Constraint_Error with "Count is out of range";
2481 -- It is now safe compute the length of the new vector, without fear of
2484 New_Length := Old_Length + Count;
2486 -- The second constraint is that the new Last index value cannot exceed
2487 -- Index_Type'Last. In each branch below, we calculate the maximum
2488 -- length (computed from the range of values in Index_Type), and then
2489 -- compare the new length to the maximum length. If the new length is
2490 -- acceptable, then we compute the new last index from that.
2492 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2493 -- We have to handle the case when there might be more values in the
2494 -- range of Index_Type than in the range of Count_Type.
2496 if Index_Type
'First <= 0 then
2498 -- We know that No_Index (the same as Index_Type'First - 1) is
2499 -- less than 0, so it is safe to compute the following sum without
2500 -- fear of overflow.
2502 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
2504 if Index
<= Index_Type
'Last then
2506 -- We have determined that range of Index_Type has at least as
2507 -- many values as in Count_Type, so Count_Type'Last is the
2508 -- maximum number of items that are allowed.
2510 Max_Length
:= Count_Type
'Last;
2513 -- The range of Index_Type has fewer values than in Count_Type,
2514 -- so the maximum number of items is computed from the range of
2517 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2521 -- No_Index is equal or greater than 0, so we can safely compute
2522 -- the difference without fear of overflow (which we would have to
2523 -- worry about if No_Index were less than 0, but that case is
2526 if Index_Type
'Last - No_Index
>=
2527 Count_Type
'Pos (Count_Type
'Last)
2529 -- We have determined that range of Index_Type has at least as
2530 -- many values as in Count_Type, so Count_Type'Last is the
2531 -- maximum number of items that are allowed.
2533 Max_Length
:= Count_Type
'Last;
2536 -- The range of Index_Type has fewer values than in Count_Type,
2537 -- so the maximum number of items is computed from the range of
2540 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2544 elsif Index_Type
'First <= 0 then
2546 -- We know that No_Index (the same as Index_Type'First - 1) is less
2547 -- than 0, so it is safe to compute the following sum without fear of
2550 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
2552 if J
<= Count_Type
'Base (Index_Type
'Last) then
2554 -- We have determined that range of Index_Type has at least as
2555 -- many values as in Count_Type, so Count_Type'Last is the maximum
2556 -- number of items that are allowed.
2558 Max_Length
:= Count_Type
'Last;
2561 -- The range of Index_Type has fewer values than Count_Type does,
2562 -- so the maximum number of items is computed from the range of
2566 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2570 -- No_Index is equal or greater than 0, so we can safely compute the
2571 -- difference without fear of overflow (which we would have to worry
2572 -- about if No_Index were less than 0, but that case is handled
2576 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2579 -- We have just computed the maximum length (number of items). We must
2580 -- now compare the requested length to the maximum length, as we do not
2581 -- allow a vector expand beyond the maximum (because that would create
2582 -- an internal array with a last index value greater than
2583 -- Index_Type'Last, with no way to index those elements).
2585 if New_Length
> Max_Length
then
2586 raise Constraint_Error
with "Count is out of range";
2589 -- New_Last is the last index value of the items in the container after
2590 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2591 -- compute its value from the New_Length.
2593 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2594 New_Last := No_Index + Index_Type'Base (New_Length);
2596 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2599 if Container.Elements = null then
2600 pragma Assert (Container.Last = No_Index);
2602 -- This is the simplest case, with which we must always begin: we're
2603 -- inserting items into an empty vector that hasn't allocated an
2604 -- internal array yet. Note that we don't need to check the busy bit
2605 -- here, because an empty container cannot be busy.
2607 -- In an indefinite vector, elements are allocated individually, and
2608 -- stored as access values on the internal array (the length of which
2609 -- represents the vector "capacity"), which is separately allocated.
2610 -- We have no elements here (because we're inserting "space"), so all
2611 -- we need to do is allocate the backbone.
2613 Container.Elements := new Elements_Type (New_Last);
2614 Container.Last := New_Last;
2619 -- The tampering bits exist to prevent an item from being harmfully
2620 -- manipulated while it is being visited. Query, Update, and Iterate
2621 -- increment the busy count on entry, and decrement the count on exit.
2622 -- Insert checks the count to determine whether it is being called while
2623 -- the associated callback procedure is executing.
2625 if Container.Busy > 0 then
2626 raise Program_Error with
2627 "attempt to tamper with cursors (vector is busy)";
2630 if New_Length <= Container.Elements.EA'Length then
2632 -- In this case, we are inserting elements into a vector that has
2633 -- already allocated an internal array, and the existing array has
2634 -- enough unused storage for the new items.
2637 E : Elements_Array renames Container.Elements.EA;
2640 if Before <= Container.Last then
2642 -- The new space is being inserted before some existing
2643 -- elements, so we must slide the existing elements up to
2644 -- their new home. We use the wider of Index_Type'Base and
2645 -- Count_Type'Base as the type for intermediate index values.
2647 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2648 Index
:= Before
+ Index_Type
'Base (Count
);
2650 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2653 E
(Index
.. New_Last
) := E
(Before
.. Container
.Last
);
2654 E
(Before
.. Index
- 1) := (others => null);
2658 Container
.Last
:= New_Last
;
2662 -- In this case, we're inserting elements into a vector that has already
2663 -- allocated an internal array, but the existing array does not have
2664 -- enough storage, so we must allocate a new, longer array. In order to
2665 -- guarantee that the amortized insertion cost is O(1), we always
2666 -- allocate an array whose length is some power-of-two factor of the
2667 -- current array length. (The new array cannot have a length less than
2668 -- the New_Length of the container, but its last index value cannot be
2669 -- greater than Index_Type'Last.)
2671 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
2672 while New_Capacity
< New_Length
loop
2673 if New_Capacity
> Count_Type
'Last / 2 then
2674 New_Capacity
:= Count_Type
'Last;
2678 New_Capacity
:= 2 * New_Capacity
;
2681 if New_Capacity
> Max_Length
then
2683 -- We have reached the limit of capacity, so no further expansion
2684 -- will occur. (This is not a problem, as there is never a need to
2685 -- have more capacity than the maximum container length.)
2687 New_Capacity
:= Max_Length
;
2690 -- We have computed the length of the new internal array (and this is
2691 -- what "vector capacity" means), so use that to compute its last index.
2693 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2694 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2697 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2700 -- Now we allocate the new, longer internal array. If the allocation
2701 -- fails, we have not changed any container state, so no side-effect
2702 -- will occur as a result of propagating the exception.
2704 Dst := new Elements_Type (Dst_Last);
2706 -- We have our new internal array. All that needs to be done now is to
2707 -- copy the existing items (if any) from the old array (the "source"
2708 -- array) to the new array (the "destination" array), and then
2709 -- deallocate the old array.
2712 Src : Elements_Access := Container.Elements;
2715 Dst.EA (Index_Type'First .. Before - 1) :=
2716 Src.EA (Index_Type'First .. Before - 1);
2718 if Before <= Container.Last then
2720 -- The new items are being inserted before some existing elements,
2721 -- so we must slide the existing elements up to their new home.
2723 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2724 Index
:= Before
+ Index_Type
'Base (Count
);
2726 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2729 Dst
.EA
(Index
.. New_Last
) := Src
.EA
(Before
.. Container
.Last
);
2732 -- We have copied the elements from to the old, source array to the
2733 -- new, destination array, so we can now restore invariants, and
2734 -- deallocate the old array.
2736 Container
.Elements
:= Dst
;
2737 Container
.Last
:= New_Last
;
2742 procedure Insert_Space
2743 (Container
: in out Vector
;
2745 Position
: out Cursor
;
2746 Count
: Count_Type
:= 1)
2748 Index
: Index_Type
'Base;
2751 if Before
.Container
/= null
2752 and then Before
.Container
/= Container
'Unrestricted_Access
2754 raise Program_Error
with "Before cursor denotes wrong container";
2758 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2759 Position
:= No_Element
;
2761 Position
:= (Container
'Unrestricted_Access, Before
.Index
);
2767 if Before
.Container
= null
2768 or else Before
.Index
> Container
.Last
2770 if Container
.Last
= Index_Type
'Last then
2771 raise Constraint_Error
with
2772 "vector is already at its maximum length";
2775 Index
:= Container
.Last
+ 1;
2778 Index
:= Before
.Index
;
2781 Insert_Space
(Container
, Index
, Count
);
2783 Position
:= Cursor
'(Container'Unrestricted_Access, Index);
2790 function Is_Empty (Container : Vector) return Boolean is
2792 return Container.Last < Index_Type'First;
2800 (Container : Vector;
2801 Process : not null access procedure (Position : Cursor))
2803 B : Natural renames Container'Unrestricted_Access.all.Busy;
2809 for Indx in Index_Type'First .. Container.Last loop
2810 Process (Cursor'(Container
'Unrestricted_Access, Indx
));
2821 function Iterate
(Container
: Vector
)
2822 return Vector_Iterator_Interfaces
.Reversible_Iterator
'Class
2824 V
: constant Vector_Access
:= Container
'Unrestricted_Access;
2825 B
: Natural renames V
.Busy
;
2828 -- The value of its Index component influences the behavior of the First
2829 -- and Last selector functions of the iterator object. When the Index
2830 -- component is No_Index (as is the case here), this means the iterator
2831 -- object was constructed without a start expression. This is a complete
2832 -- iterator, meaning that the iteration starts from the (logical)
2833 -- beginning of the sequence of items.
2835 -- Note: For a forward iterator, Container.First is the beginning, and
2836 -- for a reverse iterator, Container.Last is the beginning.
2838 return It
: constant Iterator
:=
2839 (Limited_Controlled
with
2848 (Container
: Vector
;
2850 return Vector_Iterator_Interfaces
.Reversible_Iterator
'Class
2852 V
: constant Vector_Access
:= Container
'Unrestricted_Access;
2853 B
: Natural renames V
.Busy
;
2856 -- It was formerly the case that when Start = No_Element, the partial
2857 -- iterator was defined to behave the same as for a complete iterator,
2858 -- and iterate over the entire sequence of items. However, those
2859 -- semantics were unintuitive and arguably error-prone (it is too easy
2860 -- to accidentally create an endless loop), and so they were changed,
2861 -- per the ARG meeting in Denver on 2011/11. However, there was no
2862 -- consensus about what positive meaning this corner case should have,
2863 -- and so it was decided to simply raise an exception. This does imply,
2864 -- however, that it is not possible to use a partial iterator to specify
2865 -- an empty sequence of items.
2867 if Start
.Container
= null then
2868 raise Constraint_Error
with
2869 "Start position for iterator equals No_Element";
2872 if Start
.Container
/= V
then
2873 raise Program_Error
with
2874 "Start cursor of Iterate designates wrong vector";
2877 if Start
.Index
> V
.Last
then
2878 raise Constraint_Error
with
2879 "Start position for iterator equals No_Element";
2882 -- The value of its Index component influences the behavior of the First
2883 -- and Last selector functions of the iterator object. When the Index
2884 -- component is not No_Index (as is the case here), it means that this
2885 -- is a partial iteration, over a subset of the complete sequence of
2886 -- items. The iterator object was constructed with a start expression,
2887 -- indicating the position from which the iteration begins. Note that
2888 -- the start position has the same value irrespective of whether this
2889 -- is a forward or reverse iteration.
2891 return It
: constant Iterator
:=
2892 (Limited_Controlled
with
2894 Index
=> Start
.Index
)
2904 function Last
(Container
: Vector
) return Cursor
is
2906 if Is_Empty
(Container
) then
2910 return (Container
'Unrestricted_Access, Container
.Last
);
2913 function Last
(Object
: Iterator
) return Cursor
is
2915 -- The value of the iterator object's Index component influences the
2916 -- behavior of the Last (and First) selector function.
2918 -- When the Index component is No_Index, this means the iterator
2919 -- object was constructed without a start expression, in which case the
2920 -- (reverse) iteration starts from the (logical) beginning of the entire
2921 -- sequence (corresponding to Container.Last, for a reverse iterator).
2923 -- Otherwise, this is iteration over a partial sequence of items.
2924 -- When the Index component is not No_Index, the iterator object was
2925 -- constructed with a start expression, that specifies the position
2926 -- from which the (reverse) partial iteration begins.
2928 if Object
.Index
= No_Index
then
2929 return Last
(Object
.Container
.all);
2931 return Cursor
'(Object.Container, Object.Index);
2939 function Last_Element (Container : Vector) return Element_Type is
2941 if Container.Last = No_Index then
2942 raise Constraint_Error with "Container is empty";
2946 EA : constant Element_Access :=
2947 Container.Elements.EA (Container.Last);
2950 raise Constraint_Error with "last element is empty";
2961 function Last_Index (Container : Vector) return Extended_Index is
2963 return Container.Last;
2970 function Length (Container : Vector) return Count_Type is
2971 L : constant Index_Type'Base := Container.Last;
2972 F : constant Index_Type := Index_Type'First;
2975 -- The base range of the index type (Index_Type'Base) might not include
2976 -- all values for length (Count_Type). Contrariwise, the index type
2977 -- might include values outside the range of length. Hence we use
2978 -- whatever type is wider for intermediate values when calculating
2979 -- length. Note that no matter what the index type is, the maximum
2980 -- length to which a vector is allowed to grow is always the minimum
2981 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2983 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2984 -- to have a base range of -128 .. 127, but the corresponding vector
2985 -- would have lengths in the range 0 .. 255. In this case we would need
2986 -- to use Count_Type'Base for intermediate values.
2988 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2989 -- vector would have a maximum length of 10, but the index values lie
2990 -- outside the range of Count_Type (which is only 32 bits). In this
2991 -- case we would need to use Index_Type'Base for intermediate values.
2993 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
2994 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2996 return Count_Type (L - F + 1);
3005 (Target : in out Vector;
3006 Source : in out Vector)
3009 if Target'Address = Source'Address then
3013 if Source.Busy > 0 then
3014 raise Program_Error with
3015 "attempt to tamper with cursors (Source is busy)";
3018 Clear (Target); -- Checks busy-bit
3021 Target_Elements : constant Elements_Access := Target.Elements;
3023 Target.Elements := Source.Elements;
3024 Source.Elements := Target_Elements;
3027 Target.Last := Source.Last;
3028 Source.Last := No_Index;
3035 function Next (Position : Cursor) return Cursor is
3037 if Position.Container = null then
3039 elsif Position.Index < Position.Container.Last then
3040 return (Position.Container, Position.Index + 1);
3046 function Next (Object : Iterator; Position : Cursor) return Cursor is
3048 if Position.Container = null then
3050 elsif Position.Container /= Object.Container then
3051 raise Program_Error with
3052 "Position cursor of Next designates wrong vector";
3054 return Next (Position);
3058 procedure Next (Position : in out Cursor) is
3060 if Position.Container = null then
3062 elsif Position.Index < Position.Container.Last then
3063 Position.Index := Position.Index + 1;
3065 Position := No_Element;
3073 procedure Prepend (Container : in out Vector; New_Item : Vector) is
3075 Insert (Container, Index_Type'First, New_Item);
3079 (Container : in out Vector;
3080 New_Item : Element_Type;
3081 Count : Count_Type := 1)
3084 Insert (Container, Index_Type'First, New_Item, Count);
3091 procedure Previous (Position : in out Cursor) is
3093 if Position.Container = null then
3095 elsif Position.Index > Index_Type'First then
3096 Position.Index := Position.Index - 1;
3098 Position := No_Element;
3102 function Previous (Position : Cursor) return Cursor is
3104 if Position.Container = null then
3106 elsif Position.Index > Index_Type'First then
3107 return (Position.Container, Position.Index - 1);
3113 function Previous (Object : Iterator; Position : Cursor) return Cursor is
3115 if Position.Container = null then
3117 elsif Position.Container /= Object.Container then
3118 raise Program_Error with
3119 "Position cursor of Previous designates wrong vector";
3121 return Previous (Position);
3129 procedure Query_Element
3130 (Container : Vector;
3132 Process : not null access procedure (Element : Element_Type))
3134 V : Vector renames Container'Unrestricted_Access.all;
3135 B : Natural renames V.Busy;
3136 L : Natural renames V.Lock;
3139 if Index > Container.Last then
3140 raise Constraint_Error with "Index is out of range";
3143 if V.Elements.EA (Index) = null then
3144 raise Constraint_Error with "element is null";
3151 Process (V.Elements.EA (Index).all);
3163 procedure Query_Element
3165 Process : not null access procedure (Element : Element_Type))
3168 if Position.Container = null then
3169 raise Constraint_Error with "Position cursor has no element";
3171 Query_Element (Position.Container.all, Position.Index, Process);
3180 (Stream : not null access Root_Stream_Type'Class;
3181 Container : out Vector)
3183 Length : Count_Type'Base;
3184 Last : Index_Type'Base := Index_Type'Pred (Index_Type'First);
3190 Count_Type'Base'Read
(Stream
, Length
);
3192 if Length
> Capacity
(Container
) then
3193 Reserve_Capacity
(Container
, Capacity
=> Length
);
3196 for J
in Count_Type
range 1 .. Length
loop
3199 Boolean'Read (Stream
, B
);
3202 Container
.Elements
.EA
(Last
) :=
3203 new Element_Type
'(Element_Type'Input (Stream));
3206 Container.Last := Last;
3211 (Stream : not null access Root_Stream_Type'Class;
3212 Position : out Cursor)
3215 raise Program_Error with "attempt to stream vector cursor";
3219 (Stream : not null access Root_Stream_Type'Class;
3220 Item : out Reference_Type)
3223 raise Program_Error with "attempt to stream reference";
3227 (Stream : not null access Root_Stream_Type'Class;
3228 Item : out Constant_Reference_Type)
3231 raise Program_Error with "attempt to stream reference";
3239 (Container : aliased in out Vector;
3240 Position : Cursor) return Reference_Type
3245 if Position.Container = null then
3246 raise Constraint_Error with "Position cursor has no element";
3249 if Position.Container /= Container'Unrestricted_Access then
3250 raise Program_Error with "Position cursor denotes wrong container";
3253 if Position.Index > Position.Container.Last then
3254 raise Constraint_Error with "Position cursor is out of range";
3257 E := Container.Elements.EA (Position.Index);
3260 raise Constraint_Error with "element at Position is empty";
3264 C : Vector renames Container'Unrestricted_Access.all;
3265 B : Natural renames C.Busy;
3266 L : Natural renames C.Lock;
3268 return R : constant Reference_Type :=
3269 (Element => E.all'Access,
3270 Control => (Controlled with Position.Container))
3279 (Container : aliased in out Vector;
3280 Index : Index_Type) return Reference_Type
3285 if Index > Container.Last then
3286 raise Constraint_Error with "Index is out of range";
3289 E := Container.Elements.EA (Index);
3292 raise Constraint_Error with "element at Index is empty";
3296 C : Vector renames Container'Unrestricted_Access.all;
3297 B : Natural renames C.Busy;
3298 L : Natural renames C.Lock;
3300 return R : constant Reference_Type :=
3301 (Element => E.all'Access,
3302 Control => (Controlled with Container'Unrestricted_Access))
3310 ---------------------
3311 -- Replace_Element --
3312 ---------------------
3314 procedure Replace_Element
3315 (Container : in out Vector;
3317 New_Item : Element_Type)
3320 if Index > Container.Last then
3321 raise Constraint_Error with "Index is out of range";
3324 if Container.Lock > 0 then
3325 raise Program_Error with
3326 "attempt to tamper with elements (vector is locked)";
3330 X : Element_Access := Container.Elements.EA (Index);
3332 -- The element allocator may need an accessibility check in the case
3333 -- where the actual type is class-wide or has access discriminants
3334 -- (see RM 4.8(10.1) and AI12-0035).
3336 pragma Unsuppress (Accessibility_Check);
3339 Container.Elements.EA (Index) := new Element_Type'(New_Item
);
3342 end Replace_Element
;
3344 procedure Replace_Element
3345 (Container
: in out Vector
;
3347 New_Item
: Element_Type
)
3350 if Position
.Container
= null then
3351 raise Constraint_Error
with "Position cursor has no element";
3354 if Position
.Container
/= Container
'Unrestricted_Access then
3355 raise Program_Error
with "Position cursor denotes wrong container";
3358 if Position
.Index
> Container
.Last
then
3359 raise Constraint_Error
with "Position cursor is out of range";
3362 if Container
.Lock
> 0 then
3363 raise Program_Error
with
3364 "attempt to tamper with elements (vector is locked)";
3368 X
: Element_Access
:= Container
.Elements
.EA
(Position
.Index
);
3370 -- The element allocator may need an accessibility check in the case
3371 -- where the actual type is class-wide or has access discriminants
3372 -- (see RM 4.8(10.1) and AI12-0035).
3374 pragma Unsuppress
(Accessibility_Check
);
3377 Container
.Elements
.EA
(Position
.Index
) := new Element_Type
'(New_Item);
3380 end Replace_Element;
3382 ----------------------
3383 -- Reserve_Capacity --
3384 ----------------------
3386 procedure Reserve_Capacity
3387 (Container : in out Vector;
3388 Capacity : Count_Type)
3390 N : constant Count_Type := Length (Container);
3392 Index : Count_Type'Base;
3393 Last : Index_Type'Base;
3396 -- Reserve_Capacity can be used to either expand the storage available
3397 -- for elements (this would be its typical use, in anticipation of
3398 -- future insertion), or to trim back storage. In the latter case,
3399 -- storage can only be trimmed back to the limit of the container
3400 -- length. Note that Reserve_Capacity neither deletes (active) elements
3401 -- nor inserts elements; it only affects container capacity, never
3402 -- container length.
3404 if Capacity = 0 then
3406 -- This is a request to trim back storage, to the minimum amount
3407 -- possible given the current state of the container.
3411 -- The container is empty, so in this unique case we can
3412 -- deallocate the entire internal array. Note that an empty
3413 -- container can never be busy, so there's no need to check the
3417 X : Elements_Access := Container.Elements;
3420 -- First we remove the internal array from the container, to
3421 -- handle the case when the deallocation raises an exception
3422 -- (although that's unlikely, since this is simply an array of
3423 -- access values, all of which are null).
3425 Container.Elements := null;
3427 -- Container invariants have been restored, so it is now safe
3428 -- to attempt to deallocate the internal array.
3433 elsif N < Container.Elements.EA'Length then
3435 -- The container is not empty, and the current length is less than
3436 -- the current capacity, so there's storage available to trim. In
3437 -- this case, we allocate a new internal array having a length
3438 -- that exactly matches the number of items in the
3439 -- container. (Reserve_Capacity does not delete active elements,
3440 -- so this is the best we can do with respect to minimizing
3443 if Container.Busy > 0 then
3444 raise Program_Error with
3445 "attempt to tamper with cursors (vector is busy)";
3449 subtype Array_Index_Subtype is Index_Type'Base range
3450 Index_Type'First .. Container.Last;
3452 Src : Elements_Array renames
3453 Container.Elements.EA (Array_Index_Subtype);
3455 X : Elements_Access := Container.Elements;
3458 -- Although we have isolated the old internal array that we're
3459 -- going to deallocate, we don't deallocate it until we have
3460 -- successfully allocated a new one. If there is an exception
3461 -- during allocation (because there is not enough storage), we
3462 -- let it propagate without causing any side-effect.
3464 Container.Elements := new Elements_Type'(Container
.Last
, Src
);
3466 -- We have successfully allocated a new internal array (with a
3467 -- smaller length than the old one, and containing a copy of
3468 -- just the active elements in the container), so we can
3469 -- deallocate the old array.
3478 -- Reserve_Capacity can be used to expand the storage available for
3479 -- elements, but we do not let the capacity grow beyond the number of
3480 -- values in Index_Type'Range. (Were it otherwise, there would be no way
3481 -- to refer to the elements with index values greater than
3482 -- Index_Type'Last, so that storage would be wasted.) Here we compute
3483 -- the Last index value of the new internal array, in a way that avoids
3484 -- any possibility of overflow.
3486 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3488 -- We perform a two-part test. First we determine whether the
3489 -- computed Last value lies in the base range of the type, and then
3490 -- determine whether it lies in the range of the index (sub)type.
3492 -- Last must satisfy this relation:
3493 -- First + Length - 1 <= Last
3494 -- We regroup terms:
3495 -- First - 1 <= Last - Length
3496 -- Which can rewrite as:
3497 -- No_Index <= Last - Length
3499 if Index_Type'Base'Last
- Index_Type
'Base (Capacity
) < No_Index
then
3500 raise Constraint_Error
with "Capacity is out of range";
3503 -- We now know that the computed value of Last is within the base
3504 -- range of the type, so it is safe to compute its value:
3506 Last
:= No_Index
+ Index_Type
'Base (Capacity
);
3508 -- Finally we test whether the value is within the range of the
3509 -- generic actual index subtype:
3511 if Last
> Index_Type
'Last then
3512 raise Constraint_Error
with "Capacity is out of range";
3515 elsif Index_Type
'First <= 0 then
3517 -- Here we can compute Last directly, in the normal way. We know that
3518 -- No_Index is less than 0, so there is no danger of overflow when
3519 -- adding the (positive) value of Capacity.
3521 Index
:= Count_Type
'Base (No_Index
) + Capacity
; -- Last
3523 if Index
> Count_Type
'Base (Index_Type
'Last) then
3524 raise Constraint_Error
with "Capacity is out of range";
3527 -- We know that the computed value (having type Count_Type) of Last
3528 -- is within the range of the generic actual index subtype, so it is
3529 -- safe to convert to Index_Type:
3531 Last
:= Index_Type
'Base (Index
);
3534 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3535 -- must test the length indirectly (by working backwards from the
3536 -- largest possible value of Last), in order to prevent overflow.
3538 Index
:= Count_Type
'Base (Index_Type
'Last) - Capacity
; -- No_Index
3540 if Index
< Count_Type
'Base (No_Index
) then
3541 raise Constraint_Error
with "Capacity is out of range";
3544 -- We have determined that the value of Capacity would not create a
3545 -- Last index value outside of the range of Index_Type, so we can now
3546 -- safely compute its value.
3548 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Capacity
);
3551 -- The requested capacity is non-zero, but we don't know yet whether
3552 -- this is a request for expansion or contraction of storage.
3554 if Container
.Elements
= null then
3556 -- The container is empty (it doesn't even have an internal array),
3557 -- so this represents a request to allocate storage having the given
3560 Container
.Elements
:= new Elements_Type
(Last
);
3564 if Capacity
<= N
then
3566 -- This is a request to trim back storage, but only to the limit of
3567 -- what's already in the container. (Reserve_Capacity never deletes
3568 -- active elements, it only reclaims excess storage.)
3570 if N
< Container
.Elements
.EA
'Length then
3572 -- The container is not empty (because the requested capacity is
3573 -- positive, and less than or equal to the container length), and
3574 -- the current length is less than the current capacity, so there
3575 -- is storage available to trim. In this case, we allocate a new
3576 -- internal array having a length that exactly matches the number
3577 -- of items in the container.
3579 if Container
.Busy
> 0 then
3580 raise Program_Error
with
3581 "attempt to tamper with cursors (vector is busy)";
3585 subtype Array_Index_Subtype
is Index_Type
'Base range
3586 Index_Type
'First .. Container
.Last
;
3588 Src
: Elements_Array
renames
3589 Container
.Elements
.EA
(Array_Index_Subtype
);
3591 X
: Elements_Access
:= Container
.Elements
;
3594 -- Although we have isolated the old internal array that we're
3595 -- going to deallocate, we don't deallocate it until we have
3596 -- successfully allocated a new one. If there is an exception
3597 -- during allocation (because there is not enough storage), we
3598 -- let it propagate without causing any side-effect.
3600 Container
.Elements
:= new Elements_Type
'(Container.Last, Src);
3602 -- We have successfully allocated a new internal array (with a
3603 -- smaller length than the old one, and containing a copy of
3604 -- just the active elements in the container), so it is now
3605 -- safe to deallocate the old array.
3614 -- The requested capacity is larger than the container length (the
3615 -- number of active elements). Whether this represents a request for
3616 -- expansion or contraction of the current capacity depends on what the
3617 -- current capacity is.
3619 if Capacity = Container.Elements.EA'Length then
3621 -- The requested capacity matches the existing capacity, so there's
3622 -- nothing to do here. We treat this case as a no-op, and simply
3623 -- return without checking the busy bit.
3628 -- There is a change in the capacity of a non-empty container, so a new
3629 -- internal array will be allocated. (The length of the new internal
3630 -- array could be less or greater than the old internal array. We know
3631 -- only that the length of the new internal array is greater than the
3632 -- number of active elements in the container.) We must check whether
3633 -- the container is busy before doing anything else.
3635 if Container.Busy > 0 then
3636 raise Program_Error with
3637 "attempt to tamper with cursors (vector is busy)";
3640 -- We now allocate a new internal array, having a length different from
3641 -- its current value.
3644 X : Elements_Access := Container.Elements;
3646 subtype Index_Subtype is Index_Type'Base range
3647 Index_Type'First .. Container.Last;
3650 -- We now allocate a new internal array, having a length different
3651 -- from its current value.
3653 Container.Elements := new Elements_Type (Last);
3655 -- We have successfully allocated the new internal array, so now we
3656 -- move the existing elements from the existing the old internal
3657 -- array onto the new one. Note that we're just copying access
3658 -- values, to this should not raise any exceptions.
3660 Container.Elements.EA (Index_Subtype) := X.EA (Index_Subtype);
3662 -- We have moved the elements from the old internal array, so now we
3663 -- can deallocate it.
3667 end Reserve_Capacity;
3669 ----------------------
3670 -- Reverse_Elements --
3671 ----------------------
3673 procedure Reverse_Elements (Container : in out Vector) is
3675 if Container.Length <= 1 then
3679 -- The exception behavior for the vector container must match that for
3680 -- the list container, so we check for cursor tampering here (which will
3681 -- catch more things) instead of for element tampering (which will catch
3682 -- fewer things). It's true that the elements of this vector container
3683 -- could be safely moved around while (say) an iteration is taking place
3684 -- (iteration only increments the busy counter), and so technically all
3685 -- we would need here is a test for element tampering (indicated by the
3686 -- lock counter), that's simply an artifact of our array-based
3687 -- implementation. Logically Reverse_Elements requires a check for
3688 -- cursor tampering.
3690 if Container.Busy > 0 then
3691 raise Program_Error with
3692 "attempt to tamper with cursors (vector is busy)";
3698 E : Elements_Array renames Container.Elements.EA;
3701 I := Index_Type'First;
3702 J := Container.Last;
3705 EI : constant Element_Access := E (I);
3716 end Reverse_Elements;
3722 function Reverse_Find
3723 (Container : Vector;
3724 Item : Element_Type;
3725 Position : Cursor := No_Element) return Cursor
3727 Last : Index_Type'Base;
3730 if Position.Container /= null
3731 and then Position.Container /= Container'Unrestricted_Access
3733 raise Program_Error with "Position cursor denotes wrong container";
3736 if Position.Container = null or else Position.Index > Container.Last then
3737 Last := Container.Last;
3739 Last := Position.Index;
3742 -- Per AI05-0022, the container implementation is required to detect
3743 -- element tampering by a generic actual subprogram.
3746 B : Natural renames Container'Unrestricted_Access.Busy;
3747 L : Natural renames Container'Unrestricted_Access.Lock;
3749 Result : Index_Type'Base;
3756 for Indx in reverse Index_Type'First .. Last loop
3757 if Container.Elements.EA (Indx) /= null
3758 and then Container.Elements.EA (Indx).all = Item
3768 if Result = No_Index then
3771 return Cursor'(Container
'Unrestricted_Access, Result
);
3782 ------------------------
3783 -- Reverse_Find_Index --
3784 ------------------------
3786 function Reverse_Find_Index
3787 (Container
: Vector
;
3788 Item
: Element_Type
;
3789 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
3791 B
: Natural renames Container
'Unrestricted_Access.Busy
;
3792 L
: Natural renames Container
'Unrestricted_Access.Lock
;
3794 Last
: constant Index_Type
'Base :=
3795 (if Index
> Container
.Last
then Container
.Last
else Index
);
3797 Result
: Index_Type
'Base;
3800 -- Per AI05-0022, the container implementation is required to detect
3801 -- element tampering by a generic actual subprogram.
3807 for Indx
in reverse Index_Type
'First .. Last
loop
3808 if Container
.Elements
.EA
(Indx
) /= null
3809 and then Container
.Elements
.EA
(Indx
).all = Item
3826 end Reverse_Find_Index
;
3828 ---------------------
3829 -- Reverse_Iterate --
3830 ---------------------
3832 procedure Reverse_Iterate
3833 (Container
: Vector
;
3834 Process
: not null access procedure (Position
: Cursor
))
3836 V
: Vector
renames Container
'Unrestricted_Access.all;
3837 B
: Natural renames V
.Busy
;
3843 for Indx
in reverse Index_Type
'First .. Container
.Last
loop
3844 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
3853 end Reverse_Iterate;
3859 procedure Set_Length
3860 (Container : in out Vector;
3861 Length : Count_Type)
3863 Count : constant Count_Type'Base := Container.Length - Length;
3866 -- Set_Length allows the user to set the length explicitly, instead of
3867 -- implicitly as a side-effect of deletion or insertion. If the
3868 -- requested length is less than the current length, this is equivalent
3869 -- to deleting items from the back end of the vector. If the requested
3870 -- length is greater than the current length, then this is equivalent to
3871 -- inserting "space" (nonce items) at the end.
3874 Container.Delete_Last (Count);
3876 elsif Container.Last >= Index_Type'Last then
3877 raise Constraint_Error with "vector is already at its maximum length";
3880 Container.Insert_Space (Container.Last + 1, -Count);
3889 (Container : in out Vector;
3893 if I > Container.Last then
3894 raise Constraint_Error with "I index is out of range";
3897 if J > Container.Last then
3898 raise Constraint_Error with "J index is out of range";
3905 if Container.Lock > 0 then
3906 raise Program_Error with
3907 "attempt to tamper with elements (vector is locked)";
3911 EI : Element_Access renames Container.Elements.EA (I);
3912 EJ : Element_Access renames Container.Elements.EA (J);
3914 EI_Copy : constant Element_Access := EI;
3923 (Container : in out Vector;
3927 if I.Container = null then
3928 raise Constraint_Error with "I cursor has no element";
3931 if J.Container = null then
3932 raise Constraint_Error with "J cursor has no element";
3935 if I.Container /= Container'Unrestricted_Access then
3936 raise Program_Error with "I cursor denotes wrong container";
3939 if J.Container /= Container'Unrestricted_Access then
3940 raise Program_Error with "J cursor denotes wrong container";
3943 Swap (Container, I.Index, J.Index);
3951 (Container : Vector;
3952 Index : Extended_Index) return Cursor
3955 if Index not in Index_Type'First .. Container.Last then
3959 return Cursor'(Container
'Unrestricted_Access, Index
);
3966 function To_Index
(Position
: Cursor
) return Extended_Index
is
3968 if Position
.Container
= null then
3970 elsif Position
.Index
<= Position
.Container
.Last
then
3971 return Position
.Index
;
3981 function To_Vector
(Length
: Count_Type
) return Vector
is
3982 Index
: Count_Type
'Base;
3983 Last
: Index_Type
'Base;
3984 Elements
: Elements_Access
;
3988 return Empty_Vector
;
3991 -- We create a vector object with a capacity that matches the specified
3992 -- Length, but we do not allow the vector capacity (the length of the
3993 -- internal array) to exceed the number of values in Index_Type'Range
3994 -- (otherwise, there would be no way to refer to those components via an
3995 -- index). We must therefore check whether the specified Length would
3996 -- create a Last index value greater than Index_Type'Last.
3998 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
4000 -- We perform a two-part test. First we determine whether the
4001 -- computed Last value lies in the base range of the type, and then
4002 -- determine whether it lies in the range of the index (sub)type.
4004 -- Last must satisfy this relation:
4005 -- First + Length - 1 <= Last
4006 -- We regroup terms:
4007 -- First - 1 <= Last - Length
4008 -- Which can rewrite as:
4009 -- No_Index <= Last - Length
4011 if Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
then
4012 raise Constraint_Error
with "Length is out of range";
4015 -- We now know that the computed value of Last is within the base
4016 -- range of the type, so it is safe to compute its value:
4018 Last
:= No_Index
+ Index_Type
'Base (Length
);
4020 -- Finally we test whether the value is within the range of the
4021 -- generic actual index subtype:
4023 if Last
> Index_Type
'Last then
4024 raise Constraint_Error
with "Length is out of range";
4027 elsif Index_Type
'First <= 0 then
4029 -- Here we can compute Last directly, in the normal way. We know that
4030 -- No_Index is less than 0, so there is no danger of overflow when
4031 -- adding the (positive) value of Length.
4033 Index
:= Count_Type
'Base (No_Index
) + Length
; -- Last
4035 if Index
> Count_Type
'Base (Index_Type
'Last) then
4036 raise Constraint_Error
with "Length is out of range";
4039 -- We know that the computed value (having type Count_Type) of Last
4040 -- is within the range of the generic actual index subtype, so it is
4041 -- safe to convert to Index_Type:
4043 Last
:= Index_Type
'Base (Index
);
4046 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4047 -- must test the length indirectly (by working backwards from the
4048 -- largest possible value of Last), in order to prevent overflow.
4050 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
4052 if Index
< Count_Type
'Base (No_Index
) then
4053 raise Constraint_Error
with "Length is out of range";
4056 -- We have determined that the value of Length would not create a
4057 -- Last index value outside of the range of Index_Type, so we can now
4058 -- safely compute its value.
4060 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
4063 Elements
:= new Elements_Type
(Last
);
4065 return Vector
'(Controlled with Elements, Last, 0, 0);
4069 (New_Item : Element_Type;
4070 Length : Count_Type) return Vector
4072 Index : Count_Type'Base;
4073 Last : Index_Type'Base;
4074 Elements : Elements_Access;
4078 return Empty_Vector;
4081 -- We create a vector object with a capacity that matches the specified
4082 -- Length, but we do not allow the vector capacity (the length of the
4083 -- internal array) to exceed the number of values in Index_Type'Range
4084 -- (otherwise, there would be no way to refer to those components via an
4085 -- index). We must therefore check whether the specified Length would
4086 -- create a Last index value greater than Index_Type'Last.
4088 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
4090 -- We perform a two-part test. First we determine whether the
4091 -- computed Last value lies in the base range of the type, and then
4092 -- determine whether it lies in the range of the index (sub)type.
4094 -- Last must satisfy this relation:
4095 -- First + Length - 1 <= Last
4096 -- We regroup terms:
4097 -- First - 1 <= Last - Length
4098 -- Which can rewrite as:
4099 -- No_Index <= Last - Length
4101 if Index_Type
'Base'Last - Index_Type'Base (Length) < No_Index then
4102 raise Constraint_Error with "Length is out of range";
4105 -- We now know that the computed value of Last is within the base
4106 -- range of the type, so it is safe to compute its value:
4108 Last := No_Index + Index_Type'Base (Length);
4110 -- Finally we test whether the value is within the range of the
4111 -- generic actual index subtype:
4113 if Last > Index_Type'Last then
4114 raise Constraint_Error with "Length is out of range";
4117 elsif Index_Type'First <= 0 then
4119 -- Here we can compute Last directly, in the normal way. We know that
4120 -- No_Index is less than 0, so there is no danger of overflow when
4121 -- adding the (positive) value of Length.
4123 Index := Count_Type'Base (No_Index) + Length; -- Last
4125 if Index > Count_Type'Base (Index_Type'Last) then
4126 raise Constraint_Error with "Length is out of range";
4129 -- We know that the computed value (having type Count_Type) of Last
4130 -- is within the range of the generic actual index subtype, so it is
4131 -- safe to convert to Index_Type:
4133 Last := Index_Type'Base (Index);
4136 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4137 -- must test the length indirectly (by working backwards from the
4138 -- largest possible value of Last), in order to prevent overflow.
4140 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4142 if Index < Count_Type'Base (No_Index) then
4143 raise Constraint_Error with "Length is out of range";
4146 -- We have determined that the value of Length would not create a
4147 -- Last index value outside of the range of Index_Type, so we can now
4148 -- safely compute its value.
4150 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4153 Elements := new Elements_Type (Last);
4155 -- We use Last as the index of the loop used to populate the internal
4156 -- array with items. In general, we prefer to initialize the loop index
4157 -- immediately prior to entering the loop. However, Last is also used in
4158 -- the exception handler (to reclaim elements that have been allocated,
4159 -- before propagating the exception), and the initialization of Last
4160 -- after entering the block containing the handler confuses some static
4161 -- analysis tools, with respect to whether Last has been properly
4162 -- initialized when the handler executes. So here we initialize our loop
4163 -- variable earlier than we prefer, before entering the block, so there
4166 Last := Index_Type'First;
4169 -- The element allocator may need an accessibility check in the case
4170 -- where the actual type is class-wide or has access discriminants
4171 -- (see RM 4.8(10.1) and AI12-0035).
4173 pragma Unsuppress (Accessibility_Check);
4177 Elements.EA (Last) := new Element_Type'(New_Item
);
4178 exit when Last
= Elements
.Last
;
4184 for J
in Index_Type
'First .. Last
- 1 loop
4185 Free
(Elements
.EA
(J
));
4192 return (Controlled
with Elements
, Last
, 0, 0);
4195 --------------------
4196 -- Update_Element --
4197 --------------------
4199 procedure Update_Element
4200 (Container
: in out Vector
;
4202 Process
: not null access procedure (Element
: in out Element_Type
))
4204 B
: Natural renames Container
.Busy
;
4205 L
: Natural renames Container
.Lock
;
4208 if Index
> Container
.Last
then
4209 raise Constraint_Error
with "Index is out of range";
4212 if Container
.Elements
.EA
(Index
) = null then
4213 raise Constraint_Error
with "element is null";
4220 Process
(Container
.Elements
.EA
(Index
).all);
4232 procedure Update_Element
4233 (Container
: in out Vector
;
4235 Process
: not null access procedure (Element
: in out Element_Type
))
4238 if Position
.Container
= null then
4239 raise Constraint_Error
with "Position cursor has no element";
4241 elsif Position
.Container
/= Container
'Unrestricted_Access then
4242 raise Program_Error
with "Position cursor denotes wrong container";
4245 Update_Element
(Container
, Position
.Index
, Process
);
4254 (Stream
: not null access Root_Stream_Type
'Class;
4257 N
: constant Count_Type
:= Length
(Container
);
4260 Count_Type
'Base'Write (Stream, N);
4267 E : Elements_Array renames Container.Elements.EA;
4270 for Indx in Index_Type'First .. Container.Last loop
4271 if E (Indx) = null then
4272 Boolean'Write (Stream, False);
4274 Boolean'Write (Stream, True);
4275 Element_Type'Output (Stream, E (Indx).all);
4282 (Stream : not null access Root_Stream_Type'Class;
4286 raise Program_Error with "attempt to stream vector cursor";
4290 (Stream : not null access Root_Stream_Type'Class;
4291 Item : Reference_Type)
4294 raise Program_Error with "attempt to stream reference";
4298 (Stream : not null access Root_Stream_Type'Class;
4299 Item : Constant_Reference_Type)
4302 raise Program_Error with "attempt to stream reference";
4305 end Ada.Containers.Indefinite_Vectors;