1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . V E C T O R S --
9 -- Copyright (C) 2004-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
.Vectors
is
38 new Ada
.Unchecked_Deallocation
(Elements_Type
, Elements_Access
);
40 type Iterator
is new Limited_Controlled
and
41 Vector_Iterator_Interfaces
.Reversible_Iterator
with
43 Container
: Vector_Access
;
44 Index
: Index_Type
'Base;
47 overriding
procedure Finalize
(Object
: in out Iterator
);
49 overriding
function First
(Object
: Iterator
) return Cursor
;
50 overriding
function Last
(Object
: Iterator
) return Cursor
;
52 overriding
function Next
54 Position
: Cursor
) return Cursor
;
56 overriding
function Previous
58 Position
: Cursor
) return Cursor
;
64 function "&" (Left
, Right
: Vector
) return Vector
is
65 LN
: constant Count_Type
:= Length
(Left
);
66 RN
: constant Count_Type
:= Length
(Right
);
67 N
: Count_Type
'Base; -- length of result
68 J
: Count_Type
'Base; -- for computing intermediate index values
69 Last
: Index_Type
'Base; -- Last index of result
72 -- We decide that the capacity of the result is the sum of the lengths
73 -- of the vector parameters. We could decide to make it larger, but we
74 -- have no basis for knowing how much larger, so we just allocate the
75 -- minimum amount of storage.
77 -- Here we handle the easy cases first, when one of the vector
78 -- parameters is empty. (We say "easy" because there's nothing to
79 -- compute, that can potentially overflow.)
87 RE
: Elements_Array
renames
88 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
89 Elements
: constant Elements_Access
:=
90 new Elements_Type
'(Right.Last, RE);
92 return (Controlled with Elements, Right.Last, 0, 0);
98 LE : Elements_Array renames
99 Left.Elements.EA (Index_Type'First .. Left.Last);
100 Elements : constant Elements_Access :=
101 new Elements_Type'(Left
.Last
, LE
);
103 return (Controlled
with Elements
, Left
.Last
, 0, 0);
108 -- Neither of the vector parameters is empty, so must compute the length
109 -- of the result vector and its last index. (This is the harder case,
110 -- because our computations must avoid overflow.)
112 -- There are two constraints we need to satisfy. The first constraint is
113 -- that a container cannot have more than Count_Type'Last elements, so
114 -- we must check the sum of the combined lengths. Note that we cannot
115 -- simply add the lengths, because of the possibility of overflow.
117 if LN
> Count_Type
'Last - RN
then
118 raise Constraint_Error
with "new length is out of range";
121 -- It is now safe compute the length of the new vector, without fear of
126 -- The second constraint is that the new Last index value cannot
127 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
128 -- Count_Type'Base as the type for intermediate values.
130 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
132 -- We perform a two-part test. First we determine whether the
133 -- computed Last value lies in the base range of the type, and then
134 -- determine whether it lies in the range of the index (sub)type.
136 -- Last must satisfy this relation:
137 -- First + Length - 1 <= Last
139 -- First - 1 <= Last - Length
140 -- Which can rewrite as:
141 -- No_Index <= Last - Length
143 if Index_Type'Base'Last
- Index_Type
'Base (N
) < No_Index
then
144 raise Constraint_Error
with "new length is out of range";
147 -- We now know that the computed value of Last is within the base
148 -- range of the type, so it is safe to compute its value:
150 Last
:= No_Index
+ Index_Type
'Base (N
);
152 -- Finally we test whether the value is within the range of the
153 -- generic actual index subtype:
155 if Last
> Index_Type
'Last then
156 raise Constraint_Error
with "new length is out of range";
159 elsif Index_Type
'First <= 0 then
161 -- Here we can compute Last directly, in the normal way. We know that
162 -- No_Index is less than 0, so there is no danger of overflow when
163 -- adding the (positive) value of length.
165 J
:= Count_Type
'Base (No_Index
) + N
; -- Last
167 if J
> Count_Type
'Base (Index_Type
'Last) then
168 raise Constraint_Error
with "new length is out of range";
171 -- We know that the computed value (having type Count_Type) of Last
172 -- is within the range of the generic actual index subtype, so it is
173 -- safe to convert to Index_Type:
175 Last
:= Index_Type
'Base (J
);
178 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
179 -- must test the length indirectly (by working backwards from the
180 -- largest possible value of Last), in order to prevent overflow.
182 J
:= Count_Type
'Base (Index_Type
'Last) - N
; -- No_Index
184 if J
< Count_Type
'Base (No_Index
) then
185 raise Constraint_Error
with "new length is out of range";
188 -- We have determined that the result length would not create a Last
189 -- index value outside of the range of Index_Type, so we can now
190 -- safely compute its value.
192 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + N
);
196 LE
: Elements_Array
renames
197 Left
.Elements
.EA
(Index_Type
'First .. Left
.Last
);
198 RE
: Elements_Array
renames
199 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
200 Elements
: constant Elements_Access
:=
201 new Elements_Type
'(Last, LE & RE);
203 return (Controlled with Elements, Last, 0, 0);
207 function "&" (Left : Vector; Right : Element_Type) return Vector is
209 -- We decide that the capacity of the result is the sum of the lengths
210 -- of the parameters. We could decide to make it larger, but we have no
211 -- basis for knowing how much larger, so we just allocate the minimum
212 -- amount of storage.
214 -- Handle easy case first, when the vector parameter (Left) is empty
216 if Left.Is_Empty then
218 Elements : constant Elements_Access :=
220 (Last
=> Index_Type
'First,
221 EA
=> (others => Right
));
224 return (Controlled
with Elements
, Index_Type
'First, 0, 0);
228 -- The vector parameter is not empty, so we must compute the length of
229 -- the result vector and its last index, but in such a way that overflow
230 -- is avoided. We must satisfy two constraints: the new length cannot
231 -- exceed Count_Type'Last, and the new Last index cannot exceed
234 if Left
.Length
= Count_Type
'Last then
235 raise Constraint_Error
with "new length is out of range";
238 if Left
.Last
>= Index_Type
'Last then
239 raise Constraint_Error
with "new length is out of range";
243 Last
: constant Index_Type
:= Left
.Last
+ 1;
244 LE
: Elements_Array
renames
245 Left
.Elements
.EA
(Index_Type
'First .. Left
.Last
);
246 Elements
: constant Elements_Access
:=
247 new Elements_Type
'(Last => Last, EA => LE & Right);
249 return (Controlled with Elements, Last, 0, 0);
253 function "&" (Left : Element_Type; Right : Vector) return Vector is
255 -- We decide that the capacity of the result is the sum of the lengths
256 -- of the parameters. We could decide to make it larger, but we have no
257 -- basis for knowing how much larger, so we just allocate the minimum
258 -- amount of storage.
260 -- Handle easy case first, when the vector parameter (Right) is empty
262 if Right.Is_Empty then
264 Elements : constant Elements_Access :=
266 (Last
=> Index_Type
'First,
267 EA
=> (others => Left
));
269 return (Controlled
with Elements
, Index_Type
'First, 0, 0);
273 -- The vector parameter is not empty, so we must compute the length of
274 -- the result vector and its last index, but in such a way that overflow
275 -- is avoided. We must satisfy two constraints: the new length cannot
276 -- exceed Count_Type'Last, and the new Last index cannot exceed
279 if Right
.Length
= Count_Type
'Last then
280 raise Constraint_Error
with "new length is out of range";
283 if Right
.Last
>= Index_Type
'Last then
284 raise Constraint_Error
with "new length is out of range";
288 Last
: constant Index_Type
:= Right
.Last
+ 1;
290 RE
: Elements_Array
renames
291 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
293 Elements
: constant Elements_Access
:=
299 return (Controlled with Elements, Last, 0, 0);
303 function "&" (Left, Right : Element_Type) return Vector is
305 -- We decide that the capacity of the result is the sum of the lengths
306 -- of the parameters. We could decide to make it larger, but we have no
307 -- basis for knowing how much larger, so we just allocate the minimum
308 -- amount of storage.
310 -- We must compute the length of the result vector and its last index,
311 -- but in such a way that overflow is avoided. We must satisfy two
312 -- constraints: the new length cannot exceed Count_Type'Last (here, we
313 -- know that that condition is satisfied), and the new Last index cannot
314 -- exceed Index_Type'Last.
316 if Index_Type'First >= Index_Type'Last then
317 raise Constraint_Error with "new length is out of range";
321 Last : constant Index_Type := Index_Type'First + 1;
323 Elements : constant Elements_Access :=
326 EA
=> (Left
, Right
));
329 return (Controlled
with Elements
, Last
, 0, 0);
337 overriding
function "=" (Left
, Right
: Vector
) return Boolean is
338 BL
: Natural renames Left
'Unrestricted_Access.Busy
;
339 LL
: Natural renames Left
'Unrestricted_Access.Lock
;
341 BR
: Natural renames Right
'Unrestricted_Access.Busy
;
342 LR
: Natural renames Right
'Unrestricted_Access.Lock
;
347 if Left
'Address = Right
'Address then
351 if Left
.Last
/= Right
.Last
then
355 -- Per AI05-0022, the container implementation is required to detect
356 -- element tampering by a generic actual subprogram.
365 for J
in Index_Type
range Index_Type
'First .. Left
.Last
loop
366 if Left
.Elements
.EA
(J
) /= Right
.Elements
.EA
(J
) then
395 procedure Adjust
(Container
: in out Vector
) is
397 if Container
.Last
= No_Index
then
398 Container
.Elements
:= null;
403 L
: constant Index_Type
:= Container
.Last
;
404 EA
: Elements_Array
renames
405 Container
.Elements
.EA
(Index_Type
'First .. L
);
408 Container
.Elements
:= null;
412 -- Note: it may seem that the following assignment to Container.Last
413 -- is useless, since we assign it to L below. However this code is
414 -- used in case 'new Elements_Type' below raises an exception, to
415 -- keep Container in a consistent state.
417 Container
.Last
:= No_Index
;
418 Container
.Elements
:= new Elements_Type
'(L, EA);
423 procedure Adjust (Control : in out Reference_Control_Type) is
425 if Control.Container /= null then
427 C : Vector renames Control.Container.all;
428 B : Natural renames C.Busy;
429 L : Natural renames C.Lock;
441 procedure Append (Container : in out Vector; New_Item : Vector) is
443 if Is_Empty (New_Item) then
445 elsif Container.Last = Index_Type'Last then
446 raise Constraint_Error with "vector is already at its maximum length";
448 Insert (Container, Container.Last + 1, New_Item);
453 (Container : in out Vector;
454 New_Item : Element_Type;
455 Count : Count_Type := 1)
460 elsif Container.Last = Index_Type'Last then
461 raise Constraint_Error with "vector is already at its maximum length";
463 Insert (Container, Container.Last + 1, New_Item, Count);
471 procedure Assign (Target : in out Vector; Source : Vector) is
473 if Target'Address = Source'Address then
477 Target.Append (Source);
485 function Capacity (Container : Vector) return Count_Type is
487 if Container.Elements = null then
490 return Container.Elements.EA'Length;
498 procedure Clear (Container : in out Vector) is
500 if Container.Busy > 0 then
501 raise Program_Error with
502 "attempt to tamper with cursors (vector is busy)";
504 Container.Last := No_Index;
508 ------------------------
509 -- Constant_Reference --
510 ------------------------
512 function Constant_Reference
513 (Container : aliased Vector;
514 Position : Cursor) return Constant_Reference_Type
517 if Position.Container = null then
518 raise Constraint_Error with "Position cursor has no element";
521 if Position.Container /= Container'Unrestricted_Access then
522 raise Program_Error with "Position cursor denotes wrong container";
525 if Position.Index > Position.Container.Last then
526 raise Constraint_Error with "Position cursor is out of range";
530 C : Vector renames Position.Container.all;
531 B : Natural renames C.Busy;
532 L : Natural renames C.Lock;
534 return R : constant Constant_Reference_Type :=
535 (Element => Container.Elements.EA (Position.Index)'Access,
536 Control => (Controlled with Container'Unrestricted_Access))
542 end Constant_Reference;
544 function Constant_Reference
545 (Container : aliased Vector;
546 Index : Index_Type) return Constant_Reference_Type
549 if Index > Container.Last then
550 raise Constraint_Error with "Index is out of range";
553 C : Vector renames Container'Unrestricted_Access.all;
554 B : Natural renames C.Busy;
555 L : Natural renames C.Lock;
557 return R : constant Constant_Reference_Type :=
558 (Element => Container.Elements.EA (Index)'Access,
559 Control => (Controlled with Container'Unrestricted_Access))
566 end Constant_Reference;
574 Item : Element_Type) return Boolean
577 return Find_Index (Container, Item) /= No_Index;
586 Capacity : Count_Type := 0) return Vector
594 elsif Capacity >= Source.Length then
598 raise Capacity_Error with
599 "Requested capacity is less than Source length";
602 return Target : Vector do
603 Target.Reserve_Capacity (C);
604 Target.Assign (Source);
613 (Container : in out Vector;
614 Index : Extended_Index;
615 Count : Count_Type := 1)
617 Old_Last : constant Index_Type'Base := Container.Last;
618 New_Last : Index_Type'Base;
619 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
620 J : Index_Type'Base; -- first index of items that slide down
623 -- Delete removes items from the vector, the number of which is the
624 -- minimum of the specified Count and the items (if any) that exist from
625 -- Index to Container.Last. There are no constraints on the specified
626 -- value of Count (it can be larger than what's available at this
627 -- position in the vector, for example), but there are constraints on
628 -- the allowed values of the Index.
630 -- As a precondition on the generic actual Index_Type, the base type
631 -- must include Index_Type'Pred (Index_Type'First); this is the value
632 -- that Container.Last assumes when the vector is empty. However, we do
633 -- not allow that as the value for Index when specifying which items
634 -- should be deleted, so we must manually check. (That the user is
635 -- allowed to specify the value at all here is a consequence of the
636 -- declaration of the Extended_Index subtype, which includes the values
637 -- in the base range that immediately precede and immediately follow the
638 -- values in the Index_Type.)
640 if Index < Index_Type'First then
641 raise Constraint_Error with "Index is out of range (too small)";
644 -- We do allow a value greater than Container.Last to be specified as
645 -- the Index, but only if it's immediately greater. This allows the
646 -- corner case of deleting no items from the back end of the vector to
647 -- be treated as a no-op. (It is assumed that specifying an index value
648 -- greater than Last + 1 indicates some deeper flaw in the caller's
649 -- algorithm, so that case is treated as a proper error.)
651 if Index > Old_Last then
652 if Index > Old_Last + 1 then
653 raise Constraint_Error with "Index is out of range (too large)";
659 -- Here and elsewhere we treat deleting 0 items from the container as a
660 -- no-op, even when the container is busy, so we simply return.
666 -- The tampering bits exist to prevent an item from being deleted (or
667 -- otherwise harmfully manipulated) while it is being visited. Query,
668 -- Update, and Iterate increment the busy count on entry, and decrement
669 -- the count on exit. Delete checks the count to determine whether it is
670 -- being called while the associated callback procedure is executing.
672 if Container.Busy > 0 then
673 raise Program_Error with
674 "attempt to tamper with cursors (vector is busy)";
677 -- We first calculate what's available for deletion starting at
678 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
679 -- Count_Type'Base as the type for intermediate values. (See function
680 -- Length for more information.)
682 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
683 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
685 Count2 := Count_Type'Base (Old_Last - Index + 1);
688 -- If more elements are requested (Count) for deletion than are
689 -- available (Count2) for deletion beginning at Index, then everything
690 -- from Index is deleted. There are no elements to slide down, and so
691 -- all we need to do is set the value of Container.Last.
693 if Count >= Count2 then
694 Container.Last := Index - 1;
698 -- There are some elements aren't being deleted (the requested count was
699 -- less than the available count), so we must slide them down to
700 -- Index. We first calculate the index values of the respective array
701 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
702 -- type for intermediate calculations. For the elements that slide down,
703 -- index value New_Last is the last index value of their new home, and
704 -- index value J is the first index of their old home.
706 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
707 New_Last
:= Old_Last
- Index_Type
'Base (Count
);
708 J
:= Index
+ Index_Type
'Base (Count
);
710 New_Last
:= Index_Type
'Base (Count_Type
'Base (Old_Last
) - Count
);
711 J
:= Index_Type
'Base (Count_Type
'Base (Index
) + Count
);
714 -- The internal elements array isn't guaranteed to exist unless we have
715 -- elements, but we have that guarantee here because we know we have
716 -- elements to slide. The array index values for each slice have
717 -- already been determined, so we just slide down to Index the elements
718 -- that weren't deleted.
721 EA
: Elements_Array
renames Container
.Elements
.EA
;
723 EA
(Index
.. New_Last
) := EA
(J
.. Old_Last
);
724 Container
.Last
:= New_Last
;
729 (Container
: in out Vector
;
730 Position
: in out Cursor
;
731 Count
: Count_Type
:= 1)
733 pragma Warnings
(Off
, Position
);
736 if Position
.Container
= null then
737 raise Constraint_Error
with "Position cursor has no element";
739 elsif Position
.Container
/= Container
'Unrestricted_Access then
740 raise Program_Error
with "Position cursor denotes wrong container";
742 elsif Position
.Index
> Container
.Last
then
743 raise Program_Error
with "Position index is out of range";
746 Delete
(Container
, Position
.Index
, Count
);
747 Position
:= No_Element
;
755 procedure Delete_First
756 (Container
: in out Vector
;
757 Count
: Count_Type
:= 1)
763 elsif Count
>= Length
(Container
) then
768 Delete
(Container
, Index_Type
'First, Count
);
776 procedure Delete_Last
777 (Container
: in out Vector
;
778 Count
: Count_Type
:= 1)
781 -- It is not permitted to delete items while the container is busy (for
782 -- example, we're in the middle of a passive iteration). However, we
783 -- always treat deleting 0 items as a no-op, even when we're busy, so we
784 -- simply return without checking.
790 -- The tampering bits exist to prevent an item from being deleted (or
791 -- otherwise harmfully manipulated) while it is being visited. Query,
792 -- Update, and Iterate increment the busy count on entry, and decrement
793 -- the count on exit. Delete_Last checks the count to determine whether
794 -- it is being called while the associated callback procedure is
797 if Container
.Busy
> 0 then
798 raise Program_Error
with
799 "attempt to tamper with cursors (vector is busy)";
802 -- There is no restriction on how large Count can be when deleting
803 -- items. If it is equal or greater than the current length, then this
804 -- is equivalent to clearing the vector. (In particular, there's no need
805 -- for us to actually calculate the new value for Last.)
807 -- If the requested count is less than the current length, then we must
808 -- calculate the new value for Last. For the type we use the widest of
809 -- Index_Type'Base and Count_Type'Base for the intermediate values of
810 -- our calculation. (See the comments in Length for more information.)
812 if Count
>= Container
.Length
then
813 Container
.Last
:= No_Index
;
815 elsif Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
816 Container.Last := Container.Last - Index_Type'Base (Count);
820 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
830 Index : Index_Type) return Element_Type
833 if Index > Container.Last then
834 raise Constraint_Error with "Index is out of range";
836 return Container.Elements.EA (Index);
840 function Element (Position : Cursor) return Element_Type is
842 if Position.Container = null then
843 raise Constraint_Error with "Position cursor has no element";
844 elsif Position.Index > Position.Container.Last then
845 raise Constraint_Error with "Position cursor is out of range";
847 return Position.Container.Elements.EA (Position.Index);
855 procedure Finalize (Container : in out Vector) is
856 X : Elements_Access := Container.Elements;
859 if Container.Busy > 0 then
860 raise Program_Error with
861 "attempt to tamper with cursors (vector is busy)";
864 Container.Elements := null;
865 Container.Last := No_Index;
870 procedure Finalize (Object : in out Iterator) is
871 B : Natural renames Object.Container.Busy;
876 procedure Finalize (Control : in out Reference_Control_Type) is
878 if Control.Container /= null then
880 C : Vector renames Control.Container.all;
881 B : Natural renames C.Busy;
882 L : Natural renames C.Lock;
888 Control.Container := null;
899 Position : Cursor := No_Element) return Cursor
902 if Position.Container /= null then
903 if Position.Container /= Container'Unrestricted_Access then
904 raise Program_Error with "Position cursor denotes wrong container";
907 if Position.Index > Container.Last then
908 raise Program_Error with "Position index is out of range";
912 -- Per AI05-0022, the container implementation is required to detect
913 -- element tampering by a generic actual subprogram.
916 B : Natural renames Container'Unrestricted_Access.Busy;
917 L : Natural renames Container'Unrestricted_Access.Lock;
919 Result : Index_Type'Base;
926 for J in Position.Index .. Container.Last loop
927 if Container.Elements.EA (J) = Item then
936 if Result = No_Index then
939 return Cursor'(Container
'Unrestricted_Access, Result
);
958 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
960 B
: Natural renames Container
'Unrestricted_Access.Busy
;
961 L
: Natural renames Container
'Unrestricted_Access.Lock
;
963 Result
: Index_Type
'Base;
966 -- Per AI05-0022, the container implementation is required to detect
967 -- element tampering by a generic actual subprogram.
973 for Indx
in Index
.. Container
.Last
loop
974 if Container
.Elements
.EA
(Indx
) = Item
then
997 function First
(Container
: Vector
) return Cursor
is
999 if Is_Empty
(Container
) then
1002 return (Container
'Unrestricted_Access, Index_Type
'First);
1006 function First
(Object
: Iterator
) return Cursor
is
1008 -- The value of the iterator object's Index component influences the
1009 -- behavior of the First (and Last) selector function.
1011 -- When the Index component is No_Index, this means the iterator
1012 -- object was constructed without a start expression, in which case the
1013 -- (forward) iteration starts from the (logical) beginning of the entire
1014 -- sequence of items (corresponding to Container.First, for a forward
1017 -- Otherwise, this is iteration over a partial sequence of items.
1018 -- When the Index component isn't No_Index, the iterator object was
1019 -- constructed with a start expression, that specifies the position
1020 -- from which the (forward) partial iteration begins.
1022 if Object
.Index
= No_Index
then
1023 return First
(Object
.Container
.all);
1025 return Cursor
'(Object.Container, Object.Index);
1033 function First_Element (Container : Vector) return Element_Type is
1035 if Container.Last = No_Index then
1036 raise Constraint_Error with "Container is empty";
1038 return Container.Elements.EA (Index_Type'First);
1046 function First_Index (Container : Vector) return Index_Type is
1047 pragma Unreferenced (Container);
1049 return Index_Type'First;
1052 ---------------------
1053 -- Generic_Sorting --
1054 ---------------------
1056 package body Generic_Sorting is
1062 function Is_Sorted (Container : Vector) return Boolean is
1064 if Container.Last <= Index_Type'First then
1068 -- Per AI05-0022, the container implementation is required to detect
1069 -- element tampering by a generic actual subprogram.
1072 EA : Elements_Array renames Container.Elements.EA;
1074 B : Natural renames Container'Unrestricted_Access.Busy;
1075 L : Natural renames Container'Unrestricted_Access.Lock;
1084 for J in Index_Type'First .. Container.Last - 1 loop
1085 if EA (J + 1) < EA (J) then
1109 procedure Merge (Target, Source : in out Vector) is
1110 I : Index_Type'Base := Target.Last;
1111 J : Index_Type'Base;
1114 -- The semantics of Merge changed slightly per AI05-0021. It was
1115 -- originally the case that if Target and Source denoted the same
1116 -- container object, then the GNAT implementation of Merge did
1117 -- nothing. However, it was argued that RM05 did not precisely
1118 -- specify the semantics for this corner case. The decision of the
1119 -- ARG was that if Target and Source denote the same non-empty
1120 -- container object, then Program_Error is raised.
1122 if Source.Last < Index_Type'First then -- Source is empty
1126 if Target'Address = Source'Address then
1127 raise Program_Error with
1128 "Target and Source denote same non-empty container";
1131 if Target.Last < Index_Type'First then -- Target is empty
1132 Move (Target => Target, Source => Source);
1136 if Source.Busy > 0 then
1137 raise Program_Error with
1138 "attempt to tamper with cursors (vector is busy)";
1141 Target.Set_Length (Length (Target) + Length (Source));
1143 -- Per AI05-0022, the container implementation is required to detect
1144 -- element tampering by a generic actual subprogram.
1147 TA : Elements_Array renames Target.Elements.EA;
1148 SA : Elements_Array renames Source.Elements.EA;
1150 TB : Natural renames Target.Busy;
1151 TL : Natural renames Target.Lock;
1153 SB : Natural renames Source.Busy;
1154 SL : Natural renames Source.Lock;
1164 while Source.Last >= Index_Type'First loop
1165 pragma Assert (Source.Last <= Index_Type'First
1166 or else not (SA (Source.Last) <
1167 SA (Source.Last - 1)));
1169 if I < Index_Type'First then
1170 TA (Index_Type'First .. J) :=
1171 SA (Index_Type'First .. Source.Last);
1173 Source.Last := No_Index;
1177 pragma Assert (I <= Index_Type'First
1178 or else not (TA (I) < TA (I - 1)));
1180 if SA (Source.Last) < TA (I) then
1185 TA (J) := SA (Source.Last);
1186 Source.Last := Source.Last - 1;
1214 procedure Sort (Container : in out Vector) is
1216 new Generic_Array_Sort
1217 (Index_Type => Index_Type,
1218 Element_Type => Element_Type,
1219 Array_Type => Elements_Array,
1223 if Container.Last <= Index_Type'First then
1227 -- The exception behavior for the vector container must match that
1228 -- for the list container, so we check for cursor tampering here
1229 -- (which will catch more things) instead of for element tampering
1230 -- (which will catch fewer things). It's true that the elements of
1231 -- this vector container could be safely moved around while (say) an
1232 -- iteration is taking place (iteration only increments the busy
1233 -- counter), and so technically all we would need here is a test for
1234 -- element tampering (indicated by the lock counter), that's simply
1235 -- an artifact of our array-based implementation. Logically Sort
1236 -- requires a check for cursor tampering.
1238 if Container.Busy > 0 then
1239 raise Program_Error with
1240 "attempt to tamper with cursors (vector is busy)";
1243 -- Per AI05-0022, the container implementation is required to detect
1244 -- element tampering by a generic actual subprogram.
1247 B : Natural renames Container.Busy;
1248 L : Natural renames Container.Lock;
1254 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1268 end Generic_Sorting;
1274 function Has_Element (Position : Cursor) return Boolean is
1276 return Position /= No_Element;
1284 (Container : in out Vector;
1285 Before : Extended_Index;
1286 New_Item : Element_Type;
1287 Count : Count_Type := 1)
1289 Old_Length : constant Count_Type := Container.Length;
1291 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1292 New_Length : Count_Type'Base; -- sum of current length and Count
1293 New_Last : Index_Type'Base; -- last index of vector after insertion
1295 Index : Index_Type'Base; -- scratch for intermediate values
1296 J : Count_Type'Base; -- scratch
1298 New_Capacity : Count_Type'Base; -- length of new, expanded array
1299 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1300 Dst : Elements_Access; -- new, expanded internal array
1303 -- As a precondition on the generic actual Index_Type, the base type
1304 -- must include Index_Type'Pred (Index_Type'First); this is the value
1305 -- that Container.Last assumes when the vector is empty. However, we do
1306 -- not allow that as the value for Index when specifying where the new
1307 -- items should be inserted, so we must manually check. (That the user
1308 -- is allowed to specify the value at all here is a consequence of the
1309 -- declaration of the Extended_Index subtype, which includes the values
1310 -- in the base range that immediately precede and immediately follow the
1311 -- values in the Index_Type.)
1313 if Before < Index_Type'First then
1314 raise Constraint_Error with
1315 "Before index is out of range (too small)";
1318 -- We do allow a value greater than Container.Last to be specified as
1319 -- the Index, but only if it's immediately greater. This allows for the
1320 -- case of appending items to the back end of the vector. (It is assumed
1321 -- that specifying an index value greater than Last + 1 indicates some
1322 -- deeper flaw in the caller's algorithm, so that case is treated as a
1325 if Before > Container.Last and then Before > Container.Last + 1 then
1326 raise Constraint_Error with
1327 "Before index is out of range (too large)";
1330 -- We treat inserting 0 items into the container as a no-op, even when
1331 -- the container is busy, so we simply return.
1337 -- There are two constraints we need to satisfy. The first constraint is
1338 -- that a container cannot have more than Count_Type'Last elements, so
1339 -- we must check the sum of the current length and the insertion count.
1340 -- Note: we cannot simply add these values, because of the possibility
1343 if Old_Length > Count_Type'Last - Count then
1344 raise Constraint_Error with "Count is out of range";
1347 -- It is now safe compute the length of the new vector, without fear of
1350 New_Length := Old_Length + Count;
1352 -- The second constraint is that the new Last index value cannot exceed
1353 -- Index_Type'Last. In each branch below, we calculate the maximum
1354 -- length (computed from the range of values in Index_Type), and then
1355 -- compare the new length to the maximum length. If the new length is
1356 -- acceptable, then we compute the new last index from that.
1358 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1360 -- We have to handle the case when there might be more values in the
1361 -- range of Index_Type than in the range of Count_Type.
1363 if Index_Type
'First <= 0 then
1365 -- We know that No_Index (the same as Index_Type'First - 1) is
1366 -- less than 0, so it is safe to compute the following sum without
1367 -- fear of overflow.
1369 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1371 if Index
<= Index_Type
'Last then
1373 -- We have determined that range of Index_Type has at least as
1374 -- many values as in Count_Type, so Count_Type'Last is the
1375 -- maximum number of items that are allowed.
1377 Max_Length
:= Count_Type
'Last;
1380 -- The range of Index_Type has fewer values than in Count_Type,
1381 -- so the maximum number of items is computed from the range of
1384 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1388 -- No_Index is equal or greater than 0, so we can safely compute
1389 -- the difference without fear of overflow (which we would have to
1390 -- worry about if No_Index were less than 0, but that case is
1393 if Index_Type
'Last - No_Index
>=
1394 Count_Type
'Pos (Count_Type
'Last)
1396 -- We have determined that range of Index_Type has at least as
1397 -- many values as in Count_Type, so Count_Type'Last is the
1398 -- maximum number of items that are allowed.
1400 Max_Length
:= Count_Type
'Last;
1403 -- The range of Index_Type has fewer values than in Count_Type,
1404 -- so the maximum number of items is computed from the range of
1407 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1411 elsif Index_Type
'First <= 0 then
1413 -- We know that No_Index (the same as Index_Type'First - 1) is less
1414 -- than 0, so it is safe to compute the following sum without fear of
1417 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
1419 if J
<= Count_Type
'Base (Index_Type
'Last) then
1421 -- We have determined that range of Index_Type has at least as
1422 -- many values as in Count_Type, so Count_Type'Last is the maximum
1423 -- number of items that are allowed.
1425 Max_Length
:= Count_Type
'Last;
1428 -- The range of Index_Type has fewer values than Count_Type does,
1429 -- so the maximum number of items is computed from the range of
1433 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1437 -- No_Index is equal or greater than 0, so we can safely compute the
1438 -- difference without fear of overflow (which we would have to worry
1439 -- about if No_Index were less than 0, but that case is handled
1443 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1446 -- We have just computed the maximum length (number of items). We must
1447 -- now compare the requested length to the maximum length, as we do not
1448 -- allow a vector expand beyond the maximum (because that would create
1449 -- an internal array with a last index value greater than
1450 -- Index_Type'Last, with no way to index those elements).
1452 if New_Length
> Max_Length
then
1453 raise Constraint_Error
with "Count is out of range";
1456 -- New_Last is the last index value of the items in the container after
1457 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1458 -- compute its value from the New_Length.
1460 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1461 New_Last := No_Index + Index_Type'Base (New_Length);
1463 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1466 if Container.Elements = null then
1467 pragma Assert (Container.Last = No_Index);
1469 -- This is the simplest case, with which we must always begin: we're
1470 -- inserting items into an empty vector that hasn't allocated an
1471 -- internal array yet. Note that we don't need to check the busy bit
1472 -- here, because an empty container cannot be busy.
1474 -- In order to preserve container invariants, we allocate the new
1475 -- internal array first, before setting the Last index value, in case
1476 -- the allocation fails (which can happen either because there is no
1477 -- storage available, or because element initialization fails).
1479 Container.Elements := new Elements_Type'
1481 EA
=> (others => New_Item
));
1483 -- The allocation of the new, internal array succeeded, so it is now
1484 -- safe to update the Last index, restoring container invariants.
1486 Container
.Last
:= New_Last
;
1491 -- The tampering bits exist to prevent an item from being harmfully
1492 -- manipulated while it is being visited. Query, Update, and Iterate
1493 -- increment the busy count on entry, and decrement the count on
1494 -- exit. Insert checks the count to determine whether it is being called
1495 -- while the associated callback procedure is executing.
1497 if Container
.Busy
> 0 then
1498 raise Program_Error
with
1499 "attempt to tamper with cursors (vector is busy)";
1502 -- An internal array has already been allocated, so we must determine
1503 -- whether there is enough unused storage for the new items.
1505 if New_Length
<= Container
.Elements
.EA
'Length then
1507 -- In this case, we're inserting elements into a vector that has
1508 -- already allocated an internal array, and the existing array has
1509 -- enough unused storage for the new items.
1512 EA
: Elements_Array
renames Container
.Elements
.EA
;
1515 if Before
> Container
.Last
then
1517 -- The new items are being appended to the vector, so no
1518 -- sliding of existing elements is required.
1520 EA
(Before
.. New_Last
) := (others => New_Item
);
1523 -- The new items are being inserted before some existing
1524 -- elements, so we must slide the existing elements up to their
1525 -- new home. We use the wider of Index_Type'Base and
1526 -- Count_Type'Base as the type for intermediate index values.
1528 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1529 Index := Before + Index_Type'Base (Count);
1531 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1534 EA (Index .. New_Last) := EA (Before .. Container.Last);
1535 EA (Before .. Index - 1) := (others => New_Item);
1539 Container.Last := New_Last;
1543 -- In this case, we're inserting elements into a vector that has already
1544 -- allocated an internal array, but the existing array does not have
1545 -- enough storage, so we must allocate a new, longer array. In order to
1546 -- guarantee that the amortized insertion cost is O(1), we always
1547 -- allocate an array whose length is some power-of-two factor of the
1548 -- current array length. (The new array cannot have a length less than
1549 -- the New_Length of the container, but its last index value cannot be
1550 -- greater than Index_Type'Last.)
1552 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1553 while New_Capacity < New_Length loop
1554 if New_Capacity > Count_Type'Last / 2 then
1555 New_Capacity := Count_Type'Last;
1558 New_Capacity := 2 * New_Capacity;
1562 if New_Capacity > Max_Length then
1564 -- We have reached the limit of capacity, so no further expansion
1565 -- will occur. (This is not a problem, as there is never a need to
1566 -- have more capacity than the maximum container length.)
1568 New_Capacity := Max_Length;
1571 -- We have computed the length of the new internal array (and this is
1572 -- what "vector capacity" means), so use that to compute its last index.
1574 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1575 Dst_Last
:= No_Index
+ Index_Type
'Base (New_Capacity
);
1578 Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Capacity
);
1581 -- Now we allocate the new, longer internal array. If the allocation
1582 -- fails, we have not changed any container state, so no side-effect
1583 -- will occur as a result of propagating the exception.
1585 Dst
:= new Elements_Type
(Dst_Last
);
1587 -- We have our new internal array. All that needs to be done now is to
1588 -- copy the existing items (if any) from the old array (the "source"
1589 -- array, object SA below) to the new array (the "destination" array,
1590 -- object DA below), and then deallocate the old array.
1593 SA
: Elements_Array
renames Container
.Elements
.EA
; -- source
1594 DA
: Elements_Array
renames Dst
.EA
; -- destination
1597 DA
(Index_Type
'First .. Before
- 1) :=
1598 SA
(Index_Type
'First .. Before
- 1);
1600 if Before
> Container
.Last
then
1601 DA
(Before
.. New_Last
) := (others => New_Item
);
1604 -- The new items are being inserted before some existing elements,
1605 -- so we must slide the existing elements up to their new home.
1607 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1608 Index := Before + Index_Type'Base (Count);
1610 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1613 DA (Before .. Index - 1) := (others => New_Item);
1614 DA (Index .. New_Last) := SA (Before .. Container.Last);
1623 -- We have successfully copied the items onto the new array, so the
1624 -- final thing to do is deallocate the old array.
1627 X : Elements_Access := Container.Elements;
1630 -- We first isolate the old internal array, removing it from the
1631 -- container and replacing it with the new internal array, before we
1632 -- deallocate the old array (which can fail if finalization of
1633 -- elements propagates an exception).
1635 Container.Elements := Dst;
1636 Container.Last := New_Last;
1638 -- The container invariants have been restored, so it is now safe to
1639 -- attempt to deallocate the old array.
1646 (Container : in out Vector;
1647 Before : Extended_Index;
1650 N : constant Count_Type := Length (New_Item);
1651 J : Index_Type'Base;
1654 -- Use Insert_Space to create the "hole" (the destination slice) into
1655 -- which we copy the source items.
1657 Insert_Space (Container, Before, Count => N);
1661 -- There's nothing else to do here (vetting of parameters was
1662 -- performed already in Insert_Space), so we simply return.
1667 -- We calculate the last index value of the destination slice using the
1668 -- wider of Index_Type'Base and count_Type'Base.
1670 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1671 J
:= (Before
- 1) + Index_Type
'Base (N
);
1673 J
:= Index_Type
'Base (Count_Type
'Base (Before
- 1) + N
);
1676 if Container
'Address /= New_Item
'Address then
1678 -- This is the simple case. New_Item denotes an object different
1679 -- from Container, so there's nothing special we need to do to copy
1680 -- the source items to their destination, because all of the source
1681 -- items are contiguous.
1683 Container
.Elements
.EA
(Before
.. J
) :=
1684 New_Item
.Elements
.EA
(Index_Type
'First .. New_Item
.Last
);
1689 -- New_Item denotes the same object as Container, so an insertion has
1690 -- potentially split the source items. The destination is always the
1691 -- range [Before, J], but the source is [Index_Type'First, Before) and
1692 -- (J, Container.Last]. We perform the copy in two steps, using each of
1693 -- the two slices of the source items.
1696 L
: constant Index_Type
'Base := Before
- 1;
1698 subtype Src_Index_Subtype
is Index_Type
'Base range
1699 Index_Type
'First .. L
;
1701 Src
: Elements_Array
renames
1702 Container
.Elements
.EA
(Src_Index_Subtype
);
1704 K
: Index_Type
'Base;
1707 -- We first copy the source items that precede the space we
1708 -- inserted. Index value K is the last index of that portion
1709 -- destination that receives this slice of the source. (If Before
1710 -- equals Index_Type'First, then this first source slice will be
1711 -- empty, which is harmless.)
1713 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1714 K := L + Index_Type'Base (Src'Length);
1716 K := Index_Type'Base (Count_Type'Base (L) + Src'Length);
1719 Container.Elements.EA (Before .. K) := Src;
1721 if Src'Length = N then
1723 -- The new items were effectively appended to the container, so we
1724 -- have already copied all of the items that need to be copied.
1725 -- We return early here, even though the source slice below is
1726 -- empty (so the assignment would be harmless), because we want to
1727 -- avoid computing J + 1, which will overflow if J equals
1728 -- Index_Type'Base'Last
.
1735 -- Note that we want to avoid computing J + 1 here, in case J equals
1736 -- Index_Type'Base'Last. We prevent that by returning early above,
1737 -- immediately after copying the first slice of the source, and
1738 -- determining that this second slice of the source is empty.
1740 F
: constant Index_Type
'Base := J
+ 1;
1742 subtype Src_Index_Subtype
is Index_Type
'Base range
1743 F
.. Container
.Last
;
1745 Src
: Elements_Array
renames
1746 Container
.Elements
.EA
(Src_Index_Subtype
);
1748 K
: Index_Type
'Base;
1751 -- We next copy the source items that follow the space we inserted.
1752 -- Index value K is the first index of that portion of the
1753 -- destination that receives this slice of the source. (For the
1754 -- reasons given above, this slice is guaranteed to be non-empty.)
1756 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1757 K := F - Index_Type'Base (Src'Length);
1759 K := Index_Type'Base (Count_Type'Base (F) - Src'Length);
1762 Container.Elements.EA (K .. J) := Src;
1767 (Container : in out Vector;
1771 Index : Index_Type'Base;
1774 if Before.Container /= null
1775 and then Before.Container /= Container'Unrestricted_Access
1777 raise Program_Error with "Before cursor denotes wrong container";
1780 if Is_Empty (New_Item) then
1784 if Before.Container = null or else Before.Index > Container.Last then
1785 if Container.Last = Index_Type'Last then
1786 raise Constraint_Error with
1787 "vector is already at its maximum length";
1790 Index := Container.Last + 1;
1793 Index := Before.Index;
1796 Insert (Container, Index, New_Item);
1800 (Container : in out Vector;
1803 Position : out Cursor)
1805 Index : Index_Type'Base;
1808 if Before.Container /= null
1809 and then Before.Container /= Container'Unrestricted_Access
1811 raise Program_Error with "Before cursor denotes wrong container";
1814 if Is_Empty (New_Item) then
1815 if Before.Container = null or else Before.Index > Container.Last then
1816 Position := No_Element;
1818 Position := (Container'Unrestricted_Access, Before.Index);
1824 if Before.Container = null or else Before.Index > Container.Last then
1825 if Container.Last = Index_Type'Last then
1826 raise Constraint_Error with
1827 "vector is already at its maximum length";
1830 Index := Container.Last + 1;
1833 Index := Before.Index;
1836 Insert (Container, Index, New_Item);
1838 Position := (Container'Unrestricted_Access, Index);
1842 (Container : in out Vector;
1844 New_Item : Element_Type;
1845 Count : Count_Type := 1)
1847 Index : Index_Type'Base;
1850 if Before.Container /= null
1851 and then Before.Container /= Container'Unrestricted_Access
1853 raise Program_Error with "Before cursor denotes wrong container";
1860 if Before.Container = null or else Before.Index > Container.Last then
1861 if Container.Last = Index_Type'Last then
1862 raise Constraint_Error with
1863 "vector is already at its maximum length";
1865 Index := Container.Last + 1;
1869 Index := Before.Index;
1872 Insert (Container, Index, New_Item, Count);
1876 (Container : in out Vector;
1878 New_Item : Element_Type;
1879 Position : out Cursor;
1880 Count : Count_Type := 1)
1882 Index : Index_Type'Base;
1885 if Before.Container /= null
1886 and then Before.Container /= Container'Unrestricted_Access
1888 raise Program_Error with "Before cursor denotes wrong container";
1892 if Before.Container = null or else Before.Index > Container.Last then
1893 Position := No_Element;
1895 Position := (Container'Unrestricted_Access, Before.Index);
1901 if Before.Container = null or else Before.Index > Container.Last then
1902 if Container.Last = Index_Type'Last then
1903 raise Constraint_Error with
1904 "vector is already at its maximum length";
1907 Index := Container.Last + 1;
1910 Index := Before.Index;
1913 Insert (Container, Index, New_Item, Count);
1915 Position := (Container'Unrestricted_Access, Index);
1919 (Container : in out Vector;
1920 Before : Extended_Index;
1921 Count : Count_Type := 1)
1923 New_Item : Element_Type; -- Default-initialized value
1924 pragma Warnings (Off, New_Item);
1927 Insert (Container, Before, New_Item, Count);
1931 (Container : in out Vector;
1933 Position : out Cursor;
1934 Count : Count_Type := 1)
1936 New_Item : Element_Type; -- Default-initialized value
1937 pragma Warnings (Off, New_Item);
1939 Insert (Container, Before, New_Item, Position, Count);
1946 procedure Insert_Space
1947 (Container : in out Vector;
1948 Before : Extended_Index;
1949 Count : Count_Type := 1)
1951 Old_Length : constant Count_Type := Container.Length;
1953 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1954 New_Length : Count_Type'Base; -- sum of current length and Count
1955 New_Last : Index_Type'Base; -- last index of vector after insertion
1957 Index : Index_Type'Base; -- scratch for intermediate values
1958 J : Count_Type'Base; -- scratch
1960 New_Capacity : Count_Type'Base; -- length of new, expanded array
1961 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1962 Dst : Elements_Access; -- new, expanded internal array
1965 -- As a precondition on the generic actual Index_Type, the base type
1966 -- must include Index_Type'Pred (Index_Type'First); this is the value
1967 -- that Container.Last assumes when the vector is empty. However, we do
1968 -- not allow that as the value for Index when specifying where the new
1969 -- items should be inserted, so we must manually check. (That the user
1970 -- is allowed to specify the value at all here is a consequence of the
1971 -- declaration of the Extended_Index subtype, which includes the values
1972 -- in the base range that immediately precede and immediately follow the
1973 -- values in the Index_Type.)
1975 if Before < Index_Type'First then
1976 raise Constraint_Error with
1977 "Before index is out of range (too small)";
1980 -- We do allow a value greater than Container.Last to be specified as
1981 -- the Index, but only if it's immediately greater. This allows for the
1982 -- case of appending items to the back end of the vector. (It is assumed
1983 -- that specifying an index value greater than Last + 1 indicates some
1984 -- deeper flaw in the caller's algorithm, so that case is treated as a
1987 if Before > Container.Last and then Before > Container.Last + 1 then
1988 raise Constraint_Error with
1989 "Before index is out of range (too large)";
1992 -- We treat inserting 0 items into the container as a no-op, even when
1993 -- the container is busy, so we simply return.
1999 -- There are two constraints we need to satisfy. The first constraint is
2000 -- that a container cannot have more than Count_Type'Last elements, so
2001 -- we must check the sum of the current length and the insertion count.
2002 -- Note: we cannot simply add these values, because of the possibility
2005 if Old_Length > Count_Type'Last - Count then
2006 raise Constraint_Error with "Count is out of range";
2009 -- It is now safe compute the length of the new vector, without fear of
2012 New_Length := Old_Length + Count;
2014 -- The second constraint is that the new Last index value cannot exceed
2015 -- Index_Type'Last. In each branch below, we calculate the maximum
2016 -- length (computed from the range of values in Index_Type), and then
2017 -- compare the new length to the maximum length. If the new length is
2018 -- acceptable, then we compute the new last index from that.
2020 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2022 -- We have to handle the case when there might be more values in the
2023 -- range of Index_Type than in the range of Count_Type.
2025 if Index_Type
'First <= 0 then
2027 -- We know that No_Index (the same as Index_Type'First - 1) is
2028 -- less than 0, so it is safe to compute the following sum without
2029 -- fear of overflow.
2031 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
2033 if Index
<= Index_Type
'Last then
2035 -- We have determined that range of Index_Type has at least as
2036 -- many values as in Count_Type, so Count_Type'Last is the
2037 -- maximum number of items that are allowed.
2039 Max_Length
:= Count_Type
'Last;
2042 -- The range of Index_Type has fewer values than in Count_Type,
2043 -- so the maximum number of items is computed from the range of
2046 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2050 -- No_Index is equal or greater than 0, so we can safely compute
2051 -- the difference without fear of overflow (which we would have to
2052 -- worry about if No_Index were less than 0, but that case is
2055 if Index_Type
'Last - No_Index
>=
2056 Count_Type
'Pos (Count_Type
'Last)
2058 -- We have determined that range of Index_Type has at least as
2059 -- many values as in Count_Type, so Count_Type'Last is the
2060 -- maximum number of items that are allowed.
2062 Max_Length
:= Count_Type
'Last;
2065 -- The range of Index_Type has fewer values than in Count_Type,
2066 -- so the maximum number of items is computed from the range of
2069 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2073 elsif Index_Type
'First <= 0 then
2075 -- We know that No_Index (the same as Index_Type'First - 1) is less
2076 -- than 0, so it is safe to compute the following sum without fear of
2079 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
2081 if J
<= Count_Type
'Base (Index_Type
'Last) then
2083 -- We have determined that range of Index_Type has at least as
2084 -- many values as in Count_Type, so Count_Type'Last is the maximum
2085 -- number of items that are allowed.
2087 Max_Length
:= Count_Type
'Last;
2090 -- The range of Index_Type has fewer values than Count_Type does,
2091 -- so the maximum number of items is computed from the range of
2095 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2099 -- No_Index is equal or greater than 0, so we can safely compute the
2100 -- difference without fear of overflow (which we would have to worry
2101 -- about if No_Index were less than 0, but that case is handled
2105 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2108 -- We have just computed the maximum length (number of items). We must
2109 -- now compare the requested length to the maximum length, as we do not
2110 -- allow a vector expand beyond the maximum (because that would create
2111 -- an internal array with a last index value greater than
2112 -- Index_Type'Last, with no way to index those elements).
2114 if New_Length
> Max_Length
then
2115 raise Constraint_Error
with "Count is out of range";
2118 -- New_Last is the last index value of the items in the container after
2119 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2120 -- compute its value from the New_Length.
2122 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2123 New_Last := No_Index + Index_Type'Base (New_Length);
2125 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2128 if Container.Elements = null then
2129 pragma Assert (Container.Last = No_Index);
2131 -- This is the simplest case, with which we must always begin: we're
2132 -- inserting items into an empty vector that hasn't allocated an
2133 -- internal array yet. Note that we don't need to check the busy bit
2134 -- here, because an empty container cannot be busy.
2136 -- In order to preserve container invariants, we allocate the new
2137 -- internal array first, before setting the Last index value, in case
2138 -- the allocation fails (which can happen either because there is no
2139 -- storage available, or because default-valued element
2140 -- initialization fails).
2142 Container.Elements := new Elements_Type (New_Last);
2144 -- The allocation of the new, internal array succeeded, so it is now
2145 -- safe to update the Last index, restoring container invariants.
2147 Container.Last := New_Last;
2152 -- The tampering bits exist to prevent an item from being harmfully
2153 -- manipulated while it is being visited. Query, Update, and Iterate
2154 -- increment the busy count on entry, and decrement the count on
2155 -- exit. Insert checks the count to determine whether it is being called
2156 -- while the associated callback procedure is executing.
2158 if Container.Busy > 0 then
2159 raise Program_Error with
2160 "attempt to tamper with cursors (vector is busy)";
2163 -- An internal array has already been allocated, so we must determine
2164 -- whether there is enough unused storage for the new items.
2166 if New_Last <= Container.Elements.Last then
2168 -- In this case, we're inserting space into a vector that has already
2169 -- allocated an internal array, and the existing array has enough
2170 -- unused storage for the new items.
2173 EA : Elements_Array renames Container.Elements.EA;
2176 if Before <= Container.Last then
2178 -- The space is being inserted before some existing elements,
2179 -- so we must slide the existing elements up to their new
2180 -- home. We use the wider of Index_Type'Base and
2181 -- Count_Type'Base as the type for intermediate index values.
2183 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2184 Index
:= Before
+ Index_Type
'Base (Count
);
2187 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2190 EA
(Index
.. New_Last
) := EA
(Before
.. Container
.Last
);
2194 Container
.Last
:= New_Last
;
2198 -- In this case, we're inserting space into a vector that has already
2199 -- allocated an internal array, but the existing array does not have
2200 -- enough storage, so we must allocate a new, longer array. In order to
2201 -- guarantee that the amortized insertion cost is O(1), we always
2202 -- allocate an array whose length is some power-of-two factor of the
2203 -- current array length. (The new array cannot have a length less than
2204 -- the New_Length of the container, but its last index value cannot be
2205 -- greater than Index_Type'Last.)
2207 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
2208 while New_Capacity
< New_Length
loop
2209 if New_Capacity
> Count_Type
'Last / 2 then
2210 New_Capacity
:= Count_Type
'Last;
2214 New_Capacity
:= 2 * New_Capacity
;
2217 if New_Capacity
> Max_Length
then
2219 -- We have reached the limit of capacity, so no further expansion
2220 -- will occur. (This is not a problem, as there is never a need to
2221 -- have more capacity than the maximum container length.)
2223 New_Capacity
:= Max_Length
;
2226 -- We have computed the length of the new internal array (and this is
2227 -- what "vector capacity" means), so use that to compute its last index.
2229 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2230 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2233 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2236 -- Now we allocate the new, longer internal array. If the allocation
2237 -- fails, we have not changed any container state, so no side-effect
2238 -- will occur as a result of propagating the exception.
2240 Dst := new Elements_Type (Dst_Last);
2242 -- We have our new internal array. All that needs to be done now is to
2243 -- copy the existing items (if any) from the old array (the "source"
2244 -- array, object SA below) to the new array (the "destination" array,
2245 -- object DA below), and then deallocate the old array.
2248 SA : Elements_Array renames Container.Elements.EA; -- source
2249 DA : Elements_Array renames Dst.EA; -- destination
2252 DA (Index_Type'First .. Before - 1) :=
2253 SA (Index_Type'First .. Before - 1);
2255 if Before <= Container.Last then
2257 -- The space is being inserted before some existing elements, so
2258 -- we must slide the existing elements up to their new home.
2260 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2261 Index
:= Before
+ Index_Type
'Base (Count
);
2263 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2266 DA
(Index
.. New_Last
) := SA
(Before
.. Container
.Last
);
2275 -- We have successfully copied the items onto the new array, so the
2276 -- final thing to do is restore invariants, and deallocate the old
2280 X
: Elements_Access
:= Container
.Elements
;
2283 -- We first isolate the old internal array, removing it from the
2284 -- container and replacing it with the new internal array, before we
2285 -- deallocate the old array (which can fail if finalization of
2286 -- elements propagates an exception).
2288 Container
.Elements
:= Dst
;
2289 Container
.Last
:= New_Last
;
2291 -- The container invariants have been restored, so it is now safe to
2292 -- attempt to deallocate the old array.
2298 procedure Insert_Space
2299 (Container
: in out Vector
;
2301 Position
: out Cursor
;
2302 Count
: Count_Type
:= 1)
2304 Index
: Index_Type
'Base;
2307 if Before
.Container
/= null
2308 and then Before
.Container
/= Container
'Unrestricted_Access
2310 raise Program_Error
with "Before cursor denotes wrong container";
2314 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2315 Position
:= No_Element
;
2317 Position
:= (Container
'Unrestricted_Access, Before
.Index
);
2323 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2324 if Container
.Last
= Index_Type
'Last then
2325 raise Constraint_Error
with
2326 "vector is already at its maximum length";
2328 Index
:= Container
.Last
+ 1;
2332 Index
:= Before
.Index
;
2335 Insert_Space
(Container
, Index
, Count
=> Count
);
2337 Position
:= (Container
'Unrestricted_Access, Index
);
2344 function Is_Empty
(Container
: Vector
) return Boolean is
2346 return Container
.Last
< Index_Type
'First;
2354 (Container
: Vector
;
2355 Process
: not null access procedure (Position
: Cursor
))
2357 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
2363 for Indx
in Index_Type
'First .. Container
.Last
loop
2364 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
2376 (Container : Vector)
2377 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2379 V : constant Vector_Access := Container'Unrestricted_Access;
2380 B : Natural renames V.Busy;
2383 -- The value of its Index component influences the behavior of the First
2384 -- and Last selector functions of the iterator object. When the Index
2385 -- component is No_Index (as is the case here), this means the iterator
2386 -- object was constructed without a start expression. This is a complete
2387 -- iterator, meaning that the iteration starts from the (logical)
2388 -- beginning of the sequence of items.
2390 -- Note: For a forward iterator, Container.First is the beginning, and
2391 -- for a reverse iterator, Container.Last is the beginning.
2393 return It : constant Iterator :=
2394 (Limited_Controlled with
2403 (Container : Vector;
2405 return Vector_Iterator_Interfaces.Reversible_Iterator'class
2407 V : constant Vector_Access := Container'Unrestricted_Access;
2408 B : Natural renames V.Busy;
2411 -- It was formerly the case that when Start = No_Element, the partial
2412 -- iterator was defined to behave the same as for a complete iterator,
2413 -- and iterate over the entire sequence of items. However, those
2414 -- semantics were unintuitive and arguably error-prone (it is too easy
2415 -- to accidentally create an endless loop), and so they were changed,
2416 -- per the ARG meeting in Denver on 2011/11. However, there was no
2417 -- consensus about what positive meaning this corner case should have,
2418 -- and so it was decided to simply raise an exception. This does imply,
2419 -- however, that it is not possible to use a partial iterator to specify
2420 -- an empty sequence of items.
2422 if Start.Container = null then
2423 raise Constraint_Error with
2424 "Start position for iterator equals No_Element";
2427 if Start.Container /= V then
2428 raise Program_Error with
2429 "Start cursor of Iterate designates wrong vector";
2432 if Start.Index > V.Last then
2433 raise Constraint_Error with
2434 "Start position for iterator equals No_Element";
2437 -- The value of its Index component influences the behavior of the First
2438 -- and Last selector functions of the iterator object. When the Index
2439 -- component is not No_Index (as is the case here), it means that this
2440 -- is a partial iteration, over a subset of the complete sequence of
2441 -- items. The iterator object was constructed with a start expression,
2442 -- indicating the position from which the iteration begins. Note that
2443 -- the start position has the same value irrespective of whether this
2444 -- is a forward or reverse iteration.
2446 return It : constant Iterator :=
2447 (Limited_Controlled with
2449 Index => Start.Index)
2459 function Last (Container : Vector) return Cursor is
2461 if Is_Empty (Container) then
2464 return (Container'Unrestricted_Access, Container.Last);
2468 function Last (Object : Iterator) return Cursor is
2470 -- The value of the iterator object's Index component influences the
2471 -- behavior of the Last (and First) selector function.
2473 -- When the Index component is No_Index, this means the iterator
2474 -- object was constructed without a start expression, in which case the
2475 -- (reverse) iteration starts from the (logical) beginning of the entire
2476 -- sequence (corresponding to Container.Last, for a reverse iterator).
2478 -- Otherwise, this is iteration over a partial sequence of items.
2479 -- When the Index component is not No_Index, the iterator object was
2480 -- constructed with a start expression, that specifies the position
2481 -- from which the (reverse) partial iteration begins.
2483 if Object.Index = No_Index then
2484 return Last (Object.Container.all);
2486 return Cursor'(Object
.Container
, Object
.Index
);
2494 function Last_Element
(Container
: Vector
) return Element_Type
is
2496 if Container
.Last
= No_Index
then
2497 raise Constraint_Error
with "Container is empty";
2499 return Container
.Elements
.EA
(Container
.Last
);
2507 function Last_Index
(Container
: Vector
) return Extended_Index
is
2509 return Container
.Last
;
2516 function Length
(Container
: Vector
) return Count_Type
is
2517 L
: constant Index_Type
'Base := Container
.Last
;
2518 F
: constant Index_Type
:= Index_Type
'First;
2521 -- The base range of the index type (Index_Type'Base) might not include
2522 -- all values for length (Count_Type). Contrariwise, the index type
2523 -- might include values outside the range of length. Hence we use
2524 -- whatever type is wider for intermediate values when calculating
2525 -- length. Note that no matter what the index type is, the maximum
2526 -- length to which a vector is allowed to grow is always the minimum
2527 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2529 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2530 -- to have a base range of -128 .. 127, but the corresponding vector
2531 -- would have lengths in the range 0 .. 255. In this case we would need
2532 -- to use Count_Type'Base for intermediate values.
2534 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2535 -- vector would have a maximum length of 10, but the index values lie
2536 -- outside the range of Count_Type (which is only 32 bits). In this
2537 -- case we would need to use Index_Type'Base for intermediate values.
2539 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
2540 return Count_Type
'Base (L
) - Count_Type
'Base (F
) + 1;
2542 return Count_Type
(L
- F
+ 1);
2551 (Target
: in out Vector
;
2552 Source
: in out Vector
)
2555 if Target
'Address = Source
'Address then
2559 if Target
.Busy
> 0 then
2560 raise Program_Error
with
2561 "attempt to tamper with cursors (Target is busy)";
2564 if Source
.Busy
> 0 then
2565 raise Program_Error
with
2566 "attempt to tamper with cursors (Source is busy)";
2570 Target_Elements
: constant Elements_Access
:= Target
.Elements
;
2572 Target
.Elements
:= Source
.Elements
;
2573 Source
.Elements
:= Target_Elements
;
2576 Target
.Last
:= Source
.Last
;
2577 Source
.Last
:= No_Index
;
2584 function Next
(Position
: Cursor
) return Cursor
is
2586 if Position
.Container
= null then
2588 elsif Position
.Index
< Position
.Container
.Last
then
2589 return (Position
.Container
, Position
.Index
+ 1);
2595 function Next
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
2597 if Position
.Container
= null then
2599 elsif Position
.Container
/= Object
.Container
then
2600 raise Program_Error
with
2601 "Position cursor of Next designates wrong vector";
2603 return Next
(Position
);
2607 procedure Next
(Position
: in out Cursor
) is
2609 if Position
.Container
= null then
2611 elsif Position
.Index
< Position
.Container
.Last
then
2612 Position
.Index
:= Position
.Index
+ 1;
2614 Position
:= No_Element
;
2622 procedure Prepend
(Container
: in out Vector
; New_Item
: Vector
) is
2624 Insert
(Container
, Index_Type
'First, New_Item
);
2628 (Container
: in out Vector
;
2629 New_Item
: Element_Type
;
2630 Count
: Count_Type
:= 1)
2633 Insert
(Container
, Index_Type
'First, New_Item
, Count
);
2640 function Previous
(Position
: Cursor
) return Cursor
is
2642 if Position
.Container
= null then
2644 elsif Position
.Index
> Index_Type
'First then
2645 return (Position
.Container
, Position
.Index
- 1);
2651 function Previous
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
2653 if Position
.Container
= null then
2655 elsif Position
.Container
/= Object
.Container
then
2656 raise Program_Error
with
2657 "Position cursor of Previous designates wrong vector";
2659 return Previous
(Position
);
2663 procedure Previous
(Position
: in out Cursor
) is
2665 if Position
.Container
= null then
2667 elsif Position
.Index
> Index_Type
'First then
2668 Position
.Index
:= Position
.Index
- 1;
2670 Position
:= No_Element
;
2678 procedure Query_Element
2679 (Container
: Vector
;
2681 Process
: not null access procedure (Element
: Element_Type
))
2683 V
: Vector
renames Container
'Unrestricted_Access.all;
2684 B
: Natural renames V
.Busy
;
2685 L
: Natural renames V
.Lock
;
2688 if Index
> Container
.Last
then
2689 raise Constraint_Error
with "Index is out of range";
2696 Process
(V
.Elements
.EA
(Index
));
2708 procedure Query_Element
2710 Process
: not null access procedure (Element
: Element_Type
))
2713 if Position
.Container
= null then
2714 raise Constraint_Error
with "Position cursor has no element";
2716 Query_Element
(Position
.Container
.all, Position
.Index
, Process
);
2725 (Stream
: not null access Root_Stream_Type
'Class;
2726 Container
: out Vector
)
2728 Length
: Count_Type
'Base;
2729 Last
: Index_Type
'Base := No_Index
;
2734 Count_Type
'Base'Read (Stream, Length);
2736 if Length > Capacity (Container) then
2737 Reserve_Capacity (Container, Capacity => Length);
2740 for J in Count_Type range 1 .. Length loop
2742 Element_Type'Read (Stream, Container.Elements.EA (Last));
2743 Container.Last := Last;
2748 (Stream : not null access Root_Stream_Type'Class;
2749 Position : out Cursor)
2752 raise Program_Error with "attempt to stream vector cursor";
2756 (Stream : not null access Root_Stream_Type'Class;
2757 Item : out Reference_Type)
2760 raise Program_Error with "attempt to stream reference";
2764 (Stream : not null access Root_Stream_Type'Class;
2765 Item : out Constant_Reference_Type)
2768 raise Program_Error with "attempt to stream reference";
2776 (Container : aliased in out Vector;
2777 Position : Cursor) return Reference_Type
2780 if Position.Container = null then
2781 raise Constraint_Error with "Position cursor has no element";
2784 if Position.Container /= Container'Unrestricted_Access then
2785 raise Program_Error with "Position cursor denotes wrong container";
2788 if Position.Index > Position.Container.Last then
2789 raise Constraint_Error with "Position cursor is out of range";
2793 C : Vector renames Position.Container.all;
2794 B : Natural renames C.Busy;
2795 L : Natural renames C.Lock;
2797 return R : constant Reference_Type :=
2798 (Element => Container.Elements.EA (Position.Index)'Access,
2799 Control => (Controlled with Position.Container))
2808 (Container : aliased in out Vector;
2809 Index : Index_Type) return Reference_Type
2812 if Index > Container.Last then
2813 raise Constraint_Error with "Index is out of range";
2817 C : Vector renames Container'Unrestricted_Access.all;
2818 B : Natural renames C.Busy;
2819 L : Natural renames C.Lock;
2821 return R : constant Reference_Type :=
2822 (Element => Container.Elements.EA (Index)'Access,
2823 Control => (Controlled with Container'Unrestricted_Access))
2832 ---------------------
2833 -- Replace_Element --
2834 ---------------------
2836 procedure Replace_Element
2837 (Container : in out Vector;
2839 New_Item : Element_Type)
2842 if Index > Container.Last then
2843 raise Constraint_Error with "Index is out of range";
2844 elsif Container.Lock > 0 then
2845 raise Program_Error with
2846 "attempt to tamper with elements (vector is locked)";
2848 Container.Elements.EA (Index) := New_Item;
2850 end Replace_Element;
2852 procedure Replace_Element
2853 (Container : in out Vector;
2855 New_Item : Element_Type)
2858 if Position.Container = null then
2859 raise Constraint_Error with "Position cursor has no element";
2861 elsif Position.Container /= Container'Unrestricted_Access then
2862 raise Program_Error with "Position cursor denotes wrong container";
2864 elsif Position.Index > Container.Last then
2865 raise Constraint_Error with "Position cursor is out of range";
2868 if Container.Lock > 0 then
2869 raise Program_Error with
2870 "attempt to tamper with elements (vector is locked)";
2873 Container.Elements.EA (Position.Index) := New_Item;
2875 end Replace_Element;
2877 ----------------------
2878 -- Reserve_Capacity --
2879 ----------------------
2881 procedure Reserve_Capacity
2882 (Container : in out Vector;
2883 Capacity : Count_Type)
2885 N : constant Count_Type := Length (Container);
2887 Index : Count_Type'Base;
2888 Last : Index_Type'Base;
2891 -- Reserve_Capacity can be used to either expand the storage available
2892 -- for elements (this would be its typical use, in anticipation of
2893 -- future insertion), or to trim back storage. In the latter case,
2894 -- storage can only be trimmed back to the limit of the container
2895 -- length. Note that Reserve_Capacity neither deletes (active) elements
2896 -- nor inserts elements; it only affects container capacity, never
2897 -- container length.
2899 if Capacity = 0 then
2901 -- This is a request to trim back storage, to the minimum amount
2902 -- possible given the current state of the container.
2906 -- The container is empty, so in this unique case we can
2907 -- deallocate the entire internal array. Note that an empty
2908 -- container can never be busy, so there's no need to check the
2912 X : Elements_Access := Container.Elements;
2915 -- First we remove the internal array from the container, to
2916 -- handle the case when the deallocation raises an exception.
2918 Container.Elements := null;
2920 -- Container invariants have been restored, so it is now safe
2921 -- to attempt to deallocate the internal array.
2926 elsif N < Container.Elements.EA'Length then
2928 -- The container is not empty, and the current length is less than
2929 -- the current capacity, so there's storage available to trim. In
2930 -- this case, we allocate a new internal array having a length
2931 -- that exactly matches the number of items in the
2932 -- container. (Reserve_Capacity does not delete active elements,
2933 -- so this is the best we can do with respect to minimizing
2936 if Container.Busy > 0 then
2937 raise Program_Error with
2938 "attempt to tamper with cursors (vector is busy)";
2942 subtype Src_Index_Subtype is Index_Type'Base range
2943 Index_Type'First .. Container.Last;
2945 Src : Elements_Array renames
2946 Container.Elements.EA (Src_Index_Subtype);
2948 X : Elements_Access := Container.Elements;
2951 -- Although we have isolated the old internal array that we're
2952 -- going to deallocate, we don't deallocate it until we have
2953 -- successfully allocated a new one. If there is an exception
2954 -- during allocation (either because there is not enough
2955 -- storage, or because initialization of the elements fails),
2956 -- we let it propagate without causing any side-effect.
2958 Container.Elements := new Elements_Type'(Container
.Last
, Src
);
2960 -- We have successfully allocated a new internal array (with a
2961 -- smaller length than the old one, and containing a copy of
2962 -- just the active elements in the container), so it is now
2963 -- safe to attempt to deallocate the old array. The old array
2964 -- has been isolated, and container invariants have been
2965 -- restored, so if the deallocation fails (because finalization
2966 -- of the elements fails), we simply let it propagate.
2975 -- Reserve_Capacity can be used to expand the storage available for
2976 -- elements, but we do not let the capacity grow beyond the number of
2977 -- values in Index_Type'Range. (Were it otherwise, there would be no way
2978 -- to refer to the elements with an index value greater than
2979 -- Index_Type'Last, so that storage would be wasted.) Here we compute
2980 -- the Last index value of the new internal array, in a way that avoids
2981 -- any possibility of overflow.
2983 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2985 -- We perform a two-part test. First we determine whether the
2986 -- computed Last value lies in the base range of the type, and then
2987 -- determine whether it lies in the range of the index (sub)type.
2989 -- Last must satisfy this relation:
2990 -- First + Length - 1 <= Last
2991 -- We regroup terms:
2992 -- First - 1 <= Last - Length
2993 -- Which can rewrite as:
2994 -- No_Index <= Last - Length
2996 if Index_Type'Base'Last
- Index_Type
'Base (Capacity
) < No_Index
then
2997 raise Constraint_Error
with "Capacity is out of range";
3000 -- We now know that the computed value of Last is within the base
3001 -- range of the type, so it is safe to compute its value:
3003 Last
:= No_Index
+ Index_Type
'Base (Capacity
);
3005 -- Finally we test whether the value is within the range of the
3006 -- generic actual index subtype:
3008 if Last
> Index_Type
'Last then
3009 raise Constraint_Error
with "Capacity is out of range";
3012 elsif Index_Type
'First <= 0 then
3014 -- Here we can compute Last directly, in the normal way. We know that
3015 -- No_Index is less than 0, so there is no danger of overflow when
3016 -- adding the (positive) value of Capacity.
3018 Index
:= Count_Type
'Base (No_Index
) + Capacity
; -- Last
3020 if Index
> Count_Type
'Base (Index_Type
'Last) then
3021 raise Constraint_Error
with "Capacity is out of range";
3024 -- We know that the computed value (having type Count_Type) of Last
3025 -- is within the range of the generic actual index subtype, so it is
3026 -- safe to convert to Index_Type:
3028 Last
:= Index_Type
'Base (Index
);
3031 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3032 -- must test the length indirectly (by working backwards from the
3033 -- largest possible value of Last), in order to prevent overflow.
3035 Index
:= Count_Type
'Base (Index_Type
'Last) - Capacity
; -- No_Index
3037 if Index
< Count_Type
'Base (No_Index
) then
3038 raise Constraint_Error
with "Capacity is out of range";
3041 -- We have determined that the value of Capacity would not create a
3042 -- Last index value outside of the range of Index_Type, so we can now
3043 -- safely compute its value.
3045 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Capacity
);
3048 -- The requested capacity is non-zero, but we don't know yet whether
3049 -- this is a request for expansion or contraction of storage.
3051 if Container
.Elements
= null then
3053 -- The container is empty (it doesn't even have an internal array),
3054 -- so this represents a request to allocate (expand) storage having
3055 -- the given capacity.
3057 Container
.Elements
:= new Elements_Type
(Last
);
3061 if Capacity
<= N
then
3063 -- This is a request to trim back storage, but only to the limit of
3064 -- what's already in the container. (Reserve_Capacity never deletes
3065 -- active elements, it only reclaims excess storage.)
3067 if N
< Container
.Elements
.EA
'Length then
3069 -- The container is not empty (because the requested capacity is
3070 -- positive, and less than or equal to the container length), and
3071 -- the current length is less than the current capacity, so
3072 -- there's storage available to trim. In this case, we allocate a
3073 -- new internal array having a length that exactly matches the
3074 -- number of items in the container.
3076 if Container
.Busy
> 0 then
3077 raise Program_Error
with
3078 "attempt to tamper with cursors (vector is busy)";
3082 subtype Src_Index_Subtype
is Index_Type
'Base range
3083 Index_Type
'First .. Container
.Last
;
3085 Src
: Elements_Array
renames
3086 Container
.Elements
.EA
(Src_Index_Subtype
);
3088 X
: Elements_Access
:= Container
.Elements
;
3091 -- Although we have isolated the old internal array that we're
3092 -- going to deallocate, we don't deallocate it until we have
3093 -- successfully allocated a new one. If there is an exception
3094 -- during allocation (either because there is not enough
3095 -- storage, or because initialization of the elements fails),
3096 -- we let it propagate without causing any side-effect.
3098 Container
.Elements
:= new Elements_Type
'(Container.Last, Src);
3100 -- We have successfully allocated a new internal array (with a
3101 -- smaller length than the old one, and containing a copy of
3102 -- just the active elements in the container), so it is now
3103 -- safe to attempt to deallocate the old array. The old array
3104 -- has been isolated, and container invariants have been
3105 -- restored, so if the deallocation fails (because finalization
3106 -- of the elements fails), we simply let it propagate.
3115 -- The requested capacity is larger than the container length (the
3116 -- number of active elements). Whether this represents a request for
3117 -- expansion or contraction of the current capacity depends on what the
3118 -- current capacity is.
3120 if Capacity = Container.Elements.EA'Length then
3122 -- The requested capacity matches the existing capacity, so there's
3123 -- nothing to do here. We treat this case as a no-op, and simply
3124 -- return without checking the busy bit.
3129 -- There is a change in the capacity of a non-empty container, so a new
3130 -- internal array will be allocated. (The length of the new internal
3131 -- array could be less or greater than the old internal array. We know
3132 -- only that the length of the new internal array is greater than the
3133 -- number of active elements in the container.) We must check whether
3134 -- the container is busy before doing anything else.
3136 if Container.Busy > 0 then
3137 raise Program_Error with
3138 "attempt to tamper with cursors (vector is busy)";
3141 -- We now allocate a new internal array, having a length different from
3142 -- its current value.
3145 E : Elements_Access := new Elements_Type (Last);
3148 -- We have successfully allocated the new internal array. We first
3149 -- attempt to copy the existing elements from the old internal array
3150 -- ("src" elements) onto the new internal array ("tgt" elements).
3153 subtype Index_Subtype is Index_Type'Base range
3154 Index_Type'First .. Container.Last;
3156 Src : Elements_Array renames
3157 Container.Elements.EA (Index_Subtype);
3159 Tgt : Elements_Array renames E.EA (Index_Subtype);
3170 -- We have successfully copied the existing elements onto the new
3171 -- internal array, so now we can attempt to deallocate the old one.
3174 X : Elements_Access := Container.Elements;
3177 -- First we isolate the old internal array, and replace it in the
3178 -- container with the new internal array.
3180 Container.Elements := E;
3182 -- Container invariants have been restored, so it is now safe to
3183 -- attempt to deallocate the old internal array.
3188 end Reserve_Capacity;
3190 ----------------------
3191 -- Reverse_Elements --
3192 ----------------------
3194 procedure Reverse_Elements (Container : in out Vector) is
3196 if Container.Length <= 1 then
3200 -- The exception behavior for the vector container must match that for
3201 -- the list container, so we check for cursor tampering here (which will
3202 -- catch more things) instead of for element tampering (which will catch
3203 -- fewer things). It's true that the elements of this vector container
3204 -- could be safely moved around while (say) an iteration is taking place
3205 -- (iteration only increments the busy counter), and so technically
3206 -- all we would need here is a test for element tampering (indicated
3207 -- by the lock counter), that's simply an artifact of our array-based
3208 -- implementation. Logically Reverse_Elements requires a check for
3209 -- cursor tampering.
3211 if Container.Busy > 0 then
3212 raise Program_Error with
3213 "attempt to tamper with cursors (vector is busy)";
3219 E : Elements_Type renames Container.Elements.all;
3222 K := Index_Type'First;
3223 J := Container.Last;
3226 EK : constant Element_Type := E.EA (K);
3228 E.EA (K) := E.EA (J);
3236 end Reverse_Elements;
3242 function Reverse_Find
3243 (Container : Vector;
3244 Item : Element_Type;
3245 Position : Cursor := No_Element) return Cursor
3247 Last : Index_Type'Base;
3250 if Position.Container /= null
3251 and then Position.Container /= Container'Unrestricted_Access
3253 raise Program_Error with "Position cursor denotes wrong container";
3257 (if Position.Container = null or else Position.Index > Container.Last
3259 else Position.Index);
3261 -- Per AI05-0022, the container implementation is required to detect
3262 -- element tampering by a generic actual subprogram.
3265 B : Natural renames Container'Unrestricted_Access.Busy;
3266 L : Natural renames Container'Unrestricted_Access.Lock;
3268 Result : Index_Type'Base;
3275 for Indx in reverse Index_Type'First .. Last loop
3276 if Container.Elements.EA (Indx) = Item then
3285 if Result = No_Index then
3288 return Cursor'(Container
'Unrestricted_Access, Result
);
3300 ------------------------
3301 -- Reverse_Find_Index --
3302 ------------------------
3304 function Reverse_Find_Index
3305 (Container
: Vector
;
3306 Item
: Element_Type
;
3307 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
3309 B
: Natural renames Container
'Unrestricted_Access.Busy
;
3310 L
: Natural renames Container
'Unrestricted_Access.Lock
;
3312 Last
: constant Index_Type
'Base :=
3313 Index_Type
'Min (Container
.Last
, Index
);
3315 Result
: Index_Type
'Base;
3318 -- Per AI05-0022, the container implementation is required to detect
3319 -- element tampering by a generic actual subprogram.
3325 for Indx
in reverse Index_Type
'First .. Last
loop
3326 if Container
.Elements
.EA
(Indx
) = Item
then
3343 end Reverse_Find_Index
;
3345 ---------------------
3346 -- Reverse_Iterate --
3347 ---------------------
3349 procedure Reverse_Iterate
3350 (Container
: Vector
;
3351 Process
: not null access procedure (Position
: Cursor
))
3353 V
: Vector
renames Container
'Unrestricted_Access.all;
3354 B
: Natural renames V
.Busy
;
3360 for Indx
in reverse Index_Type
'First .. Container
.Last
loop
3361 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
3370 end Reverse_Iterate;
3376 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
3377 Count : constant Count_Type'Base := Container.Length - Length;
3380 -- Set_Length allows the user to set the length explicitly, instead
3381 -- of implicitly as a side-effect of deletion or insertion. If the
3382 -- requested length is less than the current length, this is equivalent
3383 -- to deleting items from the back end of the vector. If the requested
3384 -- length is greater than the current length, then this is equivalent
3385 -- to inserting "space" (nonce items) at the end.
3388 Container.Delete_Last (Count);
3390 elsif Container.Last >= Index_Type'Last then
3391 raise Constraint_Error with "vector is already at its maximum length";
3394 Container.Insert_Space (Container.Last + 1, -Count);
3402 procedure Swap (Container : in out Vector; I, J : Index_Type) is
3404 if I > Container.Last then
3405 raise Constraint_Error with "I index is out of range";
3408 if J > Container.Last then
3409 raise Constraint_Error with "J index is out of range";
3416 if Container.Lock > 0 then
3417 raise Program_Error with
3418 "attempt to tamper with elements (vector is locked)";
3422 EI_Copy : constant Element_Type := Container.Elements.EA (I);
3424 Container.Elements.EA (I) := Container.Elements.EA (J);
3425 Container.Elements.EA (J) := EI_Copy;
3429 procedure Swap (Container : in out Vector; I, J : Cursor) is
3431 if I.Container = null then
3432 raise Constraint_Error with "I cursor has no element";
3434 elsif J.Container = null then
3435 raise Constraint_Error with "J cursor has no element";
3437 elsif I.Container /= Container'Unrestricted_Access then
3438 raise Program_Error with "I cursor denotes wrong container";
3440 elsif J.Container /= Container'Unrestricted_Access then
3441 raise Program_Error with "J cursor denotes wrong container";
3444 Swap (Container, I.Index, J.Index);
3453 (Container : Vector;
3454 Index : Extended_Index) return Cursor
3457 if Index not in Index_Type'First .. Container.Last then
3460 return (Container'Unrestricted_Access, Index);
3468 function To_Index (Position : Cursor) return Extended_Index is
3470 if Position.Container = null then
3472 elsif Position.Index <= Position.Container.Last then
3473 return Position.Index;
3483 function To_Vector (Length : Count_Type) return Vector is
3484 Index : Count_Type'Base;
3485 Last : Index_Type'Base;
3486 Elements : Elements_Access;
3490 return Empty_Vector;
3493 -- We create a vector object with a capacity that matches the specified
3494 -- Length, but we do not allow the vector capacity (the length of the
3495 -- internal array) to exceed the number of values in Index_Type'Range
3496 -- (otherwise, there would be no way to refer to those components via an
3497 -- index). We must therefore check whether the specified Length would
3498 -- create a Last index value greater than Index_Type'Last.
3500 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
3502 -- We perform a two-part test. First we determine whether the
3503 -- computed Last value lies in the base range of the type, and then
3504 -- determine whether it lies in the range of the index (sub)type.
3506 -- Last must satisfy this relation:
3507 -- First + Length - 1 <= Last
3508 -- We regroup terms:
3509 -- First - 1 <= Last - Length
3510 -- Which can rewrite as:
3511 -- No_Index <= Last - Length
3513 if Index_Type
'Base'Last - Index_Type'Base (Length) < No_Index then
3514 raise Constraint_Error with "Length is out of range";
3517 -- We now know that the computed value of Last is within the base
3518 -- range of the type, so it is safe to compute its value:
3520 Last := No_Index + Index_Type'Base (Length);
3522 -- Finally we test whether the value is within the range of the
3523 -- generic actual index subtype:
3525 if Last > Index_Type'Last then
3526 raise Constraint_Error with "Length is out of range";
3529 elsif Index_Type'First <= 0 then
3531 -- Here we can compute Last directly, in the normal way. We know that
3532 -- No_Index is less than 0, so there is no danger of overflow when
3533 -- adding the (positive) value of Length.
3535 Index := Count_Type'Base (No_Index) + Length; -- Last
3537 if Index > Count_Type'Base (Index_Type'Last) then
3538 raise Constraint_Error with "Length is out of range";
3541 -- We know that the computed value (having type Count_Type) of Last
3542 -- is within the range of the generic actual index subtype, so it is
3543 -- safe to convert to Index_Type:
3545 Last := Index_Type'Base (Index);
3548 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3549 -- must test the length indirectly (by working backwards from the
3550 -- largest possible value of Last), in order to prevent overflow.
3552 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3554 if Index < Count_Type'Base (No_Index) then
3555 raise Constraint_Error with "Length is out of range";
3558 -- We have determined that the value of Length would not create a
3559 -- Last index value outside of the range of Index_Type, so we can now
3560 -- safely compute its value.
3562 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3565 Elements := new Elements_Type (Last);
3567 return Vector'(Controlled
with Elements
, Last
, 0, 0);
3571 (New_Item
: Element_Type
;
3572 Length
: Count_Type
) return Vector
3574 Index
: Count_Type
'Base;
3575 Last
: Index_Type
'Base;
3576 Elements
: Elements_Access
;
3580 return Empty_Vector
;
3583 -- We create a vector object with a capacity that matches the specified
3584 -- Length, but we do not allow the vector capacity (the length of the
3585 -- internal array) to exceed the number of values in Index_Type'Range
3586 -- (otherwise, there would be no way to refer to those components via an
3587 -- index). We must therefore check whether the specified Length would
3588 -- create a Last index value greater than Index_Type'Last.
3590 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3592 -- We perform a two-part test. First we determine whether the
3593 -- computed Last value lies in the base range of the type, and then
3594 -- determine whether it lies in the range of the index (sub)type.
3596 -- Last must satisfy this relation:
3597 -- First + Length - 1 <= Last
3598 -- We regroup terms:
3599 -- First - 1 <= Last - Length
3600 -- Which can rewrite as:
3601 -- No_Index <= Last - Length
3603 if Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
then
3604 raise Constraint_Error
with "Length is out of range";
3607 -- We now know that the computed value of Last is within the base
3608 -- range of the type, so it is safe to compute its value:
3610 Last
:= No_Index
+ Index_Type
'Base (Length
);
3612 -- Finally we test whether the value is within the range of the
3613 -- generic actual index subtype:
3615 if Last
> Index_Type
'Last then
3616 raise Constraint_Error
with "Length is out of range";
3619 elsif Index_Type
'First <= 0 then
3621 -- Here we can compute Last directly, in the normal way. We know that
3622 -- No_Index is less than 0, so there is no danger of overflow when
3623 -- adding the (positive) value of Length.
3625 Index
:= Count_Type
'Base (No_Index
) + Length
; -- same value as V.Last
3627 if Index
> Count_Type
'Base (Index_Type
'Last) then
3628 raise Constraint_Error
with "Length is out of range";
3631 -- We know that the computed value (having type Count_Type) of Last
3632 -- is within the range of the generic actual index subtype, so it is
3633 -- safe to convert to Index_Type:
3635 Last
:= Index_Type
'Base (Index
);
3638 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3639 -- must test the length indirectly (by working backwards from the
3640 -- largest possible value of Last), in order to prevent overflow.
3642 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
3644 if Index
< Count_Type
'Base (No_Index
) then
3645 raise Constraint_Error
with "Length is out of range";
3648 -- We have determined that the value of Length would not create a
3649 -- Last index value outside of the range of Index_Type, so we can now
3650 -- safely compute its value.
3652 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
3655 Elements
:= new Elements_Type
'(Last, EA => (others => New_Item));
3657 return Vector'(Controlled
with Elements
, Last
, 0, 0);
3660 --------------------
3661 -- Update_Element --
3662 --------------------
3664 procedure Update_Element
3665 (Container
: in out Vector
;
3667 Process
: not null access procedure (Element
: in out Element_Type
))
3669 B
: Natural renames Container
.Busy
;
3670 L
: Natural renames Container
.Lock
;
3673 if Index
> Container
.Last
then
3674 raise Constraint_Error
with "Index is out of range";
3681 Process
(Container
.Elements
.EA
(Index
));
3693 procedure Update_Element
3694 (Container
: in out Vector
;
3696 Process
: not null access procedure (Element
: in out Element_Type
))
3699 if Position
.Container
= null then
3700 raise Constraint_Error
with "Position cursor has no element";
3701 elsif Position
.Container
/= Container
'Unrestricted_Access then
3702 raise Program_Error
with "Position cursor denotes wrong container";
3704 Update_Element
(Container
, Position
.Index
, Process
);
3713 (Stream
: not null access Root_Stream_Type
'Class;
3717 Count_Type
'Base'Write (Stream, Length (Container));
3719 for J in Index_Type'First .. Container.Last loop
3720 Element_Type'Write (Stream, Container.Elements.EA (J));
3725 (Stream : not null access Root_Stream_Type'Class;
3729 raise Program_Error with "attempt to stream vector cursor";
3733 (Stream : not null access Root_Stream_Type'Class;
3734 Item : Reference_Type)
3737 raise Program_Error with "attempt to stream reference";
3741 (Stream : not null access Root_Stream_Type'Class;
3742 Item : Constant_Reference_Type)
3745 raise Program_Error with "attempt to stream reference";
3748 end Ada.Containers.Vectors;