1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ V E C T O R S --
9 -- Copyright (C) 2004-2015, 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
;
32 with System
; use type System
.Address
;
34 package body Ada
.Containers
.Bounded_Vectors
is
36 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
37 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
38 -- See comment in Ada.Containers.Helpers
40 -----------------------
41 -- Local Subprograms --
42 -----------------------
44 function To_Array_Index
(Index
: Index_Type
'Base) return Count_Type
'Base;
50 function "&" (Left
, Right
: Vector
) return Vector
is
51 LN
: constant Count_Type
:= Length
(Left
);
52 RN
: constant Count_Type
:= Length
(Right
);
53 N
: Count_Type
'Base; -- length of result
54 J
: Count_Type
'Base; -- for computing intermediate index values
55 Last
: Index_Type
'Base; -- Last index of result
58 -- We decide that the capacity of the result is the sum of the lengths
59 -- of the vector parameters. We could decide to make it larger, but we
60 -- have no basis for knowing how much larger, so we just allocate the
61 -- minimum amount of storage.
63 -- Here we handle the easy cases first, when one of the vector
64 -- parameters is empty. (We say "easy" because there's nothing to
65 -- compute, that can potentially overflow.)
72 return Vector
'(Capacity => RN,
73 Elements => Right.Elements (1 .. RN),
79 return Vector'(Capacity
=> LN
,
80 Elements
=> Left
.Elements
(1 .. LN
),
85 -- Neither of the vector parameters is empty, so must compute the length
86 -- of the result vector and its last index. (This is the harder case,
87 -- because our computations must avoid overflow.)
89 -- There are two constraints we need to satisfy. The first constraint is
90 -- that a container cannot have more than Count_Type'Last elements, so
91 -- we must check the sum of the combined lengths. Note that we cannot
92 -- simply add the lengths, because of the possibility of overflow.
94 if Checks
and then LN
> Count_Type
'Last - RN
then
95 raise Constraint_Error
with "new length is out of range";
98 -- It is now safe to compute the length of the new vector, without fear
103 -- The second constraint is that the new Last index value cannot
104 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
105 -- Count_Type'Base as the type for intermediate values.
107 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
109 -- We perform a two-part test. First we determine whether the
110 -- computed Last value lies in the base range of the type, and then
111 -- determine whether it lies in the range of the index (sub)type.
113 -- Last must satisfy this relation:
114 -- First + Length - 1 <= Last
116 -- First - 1 <= Last - Length
117 -- Which can rewrite as:
118 -- No_Index <= Last - Length
121 Index_Type'Base'Last
- Index_Type
'Base (N
) < No_Index
123 raise Constraint_Error
with "new length is out of range";
126 -- We now know that the computed value of Last is within the base
127 -- range of the type, so it is safe to compute its value:
129 Last
:= No_Index
+ Index_Type
'Base (N
);
131 -- Finally we test whether the value is within the range of the
132 -- generic actual index subtype:
134 if Checks
and then Last
> Index_Type
'Last then
135 raise Constraint_Error
with "new length is out of range";
138 elsif Index_Type
'First <= 0 then
140 -- Here we can compute Last directly, in the normal way. We know that
141 -- No_Index is less than 0, so there is no danger of overflow when
142 -- adding the (positive) value of length.
144 J
:= Count_Type
'Base (No_Index
) + N
; -- Last
146 if Checks
and then J
> Count_Type
'Base (Index_Type
'Last) then
147 raise Constraint_Error
with "new length is out of range";
150 -- We know that the computed value (having type Count_Type) of Last
151 -- is within the range of the generic actual index subtype, so it is
152 -- safe to convert to Index_Type:
154 Last
:= Index_Type
'Base (J
);
157 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
158 -- must test the length indirectly (by working backwards from the
159 -- largest possible value of Last), in order to prevent overflow.
161 J
:= Count_Type
'Base (Index_Type
'Last) - N
; -- No_Index
163 if Checks
and then J
< Count_Type
'Base (No_Index
) then
164 raise Constraint_Error
with "new length is out of range";
167 -- We have determined that the result length would not create a Last
168 -- index value outside of the range of Index_Type, so we can now
169 -- safely compute its value.
171 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + N
);
175 LE
: Elements_Array
renames Left
.Elements
(1 .. LN
);
176 RE
: Elements_Array
renames Right
.Elements
(1 .. RN
);
179 return Vector
'(Capacity => N,
186 function "&" (Left : Vector; Right : Element_Type) return Vector is
187 LN : constant Count_Type := Length (Left);
190 -- We decide that the capacity of the result is the sum of the lengths
191 -- of the parameters. We could decide to make it larger, but we have no
192 -- basis for knowing how much larger, so we just allocate the minimum
193 -- amount of storage.
195 -- We must compute the length of the result vector and its last index,
196 -- but in such a way that overflow is avoided. We must satisfy two
197 -- constraints: the new length cannot exceed Count_Type'Last, and the
198 -- new Last index cannot exceed Index_Type'Last.
200 if Checks and then LN = Count_Type'Last then
201 raise Constraint_Error with "new length is out of range";
204 if Checks and then Left.Last >= Index_Type'Last then
205 raise Constraint_Error with "new length is out of range";
208 return Vector'(Capacity
=> LN
+ 1,
209 Elements
=> Left
.Elements
(1 .. LN
) & Right
,
210 Last
=> Left
.Last
+ 1,
214 function "&" (Left
: Element_Type
; Right
: Vector
) return Vector
is
215 RN
: constant Count_Type
:= Length
(Right
);
218 -- We decide that the capacity of the result is the sum of the lengths
219 -- of the parameters. We could decide to make it larger, but we have no
220 -- basis for knowing how much larger, so we just allocate the minimum
221 -- amount of storage.
223 -- We compute the length of the result vector and its last index, but in
224 -- such a way that overflow is avoided. We must satisfy two constraints:
225 -- the new length cannot exceed Count_Type'Last, and the new Last index
226 -- cannot exceed Index_Type'Last.
228 if Checks
and then RN
= Count_Type
'Last then
229 raise Constraint_Error
with "new length is out of range";
232 if Checks
and then Right
.Last
>= Index_Type
'Last then
233 raise Constraint_Error
with "new length is out of range";
236 return Vector
'(Capacity => 1 + RN,
237 Elements => Left & Right.Elements (1 .. RN),
238 Last => Right.Last + 1,
242 function "&" (Left, Right : Element_Type) return Vector is
244 -- We decide that the capacity of the result is the sum of the lengths
245 -- of the parameters. We could decide to make it larger, but we have no
246 -- basis for knowing how much larger, so we just allocate the minimum
247 -- amount of storage.
249 -- We must compute the length of the result vector and its last index,
250 -- but in such a way that overflow is avoided. We must satisfy two
251 -- constraints: the new length cannot exceed Count_Type'Last (here, we
252 -- know that that condition is satisfied), and the new Last index cannot
253 -- exceed Index_Type'Last.
255 if Checks and then Index_Type'First >= Index_Type'Last then
256 raise Constraint_Error with "new length is out of range";
259 return Vector'(Capacity
=> 2,
260 Elements
=> (Left
, Right
),
261 Last
=> Index_Type
'First + 1,
269 overriding
function "=" (Left
, Right
: Vector
) return Boolean is
271 if Left
.Last
/= Right
.Last
then
275 if Left
.Length
= 0 then
280 -- Per AI05-0022, the container implementation is required to detect
281 -- element tampering by a generic actual subprogram.
283 Lock_Left
: With_Lock
(Left
.TC
'Unrestricted_Access);
284 Lock_Right
: With_Lock
(Right
.TC
'Unrestricted_Access);
286 for J
in Count_Type
range 1 .. Left
.Length
loop
287 if Left
.Elements
(J
) /= Right
.Elements
(J
) then
300 procedure Assign
(Target
: in out Vector
; Source
: Vector
) is
302 if Target
'Address = Source
'Address then
306 if Checks
and then Target
.Capacity
< Source
.Length
then
307 raise Capacity_Error
-- ???
308 with "Target capacity is less than Source length";
313 Target
.Elements
(1 .. Source
.Length
) :=
314 Source
.Elements
(1 .. Source
.Length
);
316 Target
.Last
:= Source
.Last
;
323 procedure Append
(Container
: in out Vector
; New_Item
: Vector
) is
325 if New_Item
.Is_Empty
then
329 if Checks
and then Container
.Last
>= Index_Type
'Last then
330 raise Constraint_Error
with "vector is already at its maximum length";
333 Container
.Insert
(Container
.Last
+ 1, New_Item
);
337 (Container
: in out Vector
;
338 New_Item
: Element_Type
;
339 Count
: Count_Type
:= 1)
346 if Checks
and then Container
.Last
>= Index_Type
'Last then
347 raise Constraint_Error
with "vector is already at its maximum length";
350 Container
.Insert
(Container
.Last
+ 1, New_Item
, Count
);
357 function Capacity
(Container
: Vector
) return Count_Type
is
359 return Container
.Elements
'Length;
366 procedure Clear
(Container
: in out Vector
) is
368 TC_Check
(Container
.TC
);
370 Container
.Last
:= No_Index
;
373 ------------------------
374 -- Constant_Reference --
375 ------------------------
377 function Constant_Reference
378 (Container
: aliased Vector
;
379 Position
: Cursor
) return Constant_Reference_Type
382 if Checks
and then Position
.Container
= null then
383 raise Constraint_Error
with "Position cursor has no element";
386 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
388 raise Program_Error
with "Position cursor denotes wrong container";
391 if Checks
and then Position
.Index
> Position
.Container
.Last
then
392 raise Constraint_Error
with "Position cursor is out of range";
396 A
: Elements_Array
renames Container
.Elements
;
397 J
: constant Count_Type
:= To_Array_Index
(Position
.Index
);
398 TC
: constant Tamper_Counts_Access
:=
399 Container
.TC
'Unrestricted_Access;
401 return R
: constant Constant_Reference_Type
:=
402 (Element
=> A
(J
)'Access,
403 Control
=> (Controlled
with TC
))
408 end Constant_Reference
;
410 function Constant_Reference
411 (Container
: aliased Vector
;
412 Index
: Index_Type
) return Constant_Reference_Type
415 if Checks
and then Index
> Container
.Last
then
416 raise Constraint_Error
with "Index is out of range";
420 A
: Elements_Array
renames Container
.Elements
;
421 J
: constant Count_Type
:= To_Array_Index
(Index
);
422 TC
: constant Tamper_Counts_Access
:=
423 Container
.TC
'Unrestricted_Access;
425 return R
: constant Constant_Reference_Type
:=
426 (Element
=> A
(J
)'Access,
427 Control
=> (Controlled
with TC
))
432 end Constant_Reference
;
440 Item
: Element_Type
) return Boolean
443 return Find_Index
(Container
, Item
) /= No_Index
;
452 Capacity
: Count_Type
:= 0) return Vector
460 elsif Capacity
>= Source
.Length
then
465 with "Requested capacity is less than Source length";
468 return Target
: Vector
(C
) do
469 Target
.Elements
(1 .. Source
.Length
) :=
470 Source
.Elements
(1 .. Source
.Length
);
472 Target
.Last
:= Source
.Last
;
481 (Container
: in out Vector
;
482 Index
: Extended_Index
;
483 Count
: Count_Type
:= 1)
485 Old_Last
: constant Index_Type
'Base := Container
.Last
;
486 Old_Len
: constant Count_Type
:= Container
.Length
;
487 New_Last
: Index_Type
'Base;
488 Count2
: Count_Type
'Base; -- count of items from Index to Old_Last
489 Off
: Count_Type
'Base; -- Index expressed as offset from IT'First
492 -- Delete removes items from the vector, the number of which is the
493 -- minimum of the specified Count and the items (if any) that exist from
494 -- Index to Container.Last. There are no constraints on the specified
495 -- value of Count (it can be larger than what's available at this
496 -- position in the vector, for example), but there are constraints on
497 -- the allowed values of the Index.
499 -- As a precondition on the generic actual Index_Type, the base type
500 -- must include Index_Type'Pred (Index_Type'First); this is the value
501 -- that Container.Last assumes when the vector is empty. However, we do
502 -- not allow that as the value for Index when specifying which items
503 -- should be deleted, so we must manually check. (That the user is
504 -- allowed to specify the value at all here is a consequence of the
505 -- declaration of the Extended_Index subtype, which includes the values
506 -- in the base range that immediately precede and immediately follow the
507 -- values in the Index_Type.)
509 if Checks
and then Index
< Index_Type
'First then
510 raise Constraint_Error
with "Index is out of range (too small)";
513 -- We do allow a value greater than Container.Last to be specified as
514 -- the Index, but only if it's immediately greater. This allows the
515 -- corner case of deleting no items from the back end of the vector to
516 -- be treated as a no-op. (It is assumed that specifying an index value
517 -- greater than Last + 1 indicates some deeper flaw in the caller's
518 -- algorithm, so that case is treated as a proper error.)
520 if Index
> Old_Last
then
521 if Checks
and then Index
> Old_Last
+ 1 then
522 raise Constraint_Error
with "Index is out of range (too large)";
528 -- Here and elsewhere we treat deleting 0 items from the container as a
529 -- no-op, even when the container is busy, so we simply return.
535 -- The tampering bits exist to prevent an item from being deleted (or
536 -- otherwise harmfully manipulated) while it is being visited. Query,
537 -- Update, and Iterate increment the busy count on entry, and decrement
538 -- the count on exit. Delete checks the count to determine whether it is
539 -- being called while the associated callback procedure is executing.
541 TC_Check
(Container
.TC
);
543 -- We first calculate what's available for deletion starting at
544 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
545 -- Count_Type'Base as the type for intermediate values. (See function
546 -- Length for more information.)
548 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
549 Count2
:= Count_Type
'Base (Old_Last
) - Count_Type
'Base (Index
) + 1;
551 Count2
:= Count_Type
'Base (Old_Last
- Index
+ 1);
554 -- If more elements are requested (Count) for deletion than are
555 -- available (Count2) for deletion beginning at Index, then everything
556 -- from Index is deleted. There are no elements to slide down, and so
557 -- all we need to do is set the value of Container.Last.
559 if Count
>= Count2
then
560 Container
.Last
:= Index
- 1;
564 -- There are some elements aren't being deleted (the requested count was
565 -- less than the available count), so we must slide them down to
566 -- Index. We first calculate the index values of the respective array
567 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
568 -- type for intermediate calculations.
570 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
571 Off := Count_Type'Base (Index - Index_Type'First);
572 New_Last := Old_Last - Index_Type'Base (Count);
574 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
575 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
578 -- The array index values for each slice have already been determined,
579 -- so we just slide down to Index the elements that weren't deleted.
582 EA : Elements_Array renames Container.Elements;
583 Idx : constant Count_Type := EA'First + Off;
585 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
586 Container.Last := New_Last;
591 (Container : in out Vector;
592 Position : in out Cursor;
593 Count : Count_Type := 1)
595 pragma Warnings (Off, Position);
598 if Checks and then Position.Container = null then
599 raise Constraint_Error with "Position cursor has no element";
602 if Checks and then Position.Container /= Container'Unrestricted_Access
604 raise Program_Error with "Position cursor denotes wrong container";
607 if Checks and then Position.Index > Container.Last then
608 raise Program_Error with "Position index is out of range";
611 Delete (Container, Position.Index, Count);
612 Position := No_Element;
619 procedure Delete_First
620 (Container : in out Vector;
621 Count : Count_Type := 1)
627 elsif Count >= Length (Container) then
632 Delete (Container, Index_Type'First, Count);
640 procedure Delete_Last
641 (Container : in out Vector;
642 Count : Count_Type := 1)
645 -- It is not permitted to delete items while the container is busy (for
646 -- example, we're in the middle of a passive iteration). However, we
647 -- always treat deleting 0 items as a no-op, even when we're busy, so we
648 -- simply return without checking.
654 -- The tampering bits exist to prevent an item from being deleted (or
655 -- otherwise harmfully manipulated) while it is being visited. Query,
656 -- Update, and Iterate increment the busy count on entry, and decrement
657 -- the count on exit. Delete_Last checks the count to determine whether
658 -- it is being called while the associated callback procedure is
661 TC_Check (Container.TC);
663 -- There is no restriction on how large Count can be when deleting
664 -- items. If it is equal or greater than the current length, then this
665 -- is equivalent to clearing the vector. (In particular, there's no need
666 -- for us to actually calculate the new value for Last.)
668 -- If the requested count is less than the current length, then we must
669 -- calculate the new value for Last. For the type we use the widest of
670 -- Index_Type'Base and Count_Type'Base for the intermediate values of
671 -- our calculation. (See the comments in Length for more information.)
673 if Count >= Container.Length then
674 Container.Last := No_Index;
676 elsif Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
677 Container
.Last
:= Container
.Last
- Index_Type
'Base (Count
);
681 Index_Type
'Base (Count_Type
'Base (Container
.Last
) - Count
);
691 Index
: Index_Type
) return Element_Type
694 if Checks
and then Index
> Container
.Last
then
695 raise Constraint_Error
with "Index is out of range";
697 return Container
.Elements
(To_Array_Index
(Index
));
701 function Element
(Position
: Cursor
) return Element_Type
is
703 if Checks
and then Position
.Container
= null then
704 raise Constraint_Error
with "Position cursor has no element";
706 return Position
.Container
.Element
(Position
.Index
);
714 procedure Finalize
(Object
: in out Iterator
) is
716 Unbusy
(Object
.Container
.TC
);
726 Position
: Cursor
:= No_Element
) return Cursor
729 if Position
.Container
/= null then
730 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
732 raise Program_Error
with "Position cursor denotes wrong container";
735 if Checks
and then Position
.Index
> Container
.Last
then
736 raise Program_Error
with "Position index is out of range";
740 -- Per AI05-0022, the container implementation is required to detect
741 -- element tampering by a generic actual subprogram.
744 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
746 for J
in Position
.Index
.. Container
.Last
loop
747 if Container
.Elements
(To_Array_Index
(J
)) = Item
then
748 return Cursor
'(Container'Unrestricted_Access, J);
763 Index : Index_Type := Index_Type'First) return Extended_Index
765 -- Per AI05-0022, the container implementation is required to detect
766 -- element tampering by a generic actual subprogram.
768 Lock : With_Lock (Container.TC'Unrestricted_Access);
770 for Indx in Index .. Container.Last loop
771 if Container.Elements (To_Array_Index (Indx)) = Item then
783 function First (Container : Vector) return Cursor is
785 if Is_Empty (Container) then
788 return (Container'Unrestricted_Access, Index_Type'First);
792 function First (Object : Iterator) return Cursor is
794 -- The value of the iterator object's Index component influences the
795 -- behavior of the First (and Last) selector function.
797 -- When the Index component is No_Index, this means the iterator
798 -- object was constructed without a start expression, in which case the
799 -- (forward) iteration starts from the (logical) beginning of the entire
800 -- sequence of items (corresponding to Container.First, for a forward
803 -- Otherwise, this is iteration over a partial sequence of items.
804 -- When the Index component isn't No_Index, the iterator object was
805 -- constructed with a start expression, that specifies the position
806 -- from which the (forward) partial iteration begins.
808 if Object.Index = No_Index then
809 return First (Object.Container.all);
811 return Cursor'(Object
.Container
, Object
.Index
);
819 function First_Element
(Container
: Vector
) return Element_Type
is
821 if Checks
and then Container
.Last
= No_Index
then
822 raise Constraint_Error
with "Container is empty";
825 return Container
.Elements
(To_Array_Index
(Index_Type
'First));
832 function First_Index
(Container
: Vector
) return Index_Type
is
833 pragma Unreferenced
(Container
);
835 return Index_Type
'First;
838 ---------------------
839 -- Generic_Sorting --
840 ---------------------
842 package body Generic_Sorting
is
848 function Is_Sorted
(Container
: Vector
) return Boolean is
850 if Container
.Last
<= Index_Type
'First then
854 -- Per AI05-0022, the container implementation is required to detect
855 -- element tampering by a generic actual subprogram.
858 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
859 EA
: Elements_Array
renames Container
.Elements
;
861 for J
in 1 .. Container
.Length
- 1 loop
862 if EA
(J
+ 1) < EA
(J
) then
875 procedure Merge
(Target
, Source
: in out Vector
) is
879 -- The semantics of Merge changed slightly per AI05-0021. It was
880 -- originally the case that if Target and Source denoted the same
881 -- container object, then the GNAT implementation of Merge did
882 -- nothing. However, it was argued that RM05 did not precisely
883 -- specify the semantics for this corner case. The decision of the
884 -- ARG was that if Target and Source denote the same non-empty
885 -- container object, then Program_Error is raised.
887 if Source
.Is_Empty
then
891 if Checks
and then Target
'Address = Source
'Address then
892 raise Program_Error
with
893 "Target and Source denote same non-empty container";
896 if Target
.Is_Empty
then
897 Move
(Target
=> Target
, Source
=> Source
);
901 TC_Check
(Source
.TC
);
904 Target
.Set_Length
(I
+ Source
.Length
);
906 -- Per AI05-0022, the container implementation is required to detect
907 -- element tampering by a generic actual subprogram.
910 TA
: Elements_Array
renames Target
.Elements
;
911 SA
: Elements_Array
renames Source
.Elements
;
913 Lock_Target
: With_Lock
(Target
.TC
'Unchecked_Access);
914 Lock_Source
: With_Lock
(Source
.TC
'Unchecked_Access);
917 while not Source
.Is_Empty
loop
918 pragma Assert
(Source
.Length
<= 1
919 or else not (SA
(Source
.Length
) < SA
(Source
.Length
- 1)));
922 TA
(1 .. J
) := SA
(1 .. Source
.Length
);
923 Source
.Last
:= No_Index
;
927 pragma Assert
(I
<= 1
928 or else not (TA
(I
) < TA
(I
- 1)));
930 if SA
(Source
.Length
) < TA
(I
) then
935 TA
(J
) := SA
(Source
.Length
);
936 Source
.Last
:= Source
.Last
- 1;
948 procedure Sort
(Container
: in out Vector
) is
950 new Generic_Array_Sort
951 (Index_Type
=> Count_Type
,
952 Element_Type
=> Element_Type
,
953 Array_Type
=> Elements_Array
,
957 if Container
.Last
<= Index_Type
'First then
961 -- The exception behavior for the vector container must match that
962 -- for the list container, so we check for cursor tampering here
963 -- (which will catch more things) instead of for element tampering
964 -- (which will catch fewer things). It's true that the elements of
965 -- this vector container could be safely moved around while (say) an
966 -- iteration is taking place (iteration only increments the busy
967 -- counter), and so technically all we would need here is a test for
968 -- element tampering (indicated by the lock counter), that's simply
969 -- an artifact of our array-based implementation. Logically Sort
970 -- requires a check for cursor tampering.
972 TC_Check
(Container
.TC
);
974 -- Per AI05-0022, the container implementation is required to detect
975 -- element tampering by a generic actual subprogram.
978 Lock
: With_Lock
(Container
.TC
'Unchecked_Access);
980 Sort
(Container
.Elements
(1 .. Container
.Length
));
986 ------------------------
987 -- Get_Element_Access --
988 ------------------------
990 function Get_Element_Access
991 (Position
: Cursor
) return not null Element_Access
is
993 return Position
.Container
.Elements
994 (To_Array_Index
(Position
.Index
))'Access;
995 end Get_Element_Access
;
1001 function Has_Element
(Position
: Cursor
) return Boolean is
1003 if Position
.Container
= null then
1007 return Position
.Index
<= Position
.Container
.Last
;
1015 (Container
: in out Vector
;
1016 Before
: Extended_Index
;
1017 New_Item
: Element_Type
;
1018 Count
: Count_Type
:= 1)
1020 EA
: Elements_Array
renames Container
.Elements
;
1021 Old_Length
: constant Count_Type
:= Container
.Length
;
1023 Max_Length
: Count_Type
'Base; -- determined from range of Index_Type
1024 New_Length
: Count_Type
'Base; -- sum of current length and Count
1026 Index
: Index_Type
'Base; -- scratch for intermediate values
1027 J
: Count_Type
'Base; -- scratch
1030 -- As a precondition on the generic actual Index_Type, the base type
1031 -- must include Index_Type'Pred (Index_Type'First); this is the value
1032 -- that Container.Last assumes when the vector is empty. However, we do
1033 -- not allow that as the value for Index when specifying where the new
1034 -- items should be inserted, so we must manually check. (That the user
1035 -- is allowed to specify the value at all here is a consequence of the
1036 -- declaration of the Extended_Index subtype, which includes the values
1037 -- in the base range that immediately precede and immediately follow the
1038 -- values in the Index_Type.)
1040 if Checks
and then Before
< Index_Type
'First then
1041 raise Constraint_Error
with
1042 "Before index is out of range (too small)";
1045 -- We do allow a value greater than Container.Last to be specified as
1046 -- the Index, but only if it's immediately greater. This allows for the
1047 -- case of appending items to the back end of the vector. (It is assumed
1048 -- that specifying an index value greater than Last + 1 indicates some
1049 -- deeper flaw in the caller's algorithm, so that case is treated as a
1052 if Checks
and then Before
> Container
.Last
1053 and then Before
> Container
.Last
+ 1
1055 raise Constraint_Error
with
1056 "Before index is out of range (too large)";
1059 -- We treat inserting 0 items into the container as a no-op, even when
1060 -- the container is busy, so we simply return.
1066 -- There are two constraints we need to satisfy. The first constraint is
1067 -- that a container cannot have more than Count_Type'Last elements, so
1068 -- we must check the sum of the current length and the insertion
1069 -- count. Note that we cannot simply add these values, because of the
1070 -- possibility of overflow.
1072 if Checks
and then Old_Length
> Count_Type
'Last - Count
then
1073 raise Constraint_Error
with "Count is out of range";
1076 -- It is now safe compute the length of the new vector, without fear of
1079 New_Length
:= Old_Length
+ Count
;
1081 -- The second constraint is that the new Last index value cannot exceed
1082 -- Index_Type'Last. In each branch below, we calculate the maximum
1083 -- length (computed from the range of values in Index_Type), and then
1084 -- compare the new length to the maximum length. If the new length is
1085 -- acceptable, then we compute the new last index from that.
1087 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1089 -- We have to handle the case when there might be more values in the
1090 -- range of Index_Type than in the range of Count_Type.
1092 if Index_Type'First <= 0 then
1094 -- We know that No_Index (the same as Index_Type'First - 1) is
1095 -- less than 0, so it is safe to compute the following sum without
1096 -- fear of overflow.
1098 Index := No_Index + Index_Type'Base (Count_Type'Last);
1100 if Index <= Index_Type'Last then
1102 -- We have determined that range of Index_Type has at least as
1103 -- many values as in Count_Type, so Count_Type'Last is the
1104 -- maximum number of items that are allowed.
1106 Max_Length := Count_Type'Last;
1109 -- The range of Index_Type has fewer values than in Count_Type,
1110 -- so the maximum number of items is computed from the range of
1113 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1117 -- No_Index is equal or greater than 0, so we can safely compute
1118 -- the difference without fear of overflow (which we would have to
1119 -- worry about if No_Index were less than 0, but that case is
1122 if Index_Type'Last - No_Index >=
1123 Count_Type'Pos (Count_Type'Last)
1125 -- We have determined that range of Index_Type has at least as
1126 -- many values as in Count_Type, so Count_Type'Last is the
1127 -- maximum number of items that are allowed.
1129 Max_Length := Count_Type'Last;
1132 -- The range of Index_Type has fewer values than in Count_Type,
1133 -- so the maximum number of items is computed from the range of
1136 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1140 elsif Index_Type'First <= 0 then
1142 -- We know that No_Index (the same as Index_Type'First - 1) is less
1143 -- than 0, so it is safe to compute the following sum without fear of
1146 J := Count_Type'Base (No_Index) + Count_Type'Last;
1148 if J <= Count_Type'Base (Index_Type'Last) then
1150 -- We have determined that range of Index_Type has at least as
1151 -- many values as in Count_Type, so Count_Type'Last is the maximum
1152 -- number of items that are allowed.
1154 Max_Length := Count_Type'Last;
1157 -- The range of Index_Type has fewer values than Count_Type does,
1158 -- so the maximum number of items is computed from the range of
1162 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1166 -- No_Index is equal or greater than 0, so we can safely compute the
1167 -- difference without fear of overflow (which we would have to worry
1168 -- about if No_Index were less than 0, but that case is handled
1172 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1175 -- We have just computed the maximum length (number of items). We must
1176 -- now compare the requested length to the maximum length, as we do not
1177 -- allow a vector expand beyond the maximum (because that would create
1178 -- an internal array with a last index value greater than
1179 -- Index_Type'Last, with no way to index those elements).
1181 if Checks and then New_Length > Max_Length then
1182 raise Constraint_Error with "Count is out of range";
1185 -- The tampering bits exist to prevent an item from being harmfully
1186 -- manipulated while it is being visited. Query, Update, and Iterate
1187 -- increment the busy count on entry, and decrement the count on
1188 -- exit. Insert checks the count to determine whether it is being called
1189 -- while the associated callback procedure is executing.
1191 TC_Check (Container.TC);
1193 if Checks and then New_Length > Container.Capacity then
1194 raise Capacity_Error with "New length is larger than capacity";
1197 J := To_Array_Index (Before);
1199 if Before > Container.Last then
1201 -- The new items are being appended to the vector, so no
1202 -- sliding of existing elements is required.
1204 EA (J .. New_Length) := (others => New_Item);
1207 -- The new items are being inserted before some existing
1208 -- elements, so we must slide the existing elements up to their
1211 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1212 EA (J .. J + Count - 1) := (others => New_Item);
1215 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1216 Container
.Last
:= No_Index
+ Index_Type
'Base (New_Length
);
1220 Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Length
);
1225 (Container
: in out Vector
;
1226 Before
: Extended_Index
;
1229 N
: constant Count_Type
:= Length
(New_Item
);
1230 B
: Count_Type
; -- index Before converted to Count_Type
1233 -- Use Insert_Space to create the "hole" (the destination slice) into
1234 -- which we copy the source items.
1236 Insert_Space
(Container
, Before
, Count
=> N
);
1239 -- There's nothing else to do here (vetting of parameters was
1240 -- performed already in Insert_Space), so we simply return.
1245 B
:= To_Array_Index
(Before
);
1247 if Container
'Address /= New_Item
'Address then
1248 -- This is the simple case. New_Item denotes an object different
1249 -- from Container, so there's nothing special we need to do to copy
1250 -- the source items to their destination, because all of the source
1251 -- items are contiguous.
1253 Container
.Elements
(B
.. B
+ N
- 1) := New_Item
.Elements
(1 .. N
);
1257 -- We refer to array index value Before + N - 1 as J. This is the last
1258 -- index value of the destination slice.
1260 -- New_Item denotes the same object as Container, so an insertion has
1261 -- potentially split the source items. The destination is always the
1262 -- range [Before, J], but the source is [Index_Type'First, Before) and
1263 -- (J, Container.Last]. We perform the copy in two steps, using each of
1264 -- the two slices of the source items.
1267 subtype Src_Index_Subtype
is Count_Type
'Base range 1 .. B
- 1;
1269 Src
: Elements_Array
renames Container
.Elements
(Src_Index_Subtype
);
1272 -- We first copy the source items that precede the space we
1273 -- inserted. (If Before equals Index_Type'First, then this first
1274 -- source slice will be empty, which is harmless.)
1276 Container
.Elements
(B
.. B
+ Src
'Length - 1) := Src
;
1280 subtype Src_Index_Subtype
is Count_Type
'Base range
1281 B
+ N
.. Container
.Length
;
1283 Src
: Elements_Array
renames Container
.Elements
(Src_Index_Subtype
);
1286 -- We next copy the source items that follow the space we inserted.
1288 Container
.Elements
(B
+ N
- Src
'Length .. B
+ N
- 1) := Src
;
1293 (Container
: in out Vector
;
1297 Index
: Index_Type
'Base;
1300 if Checks
and then Before
.Container
/= null
1301 and then Before
.Container
/= Container
'Unchecked_Access
1303 raise Program_Error
with "Before cursor denotes wrong container";
1306 if Is_Empty
(New_Item
) then
1310 if Before
.Container
= null
1311 or else Before
.Index
> Container
.Last
1313 if Checks
and then Container
.Last
= Index_Type
'Last then
1314 raise Constraint_Error
with
1315 "vector is already at its maximum length";
1318 Index
:= Container
.Last
+ 1;
1321 Index
:= Before
.Index
;
1324 Insert
(Container
, Index
, New_Item
);
1328 (Container
: in out Vector
;
1331 Position
: out Cursor
)
1333 Index
: Index_Type
'Base;
1336 if Checks
and then Before
.Container
/= null
1337 and then Before
.Container
/= Container
'Unchecked_Access
1339 raise Program_Error
with "Before cursor denotes wrong container";
1342 if Is_Empty
(New_Item
) then
1343 if Before
.Container
= null
1344 or else Before
.Index
> Container
.Last
1346 Position
:= No_Element
;
1348 Position
:= (Container
'Unchecked_Access, Before
.Index
);
1354 if Before
.Container
= null
1355 or else Before
.Index
> Container
.Last
1357 if Checks
and then Container
.Last
= Index_Type
'Last then
1358 raise Constraint_Error
with
1359 "vector is already at its maximum length";
1362 Index
:= Container
.Last
+ 1;
1365 Index
:= Before
.Index
;
1368 Insert
(Container
, Index
, New_Item
);
1370 Position
:= Cursor
'(Container'Unchecked_Access, Index);
1374 (Container : in out Vector;
1376 New_Item : Element_Type;
1377 Count : Count_Type := 1)
1379 Index : Index_Type'Base;
1382 if Checks and then Before.Container /= null
1383 and then Before.Container /= Container'Unchecked_Access
1385 raise Program_Error with "Before cursor denotes wrong container";
1392 if Before.Container = null
1393 or else Before.Index > Container.Last
1395 if Checks and then Container.Last = Index_Type'Last then
1396 raise Constraint_Error with
1397 "vector is already at its maximum length";
1400 Index := Container.Last + 1;
1403 Index := Before.Index;
1406 Insert (Container, Index, New_Item, Count);
1410 (Container : in out Vector;
1412 New_Item : Element_Type;
1413 Position : out Cursor;
1414 Count : Count_Type := 1)
1416 Index : Index_Type'Base;
1419 if Checks and then Before.Container /= null
1420 and then Before.Container /= Container'Unchecked_Access
1422 raise Program_Error with "Before cursor denotes wrong container";
1426 if Before.Container = null
1427 or else Before.Index > Container.Last
1429 Position := No_Element;
1431 Position := (Container'Unchecked_Access, Before.Index);
1437 if Before.Container = null
1438 or else Before.Index > Container.Last
1440 if Checks and then Container.Last = Index_Type'Last then
1441 raise Constraint_Error with
1442 "vector is already at its maximum length";
1445 Index := Container.Last + 1;
1448 Index := Before.Index;
1451 Insert (Container, Index, New_Item, Count);
1453 Position := Cursor'(Container
'Unchecked_Access, Index
);
1457 (Container
: in out Vector
;
1458 Before
: Extended_Index
;
1459 Count
: Count_Type
:= 1)
1461 New_Item
: Element_Type
; -- Default-initialized value
1462 pragma Warnings
(Off
, New_Item
);
1465 Insert
(Container
, Before
, New_Item
, Count
);
1469 (Container
: in out Vector
;
1471 Position
: out Cursor
;
1472 Count
: Count_Type
:= 1)
1474 New_Item
: Element_Type
; -- Default-initialized value
1475 pragma Warnings
(Off
, New_Item
);
1478 Insert
(Container
, Before
, New_Item
, Position
, Count
);
1485 procedure Insert_Space
1486 (Container
: in out Vector
;
1487 Before
: Extended_Index
;
1488 Count
: Count_Type
:= 1)
1490 EA
: Elements_Array
renames Container
.Elements
;
1491 Old_Length
: constant Count_Type
:= Container
.Length
;
1493 Max_Length
: Count_Type
'Base; -- determined from range of Index_Type
1494 New_Length
: Count_Type
'Base; -- sum of current length and Count
1496 Index
: Index_Type
'Base; -- scratch for intermediate values
1497 J
: Count_Type
'Base; -- scratch
1500 -- As a precondition on the generic actual Index_Type, the base type
1501 -- must include Index_Type'Pred (Index_Type'First); this is the value
1502 -- that Container.Last assumes when the vector is empty. However, we do
1503 -- not allow that as the value for Index when specifying where the new
1504 -- items should be inserted, so we must manually check. (That the user
1505 -- is allowed to specify the value at all here is a consequence of the
1506 -- declaration of the Extended_Index subtype, which includes the values
1507 -- in the base range that immediately precede and immediately follow the
1508 -- values in the Index_Type.)
1510 if Checks
and then Before
< Index_Type
'First then
1511 raise Constraint_Error
with
1512 "Before index is out of range (too small)";
1515 -- We do allow a value greater than Container.Last to be specified as
1516 -- the Index, but only if it's immediately greater. This allows for the
1517 -- case of appending items to the back end of the vector. (It is assumed
1518 -- that specifying an index value greater than Last + 1 indicates some
1519 -- deeper flaw in the caller's algorithm, so that case is treated as a
1522 if Checks
and then Before
> Container
.Last
1523 and then Before
> Container
.Last
+ 1
1525 raise Constraint_Error
with
1526 "Before index is out of range (too large)";
1529 -- We treat inserting 0 items into the container as a no-op, even when
1530 -- the container is busy, so we simply return.
1536 -- There are two constraints we need to satisfy. The first constraint is
1537 -- that a container cannot have more than Count_Type'Last elements, so
1538 -- we must check the sum of the current length and the insertion count.
1539 -- Note that we cannot simply add these values, because of the
1540 -- possibility of overflow.
1542 if Checks
and then Old_Length
> Count_Type
'Last - Count
then
1543 raise Constraint_Error
with "Count is out of range";
1546 -- It is now safe compute the length of the new vector, without fear of
1549 New_Length
:= Old_Length
+ Count
;
1551 -- The second constraint is that the new Last index value cannot exceed
1552 -- Index_Type'Last. In each branch below, we calculate the maximum
1553 -- length (computed from the range of values in Index_Type), and then
1554 -- compare the new length to the maximum length. If the new length is
1555 -- acceptable, then we compute the new last index from that.
1557 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1559 -- We have to handle the case when there might be more values in the
1560 -- range of Index_Type than in the range of Count_Type.
1562 if Index_Type'First <= 0 then
1564 -- We know that No_Index (the same as Index_Type'First - 1) is
1565 -- less than 0, so it is safe to compute the following sum without
1566 -- fear of overflow.
1568 Index := No_Index + Index_Type'Base (Count_Type'Last);
1570 if Index <= Index_Type'Last then
1572 -- We have determined that range of Index_Type has at least as
1573 -- many values as in Count_Type, so Count_Type'Last is the
1574 -- maximum number of items that are allowed.
1576 Max_Length := Count_Type'Last;
1579 -- The range of Index_Type has fewer values than in Count_Type,
1580 -- so the maximum number of items is computed from the range of
1583 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1587 -- No_Index is equal or greater than 0, so we can safely compute
1588 -- the difference without fear of overflow (which we would have to
1589 -- worry about if No_Index were less than 0, but that case is
1592 if Index_Type'Last - No_Index >=
1593 Count_Type'Pos (Count_Type'Last)
1595 -- We have determined that range of Index_Type has at least as
1596 -- many values as in Count_Type, so Count_Type'Last is the
1597 -- maximum number of items that are allowed.
1599 Max_Length := Count_Type'Last;
1602 -- The range of Index_Type has fewer values than in Count_Type,
1603 -- so the maximum number of items is computed from the range of
1606 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1610 elsif Index_Type'First <= 0 then
1612 -- We know that No_Index (the same as Index_Type'First - 1) is less
1613 -- than 0, so it is safe to compute the following sum without fear of
1616 J := Count_Type'Base (No_Index) + Count_Type'Last;
1618 if J <= Count_Type'Base (Index_Type'Last) then
1620 -- We have determined that range of Index_Type has at least as
1621 -- many values as in Count_Type, so Count_Type'Last is the maximum
1622 -- number of items that are allowed.
1624 Max_Length := Count_Type'Last;
1627 -- The range of Index_Type has fewer values than Count_Type does,
1628 -- so the maximum number of items is computed from the range of
1632 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1636 -- No_Index is equal or greater than 0, so we can safely compute the
1637 -- difference without fear of overflow (which we would have to worry
1638 -- about if No_Index were less than 0, but that case is handled
1642 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1645 -- We have just computed the maximum length (number of items). We must
1646 -- now compare the requested length to the maximum length, as we do not
1647 -- allow a vector expand beyond the maximum (because that would create
1648 -- an internal array with a last index value greater than
1649 -- Index_Type'Last, with no way to index those elements).
1651 if Checks and then New_Length > Max_Length then
1652 raise Constraint_Error with "Count is out of range";
1655 -- The tampering bits exist to prevent an item from being harmfully
1656 -- manipulated while it is being visited. Query, Update, and Iterate
1657 -- increment the busy count on entry, and decrement the count on
1658 -- exit. Insert checks the count to determine whether it is being called
1659 -- while the associated callback procedure is executing.
1661 TC_Check (Container.TC);
1663 -- An internal array has already been allocated, so we need to check
1664 -- whether there is enough unused storage for the new items.
1666 if Checks and then New_Length > Container.Capacity then
1667 raise Capacity_Error with "New length is larger than capacity";
1670 -- In this case, we're inserting space into a vector that has already
1671 -- allocated an internal array, and the existing array has enough
1672 -- unused storage for the new items.
1674 if Before <= Container.Last then
1676 -- The space is being inserted before some existing elements,
1677 -- so we must slide the existing elements up to their new home.
1679 J := To_Array_Index (Before);
1680 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1683 -- New_Last is the last index value of the items in the container after
1684 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1685 -- compute its value from the New_Length.
1687 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1688 Container
.Last
:= No_Index
+ Index_Type
'Base (New_Length
);
1692 Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Length
);
1696 procedure Insert_Space
1697 (Container
: in out Vector
;
1699 Position
: out Cursor
;
1700 Count
: Count_Type
:= 1)
1702 Index
: Index_Type
'Base;
1705 if Checks
and then Before
.Container
/= null
1706 and then Before
.Container
/= Container
'Unchecked_Access
1708 raise Program_Error
with "Before cursor denotes wrong container";
1712 if Before
.Container
= null
1713 or else Before
.Index
> Container
.Last
1715 Position
:= No_Element
;
1717 Position
:= (Container
'Unchecked_Access, Before
.Index
);
1723 if Before
.Container
= null
1724 or else Before
.Index
> Container
.Last
1726 if Checks
and then Container
.Last
= Index_Type
'Last then
1727 raise Constraint_Error
with
1728 "vector is already at its maximum length";
1731 Index
:= Container
.Last
+ 1;
1734 Index
:= Before
.Index
;
1737 Insert_Space
(Container
, Index
, Count
=> Count
);
1739 Position
:= Cursor
'(Container'Unchecked_Access, Index);
1746 function Is_Empty (Container : Vector) return Boolean is
1748 return Container.Last < Index_Type'First;
1756 (Container : Vector;
1757 Process : not null access procedure (Position : Cursor))
1759 Busy : With_Busy (Container.TC'Unrestricted_Access);
1761 for Indx in Index_Type'First .. Container.Last loop
1762 Process (Cursor'(Container
'Unrestricted_Access, Indx
));
1767 (Container
: Vector
)
1768 return Vector_Iterator_Interfaces
.Reversible_Iterator
'Class
1770 V
: constant Vector_Access
:= Container
'Unrestricted_Access;
1772 -- The value of its Index component influences the behavior of the First
1773 -- and Last selector functions of the iterator object. When the Index
1774 -- component is No_Index (as is the case here), this means the iterator
1775 -- object was constructed without a start expression. This is a complete
1776 -- iterator, meaning that the iteration starts from the (logical)
1777 -- beginning of the sequence of items.
1779 -- Note: For a forward iterator, Container.First is the beginning, and
1780 -- for a reverse iterator, Container.Last is the beginning.
1782 return It
: constant Iterator
:=
1783 (Limited_Controlled
with
1787 Busy
(Container
.TC
'Unrestricted_Access.all);
1792 (Container
: Vector
;
1794 return Vector_Iterator_Interfaces
.Reversible_Iterator
'Class
1796 V
: constant Vector_Access
:= Container
'Unrestricted_Access;
1798 -- It was formerly the case that when Start = No_Element, the partial
1799 -- iterator was defined to behave the same as for a complete iterator,
1800 -- and iterate over the entire sequence of items. However, those
1801 -- semantics were unintuitive and arguably error-prone (it is too easy
1802 -- to accidentally create an endless loop), and so they were changed,
1803 -- per the ARG meeting in Denver on 2011/11. However, there was no
1804 -- consensus about what positive meaning this corner case should have,
1805 -- and so it was decided to simply raise an exception. This does imply,
1806 -- however, that it is not possible to use a partial iterator to specify
1807 -- an empty sequence of items.
1809 if Checks
and then Start
.Container
= null then
1810 raise Constraint_Error
with
1811 "Start position for iterator equals No_Element";
1814 if Checks
and then Start
.Container
/= V
then
1815 raise Program_Error
with
1816 "Start cursor of Iterate designates wrong vector";
1819 if Checks
and then Start
.Index
> V
.Last
then
1820 raise Constraint_Error
with
1821 "Start position for iterator equals No_Element";
1824 -- The value of its Index component influences the behavior of the First
1825 -- and Last selector functions of the iterator object. When the Index
1826 -- component is not No_Index (as is the case here), it means that this
1827 -- is a partial iteration, over a subset of the complete sequence of
1828 -- items. The iterator object was constructed with a start expression,
1829 -- indicating the position from which the iteration begins. Note that
1830 -- the start position has the same value irrespective of whether this is
1831 -- a forward or reverse iteration.
1833 return It
: constant Iterator
:=
1834 (Limited_Controlled
with
1836 Index
=> Start
.Index
)
1838 Busy
(Container
.TC
'Unrestricted_Access.all);
1846 function Last
(Container
: Vector
) return Cursor
is
1848 if Is_Empty
(Container
) then
1851 return (Container
'Unrestricted_Access, Container
.Last
);
1855 function Last
(Object
: Iterator
) return Cursor
is
1857 -- The value of the iterator object's Index component influences the
1858 -- behavior of the Last (and First) selector function.
1860 -- When the Index component is No_Index, this means the iterator object
1861 -- was constructed without a start expression, in which case the
1862 -- (reverse) iteration starts from the (logical) beginning of the entire
1863 -- sequence (corresponding to Container.Last, for a reverse iterator).
1865 -- Otherwise, this is iteration over a partial sequence of items. When
1866 -- the Index component is not No_Index, the iterator object was
1867 -- constructed with a start expression, that specifies the position from
1868 -- which the (reverse) partial iteration begins.
1870 if Object
.Index
= No_Index
then
1871 return Last
(Object
.Container
.all);
1873 return Cursor
'(Object.Container, Object.Index);
1881 function Last_Element (Container : Vector) return Element_Type is
1883 if Checks and then Container.Last = No_Index then
1884 raise Constraint_Error with "Container is empty";
1887 return Container.Elements (Container.Length);
1894 function Last_Index (Container : Vector) return Extended_Index is
1896 return Container.Last;
1903 function Length (Container : Vector) return Count_Type is
1904 L : constant Index_Type'Base := Container.Last;
1905 F : constant Index_Type := Index_Type'First;
1908 -- The base range of the index type (Index_Type'Base) might not include
1909 -- all values for length (Count_Type). Contrariwise, the index type
1910 -- might include values outside the range of length. Hence we use
1911 -- whatever type is wider for intermediate values when calculating
1912 -- length. Note that no matter what the index type is, the maximum
1913 -- length to which a vector is allowed to grow is always the minimum
1914 -- of Count_Type'Last and (IT'Last - IT'First + 1).
1916 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
1917 -- to have a base range of -128 .. 127, but the corresponding vector
1918 -- would have lengths in the range 0 .. 255. In this case we would need
1919 -- to use Count_Type'Base for intermediate values.
1921 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
1922 -- vector would have a maximum length of 10, but the index values lie
1923 -- outside the range of Count_Type (which is only 32 bits). In this
1924 -- case we would need to use Index_Type'Base for intermediate values.
1926 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
1927 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
1929 return Count_Type (L - F + 1);
1938 (Target : in out Vector;
1939 Source : in out Vector)
1942 if Target'Address = Source'Address then
1946 if Checks and then Target.Capacity < Source.Length then
1947 raise Capacity_Error -- ???
1948 with "Target capacity is less than Source length";
1951 TC_Check (Target.TC);
1952 TC_Check (Source.TC);
1954 -- Clear Target now, in case element assignment fails
1956 Target.Last := No_Index;
1958 Target.Elements (1 .. Source.Length) :=
1959 Source.Elements (1 .. Source.Length);
1961 Target.Last := Source.Last;
1962 Source.Last := No_Index;
1969 function Next (Position : Cursor) return Cursor is
1971 if Position.Container = null then
1973 elsif Position.Index < Position.Container.Last then
1974 return (Position.Container, Position.Index + 1);
1980 function Next (Object : Iterator; Position : Cursor) return Cursor is
1982 if Position.Container = null then
1986 if Checks and then Position.Container /= Object.Container then
1987 raise Program_Error with
1988 "Position cursor of Next designates wrong vector";
1991 return Next (Position);
1994 procedure Next (Position : in out Cursor) is
1996 if Position.Container = null then
1998 elsif Position.Index < Position.Container.Last then
1999 Position.Index := Position.Index + 1;
2001 Position := No_Element;
2009 procedure Prepend (Container : in out Vector; New_Item : Vector) is
2011 Insert (Container, Index_Type'First, New_Item);
2015 (Container : in out Vector;
2016 New_Item : Element_Type;
2017 Count : Count_Type := 1)
2030 procedure Previous (Position : in out Cursor) is
2032 if Position.Container = null then
2034 elsif Position.Index > Index_Type'First then
2035 Position.Index := Position.Index - 1;
2037 Position := No_Element;
2041 function Previous (Position : Cursor) return Cursor is
2043 if Position.Container = null then
2045 elsif Position.Index > Index_Type'First then
2046 return (Position.Container, Position.Index - 1);
2052 function Previous (Object : Iterator; Position : Cursor) return Cursor is
2054 if Position.Container = null then
2058 if Checks and then Position.Container /= Object.Container then
2059 raise Program_Error with
2060 "Position cursor of Previous designates wrong vector";
2063 return Previous (Position);
2066 ----------------------
2067 -- Pseudo_Reference --
2068 ----------------------
2070 function Pseudo_Reference
2071 (Container : aliased Vector'Class) return Reference_Control_Type
2073 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
2075 return R : constant Reference_Control_Type := (Controlled with TC) do
2078 end Pseudo_Reference;
2084 procedure Query_Element
2085 (Container : Vector;
2087 Process : not null access procedure (Element : Element_Type))
2089 Lock : With_Lock (Container.TC'Unrestricted_Access);
2090 V : Vector renames Container'Unrestricted_Access.all;
2092 if Checks and then Index > Container.Last then
2093 raise Constraint_Error with "Index is out of range";
2096 Process (V.Elements (To_Array_Index (Index)));
2099 procedure Query_Element
2101 Process : not null access procedure (Element : Element_Type))
2104 if Checks and then Position.Container = null then
2105 raise Constraint_Error with "Position cursor has no element";
2108 Query_Element (Position.Container.all, Position.Index, Process);
2116 (Stream : not null access Root_Stream_Type'Class;
2117 Container : out Vector)
2119 Length : Count_Type'Base;
2120 Last : Index_Type'Base := No_Index;
2125 Count_Type'Base'Read
(Stream
, Length
);
2127 Reserve_Capacity
(Container
, Capacity
=> Length
);
2129 for Idx
in Count_Type
range 1 .. Length
loop
2131 Element_Type
'Read (Stream
, Container
.Elements
(Idx
));
2132 Container
.Last
:= Last
;
2137 (Stream
: not null access Root_Stream_Type
'Class;
2138 Position
: out Cursor
)
2141 raise Program_Error
with "attempt to stream vector cursor";
2145 (Stream
: not null access Root_Stream_Type
'Class;
2146 Item
: out Reference_Type
)
2149 raise Program_Error
with "attempt to stream reference";
2153 (Stream
: not null access Root_Stream_Type
'Class;
2154 Item
: out Constant_Reference_Type
)
2157 raise Program_Error
with "attempt to stream reference";
2165 (Container
: aliased in out Vector
;
2166 Position
: Cursor
) return Reference_Type
2169 if Checks
and then Position
.Container
= null then
2170 raise Constraint_Error
with "Position cursor has no element";
2173 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2175 raise Program_Error
with "Position cursor denotes wrong container";
2178 if Checks
and then Position
.Index
> Position
.Container
.Last
then
2179 raise Constraint_Error
with "Position cursor is out of range";
2183 A
: Elements_Array
renames Container
.Elements
;
2184 J
: constant Count_Type
:= To_Array_Index
(Position
.Index
);
2185 TC
: constant Tamper_Counts_Access
:=
2186 Container
.TC
'Unrestricted_Access;
2188 return R
: constant Reference_Type
:=
2189 (Element
=> A
(J
)'Access,
2190 Control
=> (Controlled
with TC
))
2198 (Container
: aliased in out Vector
;
2199 Index
: Index_Type
) return Reference_Type
2202 if Checks
and then Index
> Container
.Last
then
2203 raise Constraint_Error
with "Index is out of range";
2207 A
: Elements_Array
renames Container
.Elements
;
2208 J
: constant Count_Type
:= To_Array_Index
(Index
);
2209 TC
: constant Tamper_Counts_Access
:=
2210 Container
.TC
'Unrestricted_Access;
2212 return R
: constant Reference_Type
:=
2213 (Element
=> A
(J
)'Access,
2214 Control
=> (Controlled
with TC
))
2221 ---------------------
2222 -- Replace_Element --
2223 ---------------------
2225 procedure Replace_Element
2226 (Container
: in out Vector
;
2228 New_Item
: Element_Type
)
2231 if Checks
and then Index
> Container
.Last
then
2232 raise Constraint_Error
with "Index is out of range";
2235 TE_Check
(Container
.TC
);
2237 Container
.Elements
(To_Array_Index
(Index
)) := New_Item
;
2238 end Replace_Element
;
2240 procedure Replace_Element
2241 (Container
: in out Vector
;
2243 New_Item
: Element_Type
)
2246 if Checks
and then Position
.Container
= null then
2247 raise Constraint_Error
with "Position cursor has no element";
2250 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2252 raise Program_Error
with "Position cursor denotes wrong container";
2255 if Checks
and then Position
.Index
> Container
.Last
then
2256 raise Constraint_Error
with "Position cursor is out of range";
2259 TE_Check
(Container
.TC
);
2261 Container
.Elements
(To_Array_Index
(Position
.Index
)) := New_Item
;
2262 end Replace_Element
;
2264 ----------------------
2265 -- Reserve_Capacity --
2266 ----------------------
2268 procedure Reserve_Capacity
2269 (Container
: in out Vector
;
2270 Capacity
: Count_Type
)
2273 if Checks
and then Capacity
> Container
.Capacity
then
2274 raise Capacity_Error
with "Capacity is out of range";
2276 end Reserve_Capacity
;
2278 ----------------------
2279 -- Reverse_Elements --
2280 ----------------------
2282 procedure Reverse_Elements
(Container
: in out Vector
) is
2283 E
: Elements_Array
renames Container
.Elements
;
2288 if Container
.Length
<= 1 then
2292 -- The exception behavior for the vector container must match that for
2293 -- the list container, so we check for cursor tampering here (which will
2294 -- catch more things) instead of for element tampering (which will catch
2295 -- fewer things). It's true that the elements of this vector container
2296 -- could be safely moved around while (say) an iteration is taking place
2297 -- (iteration only increments the busy counter), and so technically
2298 -- all we would need here is a test for element tampering (indicated
2299 -- by the lock counter), that's simply an artifact of our array-based
2300 -- implementation. Logically Reverse_Elements requires a check for
2301 -- cursor tampering.
2303 TC_Check
(Container
.TC
);
2306 Jdx
:= Container
.Length
;
2307 while Idx
< Jdx
loop
2309 EI
: constant Element_Type
:= E
(Idx
);
2319 end Reverse_Elements
;
2325 function Reverse_Find
2326 (Container
: Vector
;
2327 Item
: Element_Type
;
2328 Position
: Cursor
:= No_Element
) return Cursor
2330 Last
: Index_Type
'Base;
2333 if Checks
and then Position
.Container
/= null
2334 and then Position
.Container
/= Container
'Unrestricted_Access
2336 raise Program_Error
with "Position cursor denotes wrong container";
2340 (if Position
.Container
= null or else Position
.Index
> Container
.Last
2342 else Position
.Index
);
2344 -- Per AI05-0022, the container implementation is required to detect
2345 -- element tampering by a generic actual subprogram.
2348 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
2350 for Indx
in reverse Index_Type
'First .. Last
loop
2351 if Container
.Elements
(To_Array_Index
(Indx
)) = Item
then
2352 return Cursor
'(Container'Unrestricted_Access, Indx);
2360 ------------------------
2361 -- Reverse_Find_Index --
2362 ------------------------
2364 function Reverse_Find_Index
2365 (Container : Vector;
2366 Item : Element_Type;
2367 Index : Index_Type := Index_Type'Last) return Extended_Index
2369 -- Per AI05-0022, the container implementation is required to detect
2370 -- element tampering by a generic actual subprogram.
2372 Lock : With_Lock (Container.TC'Unrestricted_Access);
2374 Last : constant Index_Type'Base :=
2375 Index_Type'Min (Container.Last, Index);
2378 for Indx in reverse Index_Type'First .. Last loop
2379 if Container.Elements (To_Array_Index (Indx)) = Item then
2385 end Reverse_Find_Index;
2387 ---------------------
2388 -- Reverse_Iterate --
2389 ---------------------
2391 procedure Reverse_Iterate
2392 (Container : Vector;
2393 Process : not null access procedure (Position : Cursor))
2395 Busy : With_Busy (Container.TC'Unrestricted_Access);
2397 for Indx in reverse Index_Type'First .. Container.Last loop
2398 Process (Cursor'(Container
'Unrestricted_Access, Indx
));
2400 end Reverse_Iterate
;
2406 procedure Set_Length
(Container
: in out Vector
; Length
: Count_Type
) is
2407 Count
: constant Count_Type
'Base := Container
.Length
- Length
;
2410 -- Set_Length allows the user to set the length explicitly, instead of
2411 -- implicitly as a side-effect of deletion or insertion. If the
2412 -- requested length is less than the current length, this is equivalent
2413 -- to deleting items from the back end of the vector. If the requested
2414 -- length is greater than the current length, then this is equivalent to
2415 -- inserting "space" (nonce items) at the end.
2418 Container
.Delete_Last
(Count
);
2419 elsif Checks
and then Container
.Last
>= Index_Type
'Last then
2420 raise Constraint_Error
with "vector is already at its maximum length";
2422 Container
.Insert_Space
(Container
.Last
+ 1, -Count
);
2430 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
2431 E
: Elements_Array
renames Container
.Elements
;
2434 if Checks
and then I
> Container
.Last
then
2435 raise Constraint_Error
with "I index is out of range";
2438 if Checks
and then J
> Container
.Last
then
2439 raise Constraint_Error
with "J index is out of range";
2446 TE_Check
(Container
.TC
);
2449 EI_Copy
: constant Element_Type
:= E
(To_Array_Index
(I
));
2451 E
(To_Array_Index
(I
)) := E
(To_Array_Index
(J
));
2452 E
(To_Array_Index
(J
)) := EI_Copy
;
2456 procedure Swap
(Container
: in out Vector
; I
, J
: Cursor
) is
2458 if Checks
and then I
.Container
= null then
2459 raise Constraint_Error
with "I cursor has no element";
2462 if Checks
and then J
.Container
= null then
2463 raise Constraint_Error
with "J cursor has no element";
2466 if Checks
and then I
.Container
/= Container
'Unrestricted_Access then
2467 raise Program_Error
with "I cursor denotes wrong container";
2470 if Checks
and then J
.Container
/= Container
'Unrestricted_Access then
2471 raise Program_Error
with "J cursor denotes wrong container";
2474 Swap
(Container
, I
.Index
, J
.Index
);
2477 --------------------
2478 -- To_Array_Index --
2479 --------------------
2481 function To_Array_Index
(Index
: Index_Type
'Base) return Count_Type
'Base is
2482 Offset
: Count_Type
'Base;
2486 -- Index >= Index_Type'First
2487 -- hence we also know that
2488 -- Index - Index_Type'First >= 0
2490 -- The issue is that even though 0 is guaranteed to be a value in
2491 -- the type Index_Type'Base, there's no guarantee that the difference
2492 -- is a value in that type. To prevent overflow we use the wider
2493 -- of Count_Type'Base and Index_Type'Base to perform intermediate
2496 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2497 Offset := Count_Type'Base (Index - Index_Type'First);
2500 Offset := Count_Type'Base (Index) -
2501 Count_Type'Base (Index_Type'First);
2504 -- The array index subtype for all container element arrays
2505 -- always starts with 1.
2515 (Container : Vector;
2516 Index : Extended_Index) return Cursor
2519 if Index not in Index_Type'First .. Container.Last then
2523 return Cursor'(Container
'Unrestricted_Access, Index
);
2530 function To_Index
(Position
: Cursor
) return Extended_Index
is
2532 if Position
.Container
= null then
2536 if Position
.Index
<= Position
.Container
.Last
then
2537 return Position
.Index
;
2547 function To_Vector
(Length
: Count_Type
) return Vector
is
2548 Index
: Count_Type
'Base;
2549 Last
: Index_Type
'Base;
2553 return Empty_Vector
;
2556 -- We create a vector object with a capacity that matches the specified
2557 -- Length, but we do not allow the vector capacity (the length of the
2558 -- internal array) to exceed the number of values in Index_Type'Range
2559 -- (otherwise, there would be no way to refer to those components via an
2560 -- index). We must therefore check whether the specified Length would
2561 -- create a Last index value greater than Index_Type'Last.
2563 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2564 -- We perform a two-part test. First we determine whether the
2565 -- computed Last value lies in the base range of the type, and then
2566 -- determine whether it lies in the range of the index (sub)type.
2568 -- Last must satisfy this relation:
2569 -- First + Length - 1 <= Last
2570 -- We regroup terms:
2571 -- First - 1 <= Last - Length
2572 -- Which can rewrite as:
2573 -- No_Index <= Last - Length
2576 Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
2578 raise Constraint_Error
with "Length is out of range";
2581 -- We now know that the computed value of Last is within the base
2582 -- range of the type, so it is safe to compute its value:
2584 Last
:= No_Index
+ Index_Type
'Base (Length
);
2586 -- Finally we test whether the value is within the range of the
2587 -- generic actual index subtype:
2589 if Checks
and then Last
> Index_Type
'Last then
2590 raise Constraint_Error
with "Length is out of range";
2593 elsif Index_Type
'First <= 0 then
2595 -- Here we can compute Last directly, in the normal way. We know that
2596 -- No_Index is less than 0, so there is no danger of overflow when
2597 -- adding the (positive) value of Length.
2599 Index
:= Count_Type
'Base (No_Index
) + Length
; -- Last
2601 if Checks
and then Index
> Count_Type
'Base (Index_Type
'Last) then
2602 raise Constraint_Error
with "Length is out of range";
2605 -- We know that the computed value (having type Count_Type) of Last
2606 -- is within the range of the generic actual index subtype, so it is
2607 -- safe to convert to Index_Type:
2609 Last
:= Index_Type
'Base (Index
);
2612 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2613 -- must test the length indirectly (by working backwards from the
2614 -- largest possible value of Last), in order to prevent overflow.
2616 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
2618 if Checks
and then Index
< Count_Type
'Base (No_Index
) then
2619 raise Constraint_Error
with "Length is out of range";
2622 -- We have determined that the value of Length would not create a
2623 -- Last index value outside of the range of Index_Type, so we can now
2624 -- safely compute its value.
2626 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
2629 return V
: Vector
(Capacity
=> Length
) do
2635 (New_Item
: Element_Type
;
2636 Length
: Count_Type
) return Vector
2638 Index
: Count_Type
'Base;
2639 Last
: Index_Type
'Base;
2643 return Empty_Vector
;
2646 -- We create a vector object with a capacity that matches the specified
2647 -- Length, but we do not allow the vector capacity (the length of the
2648 -- internal array) to exceed the number of values in Index_Type'Range
2649 -- (otherwise, there would be no way to refer to those components via an
2650 -- index). We must therefore check whether the specified Length would
2651 -- create a Last index value greater than Index_Type'Last.
2653 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2655 -- We perform a two-part test. First we determine whether the
2656 -- computed Last value lies in the base range of the type, and then
2657 -- determine whether it lies in the range of the index (sub)type.
2659 -- Last must satisfy this relation:
2660 -- First + Length - 1 <= Last
2661 -- We regroup terms:
2662 -- First - 1 <= Last - Length
2663 -- Which can rewrite as:
2664 -- No_Index <= Last - Length
2667 Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
2669 raise Constraint_Error
with "Length is out of range";
2672 -- We now know that the computed value of Last is within the base
2673 -- range of the type, so it is safe to compute its value:
2675 Last
:= No_Index
+ Index_Type
'Base (Length
);
2677 -- Finally we test whether the value is within the range of the
2678 -- generic actual index subtype:
2680 if Checks
and then Last
> Index_Type
'Last then
2681 raise Constraint_Error
with "Length is out of range";
2684 elsif Index_Type
'First <= 0 then
2686 -- Here we can compute Last directly, in the normal way. We know that
2687 -- No_Index is less than 0, so there is no danger of overflow when
2688 -- adding the (positive) value of Length.
2690 Index
:= Count_Type
'Base (No_Index
) + Length
; -- same value as V.Last
2692 if Checks
and then Index
> Count_Type
'Base (Index_Type
'Last) then
2693 raise Constraint_Error
with "Length is out of range";
2696 -- We know that the computed value (having type Count_Type) of Last
2697 -- is within the range of the generic actual index subtype, so it is
2698 -- safe to convert to Index_Type:
2700 Last
:= Index_Type
'Base (Index
);
2703 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2704 -- must test the length indirectly (by working backwards from the
2705 -- largest possible value of Last), in order to prevent overflow.
2707 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
2709 if Checks
and then Index
< Count_Type
'Base (No_Index
) then
2710 raise Constraint_Error
with "Length is out of range";
2713 -- We have determined that the value of Length would not create a
2714 -- Last index value outside of the range of Index_Type, so we can now
2715 -- safely compute its value.
2717 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
2720 return V
: Vector
(Capacity
=> Length
) do
2721 V
.Elements
:= (others => New_Item
);
2726 --------------------
2727 -- Update_Element --
2728 --------------------
2730 procedure Update_Element
2731 (Container
: in out Vector
;
2733 Process
: not null access procedure (Element
: in out Element_Type
))
2735 Lock
: With_Lock
(Container
.TC
'Unchecked_Access);
2737 if Checks
and then Index
> Container
.Last
then
2738 raise Constraint_Error
with "Index is out of range";
2741 Process
(Container
.Elements
(To_Array_Index
(Index
)));
2744 procedure Update_Element
2745 (Container
: in out Vector
;
2747 Process
: not null access procedure (Element
: in out Element_Type
))
2750 if Checks
and then Position
.Container
= null then
2751 raise Constraint_Error
with "Position cursor has no element";
2754 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
2756 raise Program_Error
with "Position cursor denotes wrong container";
2759 Update_Element
(Container
, Position
.Index
, Process
);
2767 (Stream
: not null access Root_Stream_Type
'Class;
2773 N
:= Container
.Length
;
2774 Count_Type
'Base'Write (Stream, N);
2776 for J in 1 .. N loop
2777 Element_Type'Write (Stream, Container.Elements (J));
2782 (Stream : not null access Root_Stream_Type'Class;
2786 raise Program_Error with "attempt to stream vector cursor";
2790 (Stream : not null access Root_Stream_Type'Class;
2791 Item : Reference_Type)
2794 raise Program_Error with "attempt to stream reference";
2798 (Stream : not null access Root_Stream_Type'Class;
2799 Item : Constant_Reference_Type)
2802 raise Program_Error with "attempt to stream reference";
2805 end Ada.Containers.Bounded_Vectors;