1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ V E C T O R S --
9 -- Copyright (C) 2004-2012, 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
.Finalization
; use Ada
.Finalization
;
33 with System
; use type System
.Address
;
35 package body Ada
.Containers
.Bounded_Vectors
is
37 type Iterator
is new Limited_Controlled
and
38 Vector_Iterator_Interfaces
.Reversible_Iterator
with
40 Container
: Vector_Access
;
41 Index
: Index_Type
'Base;
44 overriding
procedure Finalize
(Object
: in out Iterator
);
46 overriding
function First
(Object
: Iterator
) return Cursor
;
47 overriding
function Last
(Object
: Iterator
) return Cursor
;
49 overriding
function Next
51 Position
: Cursor
) return Cursor
;
53 overriding
function Previous
55 Position
: Cursor
) return Cursor
;
57 -----------------------
58 -- Local Subprograms --
59 -----------------------
61 function To_Array_Index
(Index
: Index_Type
'Base) return Count_Type
'Base;
67 function "&" (Left
, Right
: Vector
) return Vector
is
68 LN
: constant Count_Type
:= Length
(Left
);
69 RN
: constant Count_Type
:= Length
(Right
);
70 N
: Count_Type
'Base; -- length of result
71 J
: Count_Type
'Base; -- for computing intermediate index values
72 Last
: Index_Type
'Base; -- Last index of result
75 -- We decide that the capacity of the result is the sum of the lengths
76 -- of the vector parameters. We could decide to make it larger, but we
77 -- have no basis for knowing how much larger, so we just allocate the
78 -- minimum amount of storage.
80 -- Here we handle the easy cases first, when one of the vector
81 -- parameters is empty. (We say "easy" because there's nothing to
82 -- compute, that can potentially overflow.)
89 return Vector
'(Capacity => RN,
90 Elements => Right.Elements (1 .. RN),
96 return Vector'(Capacity
=> LN
,
97 Elements
=> Left
.Elements
(1 .. LN
),
102 -- Neither of the vector parameters is empty, so must compute the length
103 -- of the result vector and its last index. (This is the harder case,
104 -- because our computations must avoid overflow.)
106 -- There are two constraints we need to satisfy. The first constraint is
107 -- that a container cannot have more than Count_Type'Last elements, so
108 -- we must check the sum of the combined lengths. Note that we cannot
109 -- simply add the lengths, because of the possibility of overflow.
111 if LN
> Count_Type
'Last - RN
then
112 raise Constraint_Error
with "new length is out of range";
115 -- It is now safe compute the length of the new vector, without fear of
120 -- The second constraint is that the new Last index value cannot
121 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
122 -- Count_Type'Base as the type for intermediate values.
124 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
125 -- We perform a two-part test. First we determine whether the
126 -- computed Last value lies in the base range of the type, and then
127 -- determine whether it lies in the range of the index (sub)type.
129 -- Last must satisfy this relation:
130 -- First + Length - 1 <= Last
132 -- First - 1 <= Last - Length
133 -- Which can rewrite as:
134 -- No_Index <= Last - Length
136 if Index_Type'Base'Last
- Index_Type
'Base (N
) < No_Index
then
137 raise Constraint_Error
with "new length is out of range";
140 -- We now know that the computed value of Last is within the base
141 -- range of the type, so it is safe to compute its value:
143 Last
:= No_Index
+ Index_Type
'Base (N
);
145 -- Finally we test whether the value is within the range of the
146 -- generic actual index subtype:
148 if Last
> Index_Type
'Last then
149 raise Constraint_Error
with "new length is out of range";
152 elsif Index_Type
'First <= 0 then
153 -- Here we can compute Last directly, in the normal way. We know that
154 -- No_Index is less than 0, so there is no danger of overflow when
155 -- adding the (positive) value of length.
157 J
:= Count_Type
'Base (No_Index
) + N
; -- Last
159 if J
> Count_Type
'Base (Index_Type
'Last) then
160 raise Constraint_Error
with "new length is out of range";
163 -- We know that the computed value (having type Count_Type) of Last
164 -- is within the range of the generic actual index subtype, so it is
165 -- safe to convert to Index_Type:
167 Last
:= Index_Type
'Base (J
);
170 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
171 -- must test the length indirectly (by working backwards from the
172 -- largest possible value of Last), in order to prevent overflow.
174 J
:= Count_Type
'Base (Index_Type
'Last) - N
; -- No_Index
176 if J
< Count_Type
'Base (No_Index
) then
177 raise Constraint_Error
with "new length is out of range";
180 -- We have determined that the result length would not create a Last
181 -- index value outside of the range of Index_Type, so we can now
182 -- safely compute its value.
184 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + N
);
188 LE
: Elements_Array
renames Left
.Elements
(1 .. LN
);
189 RE
: Elements_Array
renames Right
.Elements
(1 .. RN
);
192 return Vector
'(Capacity => N,
199 function "&" (Left : Vector; Right : Element_Type) return Vector is
200 LN : constant Count_Type := Length (Left);
203 -- We decide that the capacity of the result is the sum of the lengths
204 -- of the parameters. We could decide to make it larger, but we have no
205 -- basis for knowing how much larger, so we just allocate the minimum
206 -- amount of storage.
208 -- We must compute the length of the result vector and its last index,
209 -- but in such a way that overflow is avoided. We must satisfy two
210 -- constraints: the new length cannot exceed Count_Type'Last, and the
211 -- new Last index cannot exceed Index_Type'Last.
213 if LN = Count_Type'Last then
214 raise Constraint_Error with "new length is out of range";
217 if Left.Last >= Index_Type'Last then
218 raise Constraint_Error with "new length is out of range";
221 return Vector'(Capacity
=> LN
+ 1,
222 Elements
=> Left
.Elements
(1 .. LN
) & Right
,
223 Last
=> Left
.Last
+ 1,
227 function "&" (Left
: Element_Type
; Right
: Vector
) return Vector
is
228 RN
: constant Count_Type
:= Length
(Right
);
231 -- We decide that the capacity of the result is the sum of the lengths
232 -- of the parameters. We could decide to make it larger, but we have no
233 -- basis for knowing how much larger, so we just allocate the minimum
234 -- amount of storage.
236 -- We compute the length of the result vector and its last index, but in
237 -- such a way that overflow is avoided. We must satisfy two constraints:
238 -- the new length cannot exceed Count_Type'Last, and the new Last index
239 -- cannot exceed Index_Type'Last.
241 if RN
= Count_Type
'Last then
242 raise Constraint_Error
with "new length is out of range";
245 if Right
.Last
>= Index_Type
'Last then
246 raise Constraint_Error
with "new length is out of range";
249 return Vector
'(Capacity => 1 + RN,
250 Elements => Left & Right.Elements (1 .. RN),
251 Last => Right.Last + 1,
255 function "&" (Left, Right : Element_Type) 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 -- We must compute the length of the result vector and its last index,
263 -- but in such a way that overflow is avoided. We must satisfy two
264 -- constraints: the new length cannot exceed Count_Type'Last (here, we
265 -- know that that condition is satisfied), and the new Last index cannot
266 -- exceed Index_Type'Last.
268 if Index_Type'First >= Index_Type'Last then
269 raise Constraint_Error with "new length is out of range";
272 return Vector'(Capacity
=> 2,
273 Elements
=> (Left
, Right
),
274 Last
=> Index_Type
'First + 1,
282 overriding
function "=" (Left
, Right
: Vector
) return Boolean is
284 if Left
'Address = Right
'Address then
288 if Left
.Last
/= Right
.Last
then
292 for J
in Count_Type
range 1 .. Left
.Length
loop
293 if Left
.Elements
(J
) /= Right
.Elements
(J
) then
305 procedure Assign
(Target
: in out Vector
; Source
: Vector
) is
307 if Target
'Address = Source
'Address then
311 if Target
.Capacity
< Source
.Length
then
312 raise Capacity_Error
-- ???
313 with "Target capacity is less than Source length";
318 Target
.Elements
(1 .. Source
.Length
) :=
319 Source
.Elements
(1 .. Source
.Length
);
321 Target
.Last
:= Source
.Last
;
328 procedure Append
(Container
: in out Vector
; New_Item
: Vector
) is
330 if New_Item
.Is_Empty
then
334 if Container
.Last
>= Index_Type
'Last then
335 raise Constraint_Error
with "vector is already at its maximum length";
338 Container
.Insert
(Container
.Last
+ 1, New_Item
);
342 (Container
: in out Vector
;
343 New_Item
: Element_Type
;
344 Count
: Count_Type
:= 1)
351 if Container
.Last
>= Index_Type
'Last then
352 raise Constraint_Error
with "vector is already at its maximum length";
355 Container
.Insert
(Container
.Last
+ 1, New_Item
, Count
);
362 function Capacity
(Container
: Vector
) return Count_Type
is
364 return Container
.Elements
'Length;
371 procedure Clear
(Container
: in out Vector
) is
373 if Container
.Busy
> 0 then
374 raise Program_Error
with
375 "attempt to tamper with cursors (vector is busy)";
378 Container
.Last
:= No_Index
;
381 ------------------------
382 -- Constant_Reference --
383 ------------------------
385 function Constant_Reference
386 (Container
: aliased Vector
;
387 Position
: Cursor
) return Constant_Reference_Type
390 if Position
.Container
= null then
391 raise Constraint_Error
with "Position cursor has no element";
394 if Position
.Container
/= Container
'Unrestricted_Access then
395 raise Program_Error
with "Position cursor denotes wrong container";
398 if Position
.Index
> Position
.Container
.Last
then
399 raise Constraint_Error
with "Position cursor is out of range";
403 A
: Elements_Array
renames Container
.Elements
;
404 I
: constant Count_Type
:= To_Array_Index
(Position
.Index
);
406 return (Element
=> A
(I
)'Access);
408 end Constant_Reference
;
410 function Constant_Reference
411 (Container
: aliased Vector
;
412 Index
: Index_Type
) return Constant_Reference_Type
415 if Index
> Container
.Last
then
416 raise Constraint_Error
with "Index is out of range";
420 A
: Elements_Array
renames Container
.Elements
;
421 I
: constant Count_Type
:= To_Array_Index
(Index
);
423 return (Element
=> A
(I
)'Access);
425 end Constant_Reference
;
433 Item
: Element_Type
) return Boolean
436 return Find_Index
(Container
, Item
) /= No_Index
;
445 Capacity
: Count_Type
:= 0) return Vector
453 elsif Capacity
>= Source
.Length
then
458 with "Requested capacity is less than Source length";
461 return Target
: Vector
(C
) do
462 Target
.Elements
(1 .. Source
.Length
) :=
463 Source
.Elements
(1 .. Source
.Length
);
465 Target
.Last
:= Source
.Last
;
474 (Container
: in out Vector
;
475 Index
: Extended_Index
;
476 Count
: Count_Type
:= 1)
478 Old_Last
: constant Index_Type
'Base := Container
.Last
;
479 Old_Len
: constant Count_Type
:= Container
.Length
;
480 New_Last
: Index_Type
'Base;
481 Count2
: Count_Type
'Base; -- count of items from Index to Old_Last
482 Off
: Count_Type
'Base; -- Index expressed as offset from IT'First
485 -- Delete removes items from the vector, the number of which is the
486 -- minimum of the specified Count and the items (if any) that exist from
487 -- Index to Container.Last. There are no constraints on the specified
488 -- value of Count (it can be larger than what's available at this
489 -- position in the vector, for example), but there are constraints on
490 -- the allowed values of the Index.
492 -- As a precondition on the generic actual Index_Type, the base type
493 -- must include Index_Type'Pred (Index_Type'First); this is the value
494 -- that Container.Last assumes when the vector is empty. However, we do
495 -- not allow that as the value for Index when specifying which items
496 -- should be deleted, so we must manually check. (That the user is
497 -- allowed to specify the value at all here is a consequence of the
498 -- declaration of the Extended_Index subtype, which includes the values
499 -- in the base range that immediately precede and immediately follow the
500 -- values in the Index_Type.)
502 if Index
< Index_Type
'First then
503 raise Constraint_Error
with "Index is out of range (too small)";
506 -- We do allow a value greater than Container.Last to be specified as
507 -- the Index, but only if it's immediately greater. This allows the
508 -- corner case of deleting no items from the back end of the vector to
509 -- be treated as a no-op. (It is assumed that specifying an index value
510 -- greater than Last + 1 indicates some deeper flaw in the caller's
511 -- algorithm, so that case is treated as a proper error.)
513 if Index
> Old_Last
then
514 if Index
> Old_Last
+ 1 then
515 raise Constraint_Error
with "Index is out of range (too large)";
521 -- Here and elsewhere we treat deleting 0 items from the container as a
522 -- no-op, even when the container is busy, so we simply return.
528 -- The tampering bits exist to prevent an item from being deleted (or
529 -- otherwise harmfully manipulated) while it is being visited. Query,
530 -- Update, and Iterate increment the busy count on entry, and decrement
531 -- the count on exit. Delete checks the count to determine whether it is
532 -- being called while the associated callback procedure is executing.
534 if Container
.Busy
> 0 then
535 raise Program_Error
with
536 "attempt to tamper with cursors (vector is busy)";
539 -- We first calculate what's available for deletion starting at
540 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
541 -- Count_Type'Base as the type for intermediate values. (See function
542 -- Length for more information.)
544 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
545 Count2
:= Count_Type
'Base (Old_Last
) - Count_Type
'Base (Index
) + 1;
548 Count2
:= Count_Type
'Base (Old_Last
- Index
+ 1);
551 -- If more elements are requested (Count) for deletion than are
552 -- available (Count2) for deletion beginning at Index, then everything
553 -- from Index is deleted. There are no elements to slide down, and so
554 -- all we need to do is set the value of Container.Last.
556 if Count
>= Count2
then
557 Container
.Last
:= Index
- 1;
561 -- There are some elements aren't being deleted (the requested count was
562 -- less than the available count), so we must slide them down to
563 -- Index. We first calculate the index values of the respective array
564 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
565 -- type for intermediate calculations.
567 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
568 Off := Count_Type'Base (Index - Index_Type'First);
569 New_Last := Old_Last - Index_Type'Base (Count);
572 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
573 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
576 -- The array index values for each slice have already been determined,
577 -- so we just slide down to Index the elements that weren't deleted.
580 EA : Elements_Array renames Container.Elements;
581 Idx : constant Count_Type := EA'First + Off;
584 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
585 Container.Last := New_Last;
590 (Container : in out Vector;
591 Position : in out Cursor;
592 Count : Count_Type := 1)
594 pragma Warnings (Off, Position);
597 if Position.Container = null then
598 raise Constraint_Error with "Position cursor has no element";
601 if Position.Container /= Container'Unrestricted_Access then
602 raise Program_Error with "Position cursor denotes wrong container";
605 if Position.Index > Container.Last then
606 raise Program_Error with "Position index is out of range";
609 Delete (Container, Position.Index, Count);
610 Position := No_Element;
617 procedure Delete_First
618 (Container : in out Vector;
619 Count : Count_Type := 1)
626 if Count >= Length (Container) then
631 Delete (Container, Index_Type'First, Count);
638 procedure Delete_Last
639 (Container : in out Vector;
640 Count : Count_Type := 1)
643 -- It is not permitted to delete items while the container is busy (for
644 -- example, we're in the middle of a passive iteration). However, we
645 -- always treat deleting 0 items as a no-op, even when we're busy, so we
646 -- simply return without checking.
652 -- The tampering bits exist to prevent an item from being deleted (or
653 -- otherwise harmfully manipulated) while it is being visited. Query,
654 -- Update, and Iterate increment the busy count on entry, and decrement
655 -- the count on exit. Delete_Last checks the count to determine whether
656 -- it is being called while the associated callback procedure is
659 if Container.Busy > 0 then
660 raise Program_Error with
661 "attempt to tamper with cursors (vector is busy)";
664 -- There is no restriction on how large Count can be when deleting
665 -- items. If it is equal or greater than the current length, then this
666 -- is equivalent to clearing the vector. (In particular, there's no need
667 -- for us to actually calculate the new value for Last.)
669 -- If the requested count is less than the current length, then we must
670 -- calculate the new value for Last. For the type we use the widest of
671 -- Index_Type'Base and Count_Type'Base for the intermediate values of
672 -- our calculation. (See the comments in Length for more information.)
674 if Count >= Container.Length then
675 Container.Last := No_Index;
677 elsif Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
678 Container
.Last
:= Container
.Last
- Index_Type
'Base (Count
);
682 Index_Type
'Base (Count_Type
'Base (Container
.Last
) - Count
);
692 Index
: Index_Type
) return Element_Type
695 if Index
> Container
.Last
then
696 raise Constraint_Error
with "Index is out of range";
698 return Container
.Elements
(To_Array_Index
(Index
));
702 function Element
(Position
: Cursor
) return Element_Type
is
704 if Position
.Container
= null then
705 raise Constraint_Error
with "Position cursor has no element";
707 return Position
.Container
.Element
(Position
.Index
);
715 procedure Finalize
(Object
: in out Iterator
) is
716 B
: Natural renames Object
.Container
.Busy
;
728 Position
: Cursor
:= No_Element
) return Cursor
731 if Position
.Container
/= null then
732 if Position
.Container
/= Container
'Unrestricted_Access then
733 raise Program_Error
with "Position cursor denotes wrong container";
736 if Position
.Index
> Container
.Last
then
737 raise Program_Error
with "Position index is out of range";
741 for J
in Position
.Index
.. Container
.Last
loop
742 if Container
.Elements
(To_Array_Index
(J
)) = Item
then
743 return (Container
'Unrestricted_Access, J
);
757 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
760 for Indx
in Index
.. Container
.Last
loop
761 if Container
.Elements
(To_Array_Index
(Indx
)) = Item
then
773 function First
(Container
: Vector
) return Cursor
is
775 if Is_Empty
(Container
) then
778 return (Container
'Unrestricted_Access, Index_Type
'First);
782 function First
(Object
: Iterator
) return Cursor
is
784 -- The value of the iterator object's Index component influences the
785 -- behavior of the First (and Last) selector function.
787 -- When the Index component is No_Index, this means the iterator
788 -- object was constructed without a start expression, in which case the
789 -- (forward) iteration starts from the (logical) beginning of the entire
790 -- sequence of items (corresponding to Container.First, for a forward
793 -- Otherwise, this is iteration over a partial sequence of items.
794 -- When the Index component isn't No_Index, the iterator object was
795 -- constructed with a start expression, that specifies the position
796 -- from which the (forward) partial iteration begins.
798 if Object
.Index
= No_Index
then
799 return First
(Object
.Container
.all);
801 return Cursor
'(Object.Container, Object.Index);
809 function First_Element (Container : Vector) return Element_Type is
811 if Container.Last = No_Index then
812 raise Constraint_Error with "Container is empty";
814 return Container.Elements (To_Array_Index (Index_Type'First));
822 function First_Index (Container : Vector) return Index_Type is
823 pragma Unreferenced (Container);
825 return Index_Type'First;
828 ---------------------
829 -- Generic_Sorting --
830 ---------------------
832 package body Generic_Sorting is
838 function Is_Sorted (Container : Vector) return Boolean is
840 if Container.Last <= Index_Type'First then
845 EA : Elements_Array renames Container.Elements;
847 for J in 1 .. Container.Length - 1 loop
848 if EA (J + 1) < EA (J) then
861 procedure Merge (Target, Source : in out Vector) is
866 -- The semantics of Merge changed slightly per AI05-0021. It was
867 -- originally the case that if Target and Source denoted the same
868 -- container object, then the GNAT implementation of Merge did
869 -- nothing. However, it was argued that RM05 did not precisely
870 -- specify the semantics for this corner case. The decision of the
871 -- ARG was that if Target and Source denote the same non-empty
872 -- container object, then Program_Error is raised.
874 if Source.Is_Empty then
878 if Target'Address = Source'Address then
879 raise Program_Error with
880 "Target and Source denote same non-empty container";
883 if Target.Is_Empty then
884 Move (Target => Target, Source => Source);
888 if Source.Busy > 0 then
889 raise Program_Error with
890 "attempt to tamper with cursors (vector is busy)";
894 Target.Set_Length (I + Source.Length);
897 TA : Elements_Array renames Target.Elements;
898 SA : Elements_Array renames Source.Elements;
902 while not Source.Is_Empty loop
903 pragma Assert (Source.Length <= 1
904 or else not (SA (Source.Length) <
905 SA (Source.Length - 1)));
908 TA (1 .. J) := SA (1 .. Source.Length);
909 Source.Last := No_Index;
913 pragma Assert (I <= 1
914 or else not (TA (I) < TA (I - 1)));
916 if SA (Source.Length) < TA (I) then
921 TA (J) := SA (Source.Length);
922 Source.Last := Source.Last - 1;
934 procedure Sort (Container : in out Vector) is
936 new Generic_Array_Sort
937 (Index_Type => Count_Type,
938 Element_Type => Element_Type,
939 Array_Type => Elements_Array,
943 if Container.Last <= Index_Type'First then
947 -- The exception behavior for the vector container must match that
948 -- for the list container, so we check for cursor tampering here
949 -- (which will catch more things) instead of for element tampering
950 -- (which will catch fewer things). It's true that the elements of
951 -- this vector container could be safely moved around while (say) an
952 -- iteration is taking place (iteration only increments the busy
953 -- counter), and so technically all we would need here is a test for
954 -- element tampering (indicated by the lock counter), that's simply
955 -- an artifact of our array-based implementation. Logically Sort
956 -- requires a check for cursor tampering.
958 if Container.Busy > 0 then
959 raise Program_Error with
960 "attempt to tamper with cursors (vector is busy)";
963 Sort (Container.Elements (1 .. Container.Length));
972 function Has_Element (Position : Cursor) return Boolean is
974 if Position.Container = null then
978 return Position.Index <= Position.Container.Last;
986 (Container : in out Vector;
987 Before : Extended_Index;
988 New_Item : Element_Type;
989 Count : Count_Type := 1)
991 EA : Elements_Array renames Container.Elements;
992 Old_Length : constant Count_Type := Container.Length;
994 Max_Length : Count_Type'Base; -- determined from range of Index_Type
995 New_Length : Count_Type'Base; -- sum of current length and Count
997 Index : Index_Type'Base; -- scratch for intermediate values
998 J : Count_Type'Base; -- scratch
1001 -- As a precondition on the generic actual Index_Type, the base type
1002 -- must include Index_Type'Pred (Index_Type'First); this is the value
1003 -- that Container.Last assumes when the vector is empty. However, we do
1004 -- not allow that as the value for Index when specifying where the new
1005 -- items should be inserted, so we must manually check. (That the user
1006 -- is allowed to specify the value at all here is a consequence of the
1007 -- declaration of the Extended_Index subtype, which includes the values
1008 -- in the base range that immediately precede and immediately follow the
1009 -- values in the Index_Type.)
1011 if Before < Index_Type'First then
1012 raise Constraint_Error with
1013 "Before index is out of range (too small)";
1016 -- We do allow a value greater than Container.Last to be specified as
1017 -- the Index, but only if it's immediately greater. This allows for the
1018 -- case of appending items to the back end of the vector. (It is assumed
1019 -- that specifying an index value greater than Last + 1 indicates some
1020 -- deeper flaw in the caller's algorithm, so that case is treated as a
1023 if Before > Container.Last
1024 and then Before > Container.Last + 1
1026 raise Constraint_Error with
1027 "Before index is out of range (too large)";
1030 -- We treat inserting 0 items into the container as a no-op, even when
1031 -- the container is busy, so we simply return.
1037 -- There are two constraints we need to satisfy. The first constraint is
1038 -- that a container cannot have more than Count_Type'Last elements, so
1039 -- we must check the sum of the current length and the insertion
1040 -- count. Note that we cannot simply add these values, because of the
1041 -- possibility of overflow.
1043 if Old_Length > Count_Type'Last - Count then
1044 raise Constraint_Error with "Count is out of range";
1047 -- It is now safe compute the length of the new vector, without fear of
1050 New_Length := Old_Length + Count;
1052 -- The second constraint is that the new Last index value cannot exceed
1053 -- Index_Type'Last. In each branch below, we calculate the maximum
1054 -- length (computed from the range of values in Index_Type), and then
1055 -- compare the new length to the maximum length. If the new length is
1056 -- acceptable, then we compute the new last index from that.
1058 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1059 -- We have to handle the case when there might be more values in the
1060 -- range of Index_Type than in the range of Count_Type.
1062 if Index_Type
'First <= 0 then
1063 -- We know that No_Index (the same as Index_Type'First - 1) is
1064 -- less than 0, so it is safe to compute the following sum without
1065 -- fear of overflow.
1067 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1069 if Index
<= Index_Type
'Last then
1070 -- We have determined that range of Index_Type has at least as
1071 -- many values as in Count_Type, so Count_Type'Last is the
1072 -- maximum number of items that are allowed.
1074 Max_Length
:= Count_Type
'Last;
1077 -- The range of Index_Type has fewer values than in Count_Type,
1078 -- so the maximum number of items is computed from the range of
1081 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1085 -- No_Index is equal or greater than 0, so we can safely compute
1086 -- the difference without fear of overflow (which we would have to
1087 -- worry about if No_Index were less than 0, but that case is
1090 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1093 elsif Index_Type
'First <= 0 then
1094 -- We know that No_Index (the same as Index_Type'First - 1) is less
1095 -- than 0, so it is safe to compute the following sum without fear of
1098 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
1100 if J
<= Count_Type
'Base (Index_Type
'Last) then
1101 -- We have determined that range of Index_Type has at least as
1102 -- many values as in Count_Type, so Count_Type'Last is the maximum
1103 -- number of items that are allowed.
1105 Max_Length
:= Count_Type
'Last;
1108 -- The range of Index_Type has fewer values than Count_Type does,
1109 -- so the maximum number of items is computed from the range of
1113 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1117 -- No_Index is equal or greater than 0, so we can safely compute the
1118 -- difference without fear of overflow (which we would have to worry
1119 -- about if No_Index were less than 0, but that case is handled
1123 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1126 -- We have just computed the maximum length (number of items). We must
1127 -- now compare the requested length to the maximum length, as we do not
1128 -- allow a vector expand beyond the maximum (because that would create
1129 -- an internal array with a last index value greater than
1130 -- Index_Type'Last, with no way to index those elements).
1132 if New_Length
> Max_Length
then
1133 raise Constraint_Error
with "Count is out of range";
1136 -- The tampering bits exist to prevent an item from being harmfully
1137 -- manipulated while it is being visited. Query, Update, and Iterate
1138 -- increment the busy count on entry, and decrement the count on
1139 -- exit. Insert checks the count to determine whether it is being called
1140 -- while the associated callback procedure is executing.
1142 if Container
.Busy
> 0 then
1143 raise Program_Error
with
1144 "attempt to tamper with cursors (vector is busy)";
1147 if New_Length
> Container
.Capacity
then
1148 raise Capacity_Error
with "New length is larger than capacity";
1151 J
:= To_Array_Index
(Before
);
1153 if Before
> Container
.Last
then
1154 -- The new items are being appended to the vector, so no
1155 -- sliding of existing elements is required.
1157 EA
(J
.. New_Length
) := (others => New_Item
);
1160 -- The new items are being inserted before some existing
1161 -- elements, so we must slide the existing elements up to their
1164 EA
(J
+ Count
.. New_Length
) := EA
(J
.. Old_Length
);
1165 EA
(J
.. J
+ Count
- 1) := (others => New_Item
);
1168 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1169 Container.Last := No_Index + Index_Type'Base (New_Length);
1173 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1178 (Container : in out Vector;
1179 Before : Extended_Index;
1182 N : constant Count_Type := Length (New_Item);
1183 B : Count_Type; -- index Before converted to Count_Type
1186 -- Use Insert_Space to create the "hole" (the destination slice) into
1187 -- which we copy the source items.
1189 Insert_Space (Container, Before, Count => N);
1192 -- There's nothing else to do here (vetting of parameters was
1193 -- performed already in Insert_Space), so we simply return.
1198 B := To_Array_Index (Before);
1200 if Container'Address /= New_Item'Address then
1201 -- This is the simple case. New_Item denotes an object different
1202 -- from Container, so there's nothing special we need to do to copy
1203 -- the source items to their destination, because all of the source
1204 -- items are contiguous.
1206 Container.Elements (B .. B + N - 1) := New_Item.Elements (1 .. N);
1210 -- We refer to array index value Before + N - 1 as J. This is the last
1211 -- index value of the destination slice.
1213 -- New_Item denotes the same object as Container, so an insertion has
1214 -- potentially split the source items. The destination is always the
1215 -- range [Before, J], but the source is [Index_Type'First, Before) and
1216 -- (J, Container.Last]. We perform the copy in two steps, using each of
1217 -- the two slices of the source items.
1220 subtype Src_Index_Subtype is Count_Type'Base range 1 .. B - 1;
1222 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1225 -- We first copy the source items that precede the space we
1226 -- inserted. (If Before equals Index_Type'First, then this first
1227 -- source slice will be empty, which is harmless.)
1229 Container.Elements (B .. B + Src'Length - 1) := Src;
1233 subtype Src_Index_Subtype is Count_Type'Base range
1234 B + N .. Container.Length;
1236 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1239 -- We next copy the source items that follow the space we inserted.
1241 Container.Elements (B + N - Src'Length .. B + N - 1) := Src;
1246 (Container : in out Vector;
1250 Index : Index_Type'Base;
1253 if Before.Container /= null
1254 and then Before.Container /= Container'Unchecked_Access
1256 raise Program_Error with "Before cursor denotes wrong container";
1259 if Is_Empty (New_Item) then
1263 if Before.Container = null
1264 or else Before.Index > Container.Last
1266 if Container.Last = Index_Type'Last then
1267 raise Constraint_Error with
1268 "vector is already at its maximum length";
1271 Index := Container.Last + 1;
1274 Index := Before.Index;
1277 Insert (Container, Index, New_Item);
1281 (Container : in out Vector;
1284 Position : out Cursor)
1286 Index : Index_Type'Base;
1289 if Before.Container /= null
1290 and then Before.Container /= Container'Unchecked_Access
1292 raise Program_Error with "Before cursor denotes wrong container";
1295 if Is_Empty (New_Item) then
1296 if Before.Container = null
1297 or else Before.Index > Container.Last
1299 Position := No_Element;
1301 Position := (Container'Unchecked_Access, Before.Index);
1307 if Before.Container = null
1308 or else Before.Index > Container.Last
1310 if Container.Last = Index_Type'Last then
1311 raise Constraint_Error with
1312 "vector is already at its maximum length";
1315 Index := Container.Last + 1;
1318 Index := Before.Index;
1321 Insert (Container, Index, New_Item);
1323 Position := Cursor'(Container
'Unchecked_Access, Index
);
1327 (Container
: in out Vector
;
1329 New_Item
: Element_Type
;
1330 Count
: Count_Type
:= 1)
1332 Index
: Index_Type
'Base;
1335 if Before
.Container
/= null
1336 and then Before
.Container
/= Container
'Unchecked_Access
1338 raise Program_Error
with "Before cursor denotes wrong container";
1345 if Before
.Container
= null
1346 or else Before
.Index
> Container
.Last
1348 if Container
.Last
= Index_Type
'Last then
1349 raise Constraint_Error
with
1350 "vector is already at its maximum length";
1353 Index
:= Container
.Last
+ 1;
1356 Index
:= Before
.Index
;
1359 Insert
(Container
, Index
, New_Item
, Count
);
1363 (Container
: in out Vector
;
1365 New_Item
: Element_Type
;
1366 Position
: out Cursor
;
1367 Count
: Count_Type
:= 1)
1369 Index
: Index_Type
'Base;
1372 if Before
.Container
/= null
1373 and then Before
.Container
/= Container
'Unchecked_Access
1375 raise Program_Error
with "Before cursor denotes wrong container";
1379 if Before
.Container
= null
1380 or else Before
.Index
> Container
.Last
1382 Position
:= No_Element
;
1384 Position
:= (Container
'Unchecked_Access, Before
.Index
);
1390 if Before
.Container
= null
1391 or else Before
.Index
> Container
.Last
1393 if Container
.Last
= Index_Type
'Last then
1394 raise Constraint_Error
with
1395 "vector is already at its maximum length";
1398 Index
:= Container
.Last
+ 1;
1401 Index
:= Before
.Index
;
1404 Insert
(Container
, Index
, New_Item
, Count
);
1406 Position
:= Cursor
'(Container'Unchecked_Access, Index);
1410 (Container : in out Vector;
1411 Before : Extended_Index;
1412 Count : Count_Type := 1)
1414 New_Item : Element_Type; -- Default-initialized value
1415 pragma Warnings (Off, New_Item);
1418 Insert (Container, Before, New_Item, Count);
1422 (Container : in out Vector;
1424 Position : out Cursor;
1425 Count : Count_Type := 1)
1427 New_Item : Element_Type; -- Default-initialized value
1428 pragma Warnings (Off, New_Item);
1431 Insert (Container, Before, New_Item, Position, Count);
1438 procedure Insert_Space
1439 (Container : in out Vector;
1440 Before : Extended_Index;
1441 Count : Count_Type := 1)
1443 EA : Elements_Array renames Container.Elements;
1444 Old_Length : constant Count_Type := Container.Length;
1446 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1447 New_Length : Count_Type'Base; -- sum of current length and Count
1449 Index : Index_Type'Base; -- scratch for intermediate values
1450 J : Count_Type'Base; -- scratch
1453 -- As a precondition on the generic actual Index_Type, the base type
1454 -- must include Index_Type'Pred (Index_Type'First); this is the value
1455 -- that Container.Last assumes when the vector is empty. However, we do
1456 -- not allow that as the value for Index when specifying where the new
1457 -- items should be inserted, so we must manually check. (That the user
1458 -- is allowed to specify the value at all here is a consequence of the
1459 -- declaration of the Extended_Index subtype, which includes the values
1460 -- in the base range that immediately precede and immediately follow the
1461 -- values in the Index_Type.)
1463 if Before < Index_Type'First then
1464 raise Constraint_Error with
1465 "Before index is out of range (too small)";
1468 -- We do allow a value greater than Container.Last to be specified as
1469 -- the Index, but only if it's immediately greater. This allows for the
1470 -- case of appending items to the back end of the vector. (It is assumed
1471 -- that specifying an index value greater than Last + 1 indicates some
1472 -- deeper flaw in the caller's algorithm, so that case is treated as a
1475 if Before > Container.Last
1476 and then Before > Container.Last + 1
1478 raise Constraint_Error with
1479 "Before index is out of range (too large)";
1482 -- We treat inserting 0 items into the container as a no-op, even when
1483 -- the container is busy, so we simply return.
1489 -- There are two constraints we need to satisfy. The first constraint is
1490 -- that a container cannot have more than Count_Type'Last elements, so
1491 -- we must check the sum of the current length and the insertion count.
1492 -- Note that we cannot simply add these values, because of the
1493 -- possibility of overflow.
1495 if Old_Length > Count_Type'Last - Count then
1496 raise Constraint_Error with "Count is out of range";
1499 -- It is now safe compute the length of the new vector, without fear of
1502 New_Length := Old_Length + Count;
1504 -- The second constraint is that the new Last index value cannot exceed
1505 -- Index_Type'Last. In each branch below, we calculate the maximum
1506 -- length (computed from the range of values in Index_Type), and then
1507 -- compare the new length to the maximum length. If the new length is
1508 -- acceptable, then we compute the new last index from that.
1510 if Index_Type'Base'Last
>= Count_Type
'Pos (Count_Type
'Last) then
1511 -- We have to handle the case when there might be more values in the
1512 -- range of Index_Type than in the range of Count_Type.
1514 if Index_Type
'First <= 0 then
1515 -- We know that No_Index (the same as Index_Type'First - 1) is
1516 -- less than 0, so it is safe to compute the following sum without
1517 -- fear of overflow.
1519 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1521 if Index
<= Index_Type
'Last then
1522 -- We have determined that range of Index_Type has at least as
1523 -- many values as in Count_Type, so Count_Type'Last is the
1524 -- maximum number of items that are allowed.
1526 Max_Length
:= Count_Type
'Last;
1529 -- The range of Index_Type has fewer values than in Count_Type,
1530 -- so the maximum number of items is computed from the range of
1533 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1537 -- No_Index is equal or greater than 0, so we can safely compute
1538 -- the difference without fear of overflow (which we would have to
1539 -- worry about if No_Index were less than 0, but that case is
1542 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1545 elsif Index_Type
'First <= 0 then
1546 -- We know that No_Index (the same as Index_Type'First - 1) is less
1547 -- than 0, so it is safe to compute the following sum without fear of
1550 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
1552 if J
<= Count_Type
'Base (Index_Type
'Last) then
1553 -- We have determined that range of Index_Type has at least as
1554 -- many values as in Count_Type, so Count_Type'Last is the maximum
1555 -- number of items that are allowed.
1557 Max_Length
:= Count_Type
'Last;
1560 -- The range of Index_Type has fewer values than Count_Type does,
1561 -- so the maximum number of items is computed from the range of
1565 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1569 -- No_Index is equal or greater than 0, so we can safely compute the
1570 -- difference without fear of overflow (which we would have to worry
1571 -- about if No_Index were less than 0, but that case is handled
1575 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1578 -- We have just computed the maximum length (number of items). We must
1579 -- now compare the requested length to the maximum length, as we do not
1580 -- allow a vector expand beyond the maximum (because that would create
1581 -- an internal array with a last index value greater than
1582 -- Index_Type'Last, with no way to index those elements).
1584 if New_Length
> Max_Length
then
1585 raise Constraint_Error
with "Count is out of range";
1588 -- The tampering bits exist to prevent an item from being harmfully
1589 -- manipulated while it is being visited. Query, Update, and Iterate
1590 -- increment the busy count on entry, and decrement the count on
1591 -- exit. Insert checks the count to determine whether it is being called
1592 -- while the associated callback procedure is executing.
1594 if Container
.Busy
> 0 then
1595 raise Program_Error
with
1596 "attempt to tamper with cursors (vector is busy)";
1599 -- An internal array has already been allocated, so we need to check
1600 -- whether there is enough unused storage for the new items.
1602 if New_Length
> Container
.Capacity
then
1603 raise Capacity_Error
with "New length is larger than capacity";
1606 -- In this case, we're inserting space into a vector that has already
1607 -- allocated an internal array, and the existing array has enough
1608 -- unused storage for the new items.
1610 if Before
<= Container
.Last
then
1611 -- The space is being inserted before some existing elements,
1612 -- so we must slide the existing elements up to their new home.
1614 J
:= To_Array_Index
(Before
);
1615 EA
(J
+ Count
.. New_Length
) := EA
(J
.. Old_Length
);
1618 -- New_Last is the last index value of the items in the container after
1619 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1620 -- compute its value from the New_Length.
1622 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1623 Container.Last := No_Index + Index_Type'Base (New_Length);
1627 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1631 procedure Insert_Space
1632 (Container : in out Vector;
1634 Position : out Cursor;
1635 Count : Count_Type := 1)
1637 Index : Index_Type'Base;
1640 if Before.Container /= null
1641 and then Before.Container /= Container'Unchecked_Access
1643 raise Program_Error with "Before cursor denotes wrong container";
1647 if Before.Container = null
1648 or else Before.Index > Container.Last
1650 Position := No_Element;
1652 Position := (Container'Unchecked_Access, Before.Index);
1658 if Before.Container = null
1659 or else Before.Index > Container.Last
1661 if Container.Last = Index_Type'Last then
1662 raise Constraint_Error with
1663 "vector is already at its maximum length";
1666 Index := Container.Last + 1;
1669 Index := Before.Index;
1672 Insert_Space (Container, Index, Count => Count);
1674 Position := Cursor'(Container
'Unchecked_Access, Index
);
1681 function Is_Empty
(Container
: Vector
) return Boolean is
1683 return Container
.Last
< Index_Type
'First;
1691 (Container
: Vector
;
1692 Process
: not null access procedure (Position
: Cursor
))
1694 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1700 for Indx
in Index_Type
'First .. Container
.Last
loop
1701 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
1713 (Container : Vector)
1714 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1716 V : constant Vector_Access := Container'Unrestricted_Access;
1717 B : Natural renames V.Busy;
1720 -- The value of its Index component influences the behavior of the First
1721 -- and Last selector functions of the iterator object. When the Index
1722 -- component is No_Index (as is the case here), this means the iterator
1723 -- object was constructed without a start expression. This is a complete
1724 -- iterator, meaning that the iteration starts from the (logical)
1725 -- beginning of the sequence of items.
1727 -- Note: For a forward iterator, Container.First is the beginning, and
1728 -- for a reverse iterator, Container.Last is the beginning.
1730 return It : constant Iterator :=
1731 (Limited_Controlled with
1740 (Container : Vector;
1742 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1744 V : constant Vector_Access := Container'Unrestricted_Access;
1745 B : Natural renames V.Busy;
1748 -- It was formerly the case that when Start = No_Element, the partial
1749 -- iterator was defined to behave the same as for a complete iterator,
1750 -- and iterate over the entire sequence of items. However, those
1751 -- semantics were unintuitive and arguably error-prone (it is too easy
1752 -- to accidentally create an endless loop), and so they were changed,
1753 -- per the ARG meeting in Denver on 2011/11. However, there was no
1754 -- consensus about what positive meaning this corner case should have,
1755 -- and so it was decided to simply raise an exception. This does imply,
1756 -- however, that it is not possible to use a partial iterator to specify
1757 -- an empty sequence of items.
1759 if Start.Container = null then
1760 raise Constraint_Error with
1761 "Start position for iterator equals No_Element";
1764 if Start.Container /= V then
1765 raise Program_Error with
1766 "Start cursor of Iterate designates wrong vector";
1769 if Start.Index > V.Last then
1770 raise Constraint_Error with
1771 "Start position for iterator equals No_Element";
1774 -- The value of its Index component influences the behavior of the First
1775 -- and Last selector functions of the iterator object. When the Index
1776 -- component is not No_Index (as is the case here), it means that this
1777 -- is a partial iteration, over a subset of the complete sequence of
1778 -- items. The iterator object was constructed with a start expression,
1779 -- indicating the position from which the iteration begins. Note that
1780 -- the start position has the same value irrespective of whether this is
1781 -- a forward or reverse iteration.
1783 return It : constant Iterator :=
1784 (Limited_Controlled with
1786 Index => Start.Index)
1796 function Last (Container : Vector) return Cursor is
1798 if Is_Empty (Container) then
1801 return (Container'Unrestricted_Access, Container.Last);
1805 function Last (Object : Iterator) return Cursor is
1807 -- The value of the iterator object's Index component influences the
1808 -- behavior of the Last (and First) selector function.
1810 -- When the Index component is No_Index, this means the iterator object
1811 -- was constructed without a start expression, in which case the
1812 -- (reverse) iteration starts from the (logical) beginning of the entire
1813 -- sequence (corresponding to Container.Last, for a reverse iterator).
1815 -- Otherwise, this is iteration over a partial sequence of items. When
1816 -- the Index component is not No_Index, the iterator object was
1817 -- constructed with a start expression, that specifies the position from
1818 -- which the (reverse) partial iteration begins.
1820 if Object.Index = No_Index then
1821 return Last (Object.Container.all);
1823 return Cursor'(Object
.Container
, Object
.Index
);
1831 function Last_Element
(Container
: Vector
) return Element_Type
is
1833 if Container
.Last
= No_Index
then
1834 raise Constraint_Error
with "Container is empty";
1836 return Container
.Elements
(Container
.Length
);
1844 function Last_Index
(Container
: Vector
) return Extended_Index
is
1846 return Container
.Last
;
1853 function Length
(Container
: Vector
) return Count_Type
is
1854 L
: constant Index_Type
'Base := Container
.Last
;
1855 F
: constant Index_Type
:= Index_Type
'First;
1858 -- The base range of the index type (Index_Type'Base) might not include
1859 -- all values for length (Count_Type). Contrariwise, the index type
1860 -- might include values outside the range of length. Hence we use
1861 -- whatever type is wider for intermediate values when calculating
1862 -- length. Note that no matter what the index type is, the maximum
1863 -- length to which a vector is allowed to grow is always the minimum
1864 -- of Count_Type'Last and (IT'Last - IT'First + 1).
1866 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
1867 -- to have a base range of -128 .. 127, but the corresponding vector
1868 -- would have lengths in the range 0 .. 255. In this case we would need
1869 -- to use Count_Type'Base for intermediate values.
1871 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
1872 -- vector would have a maximum length of 10, but the index values lie
1873 -- outside the range of Count_Type (which is only 32 bits). In this
1874 -- case we would need to use Index_Type'Base for intermediate values.
1876 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
1877 return Count_Type
'Base (L
) - Count_Type
'Base (F
) + 1;
1879 return Count_Type
(L
- F
+ 1);
1888 (Target
: in out Vector
;
1889 Source
: in out Vector
)
1892 if Target
'Address = Source
'Address then
1896 if Target
.Capacity
< Source
.Length
then
1897 raise Capacity_Error
-- ???
1898 with "Target capacity is less than Source length";
1901 if Target
.Busy
> 0 then
1902 raise Program_Error
with
1903 "attempt to tamper with cursors (Target is busy)";
1906 if Source
.Busy
> 0 then
1907 raise Program_Error
with
1908 "attempt to tamper with cursors (Source is busy)";
1911 -- Clear Target now, in case element assignment fails
1913 Target
.Last
:= No_Index
;
1915 Target
.Elements
(1 .. Source
.Length
) :=
1916 Source
.Elements
(1 .. Source
.Length
);
1918 Target
.Last
:= Source
.Last
;
1919 Source
.Last
:= No_Index
;
1926 function Next
(Position
: Cursor
) return Cursor
is
1928 if Position
.Container
= null then
1932 if Position
.Index
< Position
.Container
.Last
then
1933 return (Position
.Container
, Position
.Index
+ 1);
1939 function Next
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
1941 if Position
.Container
= null then
1945 if Position
.Container
/= Object
.Container
then
1946 raise Program_Error
with
1947 "Position cursor of Next designates wrong vector";
1950 return Next
(Position
);
1953 procedure Next
(Position
: in out Cursor
) is
1955 if Position
.Container
= null then
1959 if Position
.Index
< Position
.Container
.Last
then
1960 Position
.Index
:= Position
.Index
+ 1;
1962 Position
:= No_Element
;
1970 procedure Prepend
(Container
: in out Vector
; New_Item
: Vector
) is
1972 Insert
(Container
, Index_Type
'First, New_Item
);
1976 (Container
: in out Vector
;
1977 New_Item
: Element_Type
;
1978 Count
: Count_Type
:= 1)
1991 procedure Previous
(Position
: in out Cursor
) is
1993 if Position
.Container
= null then
1997 if Position
.Index
> Index_Type
'First then
1998 Position
.Index
:= Position
.Index
- 1;
2000 Position
:= No_Element
;
2004 function Previous
(Position
: Cursor
) return Cursor
is
2006 if Position
.Container
= null then
2010 if Position
.Index
> Index_Type
'First then
2011 return (Position
.Container
, Position
.Index
- 1);
2017 function Previous
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
2019 if Position
.Container
= null then
2023 if Position
.Container
/= Object
.Container
then
2024 raise Program_Error
with
2025 "Position cursor of Previous designates wrong vector";
2028 return Previous
(Position
);
2035 procedure Query_Element
2036 (Container
: Vector
;
2038 Process
: not null access procedure (Element
: Element_Type
))
2040 V
: Vector
renames Container
'Unrestricted_Access.all;
2041 B
: Natural renames V
.Busy
;
2042 L
: Natural renames V
.Lock
;
2045 if Index
> Container
.Last
then
2046 raise Constraint_Error
with "Index is out of range";
2053 Process
(V
.Elements
(To_Array_Index
(Index
)));
2065 procedure Query_Element
2067 Process
: not null access procedure (Element
: Element_Type
))
2070 if Position
.Container
= null then
2071 raise Constraint_Error
with "Position cursor has no element";
2074 Query_Element
(Position
.Container
.all, Position
.Index
, Process
);
2082 (Stream
: not null access Root_Stream_Type
'Class;
2083 Container
: out Vector
)
2085 Length
: Count_Type
'Base;
2086 Last
: Index_Type
'Base := No_Index
;
2091 Count_Type
'Base'Read (Stream, Length);
2093 Reserve_Capacity (Container, Capacity => Length);
2095 for Idx in Count_Type range 1 .. Length loop
2097 Element_Type'Read (Stream, Container.Elements (Idx));
2098 Container.Last := Last;
2103 (Stream : not null access Root_Stream_Type'Class;
2104 Position : out Cursor)
2107 raise Program_Error with "attempt to stream vector cursor";
2111 (Stream : not null access Root_Stream_Type'Class;
2112 Item : out Reference_Type)
2115 raise Program_Error with "attempt to stream reference";
2119 (Stream : not null access Root_Stream_Type'Class;
2120 Item : out Constant_Reference_Type)
2123 raise Program_Error with "attempt to stream reference";
2131 (Container : aliased in out Vector;
2132 Position : Cursor) return Reference_Type
2135 if Position.Container = null then
2136 raise Constraint_Error with "Position cursor has no element";
2139 if Position.Container /= Container'Unrestricted_Access then
2140 raise Program_Error with "Position cursor denotes wrong container";
2143 if Position.Index > Position.Container.Last then
2144 raise Constraint_Error with "Position cursor is out of range";
2148 A : Elements_Array renames Container.Elements;
2149 I : constant Count_Type := To_Array_Index (Position.Index);
2151 return (Element => A (I)'Access);
2156 (Container : aliased in out Vector;
2157 Index : Index_Type) return Reference_Type
2160 if Index > Container.Last then
2161 raise Constraint_Error with "Index is out of range";
2165 A : Elements_Array renames Container.Elements;
2166 I : constant Count_Type := To_Array_Index (Index);
2168 return (Element => A (I)'Access);
2172 ---------------------
2173 -- Replace_Element --
2174 ---------------------
2176 procedure Replace_Element
2177 (Container : in out Vector;
2179 New_Item : Element_Type)
2182 if Index > Container.Last then
2183 raise Constraint_Error with "Index is out of range";
2186 if Container.Lock > 0 then
2187 raise Program_Error with
2188 "attempt to tamper with elements (vector is locked)";
2191 Container.Elements (To_Array_Index (Index)) := New_Item;
2192 end Replace_Element;
2194 procedure Replace_Element
2195 (Container : in out Vector;
2197 New_Item : Element_Type)
2200 if Position.Container = null then
2201 raise Constraint_Error with "Position cursor has no element";
2204 if Position.Container /= Container'Unrestricted_Access then
2205 raise Program_Error with "Position cursor denotes wrong container";
2208 if Position.Index > Container.Last then
2209 raise Constraint_Error with "Position cursor is out of range";
2212 if Container.Lock > 0 then
2213 raise Program_Error with
2214 "attempt to tamper with elements (vector is locked)";
2217 Container.Elements (To_Array_Index (Position.Index)) := New_Item;
2218 end Replace_Element;
2220 ----------------------
2221 -- Reserve_Capacity --
2222 ----------------------
2224 procedure Reserve_Capacity
2225 (Container : in out Vector;
2226 Capacity : Count_Type)
2229 if Capacity > Container.Capacity then
2230 raise Constraint_Error with "Capacity is out of range";
2232 end Reserve_Capacity;
2234 ----------------------
2235 -- Reverse_Elements --
2236 ----------------------
2238 procedure Reverse_Elements (Container : in out Vector) is
2239 E : Elements_Array renames Container.Elements;
2244 if Container.Length <= 1 then
2248 -- The exception behavior for the vector container must match that for
2249 -- the list container, so we check for cursor tampering here (which will
2250 -- catch more things) instead of for element tampering (which will catch
2251 -- fewer things). It's true that the elements of this vector container
2252 -- could be safely moved around while (say) an iteration is taking place
2253 -- (iteration only increments the busy counter), and so technically
2254 -- all we would need here is a test for element tampering (indicated
2255 -- by the lock counter), that's simply an artifact of our array-based
2256 -- implementation. Logically Reverse_Elements requires a check for
2257 -- cursor tampering.
2259 if Container.Busy > 0 then
2260 raise Program_Error with
2261 "attempt to tamper with cursors (vector is busy)";
2265 Jdx := Container.Length;
2266 while Idx < Jdx loop
2268 EI : constant Element_Type := E (Idx);
2278 end Reverse_Elements;
2284 function Reverse_Find
2285 (Container : Vector;
2286 Item : Element_Type;
2287 Position : Cursor := No_Element) return Cursor
2289 Last : Index_Type'Base;
2292 if Position.Container /= null
2293 and then Position.Container /= Container'Unrestricted_Access
2295 raise Program_Error with "Position cursor denotes wrong container";
2299 (if Position.Container = null or else Position.Index > Container.Last
2301 else Position.Index);
2303 for Indx in reverse Index_Type'First .. Last loop
2304 if Container.Elements (To_Array_Index (Indx)) = Item then
2305 return (Container'Unrestricted_Access, Indx);
2312 ------------------------
2313 -- Reverse_Find_Index --
2314 ------------------------
2316 function Reverse_Find_Index
2317 (Container : Vector;
2318 Item : Element_Type;
2319 Index : Index_Type := Index_Type'Last) return Extended_Index
2321 Last : constant Index_Type'Base :=
2322 Index_Type'Min (Container.Last, Index);
2325 for Indx in reverse Index_Type'First .. Last loop
2326 if Container.Elements (To_Array_Index (Indx)) = Item then
2332 end Reverse_Find_Index;
2334 ---------------------
2335 -- Reverse_Iterate --
2336 ---------------------
2338 procedure Reverse_Iterate
2339 (Container : Vector;
2340 Process : not null access procedure (Position : Cursor))
2342 V : Vector renames Container'Unrestricted_Access.all;
2343 B : Natural renames V.Busy;
2349 for Indx in reverse Index_Type'First .. Container.Last loop
2350 Process (Cursor'(Container
'Unrestricted_Access, Indx
));
2359 end Reverse_Iterate
;
2365 procedure Set_Length
(Container
: in out Vector
; Length
: Count_Type
) is
2366 Count
: constant Count_Type
'Base := Container
.Length
- Length
;
2369 -- Set_Length allows the user to set the length explicitly, instead of
2370 -- implicitly as a side-effect of deletion or insertion. If the
2371 -- requested length is less than the current length, this is equivalent
2372 -- to deleting items from the back end of the vector. If the requested
2373 -- length is greater than the current length, then this is equivalent to
2374 -- inserting "space" (nonce items) at the end.
2377 Container
.Delete_Last
(Count
);
2379 elsif Container
.Last
>= Index_Type
'Last then
2380 raise Constraint_Error
with "vector is already at its maximum length";
2383 Container
.Insert_Space
(Container
.Last
+ 1, -Count
);
2391 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
2392 E
: Elements_Array
renames Container
.Elements
;
2395 if I
> Container
.Last
then
2396 raise Constraint_Error
with "I index is out of range";
2399 if J
> Container
.Last
then
2400 raise Constraint_Error
with "J index is out of range";
2407 if Container
.Lock
> 0 then
2408 raise Program_Error
with
2409 "attempt to tamper with elements (vector is locked)";
2413 EI_Copy
: constant Element_Type
:= E
(To_Array_Index
(I
));
2415 E
(To_Array_Index
(I
)) := E
(To_Array_Index
(J
));
2416 E
(To_Array_Index
(J
)) := EI_Copy
;
2420 procedure Swap
(Container
: in out Vector
; I
, J
: Cursor
) is
2422 if I
.Container
= null then
2423 raise Constraint_Error
with "I cursor has no element";
2426 if J
.Container
= null then
2427 raise Constraint_Error
with "J cursor has no element";
2430 if I
.Container
/= Container
'Unrestricted_Access then
2431 raise Program_Error
with "I cursor denotes wrong container";
2434 if J
.Container
/= Container
'Unrestricted_Access then
2435 raise Program_Error
with "J cursor denotes wrong container";
2438 Swap
(Container
, I
.Index
, J
.Index
);
2441 --------------------
2442 -- To_Array_Index --
2443 --------------------
2445 function To_Array_Index
(Index
: Index_Type
'Base) return Count_Type
'Base is
2446 Offset
: Count_Type
'Base;
2450 -- Index >= Index_Type'First
2451 -- hence we also know that
2452 -- Index - Index_Type'First >= 0
2454 -- The issue is that even though 0 is guaranteed to be a value
2455 -- in the type Index_Type'Base, there's no guarantee that the
2456 -- difference is a value in that type. To prevent overflow we
2457 -- use the wider of Count_Type'Base and Index_Type'Base to
2458 -- perform intermediate calculations.
2460 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2461 Offset := Count_Type'Base (Index - Index_Type'First);
2464 Offset := Count_Type'Base (Index) -
2465 Count_Type'Base (Index_Type'First);
2468 -- The array index subtype for all container element arrays
2469 -- always starts with 1.
2479 (Container : Vector;
2480 Index : Extended_Index) return Cursor
2483 if Index not in Index_Type'First .. Container.Last then
2487 return Cursor'(Container
'Unrestricted_Access, Index
);
2494 function To_Index
(Position
: Cursor
) return Extended_Index
is
2496 if Position
.Container
= null then
2500 if Position
.Index
<= Position
.Container
.Last
then
2501 return Position
.Index
;
2511 function To_Vector
(Length
: Count_Type
) return Vector
is
2512 Index
: Count_Type
'Base;
2513 Last
: Index_Type
'Base;
2517 return Empty_Vector
;
2520 -- We create a vector object with a capacity that matches the specified
2521 -- Length, but we do not allow the vector capacity (the length of the
2522 -- internal array) to exceed the number of values in Index_Type'Range
2523 -- (otherwise, there would be no way to refer to those components via an
2524 -- index). We must therefore check whether the specified Length would
2525 -- create a Last index value greater than Index_Type'Last.
2527 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2528 -- We perform a two-part test. First we determine whether the
2529 -- computed Last value lies in the base range of the type, and then
2530 -- determine whether it lies in the range of the index (sub)type.
2532 -- Last must satisfy this relation:
2533 -- First + Length - 1 <= Last
2534 -- We regroup terms:
2535 -- First - 1 <= Last - Length
2536 -- Which can rewrite as:
2537 -- No_Index <= Last - Length
2539 if Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
then
2540 raise Constraint_Error
with "Length is out of range";
2543 -- We now know that the computed value of Last is within the base
2544 -- range of the type, so it is safe to compute its value:
2546 Last
:= No_Index
+ Index_Type
'Base (Length
);
2548 -- Finally we test whether the value is within the range of the
2549 -- generic actual index subtype:
2551 if Last
> Index_Type
'Last then
2552 raise Constraint_Error
with "Length is out of range";
2555 elsif Index_Type
'First <= 0 then
2557 -- Here we can compute Last directly, in the normal way. We know that
2558 -- No_Index is less than 0, so there is no danger of overflow when
2559 -- adding the (positive) value of Length.
2561 Index
:= Count_Type
'Base (No_Index
) + Length
; -- Last
2563 if Index
> Count_Type
'Base (Index_Type
'Last) then
2564 raise Constraint_Error
with "Length is out of range";
2567 -- We know that the computed value (having type Count_Type) of Last
2568 -- is within the range of the generic actual index subtype, so it is
2569 -- safe to convert to Index_Type:
2571 Last
:= Index_Type
'Base (Index
);
2574 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2575 -- must test the length indirectly (by working backwards from the
2576 -- largest possible value of Last), in order to prevent overflow.
2578 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
2580 if Index
< Count_Type
'Base (No_Index
) then
2581 raise Constraint_Error
with "Length is out of range";
2584 -- We have determined that the value of Length would not create a
2585 -- Last index value outside of the range of Index_Type, so we can now
2586 -- safely compute its value.
2588 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
2591 return V
: Vector
(Capacity
=> Length
) do
2597 (New_Item
: Element_Type
;
2598 Length
: Count_Type
) return Vector
2600 Index
: Count_Type
'Base;
2601 Last
: Index_Type
'Base;
2605 return Empty_Vector
;
2608 -- We create a vector object with a capacity that matches the specified
2609 -- Length, but we do not allow the vector capacity (the length of the
2610 -- internal array) to exceed the number of values in Index_Type'Range
2611 -- (otherwise, there would be no way to refer to those components via an
2612 -- index). We must therefore check whether the specified Length would
2613 -- create a Last index value greater than Index_Type'Last.
2615 if Index_Type
'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2617 -- We perform a two-part test. First we determine whether the
2618 -- computed Last value lies in the base range of the type, and then
2619 -- determine whether it lies in the range of the index (sub)type.
2621 -- Last must satisfy this relation:
2622 -- First + Length - 1 <= Last
2623 -- We regroup terms:
2624 -- First - 1 <= Last - Length
2625 -- Which can rewrite as:
2626 -- No_Index <= Last - Length
2628 if Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
then
2629 raise Constraint_Error
with "Length is out of range";
2632 -- We now know that the computed value of Last is within the base
2633 -- range of the type, so it is safe to compute its value:
2635 Last
:= No_Index
+ Index_Type
'Base (Length
);
2637 -- Finally we test whether the value is within the range of the
2638 -- generic actual index subtype:
2640 if Last
> Index_Type
'Last then
2641 raise Constraint_Error
with "Length is out of range";
2644 elsif Index_Type
'First <= 0 then
2646 -- Here we can compute Last directly, in the normal way. We know that
2647 -- No_Index is less than 0, so there is no danger of overflow when
2648 -- adding the (positive) value of Length.
2650 Index
:= Count_Type
'Base (No_Index
) + Length
; -- same value as V.Last
2652 if Index
> Count_Type
'Base (Index_Type
'Last) then
2653 raise Constraint_Error
with "Length is out of range";
2656 -- We know that the computed value (having type Count_Type) of Last
2657 -- is within the range of the generic actual index subtype, so it is
2658 -- safe to convert to Index_Type:
2660 Last
:= Index_Type
'Base (Index
);
2663 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2664 -- must test the length indirectly (by working backwards from the
2665 -- largest possible value of Last), in order to prevent overflow.
2667 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
2669 if Index
< Count_Type
'Base (No_Index
) then
2670 raise Constraint_Error
with "Length is out of range";
2673 -- We have determined that the value of Length would not create a
2674 -- Last index value outside of the range of Index_Type, so we can now
2675 -- safely compute its value.
2677 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
2680 return V
: Vector
(Capacity
=> Length
) do
2681 V
.Elements
:= (others => New_Item
);
2686 --------------------
2687 -- Update_Element --
2688 --------------------
2690 procedure Update_Element
2691 (Container
: in out Vector
;
2693 Process
: not null access procedure (Element
: in out Element_Type
))
2695 B
: Natural renames Container
.Busy
;
2696 L
: Natural renames Container
.Lock
;
2699 if Index
> Container
.Last
then
2700 raise Constraint_Error
with "Index is out of range";
2707 Process
(Container
.Elements
(To_Array_Index
(Index
)));
2719 procedure Update_Element
2720 (Container
: in out Vector
;
2722 Process
: not null access procedure (Element
: in out Element_Type
))
2725 if Position
.Container
= null then
2726 raise Constraint_Error
with "Position cursor has no element";
2729 if Position
.Container
/= Container
'Unrestricted_Access then
2730 raise Program_Error
with "Position cursor denotes wrong container";
2733 Update_Element
(Container
, Position
.Index
, Process
);
2741 (Stream
: not null access Root_Stream_Type
'Class;
2747 N
:= Container
.Length
;
2748 Count_Type
'Base'Write (Stream, N);
2750 for J in 1 .. N loop
2751 Element_Type'Write (Stream, Container.Elements (J));
2756 (Stream : not null access Root_Stream_Type'Class;
2760 raise Program_Error with "attempt to stream vector cursor";
2764 (Stream : not null access Root_Stream_Type'Class;
2765 Item : Reference_Type)
2768 raise Program_Error with "attempt to stream reference";
2772 (Stream : not null access Root_Stream_Type'Class;
2773 Item : Constant_Reference_Type)
2776 raise Program_Error with "attempt to stream reference";
2779 end Ada.Containers.Bounded_Vectors;