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-2014, 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
37 pragma Annotate
(CodePeer
, Skip_Analysis
);
40 new Ada
.Unchecked_Deallocation
(Elements_Type
, Elements_Access
);
42 type Iterator
is new Limited_Controlled
and
43 Vector_Iterator_Interfaces
.Reversible_Iterator
with
45 Container
: Vector_Access
;
46 Index
: Index_Type
'Base;
49 overriding
procedure Finalize
(Object
: in out Iterator
);
51 overriding
function First
(Object
: Iterator
) return Cursor
;
52 overriding
function Last
(Object
: Iterator
) return Cursor
;
54 overriding
function Next
56 Position
: Cursor
) return Cursor
;
58 overriding
function Previous
60 Position
: Cursor
) return Cursor
;
66 function "&" (Left
, Right
: Vector
) return Vector
is
67 LN
: constant Count_Type
:= Length
(Left
);
68 RN
: constant Count_Type
:= Length
(Right
);
69 N
: Count_Type
'Base; -- length of result
70 J
: Count_Type
'Base; -- for computing intermediate index values
71 Last
: Index_Type
'Base; -- Last index of result
74 -- We decide that the capacity of the result is the sum of the lengths
75 -- of the vector parameters. We could decide to make it larger, but we
76 -- have no basis for knowing how much larger, so we just allocate the
77 -- minimum amount of storage.
79 -- Here we handle the easy cases first, when one of the vector
80 -- parameters is empty. (We say "easy" because there's nothing to
81 -- compute, that can potentially overflow.)
89 RE
: Elements_Array
renames
90 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
91 Elements
: constant Elements_Access
:=
92 new Elements_Type
'(Right.Last, RE);
94 return (Controlled with Elements, Right.Last, 0, 0);
100 LE : Elements_Array renames
101 Left.Elements.EA (Index_Type'First .. Left.Last);
102 Elements : constant Elements_Access :=
103 new Elements_Type'(Left
.Last
, LE
);
105 return (Controlled
with Elements
, Left
.Last
, 0, 0);
110 -- Neither of the vector parameters is empty, so must compute the length
111 -- of the result vector and its last index. (This is the harder case,
112 -- because our computations must avoid overflow.)
114 -- There are two constraints we need to satisfy. The first constraint is
115 -- that a container cannot have more than Count_Type'Last elements, so
116 -- we must check the sum of the combined lengths. Note that we cannot
117 -- simply add the lengths, because of the possibility of overflow.
119 if LN
> Count_Type
'Last - RN
then
120 raise Constraint_Error
with "new length is out of range";
123 -- It is now safe compute the length of the new vector, without fear of
128 -- The second constraint is that the new Last index value cannot
129 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
130 -- Count_Type'Base as the type for intermediate values.
132 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
134 -- We perform a two-part test. First we determine whether the
135 -- computed Last value lies in the base range of the type, and then
136 -- determine whether it lies in the range of the index (sub)type.
138 -- Last must satisfy this relation:
139 -- First + Length - 1 <= Last
141 -- First - 1 <= Last - Length
142 -- Which can rewrite as:
143 -- No_Index <= Last - Length
145 if Index_Type'Base'Last
- Index_Type
'Base (N
) < No_Index
then
146 raise Constraint_Error
with "new length is out of range";
149 -- We now know that the computed value of Last is within the base
150 -- range of the type, so it is safe to compute its value:
152 Last
:= No_Index
+ Index_Type
'Base (N
);
154 -- Finally we test whether the value is within the range of the
155 -- generic actual index subtype:
157 if Last
> Index_Type
'Last then
158 raise Constraint_Error
with "new length is out of range";
161 elsif Index_Type
'First <= 0 then
163 -- Here we can compute Last directly, in the normal way. We know that
164 -- No_Index is less than 0, so there is no danger of overflow when
165 -- adding the (positive) value of length.
167 J
:= Count_Type
'Base (No_Index
) + N
; -- Last
169 if J
> Count_Type
'Base (Index_Type
'Last) then
170 raise Constraint_Error
with "new length is out of range";
173 -- We know that the computed value (having type Count_Type) of Last
174 -- is within the range of the generic actual index subtype, so it is
175 -- safe to convert to Index_Type:
177 Last
:= Index_Type
'Base (J
);
180 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
181 -- must test the length indirectly (by working backwards from the
182 -- largest possible value of Last), in order to prevent overflow.
184 J
:= Count_Type
'Base (Index_Type
'Last) - N
; -- No_Index
186 if J
< Count_Type
'Base (No_Index
) then
187 raise Constraint_Error
with "new length is out of range";
190 -- We have determined that the result length would not create a Last
191 -- index value outside of the range of Index_Type, so we can now
192 -- safely compute its value.
194 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + N
);
198 LE
: Elements_Array
renames
199 Left
.Elements
.EA
(Index_Type
'First .. Left
.Last
);
200 RE
: Elements_Array
renames
201 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
202 Elements
: constant Elements_Access
:=
203 new Elements_Type
'(Last, LE & RE);
205 return (Controlled with Elements, Last, 0, 0);
209 function "&" (Left : Vector; Right : Element_Type) return Vector is
211 -- We decide that the capacity of the result is the sum of the lengths
212 -- of the parameters. We could decide to make it larger, but we have no
213 -- basis for knowing how much larger, so we just allocate the minimum
214 -- amount of storage.
216 -- Handle easy case first, when the vector parameter (Left) is empty
218 if Left.Is_Empty then
220 Elements : constant Elements_Access :=
222 (Last
=> Index_Type
'First,
223 EA
=> (others => Right
));
226 return (Controlled
with Elements
, Index_Type
'First, 0, 0);
230 -- The vector parameter is not empty, so we must compute the length of
231 -- the result vector and its last index, but in such a way that overflow
232 -- is avoided. We must satisfy two constraints: the new length cannot
233 -- exceed Count_Type'Last, and the new Last index cannot exceed
236 if Left
.Length
= Count_Type
'Last then
237 raise Constraint_Error
with "new length is out of range";
240 if Left
.Last
>= Index_Type
'Last then
241 raise Constraint_Error
with "new length is out of range";
245 Last
: constant Index_Type
:= Left
.Last
+ 1;
246 LE
: Elements_Array
renames
247 Left
.Elements
.EA
(Index_Type
'First .. Left
.Last
);
248 Elements
: constant Elements_Access
:=
249 new Elements_Type
'(Last => Last, EA => LE & Right);
251 return (Controlled with Elements, Last, 0, 0);
255 function "&" (Left : Element_Type; Right : Vector) return Vector is
257 -- We decide that the capacity of the result is the sum of the lengths
258 -- of the parameters. We could decide to make it larger, but we have no
259 -- basis for knowing how much larger, so we just allocate the minimum
260 -- amount of storage.
262 -- Handle easy case first, when the vector parameter (Right) is empty
264 if Right.Is_Empty then
266 Elements : constant Elements_Access :=
268 (Last
=> Index_Type
'First,
269 EA
=> (others => Left
));
271 return (Controlled
with Elements
, Index_Type
'First, 0, 0);
275 -- The vector parameter is not empty, so we must compute the length of
276 -- the result vector and its last index, but in such a way that overflow
277 -- is avoided. We must satisfy two constraints: the new length cannot
278 -- exceed Count_Type'Last, and the new Last index cannot exceed
281 if Right
.Length
= Count_Type
'Last then
282 raise Constraint_Error
with "new length is out of range";
285 if Right
.Last
>= Index_Type
'Last then
286 raise Constraint_Error
with "new length is out of range";
290 Last
: constant Index_Type
:= Right
.Last
+ 1;
292 RE
: Elements_Array
renames
293 Right
.Elements
.EA
(Index_Type
'First .. Right
.Last
);
295 Elements
: constant Elements_Access
:=
301 return (Controlled with Elements, Last, 0, 0);
305 function "&" (Left, Right : Element_Type) return Vector is
307 -- We decide that the capacity of the result is the sum of the lengths
308 -- of the parameters. We could decide to make it larger, but we have no
309 -- basis for knowing how much larger, so we just allocate the minimum
310 -- amount of storage.
312 -- We must compute the length of the result vector and its last index,
313 -- but in such a way that overflow is avoided. We must satisfy two
314 -- constraints: the new length cannot exceed Count_Type'Last (here, we
315 -- know that that condition is satisfied), and the new Last index cannot
316 -- exceed Index_Type'Last.
318 if Index_Type'First >= Index_Type'Last then
319 raise Constraint_Error with "new length is out of range";
323 Last : constant Index_Type := Index_Type'First + 1;
325 Elements : constant Elements_Access :=
328 EA
=> (Left
, Right
));
331 return (Controlled
with Elements
, Last
, 0, 0);
339 overriding
function "=" (Left
, Right
: Vector
) return Boolean is
340 BL
: Natural renames Left
'Unrestricted_Access.Busy
;
341 LL
: Natural renames Left
'Unrestricted_Access.Lock
;
343 BR
: Natural renames Right
'Unrestricted_Access.Busy
;
344 LR
: Natural renames Right
'Unrestricted_Access.Lock
;
349 if Left
'Address = Right
'Address then
353 if Left
.Last
/= Right
.Last
then
357 -- Per AI05-0022, the container implementation is required to detect
358 -- element tampering by a generic actual subprogram.
367 for J
in Index_Type
range Index_Type
'First .. Left
.Last
loop
368 if Left
.Elements
.EA
(J
) /= Right
.Elements
.EA
(J
) then
397 procedure Adjust
(Container
: in out Vector
) is
399 if Container
.Last
= No_Index
then
400 Container
.Elements
:= null;
405 L
: constant Index_Type
:= Container
.Last
;
406 EA
: Elements_Array
renames
407 Container
.Elements
.EA
(Index_Type
'First .. L
);
410 Container
.Elements
:= null;
414 -- Note: it may seem that the following assignment to Container.Last
415 -- is useless, since we assign it to L below. However this code is
416 -- used in case 'new Elements_Type' below raises an exception, to
417 -- keep Container in a consistent state.
419 Container
.Last
:= No_Index
;
420 Container
.Elements
:= new Elements_Type
'(L, EA);
425 procedure Adjust (Control : in out Reference_Control_Type) is
427 if Control.Container /= null then
429 C : Vector renames Control.Container.all;
430 B : Natural renames C.Busy;
431 L : Natural renames C.Lock;
443 procedure Append (Container : in out Vector; New_Item : Vector) is
445 if Is_Empty (New_Item) then
447 elsif Container.Last = Index_Type'Last then
448 raise Constraint_Error with "vector is already at its maximum length";
450 Insert (Container, Container.Last + 1, New_Item);
455 (Container : in out Vector;
456 New_Item : Element_Type;
457 Count : Count_Type := 1)
462 elsif Container.Last = Index_Type'Last then
463 raise Constraint_Error with "vector is already at its maximum length";
465 Insert (Container, Container.Last + 1, New_Item, Count);
473 procedure Assign (Target : in out Vector; Source : Vector) is
475 if Target'Address = Source'Address then
479 Target.Append (Source);
487 function Capacity (Container : Vector) return Count_Type is
489 if Container.Elements = null then
492 return Container.Elements.EA'Length;
500 procedure Clear (Container : in out Vector) is
502 if Container.Busy > 0 then
503 raise Program_Error with
504 "attempt to tamper with cursors (vector is busy)";
506 Container.Last := No_Index;
510 ------------------------
511 -- Constant_Reference --
512 ------------------------
514 function Constant_Reference
515 (Container : aliased Vector;
516 Position : Cursor) return Constant_Reference_Type
519 if Position.Container = null then
520 raise Constraint_Error with "Position cursor has no element";
523 if Position.Container /= Container'Unrestricted_Access then
524 raise Program_Error with "Position cursor denotes wrong container";
527 if Position.Index > Position.Container.Last then
528 raise Constraint_Error with "Position cursor is out of range";
532 C : Vector renames Position.Container.all;
533 B : Natural renames C.Busy;
534 L : Natural renames C.Lock;
536 return R : constant Constant_Reference_Type :=
537 (Element => Container.Elements.EA (Position.Index)'Access,
538 Control => (Controlled with Container'Unrestricted_Access))
544 end Constant_Reference;
546 function Constant_Reference
547 (Container : aliased Vector;
548 Index : Index_Type) return Constant_Reference_Type
551 if Index > Container.Last then
552 raise Constraint_Error with "Index is out of range";
555 C : Vector renames Container'Unrestricted_Access.all;
556 B : Natural renames C.Busy;
557 L : Natural renames C.Lock;
559 return R : constant Constant_Reference_Type :=
560 (Element => Container.Elements.EA (Index)'Access,
561 Control => (Controlled with Container'Unrestricted_Access))
568 end Constant_Reference;
576 Item : Element_Type) return Boolean
579 return Find_Index (Container, Item) /= No_Index;
588 Capacity : Count_Type := 0) return Vector
596 elsif Capacity >= Source.Length then
600 raise Capacity_Error with
601 "Requested capacity is less than Source length";
604 return Target : Vector do
605 Target.Reserve_Capacity (C);
606 Target.Assign (Source);
615 (Container : in out Vector;
616 Index : Extended_Index;
617 Count : Count_Type := 1)
619 Old_Last : constant Index_Type'Base := Container.Last;
620 New_Last : Index_Type'Base;
621 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
622 J : Index_Type'Base; -- first index of items that slide down
625 -- Delete removes items from the vector, the number of which is the
626 -- minimum of the specified Count and the items (if any) that exist from
627 -- Index to Container.Last. There are no constraints on the specified
628 -- value of Count (it can be larger than what's available at this
629 -- position in the vector, for example), but there are constraints on
630 -- the allowed values of the Index.
632 -- As a precondition on the generic actual Index_Type, the base type
633 -- must include Index_Type'Pred (Index_Type'First); this is the value
634 -- that Container.Last assumes when the vector is empty. However, we do
635 -- not allow that as the value for Index when specifying which items
636 -- should be deleted, so we must manually check. (That the user is
637 -- allowed to specify the value at all here is a consequence of the
638 -- declaration of the Extended_Index subtype, which includes the values
639 -- in the base range that immediately precede and immediately follow the
640 -- values in the Index_Type.)
642 if Index < Index_Type'First then
643 raise Constraint_Error with "Index is out of range (too small)";
646 -- We do allow a value greater than Container.Last to be specified as
647 -- the Index, but only if it's immediately greater. This allows the
648 -- corner case of deleting no items from the back end of the vector to
649 -- be treated as a no-op. (It is assumed that specifying an index value
650 -- greater than Last + 1 indicates some deeper flaw in the caller's
651 -- algorithm, so that case is treated as a proper error.)
653 if Index > Old_Last then
654 if Index > Old_Last + 1 then
655 raise Constraint_Error with "Index is out of range (too large)";
661 -- Here and elsewhere we treat deleting 0 items from the container as a
662 -- no-op, even when the container is busy, so we simply return.
668 -- The tampering bits exist to prevent an item from being deleted (or
669 -- otherwise harmfully manipulated) while it is being visited. Query,
670 -- Update, and Iterate increment the busy count on entry, and decrement
671 -- the count on exit. Delete checks the count to determine whether it is
672 -- being called while the associated callback procedure is executing.
674 if Container.Busy > 0 then
675 raise Program_Error with
676 "attempt to tamper with cursors (vector is busy)";
679 -- We first calculate what's available for deletion starting at
680 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
681 -- Count_Type'Base as the type for intermediate values. (See function
682 -- Length for more information.)
684 if Count_Type'Base'Last
>= Index_Type
'Pos (Index_Type
'Base'Last) then
685 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
687 Count2 := Count_Type'Base (Old_Last - Index + 1);
690 -- If more elements are requested (Count) for deletion than are
691 -- available (Count2) for deletion beginning at Index, then everything
692 -- from Index is deleted. There are no elements to slide down, and so
693 -- all we need to do is set the value of Container.Last.
695 if Count >= Count2 then
696 Container.Last := Index - 1;
700 -- There are some elements aren't being deleted (the requested count was
701 -- less than the available count), so we must slide them down to
702 -- Index. We first calculate the index values of the respective array
703 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
704 -- type for intermediate calculations. For the elements that slide down,
705 -- index value New_Last is the last index value of their new home, and
706 -- index value J is the first index of their old home.
708 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
709 New_Last
:= Old_Last
- Index_Type
'Base (Count
);
710 J
:= Index
+ Index_Type
'Base (Count
);
712 New_Last
:= Index_Type
'Base (Count_Type
'Base (Old_Last
) - Count
);
713 J
:= Index_Type
'Base (Count_Type
'Base (Index
) + Count
);
716 -- The internal elements array isn't guaranteed to exist unless we have
717 -- elements, but we have that guarantee here because we know we have
718 -- elements to slide. The array index values for each slice have
719 -- already been determined, so we just slide down to Index the elements
720 -- that weren't deleted.
723 EA
: Elements_Array
renames Container
.Elements
.EA
;
725 EA
(Index
.. New_Last
) := EA
(J
.. Old_Last
);
726 Container
.Last
:= New_Last
;
731 (Container
: in out Vector
;
732 Position
: in out Cursor
;
733 Count
: Count_Type
:= 1)
735 pragma Warnings
(Off
, Position
);
738 if Position
.Container
= null then
739 raise Constraint_Error
with "Position cursor has no element";
741 elsif Position
.Container
/= Container
'Unrestricted_Access then
742 raise Program_Error
with "Position cursor denotes wrong container";
744 elsif Position
.Index
> Container
.Last
then
745 raise Program_Error
with "Position index is out of range";
748 Delete
(Container
, Position
.Index
, Count
);
749 Position
:= No_Element
;
757 procedure Delete_First
758 (Container
: in out Vector
;
759 Count
: Count_Type
:= 1)
765 elsif Count
>= Length
(Container
) then
770 Delete
(Container
, Index_Type
'First, Count
);
778 procedure Delete_Last
779 (Container
: in out Vector
;
780 Count
: Count_Type
:= 1)
783 -- It is not permitted to delete items while the container is busy (for
784 -- example, we're in the middle of a passive iteration). However, we
785 -- always treat deleting 0 items as a no-op, even when we're busy, so we
786 -- simply return without checking.
792 -- The tampering bits exist to prevent an item from being deleted (or
793 -- otherwise harmfully manipulated) while it is being visited. Query,
794 -- Update, and Iterate increment the busy count on entry, and decrement
795 -- the count on exit. Delete_Last checks the count to determine whether
796 -- it is being called while the associated callback procedure is
799 if Container
.Busy
> 0 then
800 raise Program_Error
with
801 "attempt to tamper with cursors (vector is busy)";
804 -- There is no restriction on how large Count can be when deleting
805 -- items. If it is equal or greater than the current length, then this
806 -- is equivalent to clearing the vector. (In particular, there's no need
807 -- for us to actually calculate the new value for Last.)
809 -- If the requested count is less than the current length, then we must
810 -- calculate the new value for Last. For the type we use the widest of
811 -- Index_Type'Base and Count_Type'Base for the intermediate values of
812 -- our calculation. (See the comments in Length for more information.)
814 if Count
>= Container
.Length
then
815 Container
.Last
:= No_Index
;
817 elsif Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
818 Container.Last := Container.Last - Index_Type'Base (Count);
822 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
832 Index : Index_Type) return Element_Type
835 if Index > Container.Last then
836 raise Constraint_Error with "Index is out of range";
838 return Container.Elements.EA (Index);
842 function Element (Position : Cursor) return Element_Type is
844 if Position.Container = null then
845 raise Constraint_Error with "Position cursor has no element";
846 elsif Position.Index > Position.Container.Last then
847 raise Constraint_Error with "Position cursor is out of range";
849 return Position.Container.Elements.EA (Position.Index);
857 procedure Finalize (Container : in out Vector) is
858 X : Elements_Access := Container.Elements;
861 if Container.Busy > 0 then
862 raise Program_Error with
863 "attempt to tamper with cursors (vector is busy)";
866 Container.Elements := null;
867 Container.Last := No_Index;
872 procedure Finalize (Object : in out Iterator) is
873 B : Natural renames Object.Container.Busy;
878 procedure Finalize (Control : in out Reference_Control_Type) is
880 if Control.Container /= null then
882 C : Vector renames Control.Container.all;
883 B : Natural renames C.Busy;
884 L : Natural renames C.Lock;
890 Control.Container := null;
901 Position : Cursor := No_Element) return Cursor
904 if Position.Container /= null then
905 if Position.Container /= Container'Unrestricted_Access then
906 raise Program_Error with "Position cursor denotes wrong container";
909 if Position.Index > Container.Last then
910 raise Program_Error with "Position index is out of range";
914 -- Per AI05-0022, the container implementation is required to detect
915 -- element tampering by a generic actual subprogram.
918 B : Natural renames Container'Unrestricted_Access.Busy;
919 L : Natural renames Container'Unrestricted_Access.Lock;
921 Result : Index_Type'Base;
928 for J in Position.Index .. Container.Last loop
929 if Container.Elements.EA (J) = Item then
938 if Result = No_Index then
941 return Cursor'(Container
'Unrestricted_Access, Result
);
960 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
962 B
: Natural renames Container
'Unrestricted_Access.Busy
;
963 L
: Natural renames Container
'Unrestricted_Access.Lock
;
965 Result
: Index_Type
'Base;
968 -- Per AI05-0022, the container implementation is required to detect
969 -- element tampering by a generic actual subprogram.
975 for Indx
in Index
.. Container
.Last
loop
976 if Container
.Elements
.EA
(Indx
) = Item
then
999 function First
(Container
: Vector
) return Cursor
is
1001 if Is_Empty
(Container
) then
1004 return (Container
'Unrestricted_Access, Index_Type
'First);
1008 function First
(Object
: Iterator
) return Cursor
is
1010 -- The value of the iterator object's Index component influences the
1011 -- behavior of the First (and Last) selector function.
1013 -- When the Index component is No_Index, this means the iterator
1014 -- object was constructed without a start expression, in which case the
1015 -- (forward) iteration starts from the (logical) beginning of the entire
1016 -- sequence of items (corresponding to Container.First, for a forward
1019 -- Otherwise, this is iteration over a partial sequence of items.
1020 -- When the Index component isn't No_Index, the iterator object was
1021 -- constructed with a start expression, that specifies the position
1022 -- from which the (forward) partial iteration begins.
1024 if Object
.Index
= No_Index
then
1025 return First
(Object
.Container
.all);
1027 return Cursor
'(Object.Container, Object.Index);
1035 function First_Element (Container : Vector) return Element_Type is
1037 if Container.Last = No_Index then
1038 raise Constraint_Error with "Container is empty";
1040 return Container.Elements.EA (Index_Type'First);
1048 function First_Index (Container : Vector) return Index_Type is
1049 pragma Unreferenced (Container);
1051 return Index_Type'First;
1054 ---------------------
1055 -- Generic_Sorting --
1056 ---------------------
1058 package body Generic_Sorting is
1064 function Is_Sorted (Container : Vector) return Boolean is
1066 if Container.Last <= Index_Type'First then
1070 -- Per AI05-0022, the container implementation is required to detect
1071 -- element tampering by a generic actual subprogram.
1074 EA : Elements_Array renames Container.Elements.EA;
1076 B : Natural renames Container'Unrestricted_Access.Busy;
1077 L : Natural renames Container'Unrestricted_Access.Lock;
1086 for J in Index_Type'First .. Container.Last - 1 loop
1087 if EA (J + 1) < EA (J) then
1111 procedure Merge (Target, Source : in out Vector) is
1112 I : Index_Type'Base := Target.Last;
1113 J : Index_Type'Base;
1116 -- The semantics of Merge changed slightly per AI05-0021. It was
1117 -- originally the case that if Target and Source denoted the same
1118 -- container object, then the GNAT implementation of Merge did
1119 -- nothing. However, it was argued that RM05 did not precisely
1120 -- specify the semantics for this corner case. The decision of the
1121 -- ARG was that if Target and Source denote the same non-empty
1122 -- container object, then Program_Error is raised.
1124 if Source.Last < Index_Type'First then -- Source is empty
1128 if Target'Address = Source'Address then
1129 raise Program_Error with
1130 "Target and Source denote same non-empty container";
1133 if Target.Last < Index_Type'First then -- Target is empty
1134 Move (Target => Target, Source => Source);
1138 if Source.Busy > 0 then
1139 raise Program_Error with
1140 "attempt to tamper with cursors (vector is busy)";
1143 Target.Set_Length (Length (Target) + Length (Source));
1145 -- Per AI05-0022, the container implementation is required to detect
1146 -- element tampering by a generic actual subprogram.
1149 TA : Elements_Array renames Target.Elements.EA;
1150 SA : Elements_Array renames Source.Elements.EA;
1152 TB : Natural renames Target.Busy;
1153 TL : Natural renames Target.Lock;
1155 SB : Natural renames Source.Busy;
1156 SL : Natural renames Source.Lock;
1166 while Source.Last >= Index_Type'First loop
1167 pragma Assert (Source.Last <= Index_Type'First
1168 or else not (SA (Source.Last) <
1169 SA (Source.Last - 1)));
1171 if I < Index_Type'First then
1172 TA (Index_Type'First .. J) :=
1173 SA (Index_Type'First .. Source.Last);
1175 Source.Last := No_Index;
1179 pragma Assert (I <= Index_Type'First
1180 or else not (TA (I) < TA (I - 1)));
1182 if SA (Source.Last) < TA (I) then
1187 TA (J) := SA (Source.Last);
1188 Source.Last := Source.Last - 1;
1216 procedure Sort (Container : in out Vector) is
1218 new Generic_Array_Sort
1219 (Index_Type => Index_Type,
1220 Element_Type => Element_Type,
1221 Array_Type => Elements_Array,
1225 if Container.Last <= Index_Type'First then
1229 -- The exception behavior for the vector container must match that
1230 -- for the list container, so we check for cursor tampering here
1231 -- (which will catch more things) instead of for element tampering
1232 -- (which will catch fewer things). It's true that the elements of
1233 -- this vector container could be safely moved around while (say) an
1234 -- iteration is taking place (iteration only increments the busy
1235 -- counter), and so technically all we would need here is a test for
1236 -- element tampering (indicated by the lock counter), that's simply
1237 -- an artifact of our array-based implementation. Logically Sort
1238 -- requires a check for cursor tampering.
1240 if Container.Busy > 0 then
1241 raise Program_Error with
1242 "attempt to tamper with cursors (vector is busy)";
1245 -- Per AI05-0022, the container implementation is required to detect
1246 -- element tampering by a generic actual subprogram.
1249 B : Natural renames Container.Busy;
1250 L : Natural renames Container.Lock;
1256 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1270 end Generic_Sorting;
1276 function Has_Element (Position : Cursor) return Boolean is
1278 return Position /= No_Element;
1286 (Container : in out Vector;
1287 Before : Extended_Index;
1288 New_Item : Element_Type;
1289 Count : Count_Type := 1)
1291 Old_Length : constant Count_Type := Container.Length;
1293 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1294 New_Length : Count_Type'Base; -- sum of current length and Count
1295 New_Last : Index_Type'Base; -- last index of vector after insertion
1297 Index : Index_Type'Base; -- scratch for intermediate values
1298 J : Count_Type'Base; -- scratch
1300 New_Capacity : Count_Type'Base; -- length of new, expanded array
1301 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1302 Dst : Elements_Access; -- new, expanded internal array
1305 -- As a precondition on the generic actual Index_Type, the base type
1306 -- must include Index_Type'Pred (Index_Type'First); this is the value
1307 -- that Container.Last assumes when the vector is empty. However, we do
1308 -- not allow that as the value for Index when specifying where the new
1309 -- items should be inserted, so we must manually check. (That the user
1310 -- is allowed to specify the value at all here is a consequence of the
1311 -- declaration of the Extended_Index subtype, which includes the values
1312 -- in the base range that immediately precede and immediately follow the
1313 -- values in the Index_Type.)
1315 if Before < Index_Type'First then
1316 raise Constraint_Error with
1317 "Before index is out of range (too small)";
1320 -- We do allow a value greater than Container.Last to be specified as
1321 -- the Index, but only if it's immediately greater. This allows for the
1322 -- case of appending items to the back end of the vector. (It is assumed
1323 -- that specifying an index value greater than Last + 1 indicates some
1324 -- deeper flaw in the caller's algorithm, so that case is treated as a
1327 if Before > Container.Last and then Before > Container.Last + 1 then
1328 raise Constraint_Error with
1329 "Before index is out of range (too large)";
1332 -- We treat inserting 0 items into the container as a no-op, even when
1333 -- the container is busy, so we simply return.
1339 -- There are two constraints we need to satisfy. The first constraint is
1340 -- that a container cannot have more than Count_Type'Last elements, so
1341 -- we must check the sum of the current length and the insertion count.
1342 -- Note: we cannot simply add these values, because of the possibility
1345 if Old_Length > Count_Type'Last - Count then
1346 raise Constraint_Error with "Count is out of range";
1349 -- It is now safe compute the length of the new vector, without fear of
1352 New_Length := Old_Length + Count;
1354 -- The second constraint is that the new Last index value cannot exceed
1355 -- Index_Type'Last. In each branch below, we calculate the maximum
1356 -- length (computed from the range of values in Index_Type), and then
1357 -- compare the new length to the maximum length. If the new length is
1358 -- acceptable, then we compute the new last index from that.
1360 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1362 -- We have to handle the case when there might be more values in the
1363 -- range of Index_Type than in the range of Count_Type.
1365 if Index_Type
'First <= 0 then
1367 -- We know that No_Index (the same as Index_Type'First - 1) is
1368 -- less than 0, so it is safe to compute the following sum without
1369 -- fear of overflow.
1371 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1373 if Index
<= Index_Type
'Last then
1375 -- We have determined that range of Index_Type has at least as
1376 -- many values as in Count_Type, so Count_Type'Last is the
1377 -- maximum number of items that are allowed.
1379 Max_Length
:= Count_Type
'Last;
1382 -- The range of Index_Type has fewer values than in Count_Type,
1383 -- so the maximum number of items is computed from the range of
1386 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1390 -- No_Index is equal or greater than 0, so we can safely compute
1391 -- the difference without fear of overflow (which we would have to
1392 -- worry about if No_Index were less than 0, but that case is
1395 if Index_Type
'Last - No_Index
>=
1396 Count_Type
'Pos (Count_Type
'Last)
1398 -- We have determined that range of Index_Type has at least as
1399 -- many values as in Count_Type, so Count_Type'Last is the
1400 -- maximum number of items that are allowed.
1402 Max_Length
:= Count_Type
'Last;
1405 -- The range of Index_Type has fewer values than in Count_Type,
1406 -- so the maximum number of items is computed from the range of
1409 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1413 elsif Index_Type
'First <= 0 then
1415 -- We know that No_Index (the same as Index_Type'First - 1) is less
1416 -- than 0, so it is safe to compute the following sum without fear of
1419 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
1421 if J
<= Count_Type
'Base (Index_Type
'Last) then
1423 -- We have determined that range of Index_Type has at least as
1424 -- many values as in Count_Type, so Count_Type'Last is the maximum
1425 -- number of items that are allowed.
1427 Max_Length
:= Count_Type
'Last;
1430 -- The range of Index_Type has fewer values than Count_Type does,
1431 -- so the maximum number of items is computed from the range of
1435 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1439 -- No_Index is equal or greater than 0, so we can safely compute the
1440 -- difference without fear of overflow (which we would have to worry
1441 -- about if No_Index were less than 0, but that case is handled
1445 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1448 -- We have just computed the maximum length (number of items). We must
1449 -- now compare the requested length to the maximum length, as we do not
1450 -- allow a vector expand beyond the maximum (because that would create
1451 -- an internal array with a last index value greater than
1452 -- Index_Type'Last, with no way to index those elements).
1454 if New_Length
> Max_Length
then
1455 raise Constraint_Error
with "Count is out of range";
1458 -- New_Last is the last index value of the items in the container after
1459 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1460 -- compute its value from the New_Length.
1462 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1463 New_Last := No_Index + Index_Type'Base (New_Length);
1465 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1468 if Container.Elements = null then
1469 pragma Assert (Container.Last = No_Index);
1471 -- This is the simplest case, with which we must always begin: we're
1472 -- inserting items into an empty vector that hasn't allocated an
1473 -- internal array yet. Note that we don't need to check the busy bit
1474 -- here, because an empty container cannot be busy.
1476 -- In order to preserve container invariants, we allocate the new
1477 -- internal array first, before setting the Last index value, in case
1478 -- the allocation fails (which can happen either because there is no
1479 -- storage available, or because element initialization fails).
1481 Container.Elements := new Elements_Type'
1483 EA
=> (others => New_Item
));
1485 -- The allocation of the new, internal array succeeded, so it is now
1486 -- safe to update the Last index, restoring container invariants.
1488 Container
.Last
:= New_Last
;
1493 -- The tampering bits exist to prevent an item from being harmfully
1494 -- manipulated while it is being visited. Query, Update, and Iterate
1495 -- increment the busy count on entry, and decrement the count on
1496 -- exit. Insert checks the count to determine whether it is being called
1497 -- while the associated callback procedure is executing.
1499 if Container
.Busy
> 0 then
1500 raise Program_Error
with
1501 "attempt to tamper with cursors (vector is busy)";
1504 -- An internal array has already been allocated, so we must determine
1505 -- whether there is enough unused storage for the new items.
1507 if New_Length
<= Container
.Elements
.EA
'Length then
1509 -- In this case, we're inserting elements into a vector that has
1510 -- already allocated an internal array, and the existing array has
1511 -- enough unused storage for the new items.
1514 EA
: Elements_Array
renames Container
.Elements
.EA
;
1517 if Before
> Container
.Last
then
1519 -- The new items are being appended to the vector, so no
1520 -- sliding of existing elements is required.
1522 EA
(Before
.. New_Last
) := (others => New_Item
);
1525 -- The new items are being inserted before some existing
1526 -- elements, so we must slide the existing elements up to their
1527 -- new home. We use the wider of Index_Type'Base and
1528 -- Count_Type'Base as the type for intermediate index values.
1530 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1531 Index := Before + Index_Type'Base (Count);
1533 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1536 EA (Index .. New_Last) := EA (Before .. Container.Last);
1537 EA (Before .. Index - 1) := (others => New_Item);
1541 Container.Last := New_Last;
1545 -- In this case, we're inserting elements into a vector that has already
1546 -- allocated an internal array, but the existing array does not have
1547 -- enough storage, so we must allocate a new, longer array. In order to
1548 -- guarantee that the amortized insertion cost is O(1), we always
1549 -- allocate an array whose length is some power-of-two factor of the
1550 -- current array length. (The new array cannot have a length less than
1551 -- the New_Length of the container, but its last index value cannot be
1552 -- greater than Index_Type'Last.)
1554 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1555 while New_Capacity < New_Length loop
1556 if New_Capacity > Count_Type'Last / 2 then
1557 New_Capacity := Count_Type'Last;
1560 New_Capacity := 2 * New_Capacity;
1564 if New_Capacity > Max_Length then
1566 -- We have reached the limit of capacity, so no further expansion
1567 -- will occur. (This is not a problem, as there is never a need to
1568 -- have more capacity than the maximum container length.)
1570 New_Capacity := Max_Length;
1573 -- We have computed the length of the new internal array (and this is
1574 -- what "vector capacity" means), so use that to compute its last index.
1576 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1577 Dst_Last
:= No_Index
+ Index_Type
'Base (New_Capacity
);
1580 Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Capacity
);
1583 -- Now we allocate the new, longer internal array. If the allocation
1584 -- fails, we have not changed any container state, so no side-effect
1585 -- will occur as a result of propagating the exception.
1587 Dst
:= new Elements_Type
(Dst_Last
);
1589 -- We have our new internal array. All that needs to be done now is to
1590 -- copy the existing items (if any) from the old array (the "source"
1591 -- array, object SA below) to the new array (the "destination" array,
1592 -- object DA below), and then deallocate the old array.
1595 SA
: Elements_Array
renames Container
.Elements
.EA
; -- source
1596 DA
: Elements_Array
renames Dst
.EA
; -- destination
1599 DA
(Index_Type
'First .. Before
- 1) :=
1600 SA
(Index_Type
'First .. Before
- 1);
1602 if Before
> Container
.Last
then
1603 DA
(Before
.. New_Last
) := (others => New_Item
);
1606 -- The new items are being inserted before some existing elements,
1607 -- so we must slide the existing elements up to their new home.
1609 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1610 Index := Before + Index_Type'Base (Count);
1612 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1615 DA (Before .. Index - 1) := (others => New_Item);
1616 DA (Index .. New_Last) := SA (Before .. Container.Last);
1625 -- We have successfully copied the items onto the new array, so the
1626 -- final thing to do is deallocate the old array.
1629 X : Elements_Access := Container.Elements;
1632 -- We first isolate the old internal array, removing it from the
1633 -- container and replacing it with the new internal array, before we
1634 -- deallocate the old array (which can fail if finalization of
1635 -- elements propagates an exception).
1637 Container.Elements := Dst;
1638 Container.Last := New_Last;
1640 -- The container invariants have been restored, so it is now safe to
1641 -- attempt to deallocate the old array.
1648 (Container : in out Vector;
1649 Before : Extended_Index;
1652 N : constant Count_Type := Length (New_Item);
1653 J : Index_Type'Base;
1656 -- Use Insert_Space to create the "hole" (the destination slice) into
1657 -- which we copy the source items.
1659 Insert_Space (Container, Before, Count => N);
1663 -- There's nothing else to do here (vetting of parameters was
1664 -- performed already in Insert_Space), so we simply return.
1669 -- We calculate the last index value of the destination slice using the
1670 -- wider of Index_Type'Base and count_Type'Base.
1672 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1673 J
:= (Before
- 1) + Index_Type
'Base (N
);
1675 J
:= Index_Type
'Base (Count_Type
'Base (Before
- 1) + N
);
1678 if Container
'Address /= New_Item
'Address then
1680 -- This is the simple case. New_Item denotes an object different
1681 -- from Container, so there's nothing special we need to do to copy
1682 -- the source items to their destination, because all of the source
1683 -- items are contiguous.
1685 Container
.Elements
.EA
(Before
.. J
) :=
1686 New_Item
.Elements
.EA
(Index_Type
'First .. New_Item
.Last
);
1691 -- New_Item denotes the same object as Container, so an insertion has
1692 -- potentially split the source items. The destination is always the
1693 -- range [Before, J], but the source is [Index_Type'First, Before) and
1694 -- (J, Container.Last]. We perform the copy in two steps, using each of
1695 -- the two slices of the source items.
1698 L
: constant Index_Type
'Base := Before
- 1;
1700 subtype Src_Index_Subtype
is Index_Type
'Base range
1701 Index_Type
'First .. L
;
1703 Src
: Elements_Array
renames
1704 Container
.Elements
.EA
(Src_Index_Subtype
);
1706 K
: Index_Type
'Base;
1709 -- We first copy the source items that precede the space we
1710 -- inserted. Index value K is the last index of that portion
1711 -- destination that receives this slice of the source. (If Before
1712 -- equals Index_Type'First, then this first source slice will be
1713 -- empty, which is harmless.)
1715 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1716 K := L + Index_Type'Base (Src'Length);
1718 K := Index_Type'Base (Count_Type'Base (L) + Src'Length);
1721 Container.Elements.EA (Before .. K) := Src;
1723 if Src'Length = N then
1725 -- The new items were effectively appended to the container, so we
1726 -- have already copied all of the items that need to be copied.
1727 -- We return early here, even though the source slice below is
1728 -- empty (so the assignment would be harmless), because we want to
1729 -- avoid computing J + 1, which will overflow if J equals
1730 -- Index_Type'Base'Last
.
1737 -- Note that we want to avoid computing J + 1 here, in case J equals
1738 -- Index_Type'Base'Last. We prevent that by returning early above,
1739 -- immediately after copying the first slice of the source, and
1740 -- determining that this second slice of the source is empty.
1742 F
: constant Index_Type
'Base := J
+ 1;
1744 subtype Src_Index_Subtype
is Index_Type
'Base range
1745 F
.. Container
.Last
;
1747 Src
: Elements_Array
renames
1748 Container
.Elements
.EA
(Src_Index_Subtype
);
1750 K
: Index_Type
'Base;
1753 -- We next copy the source items that follow the space we inserted.
1754 -- Index value K is the first index of that portion of the
1755 -- destination that receives this slice of the source. (For the
1756 -- reasons given above, this slice is guaranteed to be non-empty.)
1758 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1759 K := F - Index_Type'Base (Src'Length);
1761 K := Index_Type'Base (Count_Type'Base (F) - Src'Length);
1764 Container.Elements.EA (K .. J) := Src;
1769 (Container : in out Vector;
1773 Index : Index_Type'Base;
1776 if Before.Container /= null
1777 and then Before.Container /= Container'Unrestricted_Access
1779 raise Program_Error with "Before cursor denotes wrong container";
1782 if Is_Empty (New_Item) then
1786 if Before.Container = null or else Before.Index > Container.Last then
1787 if Container.Last = Index_Type'Last then
1788 raise Constraint_Error with
1789 "vector is already at its maximum length";
1792 Index := Container.Last + 1;
1795 Index := Before.Index;
1798 Insert (Container, Index, New_Item);
1802 (Container : in out Vector;
1805 Position : out Cursor)
1807 Index : Index_Type'Base;
1810 if Before.Container /= null
1811 and then Before.Container /= Container'Unrestricted_Access
1813 raise Program_Error with "Before cursor denotes wrong container";
1816 if Is_Empty (New_Item) then
1817 if Before.Container = null or else Before.Index > Container.Last then
1818 Position := No_Element;
1820 Position := (Container'Unrestricted_Access, Before.Index);
1826 if Before.Container = null or else Before.Index > Container.Last then
1827 if Container.Last = Index_Type'Last then
1828 raise Constraint_Error with
1829 "vector is already at its maximum length";
1832 Index := Container.Last + 1;
1835 Index := Before.Index;
1838 Insert (Container, Index, New_Item);
1840 Position := (Container'Unrestricted_Access, Index);
1844 (Container : in out Vector;
1846 New_Item : Element_Type;
1847 Count : Count_Type := 1)
1849 Index : Index_Type'Base;
1852 if Before.Container /= null
1853 and then Before.Container /= Container'Unrestricted_Access
1855 raise Program_Error with "Before cursor denotes wrong container";
1862 if Before.Container = null or else Before.Index > Container.Last then
1863 if Container.Last = Index_Type'Last then
1864 raise Constraint_Error with
1865 "vector is already at its maximum length";
1867 Index := Container.Last + 1;
1871 Index := Before.Index;
1874 Insert (Container, Index, New_Item, Count);
1878 (Container : in out Vector;
1880 New_Item : Element_Type;
1881 Position : out Cursor;
1882 Count : Count_Type := 1)
1884 Index : Index_Type'Base;
1887 if Before.Container /= null
1888 and then Before.Container /= Container'Unrestricted_Access
1890 raise Program_Error with "Before cursor denotes wrong container";
1894 if Before.Container = null or else Before.Index > Container.Last then
1895 Position := No_Element;
1897 Position := (Container'Unrestricted_Access, Before.Index);
1903 if Before.Container = null or else Before.Index > Container.Last then
1904 if Container.Last = Index_Type'Last then
1905 raise Constraint_Error with
1906 "vector is already at its maximum length";
1909 Index := Container.Last + 1;
1912 Index := Before.Index;
1915 Insert (Container, Index, New_Item, Count);
1917 Position := (Container'Unrestricted_Access, Index);
1921 (Container : in out Vector;
1922 Before : Extended_Index;
1923 Count : Count_Type := 1)
1925 New_Item : Element_Type; -- Default-initialized value
1926 pragma Warnings (Off, New_Item);
1929 Insert (Container, Before, New_Item, Count);
1933 (Container : in out Vector;
1935 Position : out Cursor;
1936 Count : Count_Type := 1)
1938 New_Item : Element_Type; -- Default-initialized value
1939 pragma Warnings (Off, New_Item);
1941 Insert (Container, Before, New_Item, Position, Count);
1948 procedure Insert_Space
1949 (Container : in out Vector;
1950 Before : Extended_Index;
1951 Count : Count_Type := 1)
1953 Old_Length : constant Count_Type := Container.Length;
1955 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1956 New_Length : Count_Type'Base; -- sum of current length and Count
1957 New_Last : Index_Type'Base; -- last index of vector after insertion
1959 Index : Index_Type'Base; -- scratch for intermediate values
1960 J : Count_Type'Base; -- scratch
1962 New_Capacity : Count_Type'Base; -- length of new, expanded array
1963 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1964 Dst : Elements_Access; -- new, expanded internal array
1967 -- As a precondition on the generic actual Index_Type, the base type
1968 -- must include Index_Type'Pred (Index_Type'First); this is the value
1969 -- that Container.Last assumes when the vector is empty. However, we do
1970 -- not allow that as the value for Index when specifying where the new
1971 -- items should be inserted, so we must manually check. (That the user
1972 -- is allowed to specify the value at all here is a consequence of the
1973 -- declaration of the Extended_Index subtype, which includes the values
1974 -- in the base range that immediately precede and immediately follow the
1975 -- values in the Index_Type.)
1977 if Before < Index_Type'First then
1978 raise Constraint_Error with
1979 "Before index is out of range (too small)";
1982 -- We do allow a value greater than Container.Last to be specified as
1983 -- the Index, but only if it's immediately greater. This allows for the
1984 -- case of appending items to the back end of the vector. (It is assumed
1985 -- that specifying an index value greater than Last + 1 indicates some
1986 -- deeper flaw in the caller's algorithm, so that case is treated as a
1989 if Before > Container.Last and then Before > Container.Last + 1 then
1990 raise Constraint_Error with
1991 "Before index is out of range (too large)";
1994 -- We treat inserting 0 items into the container as a no-op, even when
1995 -- the container is busy, so we simply return.
2001 -- There are two constraints we need to satisfy. The first constraint is
2002 -- that a container cannot have more than Count_Type'Last elements, so
2003 -- we must check the sum of the current length and the insertion count.
2004 -- Note: we cannot simply add these values, because of the possibility
2007 if Old_Length > Count_Type'Last - Count then
2008 raise Constraint_Error with "Count is out of range";
2011 -- It is now safe compute the length of the new vector, without fear of
2014 New_Length := Old_Length + Count;
2016 -- The second constraint is that the new Last index value cannot exceed
2017 -- Index_Type'Last. In each branch below, we calculate the maximum
2018 -- length (computed from the range of values in Index_Type), and then
2019 -- compare the new length to the maximum length. If the new length is
2020 -- acceptable, then we compute the new last index from that.
2022 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2024 -- We have to handle the case when there might be more values in the
2025 -- range of Index_Type than in the range of Count_Type.
2027 if Index_Type
'First <= 0 then
2029 -- We know that No_Index (the same as Index_Type'First - 1) is
2030 -- less than 0, so it is safe to compute the following sum without
2031 -- fear of overflow.
2033 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
2035 if Index
<= Index_Type
'Last then
2037 -- We have determined that range of Index_Type has at least as
2038 -- many values as in Count_Type, so Count_Type'Last is the
2039 -- maximum number of items that are allowed.
2041 Max_Length
:= Count_Type
'Last;
2044 -- The range of Index_Type has fewer values than in Count_Type,
2045 -- so the maximum number of items is computed from the range of
2048 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2052 -- No_Index is equal or greater than 0, so we can safely compute
2053 -- the difference without fear of overflow (which we would have to
2054 -- worry about if No_Index were less than 0, but that case is
2057 if Index_Type
'Last - No_Index
>=
2058 Count_Type
'Pos (Count_Type
'Last)
2060 -- We have determined that range of Index_Type has at least as
2061 -- many values as in Count_Type, so Count_Type'Last is the
2062 -- maximum number of items that are allowed.
2064 Max_Length
:= Count_Type
'Last;
2067 -- The range of Index_Type has fewer values than in Count_Type,
2068 -- so the maximum number of items is computed from the range of
2071 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2075 elsif Index_Type
'First <= 0 then
2077 -- We know that No_Index (the same as Index_Type'First - 1) is less
2078 -- than 0, so it is safe to compute the following sum without fear of
2081 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
2083 if J
<= Count_Type
'Base (Index_Type
'Last) then
2085 -- We have determined that range of Index_Type has at least as
2086 -- many values as in Count_Type, so Count_Type'Last is the maximum
2087 -- number of items that are allowed.
2089 Max_Length
:= Count_Type
'Last;
2092 -- The range of Index_Type has fewer values than Count_Type does,
2093 -- so the maximum number of items is computed from the range of
2097 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2101 -- No_Index is equal or greater than 0, so we can safely compute the
2102 -- difference without fear of overflow (which we would have to worry
2103 -- about if No_Index were less than 0, but that case is handled
2107 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2110 -- We have just computed the maximum length (number of items). We must
2111 -- now compare the requested length to the maximum length, as we do not
2112 -- allow a vector expand beyond the maximum (because that would create
2113 -- an internal array with a last index value greater than
2114 -- Index_Type'Last, with no way to index those elements).
2116 if New_Length
> Max_Length
then
2117 raise Constraint_Error
with "Count is out of range";
2120 -- New_Last is the last index value of the items in the container after
2121 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2122 -- compute its value from the New_Length.
2124 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2125 New_Last := No_Index + Index_Type'Base (New_Length);
2127 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2130 if Container.Elements = null then
2131 pragma Assert (Container.Last = No_Index);
2133 -- This is the simplest case, with which we must always begin: we're
2134 -- inserting items into an empty vector that hasn't allocated an
2135 -- internal array yet. Note that we don't need to check the busy bit
2136 -- here, because an empty container cannot be busy.
2138 -- In order to preserve container invariants, we allocate the new
2139 -- internal array first, before setting the Last index value, in case
2140 -- the allocation fails (which can happen either because there is no
2141 -- storage available, or because default-valued element
2142 -- initialization fails).
2144 Container.Elements := new Elements_Type (New_Last);
2146 -- The allocation of the new, internal array succeeded, so it is now
2147 -- safe to update the Last index, restoring container invariants.
2149 Container.Last := New_Last;
2154 -- The tampering bits exist to prevent an item from being harmfully
2155 -- manipulated while it is being visited. Query, Update, and Iterate
2156 -- increment the busy count on entry, and decrement the count on
2157 -- exit. Insert checks the count to determine whether it is being called
2158 -- while the associated callback procedure is executing.
2160 if Container.Busy > 0 then
2161 raise Program_Error with
2162 "attempt to tamper with cursors (vector is busy)";
2165 -- An internal array has already been allocated, so we must determine
2166 -- whether there is enough unused storage for the new items.
2168 if New_Last <= Container.Elements.Last then
2170 -- In this case, we're inserting space into a vector that has already
2171 -- allocated an internal array, and the existing array has enough
2172 -- unused storage for the new items.
2175 EA : Elements_Array renames Container.Elements.EA;
2178 if Before <= Container.Last then
2180 -- The space is being inserted before some existing elements,
2181 -- so we must slide the existing elements up to their new
2182 -- home. We use the wider of Index_Type'Base and
2183 -- Count_Type'Base as the type for intermediate index values.
2185 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2186 Index
:= Before
+ Index_Type
'Base (Count
);
2189 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2192 EA
(Index
.. New_Last
) := EA
(Before
.. Container
.Last
);
2196 Container
.Last
:= New_Last
;
2200 -- In this case, we're inserting space into a vector that has already
2201 -- allocated an internal array, but the existing array does not have
2202 -- enough storage, so we must allocate a new, longer array. In order to
2203 -- guarantee that the amortized insertion cost is O(1), we always
2204 -- allocate an array whose length is some power-of-two factor of the
2205 -- current array length. (The new array cannot have a length less than
2206 -- the New_Length of the container, but its last index value cannot be
2207 -- greater than Index_Type'Last.)
2209 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
2210 while New_Capacity
< New_Length
loop
2211 if New_Capacity
> Count_Type
'Last / 2 then
2212 New_Capacity
:= Count_Type
'Last;
2216 New_Capacity
:= 2 * New_Capacity
;
2219 if New_Capacity
> Max_Length
then
2221 -- We have reached the limit of capacity, so no further expansion
2222 -- will occur. (This is not a problem, as there is never a need to
2223 -- have more capacity than the maximum container length.)
2225 New_Capacity
:= Max_Length
;
2228 -- We have computed the length of the new internal array (and this is
2229 -- what "vector capacity" means), so use that to compute its last index.
2231 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2232 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2235 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2238 -- Now we allocate the new, longer internal array. If the allocation
2239 -- fails, we have not changed any container state, so no side-effect
2240 -- will occur as a result of propagating the exception.
2242 Dst := new Elements_Type (Dst_Last);
2244 -- We have our new internal array. All that needs to be done now is to
2245 -- copy the existing items (if any) from the old array (the "source"
2246 -- array, object SA below) to the new array (the "destination" array,
2247 -- object DA below), and then deallocate the old array.
2250 SA : Elements_Array renames Container.Elements.EA; -- source
2251 DA : Elements_Array renames Dst.EA; -- destination
2254 DA (Index_Type'First .. Before - 1) :=
2255 SA (Index_Type'First .. Before - 1);
2257 if Before <= Container.Last then
2259 -- The space is being inserted before some existing elements, so
2260 -- we must slide the existing elements up to their new home.
2262 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
2263 Index
:= Before
+ Index_Type
'Base (Count
);
2265 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2268 DA
(Index
.. New_Last
) := SA
(Before
.. Container
.Last
);
2277 -- We have successfully copied the items onto the new array, so the
2278 -- final thing to do is restore invariants, and deallocate the old
2282 X
: Elements_Access
:= Container
.Elements
;
2285 -- We first isolate the old internal array, removing it from the
2286 -- container and replacing it with the new internal array, before we
2287 -- deallocate the old array (which can fail if finalization of
2288 -- elements propagates an exception).
2290 Container
.Elements
:= Dst
;
2291 Container
.Last
:= New_Last
;
2293 -- The container invariants have been restored, so it is now safe to
2294 -- attempt to deallocate the old array.
2300 procedure Insert_Space
2301 (Container
: in out Vector
;
2303 Position
: out Cursor
;
2304 Count
: Count_Type
:= 1)
2306 Index
: Index_Type
'Base;
2309 if Before
.Container
/= null
2310 and then Before
.Container
/= Container
'Unrestricted_Access
2312 raise Program_Error
with "Before cursor denotes wrong container";
2316 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2317 Position
:= No_Element
;
2319 Position
:= (Container
'Unrestricted_Access, Before
.Index
);
2325 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2326 if Container
.Last
= Index_Type
'Last then
2327 raise Constraint_Error
with
2328 "vector is already at its maximum length";
2330 Index
:= Container
.Last
+ 1;
2334 Index
:= Before
.Index
;
2337 Insert_Space
(Container
, Index
, Count
=> Count
);
2339 Position
:= (Container
'Unrestricted_Access, Index
);
2346 function Is_Empty
(Container
: Vector
) return Boolean is
2348 return Container
.Last
< Index_Type
'First;
2356 (Container
: Vector
;
2357 Process
: not null access procedure (Position
: Cursor
))
2359 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
2365 for Indx
in Index_Type
'First .. Container
.Last
loop
2366 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
2378 (Container : Vector)
2379 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2381 V : constant Vector_Access := Container'Unrestricted_Access;
2382 B : Natural renames V.Busy;
2385 -- The value of its Index component influences the behavior of the First
2386 -- and Last selector functions of the iterator object. When the Index
2387 -- component is No_Index (as is the case here), this means the iterator
2388 -- object was constructed without a start expression. This is a complete
2389 -- iterator, meaning that the iteration starts from the (logical)
2390 -- beginning of the sequence of items.
2392 -- Note: For a forward iterator, Container.First is the beginning, and
2393 -- for a reverse iterator, Container.Last is the beginning.
2395 return It : constant Iterator :=
2396 (Limited_Controlled with
2405 (Container : Vector;
2407 return Vector_Iterator_Interfaces.Reversible_Iterator'class
2409 V : constant Vector_Access := Container'Unrestricted_Access;
2410 B : Natural renames V.Busy;
2413 -- It was formerly the case that when Start = No_Element, the partial
2414 -- iterator was defined to behave the same as for a complete iterator,
2415 -- and iterate over the entire sequence of items. However, those
2416 -- semantics were unintuitive and arguably error-prone (it is too easy
2417 -- to accidentally create an endless loop), and so they were changed,
2418 -- per the ARG meeting in Denver on 2011/11. However, there was no
2419 -- consensus about what positive meaning this corner case should have,
2420 -- and so it was decided to simply raise an exception. This does imply,
2421 -- however, that it is not possible to use a partial iterator to specify
2422 -- an empty sequence of items.
2424 if Start.Container = null then
2425 raise Constraint_Error with
2426 "Start position for iterator equals No_Element";
2429 if Start.Container /= V then
2430 raise Program_Error with
2431 "Start cursor of Iterate designates wrong vector";
2434 if Start.Index > V.Last then
2435 raise Constraint_Error with
2436 "Start position for iterator equals No_Element";
2439 -- The value of its Index component influences the behavior of the First
2440 -- and Last selector functions of the iterator object. When the Index
2441 -- component is not No_Index (as is the case here), it means that this
2442 -- is a partial iteration, over a subset of the complete sequence of
2443 -- items. The iterator object was constructed with a start expression,
2444 -- indicating the position from which the iteration begins. Note that
2445 -- the start position has the same value irrespective of whether this
2446 -- is a forward or reverse iteration.
2448 return It : constant Iterator :=
2449 (Limited_Controlled with
2451 Index => Start.Index)
2461 function Last (Container : Vector) return Cursor is
2463 if Is_Empty (Container) then
2466 return (Container'Unrestricted_Access, Container.Last);
2470 function Last (Object : Iterator) return Cursor is
2472 -- The value of the iterator object's Index component influences the
2473 -- behavior of the Last (and First) selector function.
2475 -- When the Index component is No_Index, this means the iterator
2476 -- object was constructed without a start expression, in which case the
2477 -- (reverse) iteration starts from the (logical) beginning of the entire
2478 -- sequence (corresponding to Container.Last, for a reverse iterator).
2480 -- Otherwise, this is iteration over a partial sequence of items.
2481 -- When the Index component is not No_Index, the iterator object was
2482 -- constructed with a start expression, that specifies the position
2483 -- from which the (reverse) partial iteration begins.
2485 if Object.Index = No_Index then
2486 return Last (Object.Container.all);
2488 return Cursor'(Object
.Container
, Object
.Index
);
2496 function Last_Element
(Container
: Vector
) return Element_Type
is
2498 if Container
.Last
= No_Index
then
2499 raise Constraint_Error
with "Container is empty";
2501 return Container
.Elements
.EA
(Container
.Last
);
2509 function Last_Index
(Container
: Vector
) return Extended_Index
is
2511 return Container
.Last
;
2518 function Length
(Container
: Vector
) return Count_Type
is
2519 L
: constant Index_Type
'Base := Container
.Last
;
2520 F
: constant Index_Type
:= Index_Type
'First;
2523 -- The base range of the index type (Index_Type'Base) might not include
2524 -- all values for length (Count_Type). Contrariwise, the index type
2525 -- might include values outside the range of length. Hence we use
2526 -- whatever type is wider for intermediate values when calculating
2527 -- length. Note that no matter what the index type is, the maximum
2528 -- length to which a vector is allowed to grow is always the minimum
2529 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2531 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2532 -- to have a base range of -128 .. 127, but the corresponding vector
2533 -- would have lengths in the range 0 .. 255. In this case we would need
2534 -- to use Count_Type'Base for intermediate values.
2536 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2537 -- vector would have a maximum length of 10, but the index values lie
2538 -- outside the range of Count_Type (which is only 32 bits). In this
2539 -- case we would need to use Index_Type'Base for intermediate values.
2541 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
2542 return Count_Type
'Base (L
) - Count_Type
'Base (F
) + 1;
2544 return Count_Type
(L
- F
+ 1);
2553 (Target
: in out Vector
;
2554 Source
: in out Vector
)
2557 if Target
'Address = Source
'Address then
2561 if Target
.Busy
> 0 then
2562 raise Program_Error
with
2563 "attempt to tamper with cursors (Target is busy)";
2566 if Source
.Busy
> 0 then
2567 raise Program_Error
with
2568 "attempt to tamper with cursors (Source is busy)";
2572 Target_Elements
: constant Elements_Access
:= Target
.Elements
;
2574 Target
.Elements
:= Source
.Elements
;
2575 Source
.Elements
:= Target_Elements
;
2578 Target
.Last
:= Source
.Last
;
2579 Source
.Last
:= No_Index
;
2586 function Next
(Position
: Cursor
) return Cursor
is
2588 if Position
.Container
= null then
2590 elsif Position
.Index
< Position
.Container
.Last
then
2591 return (Position
.Container
, Position
.Index
+ 1);
2597 function Next
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
2599 if Position
.Container
= null then
2601 elsif Position
.Container
/= Object
.Container
then
2602 raise Program_Error
with
2603 "Position cursor of Next designates wrong vector";
2605 return Next
(Position
);
2609 procedure Next
(Position
: in out Cursor
) is
2611 if Position
.Container
= null then
2613 elsif Position
.Index
< Position
.Container
.Last
then
2614 Position
.Index
:= Position
.Index
+ 1;
2616 Position
:= No_Element
;
2624 procedure Prepend
(Container
: in out Vector
; New_Item
: Vector
) is
2626 Insert
(Container
, Index_Type
'First, New_Item
);
2630 (Container
: in out Vector
;
2631 New_Item
: Element_Type
;
2632 Count
: Count_Type
:= 1)
2635 Insert
(Container
, Index_Type
'First, New_Item
, Count
);
2642 function Previous
(Position
: Cursor
) return Cursor
is
2644 if Position
.Container
= null then
2646 elsif Position
.Index
> Index_Type
'First then
2647 return (Position
.Container
, Position
.Index
- 1);
2653 function Previous
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
2655 if Position
.Container
= null then
2657 elsif Position
.Container
/= Object
.Container
then
2658 raise Program_Error
with
2659 "Position cursor of Previous designates wrong vector";
2661 return Previous
(Position
);
2665 procedure Previous
(Position
: in out Cursor
) is
2667 if Position
.Container
= null then
2669 elsif Position
.Index
> Index_Type
'First then
2670 Position
.Index
:= Position
.Index
- 1;
2672 Position
:= No_Element
;
2680 procedure Query_Element
2681 (Container
: Vector
;
2683 Process
: not null access procedure (Element
: Element_Type
))
2685 V
: Vector
renames Container
'Unrestricted_Access.all;
2686 B
: Natural renames V
.Busy
;
2687 L
: Natural renames V
.Lock
;
2690 if Index
> Container
.Last
then
2691 raise Constraint_Error
with "Index is out of range";
2698 Process
(V
.Elements
.EA
(Index
));
2710 procedure Query_Element
2712 Process
: not null access procedure (Element
: Element_Type
))
2715 if Position
.Container
= null then
2716 raise Constraint_Error
with "Position cursor has no element";
2718 Query_Element
(Position
.Container
.all, Position
.Index
, Process
);
2727 (Stream
: not null access Root_Stream_Type
'Class;
2728 Container
: out Vector
)
2730 Length
: Count_Type
'Base;
2731 Last
: Index_Type
'Base := No_Index
;
2736 Count_Type
'Base'Read (Stream, Length);
2738 if Length > Capacity (Container) then
2739 Reserve_Capacity (Container, Capacity => Length);
2742 for J in Count_Type range 1 .. Length loop
2744 Element_Type'Read (Stream, Container.Elements.EA (Last));
2745 Container.Last := Last;
2750 (Stream : not null access Root_Stream_Type'Class;
2751 Position : out Cursor)
2754 raise Program_Error with "attempt to stream vector cursor";
2758 (Stream : not null access Root_Stream_Type'Class;
2759 Item : out Reference_Type)
2762 raise Program_Error with "attempt to stream reference";
2766 (Stream : not null access Root_Stream_Type'Class;
2767 Item : out Constant_Reference_Type)
2770 raise Program_Error with "attempt to stream reference";
2778 (Container : aliased in out Vector;
2779 Position : Cursor) return Reference_Type
2782 if Position.Container = null then
2783 raise Constraint_Error with "Position cursor has no element";
2786 if Position.Container /= Container'Unrestricted_Access then
2787 raise Program_Error with "Position cursor denotes wrong container";
2790 if Position.Index > Position.Container.Last then
2791 raise Constraint_Error with "Position cursor is out of range";
2795 C : Vector renames Position.Container.all;
2796 B : Natural renames C.Busy;
2797 L : Natural renames C.Lock;
2799 return R : constant Reference_Type :=
2800 (Element => Container.Elements.EA (Position.Index)'Access,
2801 Control => (Controlled with Position.Container))
2810 (Container : aliased in out Vector;
2811 Index : Index_Type) return Reference_Type
2814 if Index > Container.Last then
2815 raise Constraint_Error with "Index is out of range";
2819 C : Vector renames Container'Unrestricted_Access.all;
2820 B : Natural renames C.Busy;
2821 L : Natural renames C.Lock;
2823 return R : constant Reference_Type :=
2824 (Element => Container.Elements.EA (Index)'Access,
2825 Control => (Controlled with Container'Unrestricted_Access))
2834 ---------------------
2835 -- Replace_Element --
2836 ---------------------
2838 procedure Replace_Element
2839 (Container : in out Vector;
2841 New_Item : Element_Type)
2844 if Index > Container.Last then
2845 raise Constraint_Error with "Index is out of range";
2846 elsif Container.Lock > 0 then
2847 raise Program_Error with
2848 "attempt to tamper with elements (vector is locked)";
2850 Container.Elements.EA (Index) := New_Item;
2852 end Replace_Element;
2854 procedure Replace_Element
2855 (Container : in out Vector;
2857 New_Item : Element_Type)
2860 if Position.Container = null then
2861 raise Constraint_Error with "Position cursor has no element";
2863 elsif Position.Container /= Container'Unrestricted_Access then
2864 raise Program_Error with "Position cursor denotes wrong container";
2866 elsif Position.Index > Container.Last then
2867 raise Constraint_Error with "Position cursor is out of range";
2870 if Container.Lock > 0 then
2871 raise Program_Error with
2872 "attempt to tamper with elements (vector is locked)";
2875 Container.Elements.EA (Position.Index) := New_Item;
2877 end Replace_Element;
2879 ----------------------
2880 -- Reserve_Capacity --
2881 ----------------------
2883 procedure Reserve_Capacity
2884 (Container : in out Vector;
2885 Capacity : Count_Type)
2887 N : constant Count_Type := Length (Container);
2889 Index : Count_Type'Base;
2890 Last : Index_Type'Base;
2893 -- Reserve_Capacity can be used to either expand the storage available
2894 -- for elements (this would be its typical use, in anticipation of
2895 -- future insertion), or to trim back storage. In the latter case,
2896 -- storage can only be trimmed back to the limit of the container
2897 -- length. Note that Reserve_Capacity neither deletes (active) elements
2898 -- nor inserts elements; it only affects container capacity, never
2899 -- container length.
2901 if Capacity = 0 then
2903 -- This is a request to trim back storage, to the minimum amount
2904 -- possible given the current state of the container.
2908 -- The container is empty, so in this unique case we can
2909 -- deallocate the entire internal array. Note that an empty
2910 -- container can never be busy, so there's no need to check the
2914 X : Elements_Access := Container.Elements;
2917 -- First we remove the internal array from the container, to
2918 -- handle the case when the deallocation raises an exception.
2920 Container.Elements := null;
2922 -- Container invariants have been restored, so it is now safe
2923 -- to attempt to deallocate the internal array.
2928 elsif N < Container.Elements.EA'Length then
2930 -- The container is not empty, and the current length is less than
2931 -- the current capacity, so there's storage available to trim. In
2932 -- this case, we allocate a new internal array having a length
2933 -- that exactly matches the number of items in the
2934 -- container. (Reserve_Capacity does not delete active elements,
2935 -- so this is the best we can do with respect to minimizing
2938 if Container.Busy > 0 then
2939 raise Program_Error with
2940 "attempt to tamper with cursors (vector is busy)";
2944 subtype Src_Index_Subtype is Index_Type'Base range
2945 Index_Type'First .. Container.Last;
2947 Src : Elements_Array renames
2948 Container.Elements.EA (Src_Index_Subtype);
2950 X : Elements_Access := Container.Elements;
2953 -- Although we have isolated the old internal array that we're
2954 -- going to deallocate, we don't deallocate it until we have
2955 -- successfully allocated a new one. If there is an exception
2956 -- during allocation (either because there is not enough
2957 -- storage, or because initialization of the elements fails),
2958 -- we let it propagate without causing any side-effect.
2960 Container.Elements := new Elements_Type'(Container
.Last
, Src
);
2962 -- We have successfully allocated a new internal array (with a
2963 -- smaller length than the old one, and containing a copy of
2964 -- just the active elements in the container), so it is now
2965 -- safe to attempt to deallocate the old array. The old array
2966 -- has been isolated, and container invariants have been
2967 -- restored, so if the deallocation fails (because finalization
2968 -- of the elements fails), we simply let it propagate.
2977 -- Reserve_Capacity can be used to expand the storage available for
2978 -- elements, but we do not let the capacity grow beyond the number of
2979 -- values in Index_Type'Range. (Were it otherwise, there would be no way
2980 -- to refer to the elements with an index value greater than
2981 -- Index_Type'Last, so that storage would be wasted.) Here we compute
2982 -- the Last index value of the new internal array, in a way that avoids
2983 -- any possibility of overflow.
2985 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2987 -- We perform a two-part test. First we determine whether the
2988 -- computed Last value lies in the base range of the type, and then
2989 -- determine whether it lies in the range of the index (sub)type.
2991 -- Last must satisfy this relation:
2992 -- First + Length - 1 <= Last
2993 -- We regroup terms:
2994 -- First - 1 <= Last - Length
2995 -- Which can rewrite as:
2996 -- No_Index <= Last - Length
2998 if Index_Type'Base'Last
- Index_Type
'Base (Capacity
) < No_Index
then
2999 raise Constraint_Error
with "Capacity is out of range";
3002 -- We now know that the computed value of Last is within the base
3003 -- range of the type, so it is safe to compute its value:
3005 Last
:= No_Index
+ Index_Type
'Base (Capacity
);
3007 -- Finally we test whether the value is within the range of the
3008 -- generic actual index subtype:
3010 if Last
> Index_Type
'Last then
3011 raise Constraint_Error
with "Capacity is out of range";
3014 elsif Index_Type
'First <= 0 then
3016 -- Here we can compute Last directly, in the normal way. We know that
3017 -- No_Index is less than 0, so there is no danger of overflow when
3018 -- adding the (positive) value of Capacity.
3020 Index
:= Count_Type
'Base (No_Index
) + Capacity
; -- Last
3022 if Index
> Count_Type
'Base (Index_Type
'Last) then
3023 raise Constraint_Error
with "Capacity is out of range";
3026 -- We know that the computed value (having type Count_Type) of Last
3027 -- is within the range of the generic actual index subtype, so it is
3028 -- safe to convert to Index_Type:
3030 Last
:= Index_Type
'Base (Index
);
3033 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3034 -- must test the length indirectly (by working backwards from the
3035 -- largest possible value of Last), in order to prevent overflow.
3037 Index
:= Count_Type
'Base (Index_Type
'Last) - Capacity
; -- No_Index
3039 if Index
< Count_Type
'Base (No_Index
) then
3040 raise Constraint_Error
with "Capacity is out of range";
3043 -- We have determined that the value of Capacity would not create a
3044 -- Last index value outside of the range of Index_Type, so we can now
3045 -- safely compute its value.
3047 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Capacity
);
3050 -- The requested capacity is non-zero, but we don't know yet whether
3051 -- this is a request for expansion or contraction of storage.
3053 if Container
.Elements
= null then
3055 -- The container is empty (it doesn't even have an internal array),
3056 -- so this represents a request to allocate (expand) storage having
3057 -- the given capacity.
3059 Container
.Elements
:= new Elements_Type
(Last
);
3063 if Capacity
<= N
then
3065 -- This is a request to trim back storage, but only to the limit of
3066 -- what's already in the container. (Reserve_Capacity never deletes
3067 -- active elements, it only reclaims excess storage.)
3069 if N
< Container
.Elements
.EA
'Length then
3071 -- The container is not empty (because the requested capacity is
3072 -- positive, and less than or equal to the container length), and
3073 -- the current length is less than the current capacity, so
3074 -- there's storage available to trim. In this case, we allocate a
3075 -- new internal array having a length that exactly matches the
3076 -- number of items in the container.
3078 if Container
.Busy
> 0 then
3079 raise Program_Error
with
3080 "attempt to tamper with cursors (vector is busy)";
3084 subtype Src_Index_Subtype
is Index_Type
'Base range
3085 Index_Type
'First .. Container
.Last
;
3087 Src
: Elements_Array
renames
3088 Container
.Elements
.EA
(Src_Index_Subtype
);
3090 X
: Elements_Access
:= Container
.Elements
;
3093 -- Although we have isolated the old internal array that we're
3094 -- going to deallocate, we don't deallocate it until we have
3095 -- successfully allocated a new one. If there is an exception
3096 -- during allocation (either because there is not enough
3097 -- storage, or because initialization of the elements fails),
3098 -- we let it propagate without causing any side-effect.
3100 Container
.Elements
:= new Elements_Type
'(Container.Last, Src);
3102 -- We have successfully allocated a new internal array (with a
3103 -- smaller length than the old one, and containing a copy of
3104 -- just the active elements in the container), so it is now
3105 -- safe to attempt to deallocate the old array. The old array
3106 -- has been isolated, and container invariants have been
3107 -- restored, so if the deallocation fails (because finalization
3108 -- of the elements fails), we simply let it propagate.
3117 -- The requested capacity is larger than the container length (the
3118 -- number of active elements). Whether this represents a request for
3119 -- expansion or contraction of the current capacity depends on what the
3120 -- current capacity is.
3122 if Capacity = Container.Elements.EA'Length then
3124 -- The requested capacity matches the existing capacity, so there's
3125 -- nothing to do here. We treat this case as a no-op, and simply
3126 -- return without checking the busy bit.
3131 -- There is a change in the capacity of a non-empty container, so a new
3132 -- internal array will be allocated. (The length of the new internal
3133 -- array could be less or greater than the old internal array. We know
3134 -- only that the length of the new internal array is greater than the
3135 -- number of active elements in the container.) We must check whether
3136 -- the container is busy before doing anything else.
3138 if Container.Busy > 0 then
3139 raise Program_Error with
3140 "attempt to tamper with cursors (vector is busy)";
3143 -- We now allocate a new internal array, having a length different from
3144 -- its current value.
3147 E : Elements_Access := new Elements_Type (Last);
3150 -- We have successfully allocated the new internal array. We first
3151 -- attempt to copy the existing elements from the old internal array
3152 -- ("src" elements) onto the new internal array ("tgt" elements).
3155 subtype Index_Subtype is Index_Type'Base range
3156 Index_Type'First .. Container.Last;
3158 Src : Elements_Array renames
3159 Container.Elements.EA (Index_Subtype);
3161 Tgt : Elements_Array renames E.EA (Index_Subtype);
3172 -- We have successfully copied the existing elements onto the new
3173 -- internal array, so now we can attempt to deallocate the old one.
3176 X : Elements_Access := Container.Elements;
3179 -- First we isolate the old internal array, and replace it in the
3180 -- container with the new internal array.
3182 Container.Elements := E;
3184 -- Container invariants have been restored, so it is now safe to
3185 -- attempt to deallocate the old internal array.
3190 end Reserve_Capacity;
3192 ----------------------
3193 -- Reverse_Elements --
3194 ----------------------
3196 procedure Reverse_Elements (Container : in out Vector) is
3198 if Container.Length <= 1 then
3202 -- The exception behavior for the vector container must match that for
3203 -- the list container, so we check for cursor tampering here (which will
3204 -- catch more things) instead of for element tampering (which will catch
3205 -- fewer things). It's true that the elements of this vector container
3206 -- could be safely moved around while (say) an iteration is taking place
3207 -- (iteration only increments the busy counter), and so technically
3208 -- all we would need here is a test for element tampering (indicated
3209 -- by the lock counter), that's simply an artifact of our array-based
3210 -- implementation. Logically Reverse_Elements requires a check for
3211 -- cursor tampering.
3213 if Container.Busy > 0 then
3214 raise Program_Error with
3215 "attempt to tamper with cursors (vector is busy)";
3221 E : Elements_Type renames Container.Elements.all;
3224 K := Index_Type'First;
3225 J := Container.Last;
3228 EK : constant Element_Type := E.EA (K);
3230 E.EA (K) := E.EA (J);
3238 end Reverse_Elements;
3244 function Reverse_Find
3245 (Container : Vector;
3246 Item : Element_Type;
3247 Position : Cursor := No_Element) return Cursor
3249 Last : Index_Type'Base;
3252 if Position.Container /= null
3253 and then Position.Container /= Container'Unrestricted_Access
3255 raise Program_Error with "Position cursor denotes wrong container";
3259 (if Position.Container = null or else Position.Index > Container.Last
3261 else Position.Index);
3263 -- Per AI05-0022, the container implementation is required to detect
3264 -- element tampering by a generic actual subprogram.
3267 B : Natural renames Container'Unrestricted_Access.Busy;
3268 L : Natural renames Container'Unrestricted_Access.Lock;
3270 Result : Index_Type'Base;
3277 for Indx in reverse Index_Type'First .. Last loop
3278 if Container.Elements.EA (Indx) = Item then
3287 if Result = No_Index then
3290 return Cursor'(Container
'Unrestricted_Access, Result
);
3302 ------------------------
3303 -- Reverse_Find_Index --
3304 ------------------------
3306 function Reverse_Find_Index
3307 (Container
: Vector
;
3308 Item
: Element_Type
;
3309 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
3311 B
: Natural renames Container
'Unrestricted_Access.Busy
;
3312 L
: Natural renames Container
'Unrestricted_Access.Lock
;
3314 Last
: constant Index_Type
'Base :=
3315 Index_Type
'Min (Container
.Last
, Index
);
3317 Result
: Index_Type
'Base;
3320 -- Per AI05-0022, the container implementation is required to detect
3321 -- element tampering by a generic actual subprogram.
3327 for Indx
in reverse Index_Type
'First .. Last
loop
3328 if Container
.Elements
.EA
(Indx
) = Item
then
3345 end Reverse_Find_Index
;
3347 ---------------------
3348 -- Reverse_Iterate --
3349 ---------------------
3351 procedure Reverse_Iterate
3352 (Container
: Vector
;
3353 Process
: not null access procedure (Position
: Cursor
))
3355 V
: Vector
renames Container
'Unrestricted_Access.all;
3356 B
: Natural renames V
.Busy
;
3362 for Indx
in reverse Index_Type
'First .. Container
.Last
loop
3363 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
3372 end Reverse_Iterate;
3378 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
3379 Count : constant Count_Type'Base := Container.Length - Length;
3382 -- Set_Length allows the user to set the length explicitly, instead
3383 -- of implicitly as a side-effect of deletion or insertion. If the
3384 -- requested length is less than the current length, this is equivalent
3385 -- to deleting items from the back end of the vector. If the requested
3386 -- length is greater than the current length, then this is equivalent
3387 -- to inserting "space" (nonce items) at the end.
3390 Container.Delete_Last (Count);
3392 elsif Container.Last >= Index_Type'Last then
3393 raise Constraint_Error with "vector is already at its maximum length";
3396 Container.Insert_Space (Container.Last + 1, -Count);
3404 procedure Swap (Container : in out Vector; I, J : Index_Type) is
3406 if I > Container.Last then
3407 raise Constraint_Error with "I index is out of range";
3410 if J > Container.Last then
3411 raise Constraint_Error with "J index is out of range";
3418 if Container.Lock > 0 then
3419 raise Program_Error with
3420 "attempt to tamper with elements (vector is locked)";
3424 EI_Copy : constant Element_Type := Container.Elements.EA (I);
3426 Container.Elements.EA (I) := Container.Elements.EA (J);
3427 Container.Elements.EA (J) := EI_Copy;
3431 procedure Swap (Container : in out Vector; I, J : Cursor) is
3433 if I.Container = null then
3434 raise Constraint_Error with "I cursor has no element";
3436 elsif J.Container = null then
3437 raise Constraint_Error with "J cursor has no element";
3439 elsif I.Container /= Container'Unrestricted_Access then
3440 raise Program_Error with "I cursor denotes wrong container";
3442 elsif J.Container /= Container'Unrestricted_Access then
3443 raise Program_Error with "J cursor denotes wrong container";
3446 Swap (Container, I.Index, J.Index);
3455 (Container : Vector;
3456 Index : Extended_Index) return Cursor
3459 if Index not in Index_Type'First .. Container.Last then
3462 return (Container'Unrestricted_Access, Index);
3470 function To_Index (Position : Cursor) return Extended_Index is
3472 if Position.Container = null then
3474 elsif Position.Index <= Position.Container.Last then
3475 return Position.Index;
3485 function To_Vector (Length : Count_Type) return Vector is
3486 Index : Count_Type'Base;
3487 Last : Index_Type'Base;
3488 Elements : Elements_Access;
3492 return Empty_Vector;
3495 -- We create a vector object with a capacity that matches the specified
3496 -- Length, but we do not allow the vector capacity (the length of the
3497 -- internal array) to exceed the number of values in Index_Type'Range
3498 -- (otherwise, there would be no way to refer to those components via an
3499 -- index). We must therefore check whether the specified Length would
3500 -- create a Last index value greater than Index_Type'Last.
3502 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
3504 -- We perform a two-part test. First we determine whether the
3505 -- computed Last value lies in the base range of the type, and then
3506 -- determine whether it lies in the range of the index (sub)type.
3508 -- Last must satisfy this relation:
3509 -- First + Length - 1 <= Last
3510 -- We regroup terms:
3511 -- First - 1 <= Last - Length
3512 -- Which can rewrite as:
3513 -- No_Index <= Last - Length
3515 if Index_Type
'Base'Last - Index_Type'Base (Length) < No_Index then
3516 raise Constraint_Error with "Length is out of range";
3519 -- We now know that the computed value of Last is within the base
3520 -- range of the type, so it is safe to compute its value:
3522 Last := No_Index + Index_Type'Base (Length);
3524 -- Finally we test whether the value is within the range of the
3525 -- generic actual index subtype:
3527 if Last > Index_Type'Last then
3528 raise Constraint_Error with "Length is out of range";
3531 elsif Index_Type'First <= 0 then
3533 -- Here we can compute Last directly, in the normal way. We know that
3534 -- No_Index is less than 0, so there is no danger of overflow when
3535 -- adding the (positive) value of Length.
3537 Index := Count_Type'Base (No_Index) + Length; -- Last
3539 if Index > Count_Type'Base (Index_Type'Last) then
3540 raise Constraint_Error with "Length is out of range";
3543 -- We know that the computed value (having type Count_Type) of Last
3544 -- is within the range of the generic actual index subtype, so it is
3545 -- safe to convert to Index_Type:
3547 Last := Index_Type'Base (Index);
3550 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3551 -- must test the length indirectly (by working backwards from the
3552 -- largest possible value of Last), in order to prevent overflow.
3554 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3556 if Index < Count_Type'Base (No_Index) then
3557 raise Constraint_Error with "Length is out of range";
3560 -- We have determined that the value of Length would not create a
3561 -- Last index value outside of the range of Index_Type, so we can now
3562 -- safely compute its value.
3564 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3567 Elements := new Elements_Type (Last);
3569 return Vector'(Controlled
with Elements
, Last
, 0, 0);
3573 (New_Item
: Element_Type
;
3574 Length
: Count_Type
) return Vector
3576 Index
: Count_Type
'Base;
3577 Last
: Index_Type
'Base;
3578 Elements
: Elements_Access
;
3582 return Empty_Vector
;
3585 -- We create a vector object with a capacity that matches the specified
3586 -- Length, but we do not allow the vector capacity (the length of the
3587 -- internal array) to exceed the number of values in Index_Type'Range
3588 -- (otherwise, there would be no way to refer to those components via an
3589 -- index). We must therefore check whether the specified Length would
3590 -- create a Last index value greater than Index_Type'Last.
3592 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3594 -- We perform a two-part test. First we determine whether the
3595 -- computed Last value lies in the base range of the type, and then
3596 -- determine whether it lies in the range of the index (sub)type.
3598 -- Last must satisfy this relation:
3599 -- First + Length - 1 <= Last
3600 -- We regroup terms:
3601 -- First - 1 <= Last - Length
3602 -- Which can rewrite as:
3603 -- No_Index <= Last - Length
3605 if Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
then
3606 raise Constraint_Error
with "Length is out of range";
3609 -- We now know that the computed value of Last is within the base
3610 -- range of the type, so it is safe to compute its value:
3612 Last
:= No_Index
+ Index_Type
'Base (Length
);
3614 -- Finally we test whether the value is within the range of the
3615 -- generic actual index subtype:
3617 if Last
> Index_Type
'Last then
3618 raise Constraint_Error
with "Length is out of range";
3621 elsif Index_Type
'First <= 0 then
3623 -- Here we can compute Last directly, in the normal way. We know that
3624 -- No_Index is less than 0, so there is no danger of overflow when
3625 -- adding the (positive) value of Length.
3627 Index
:= Count_Type
'Base (No_Index
) + Length
; -- same value as V.Last
3629 if Index
> Count_Type
'Base (Index_Type
'Last) then
3630 raise Constraint_Error
with "Length is out of range";
3633 -- We know that the computed value (having type Count_Type) of Last
3634 -- is within the range of the generic actual index subtype, so it is
3635 -- safe to convert to Index_Type:
3637 Last
:= Index_Type
'Base (Index
);
3640 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3641 -- must test the length indirectly (by working backwards from the
3642 -- largest possible value of Last), in order to prevent overflow.
3644 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
3646 if Index
< Count_Type
'Base (No_Index
) then
3647 raise Constraint_Error
with "Length is out of range";
3650 -- We have determined that the value of Length would not create a
3651 -- Last index value outside of the range of Index_Type, so we can now
3652 -- safely compute its value.
3654 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
3657 Elements
:= new Elements_Type
'(Last, EA => (others => New_Item));
3659 return Vector'(Controlled
with Elements
, Last
, 0, 0);
3662 --------------------
3663 -- Update_Element --
3664 --------------------
3666 procedure Update_Element
3667 (Container
: in out Vector
;
3669 Process
: not null access procedure (Element
: in out Element_Type
))
3671 B
: Natural renames Container
.Busy
;
3672 L
: Natural renames Container
.Lock
;
3675 if Index
> Container
.Last
then
3676 raise Constraint_Error
with "Index is out of range";
3683 Process
(Container
.Elements
.EA
(Index
));
3695 procedure Update_Element
3696 (Container
: in out Vector
;
3698 Process
: not null access procedure (Element
: in out Element_Type
))
3701 if Position
.Container
= null then
3702 raise Constraint_Error
with "Position cursor has no element";
3703 elsif Position
.Container
/= Container
'Unrestricted_Access then
3704 raise Program_Error
with "Position cursor denotes wrong container";
3706 Update_Element
(Container
, Position
.Index
, Process
);
3715 (Stream
: not null access Root_Stream_Type
'Class;
3719 Count_Type
'Base'Write (Stream, Length (Container));
3721 for J in Index_Type'First .. Container.Last loop
3722 Element_Type'Write (Stream, Container.Elements.EA (J));
3727 (Stream : not null access Root_Stream_Type'Class;
3731 raise Program_Error with "attempt to stream vector cursor";
3735 (Stream : not null access Root_Stream_Type'Class;
3736 Item : Reference_Type)
3739 raise Program_Error with "attempt to stream reference";
3743 (Stream : not null access Root_Stream_Type'Class;
3744 Item : Constant_Reference_Type)
3747 raise Program_Error with "attempt to stream reference";
3750 end Ada.Containers.Vectors;