1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . I N D E F I N I T E _ V E C T O R S --
9 -- Copyright (C) 2004-2018, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Containers
.Generic_Array_Sort
;
31 with Ada
.Unchecked_Deallocation
;
33 with System
; use type System
.Address
;
35 package body Ada
.Containers
.Indefinite_Vectors
is
37 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
38 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
39 -- See comment in Ada.Containers.Helpers
42 new Ada
.Unchecked_Deallocation
(Elements_Type
, Elements_Access
);
45 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
47 procedure Append_Slow_Path
48 (Container
: in out Vector
;
49 New_Item
: Element_Type
;
51 -- This is the slow path for Append. This is split out to minimize the size
52 -- of Append, because we have Inline (Append).
58 -- We decide that the capacity of the result of "&" is the minimum needed
59 -- -- the sum of the lengths of the vector parameters. We could decide to
60 -- make it larger, but we have no basis for knowing how much larger, so we
61 -- just allocate the minimum amount of storage.
63 function "&" (Left
, Right
: Vector
) return Vector
is
65 return Result
: Vector
do
66 Reserve_Capacity
(Result
, Length
(Left
) + Length
(Right
));
67 Append
(Result
, Left
);
68 Append
(Result
, Right
);
72 function "&" (Left
: Vector
; Right
: Element_Type
) return Vector
is
74 return Result
: Vector
do
75 Reserve_Capacity
(Result
, Length
(Left
) + 1);
76 Append
(Result
, Left
);
77 Append
(Result
, Right
);
81 function "&" (Left
: Element_Type
; Right
: Vector
) return Vector
is
83 return Result
: Vector
do
84 Reserve_Capacity
(Result
, 1 + Length
(Right
));
85 Append
(Result
, Left
);
86 Append
(Result
, Right
);
90 function "&" (Left
, Right
: Element_Type
) return Vector
is
92 return Result
: Vector
do
93 Reserve_Capacity
(Result
, 1 + 1);
94 Append
(Result
, Left
);
95 Append
(Result
, Right
);
103 overriding
function "=" (Left
, Right
: Vector
) return Boolean is
105 if Left
.Last
/= Right
.Last
then
109 if Left
.Length
= 0 then
114 -- Per AI05-0022, the container implementation is required to detect
115 -- element tampering by a generic actual subprogram.
117 Lock_Left
: With_Lock
(Left
.TC
'Unrestricted_Access);
118 Lock_Right
: With_Lock
(Right
.TC
'Unrestricted_Access);
120 for J
in Index_Type
range Index_Type
'First .. Left
.Last
loop
121 if Left
.Elements
.EA
(J
) = null then
122 if Right
.Elements
.EA
(J
) /= null then
126 elsif Right
.Elements
.EA
(J
) = null then
129 elsif Left
.Elements
.EA
(J
).all /= Right
.Elements
.EA
(J
).all then
142 procedure Adjust
(Container
: in out Vector
) is
144 -- If the counts are nonzero, execution is technically erroneous, but
145 -- it seems friendly to allow things like concurrent "=" on shared
148 Zero_Counts
(Container
.TC
);
150 if Container
.Last
= No_Index
then
151 Container
.Elements
:= null;
156 L
: constant Index_Type
:= Container
.Last
;
157 E
: Elements_Array
renames
158 Container
.Elements
.EA
(Index_Type
'First .. L
);
161 Container
.Elements
:= null;
162 Container
.Last
:= No_Index
;
164 Container
.Elements
:= new Elements_Type
(L
);
166 for J
in E
'Range loop
167 if E
(J
) /= null then
168 Container
.Elements
.EA
(J
) := new Element_Type
'(E (J).all);
180 procedure Append (Container : in out Vector; New_Item : Vector) is
182 if Is_Empty (New_Item) then
184 elsif Checks and then Container.Last = Index_Type'Last then
185 raise Constraint_Error with "vector is already at its maximum length";
187 Insert (Container, Container.Last + 1, New_Item);
192 (Container : in out Vector;
193 New_Item : Element_Type;
194 Count : Count_Type := 1)
197 -- In the general case, we pass the buck to Insert, but for efficiency,
198 -- we check for the usual case where Count = 1 and the vector has enough
199 -- room for at least one more element.
202 and then Container.Elements /= null
203 and then Container.Last /= Container.Elements.Last
205 TC_Check (Container.TC);
207 -- Increment Container.Last after assigning the New_Item, so we
208 -- leave the Container unmodified in case Finalize/Adjust raises
212 New_Last : constant Index_Type := Container.Last + 1;
214 -- The element allocator may need an accessibility check in the
215 -- case actual type is class-wide or has access discriminants
216 -- (see RM 4.8(10.1) and AI12-0035).
218 pragma Unsuppress (Accessibility_Check);
220 Container.Elements.EA (New_Last) := new Element_Type'(New_Item
);
221 Container
.Last
:= New_Last
;
225 Append_Slow_Path
(Container
, New_Item
, Count
);
229 ----------------------
230 -- Append_Slow_Path --
231 ----------------------
233 procedure Append_Slow_Path
234 (Container
: in out Vector
;
235 New_Item
: Element_Type
;
241 elsif Checks
and then Container
.Last
= Index_Type
'Last then
242 raise Constraint_Error
with "vector is already at its maximum length";
244 Insert
(Container
, Container
.Last
+ 1, New_Item
, Count
);
246 end Append_Slow_Path
;
252 procedure Assign
(Target
: in out Vector
; Source
: Vector
) is
254 if Target
'Address = Source
'Address then
258 Target
.Append
(Source
);
266 function Capacity
(Container
: Vector
) return Count_Type
is
268 if Container
.Elements
= null then
271 return Container
.Elements
.EA
'Length;
279 procedure Clear
(Container
: in out Vector
) is
281 TC_Check
(Container
.TC
);
283 while Container
.Last
>= Index_Type
'First loop
285 X
: Element_Access
:= Container
.Elements
.EA
(Container
.Last
);
287 Container
.Elements
.EA
(Container
.Last
) := null;
288 Container
.Last
:= Container
.Last
- 1;
294 ------------------------
295 -- Constant_Reference --
296 ------------------------
298 function Constant_Reference
299 (Container
: aliased Vector
;
300 Position
: Cursor
) return Constant_Reference_Type
304 if Position
.Container
= null then
305 raise Constraint_Error
with "Position cursor has no element";
308 if Position
.Container
/= Container
'Unrestricted_Access then
309 raise Program_Error
with "Position cursor denotes wrong container";
312 if Position
.Index
> Position
.Container
.Last
then
313 raise Constraint_Error
with "Position cursor is out of range";
318 TC
: constant Tamper_Counts_Access
:=
319 Container
.TC
'Unrestricted_Access;
321 -- The following will raise Constraint_Error if Element is null
323 return R
: constant Constant_Reference_Type
:=
324 (Element
=> Container
.Elements
.EA
(Position
.Index
),
325 Control
=> (Controlled
with TC
))
330 end Constant_Reference
;
332 function Constant_Reference
333 (Container
: aliased Vector
;
334 Index
: Index_Type
) return Constant_Reference_Type
337 if Checks
and then Index
> Container
.Last
then
338 raise Constraint_Error
with "Index is out of range";
342 TC
: constant Tamper_Counts_Access
:=
343 Container
.TC
'Unrestricted_Access;
345 -- The following will raise Constraint_Error if Element is null
347 return R
: constant Constant_Reference_Type
:=
348 (Element
=> Container
.Elements
.EA
(Index
),
349 Control
=> (Controlled
with TC
))
354 end Constant_Reference
;
362 Item
: Element_Type
) return Boolean
365 return Find_Index
(Container
, Item
) /= No_Index
;
374 Capacity
: Count_Type
:= 0) return Vector
379 if Capacity
< Source
.Length
then
380 if Checks
and then Capacity
/= 0 then
382 with "Requested capacity is less than Source length";
390 return Target
: Vector
do
391 Target
.Reserve_Capacity
(C
);
392 Target
.Assign
(Source
);
401 (Container
: in out Vector
;
402 Index
: Extended_Index
;
403 Count
: Count_Type
:= 1)
405 Old_Last
: constant Index_Type
'Base := Container
.Last
;
406 New_Last
: Index_Type
'Base;
407 Count2
: Count_Type
'Base; -- count of items from Index to Old_Last
408 J
: Index_Type
'Base; -- first index of items that slide down
411 -- Delete removes items from the vector, the number of which is the
412 -- minimum of the specified Count and the items (if any) that exist from
413 -- Index to Container.Last. There are no constraints on the specified
414 -- value of Count (it can be larger than what's available at this
415 -- position in the vector, for example), but there are constraints on
416 -- the allowed values of the Index.
418 -- As a precondition on the generic actual Index_Type, the base type
419 -- must include Index_Type'Pred (Index_Type'First); this is the value
420 -- that Container.Last assumes when the vector is empty. However, we do
421 -- not allow that as the value for Index when specifying which items
422 -- should be deleted, so we must manually check. (That the user is
423 -- allowed to specify the value at all here is a consequence of the
424 -- declaration of the Extended_Index subtype, which includes the values
425 -- in the base range that immediately precede and immediately follow the
426 -- values in the Index_Type.)
428 if Checks
and then Index
< Index_Type
'First then
429 raise Constraint_Error
with "Index is out of range (too small)";
432 -- We do allow a value greater than Container.Last to be specified as
433 -- the Index, but only if it's immediately greater. This allows the
434 -- corner case of deleting no items from the back end of the vector to
435 -- be treated as a no-op. (It is assumed that specifying an index value
436 -- greater than Last + 1 indicates some deeper flaw in the caller's
437 -- algorithm, so that case is treated as a proper error.)
439 if Index
> Old_Last
then
440 if Checks
and then Index
> Old_Last
+ 1 then
441 raise Constraint_Error
with "Index is out of range (too large)";
447 -- Here and elsewhere we treat deleting 0 items from the container as a
448 -- no-op, even when the container is busy, so we simply return.
454 -- The internal elements array isn't guaranteed to exist unless we have
455 -- elements, so we handle that case here in order to avoid having to
456 -- check it later. (Note that an empty vector can never be busy, so
457 -- there's no semantic harm in returning early.)
459 if Container
.Is_Empty
then
463 -- The tampering bits exist to prevent an item from being deleted (or
464 -- otherwise harmfully manipulated) while it is being visited. Query,
465 -- Update, and Iterate increment the busy count on entry, and decrement
466 -- the count on exit. Delete checks the count to determine whether it is
467 -- being called while the associated callback procedure is executing.
469 TC_Check
(Container
.TC
);
471 -- We first calculate what's available for deletion starting at
472 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
473 -- Count_Type'Base as the type for intermediate values. (See function
474 -- Length for more information.)
476 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
477 Count2
:= Count_Type
'Base (Old_Last
) - Count_Type
'Base (Index
) + 1;
479 Count2
:= Count_Type
'Base (Old_Last
- Index
+ 1);
482 -- If the number of elements requested (Count) for deletion is equal to
483 -- (or greater than) the number of elements available (Count2) for
484 -- deletion beginning at Index, then everything from Index to
485 -- Container.Last is deleted (this is equivalent to Delete_Last).
487 if Count
>= Count2
then
488 -- Elements in an indefinite vector are allocated, so we must iterate
489 -- over the loop and deallocate elements one-at-a-time. We work from
490 -- back to front, deleting the last element during each pass, in
491 -- order to gracefully handle deallocation failures.
494 EA
: Elements_Array
renames Container
.Elements
.EA
;
497 while Container
.Last
>= Index
loop
499 K
: constant Index_Type
:= Container
.Last
;
500 X
: Element_Access
:= EA
(K
);
503 -- We first isolate the element we're deleting, removing it
504 -- from the vector before we attempt to deallocate it, in
505 -- case the deallocation fails.
508 Container
.Last
:= K
- 1;
510 -- Container invariants have been restored, so it is now
511 -- safe to attempt to deallocate the element.
521 -- There are some elements that aren't being deleted (the requested
522 -- count was less than the available count), so we must slide them down
523 -- to Index. We first calculate the index values of the respective array
524 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
525 -- type for intermediate calculations. For the elements that slide down,
526 -- index value New_Last is the last index value of their new home, and
527 -- index value J is the first index of their old home.
529 if Index_Type
'Base'Last >= Count_Type_Last then
530 New_Last := Old_Last - Index_Type'Base (Count);
531 J := Index + Index_Type'Base (Count);
533 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
534 J := Index_Type'Base (Count_Type'Base (Index) + Count);
537 -- The internal elements array isn't guaranteed to exist unless we have
538 -- elements, but we have that guarantee here because we know we have
539 -- elements to slide. The array index values for each slice have
540 -- already been determined, so what remains to be done is to first
541 -- deallocate the elements that are being deleted, and then slide down
542 -- to Index the elements that aren't being deleted.
545 EA : Elements_Array renames Container.Elements.EA;
548 -- Before we can slide down the elements that aren't being deleted,
549 -- we need to deallocate the elements that are being deleted.
551 for K in Index .. J - 1 loop
553 X : Element_Access := EA (K);
556 -- First we remove the element we're about to deallocate from
557 -- the vector, in case the deallocation fails, in order to
558 -- preserve representation invariants.
562 -- The element has been removed from the vector, so it is now
563 -- safe to attempt to deallocate it.
569 EA (Index .. New_Last) := EA (J .. Old_Last);
570 Container.Last := New_Last;
575 (Container : in out Vector;
576 Position : in out Cursor;
577 Count : Count_Type := 1)
581 if Position.Container = null then
582 raise Constraint_Error with "Position cursor has no element";
584 elsif Position.Container /= Container'Unrestricted_Access then
585 raise Program_Error with "Position cursor denotes wrong container";
587 elsif Position.Index > Container.Last then
588 raise Program_Error with "Position index is out of range";
592 Delete (Container, Position.Index, Count);
593 Position := No_Element;
600 procedure Delete_First
601 (Container : in out Vector;
602 Count : Count_Type := 1)
608 elsif Count >= Length (Container) then
613 Delete (Container, Index_Type'First, Count);
621 procedure Delete_Last
622 (Container : in out Vector;
623 Count : Count_Type := 1)
626 -- It is not permitted to delete items while the container is busy (for
627 -- example, we're in the middle of a passive iteration). However, we
628 -- always treat deleting 0 items as a no-op, even when we're busy, so we
629 -- simply return without checking.
635 -- We cannot simply subsume the empty case into the loop below (the loop
636 -- would iterate 0 times), because we rename the internal array object
637 -- (which is allocated), but an empty vector isn't guaranteed to have
638 -- actually allocated an array. (Note that an empty vector can never be
639 -- busy, so there's no semantic harm in returning early here.)
641 if Container.Is_Empty then
645 -- The tampering bits exist to prevent an item from being deleted (or
646 -- otherwise harmfully manipulated) while it is being visited. Query,
647 -- Update, and Iterate increment the busy count on entry, and decrement
648 -- the count on exit. Delete_Last checks the count to determine whether
649 -- it is being called while the associated callback procedure is
652 TC_Check (Container.TC);
654 -- Elements in an indefinite vector are allocated, so we must iterate
655 -- over the loop and deallocate elements one-at-a-time. We work from
656 -- back to front, deleting the last element during each pass, in order
657 -- to gracefully handle deallocation failures.
660 E : Elements_Array renames Container.Elements.EA;
663 for Indx in 1 .. Count_Type'Min (Count, Container.Length) loop
665 J : constant Index_Type := Container.Last;
666 X : Element_Access := E (J);
669 -- Note that we first isolate the element we're deleting,
670 -- removing it from the vector, before we actually deallocate
671 -- it, in order to preserve representation invariants even if
672 -- the deallocation fails.
675 Container.Last := J - 1;
677 -- Container invariants have been restored, so it is now safe
678 -- to deallocate the element.
692 Index : Index_Type) return Element_Type
695 if Checks and then Index > Container.Last then
696 raise Constraint_Error with "Index is out of range";
700 EA : constant Element_Access := Container.Elements.EA (Index);
702 if Checks and then EA = null then
703 raise Constraint_Error with "element is empty";
710 function Element (Position : Cursor) return Element_Type is
713 if Position.Container = null then
714 raise Constraint_Error with "Position cursor has no element";
717 if Position.Index > Position.Container.Last then
718 raise Constraint_Error with "Position cursor is out of range";
723 EA : constant Element_Access :=
724 Position.Container.Elements.EA (Position.Index);
726 if Checks and then EA = null then
727 raise Constraint_Error with "element is empty";
738 procedure Finalize (Container : in out Vector) is
740 Clear (Container); -- Checks busy-bit
743 X : Elements_Access := Container.Elements;
745 Container.Elements := null;
750 procedure Finalize (Object : in out Iterator) is
752 Unbusy (Object.Container.TC);
762 Position : Cursor := No_Element) return Cursor
765 if Checks and then Position.Container /= null then
766 if Position.Container /= Container'Unrestricted_Access then
767 raise Program_Error with "Position cursor denotes wrong container";
770 if Position.Index > Container.Last then
771 raise Program_Error with "Position index is out of range";
775 -- Per AI05-0022, the container implementation is required to detect
776 -- element tampering by a generic actual subprogram.
779 Lock : With_Lock (Container.TC'Unrestricted_Access);
781 for J in Position.Index .. Container.Last loop
782 if Container.Elements.EA (J).all = Item then
783 return Cursor'(Container
'Unrestricted_Access, J
);
798 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
800 -- Per AI05-0022, the container implementation is required to detect
801 -- element tampering by a generic actual subprogram.
803 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
805 for Indx
in Index
.. Container
.Last
loop
806 if Container
.Elements
.EA
(Indx
).all = Item
then
818 function First
(Container
: Vector
) return Cursor
is
820 if Is_Empty
(Container
) then
824 return (Container
'Unrestricted_Access, Index_Type
'First);
827 function First
(Object
: Iterator
) return Cursor
is
829 -- The value of the iterator object's Index component influences the
830 -- behavior of the First (and Last) selector function.
832 -- When the Index component is No_Index, this means the iterator
833 -- object was constructed without a start expression, in which case the
834 -- (forward) iteration starts from the (logical) beginning of the entire
835 -- sequence of items (corresponding to Container.First, for a forward
838 -- Otherwise, this is iteration over a partial sequence of items.
839 -- When the Index component isn't No_Index, the iterator object was
840 -- constructed with a start expression, that specifies the position
841 -- from which the (forward) partial iteration begins.
843 if Object
.Index
= No_Index
then
844 return First
(Object
.Container
.all);
846 return Cursor
'(Object.Container, Object.Index);
854 function First_Element (Container : Vector) return Element_Type is
856 if Checks and then Container.Last = No_Index then
857 raise Constraint_Error with "Container is empty";
861 EA : constant Element_Access :=
862 Container.Elements.EA (Index_Type'First);
864 if Checks and then EA = null then
865 raise Constraint_Error with "first element is empty";
876 function First_Index (Container : Vector) return Index_Type is
877 pragma Unreferenced (Container);
879 return Index_Type'First;
882 ---------------------
883 -- Generic_Sorting --
884 ---------------------
886 package body Generic_Sorting is
888 -----------------------
889 -- Local Subprograms --
890 -----------------------
892 function Is_Less (L, R : Element_Access) return Boolean;
893 pragma Inline (Is_Less);
899 function Is_Less (L, R : Element_Access) return Boolean is
906 return L.all < R.all;
914 function Is_Sorted (Container : Vector) return Boolean is
916 if Container.Last <= Index_Type'First then
920 -- Per AI05-0022, the container implementation is required to detect
921 -- element tampering by a generic actual subprogram.
924 Lock : With_Lock (Container.TC'Unrestricted_Access);
925 E : Elements_Array renames Container.Elements.EA;
927 for J in Index_Type'First .. Container.Last - 1 loop
928 if Is_Less (E (J + 1), E (J)) then
941 procedure Merge (Target, Source : in out Vector) is
942 I, J : Index_Type'Base;
945 -- The semantics of Merge changed slightly per AI05-0021. It was
946 -- originally the case that if Target and Source denoted the same
947 -- container object, then the GNAT implementation of Merge did
948 -- nothing. However, it was argued that RM05 did not precisely
949 -- specify the semantics for this corner case. The decision of the
950 -- ARG was that if Target and Source denote the same non-empty
951 -- container object, then Program_Error is raised.
953 if Source.Last < Index_Type'First then -- Source is empty
957 if Checks and then Target'Address = Source'Address then
958 raise Program_Error with
959 "Target and Source denote same non-empty container";
962 if Target.Last < Index_Type'First then -- Target is empty
963 Move (Target => Target, Source => Source);
967 TC_Check (Source.TC);
969 I := Target.Last; -- original value (before Set_Length)
970 Target.Set_Length (Length (Target) + Length (Source));
972 -- Per AI05-0022, the container implementation is required to detect
973 -- element tampering by a generic actual subprogram.
976 TA : Elements_Array renames Target.Elements.EA;
977 SA : Elements_Array renames Source.Elements.EA;
979 Lock_Target : With_Lock (Target.TC'Unchecked_Access);
980 Lock_Source : With_Lock (Source.TC'Unchecked_Access);
982 J := Target.Last; -- new value (after Set_Length)
983 while Source.Last >= Index_Type'First loop
985 (Source.Last <= Index_Type'First
986 or else not (Is_Less (SA (Source.Last),
987 SA (Source.Last - 1))));
989 if I < Index_Type'First then
991 Src : Elements_Array renames
992 SA (Index_Type'First .. Source.Last);
994 TA (Index_Type'First .. J) := Src;
995 Src := (others => null);
998 Source.Last := No_Index;
1003 (I <= Index_Type'First
1004 or else not (Is_Less (TA (I), TA (I - 1))));
1007 Src : Element_Access renames SA (Source.Last);
1008 Tgt : Element_Access renames TA (I);
1011 if Is_Less (Src, Tgt) then
1012 Target.Elements.EA (J) := Tgt;
1017 Target.Elements.EA (J) := Src;
1019 Source.Last := Source.Last - 1;
1032 procedure Sort (Container : in out Vector) is
1033 procedure Sort is new Generic_Array_Sort
1034 (Index_Type => Index_Type,
1035 Element_Type => Element_Access,
1036 Array_Type => Elements_Array,
1039 -- Start of processing for Sort
1042 if Container.Last <= Index_Type'First then
1046 -- The exception behavior for the vector container must match that
1047 -- for the list container, so we check for cursor tampering here
1048 -- (which will catch more things) instead of for element tampering
1049 -- (which will catch fewer things). It's true that the elements of
1050 -- this vector container could be safely moved around while (say) an
1051 -- iteration is taking place (iteration only increments the busy
1052 -- counter), and so technically all we would need here is a test for
1053 -- element tampering (indicated by the lock counter), that's simply
1054 -- an artifact of our array-based implementation. Logically Sort
1055 -- requires a check for cursor tampering.
1057 TC_Check (Container.TC);
1059 -- Per AI05-0022, the container implementation is required to detect
1060 -- element tampering by a generic actual subprogram.
1063 Lock : With_Lock (Container.TC'Unchecked_Access);
1065 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1069 end Generic_Sorting;
1071 ------------------------
1072 -- Get_Element_Access --
1073 ------------------------
1075 function Get_Element_Access
1076 (Position : Cursor) return not null Element_Access
1078 Ptr : constant Element_Access :=
1079 Position.Container.Elements.EA (Position.Index);
1082 -- An indefinite vector may contain spaces that hold no elements.
1083 -- Any iteration over an indefinite vector with spaces will raise
1084 -- Constraint_Error.
1087 raise Constraint_Error;
1092 end Get_Element_Access;
1098 function Has_Element (Position : Cursor) return Boolean is
1100 if Position.Container = null then
1103 return Position.Index <= Position.Container.Last;
1112 (Container : in out Vector;
1113 Before : Extended_Index;
1114 New_Item : Element_Type;
1115 Count : Count_Type := 1)
1117 Old_Length : constant Count_Type := Container.Length;
1119 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1120 New_Length : Count_Type'Base; -- sum of current length and Count
1121 New_Last : Index_Type'Base; -- last index of vector after insertion
1123 Index : Index_Type'Base; -- scratch for intermediate values
1124 J : Count_Type'Base; -- scratch
1126 New_Capacity : Count_Type'Base; -- length of new, expanded array
1127 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1128 Dst : Elements_Access; -- new, expanded internal array
1132 -- As a precondition on the generic actual Index_Type, the base type
1133 -- must include Index_Type'Pred (Index_Type'First); this is the value
1134 -- that Container.Last assumes when the vector is empty. However, we
1135 -- do not allow that as the value for Index when specifying where the
1136 -- new items should be inserted, so we must manually check. (That the
1137 -- user is allowed to specify the value at all here is a consequence
1138 -- of the declaration of the Extended_Index subtype, which includes
1139 -- the values in the base range that immediately precede and
1140 -- immediately follow the values in the Index_Type.)
1142 if Before < Index_Type'First then
1143 raise Constraint_Error with
1144 "Before index is out of range (too small)";
1147 -- We do allow a value greater than Container.Last to be specified as
1148 -- the Index, but only if it's immediately greater. This allows for
1149 -- the case of appending items to the back end of the vector. (It is
1150 -- assumed that specifying an index value greater than Last + 1
1151 -- indicates some deeper flaw in the caller's algorithm, so that case
1152 -- is treated as a proper error.)
1154 if Before > Container.Last + 1 then
1155 raise Constraint_Error with
1156 "Before index is out of range (too large)";
1160 -- We treat inserting 0 items into the container as a no-op, even when
1161 -- the container is busy, so we simply return.
1167 -- There are two constraints we need to satisfy. The first constraint is
1168 -- that a container cannot have more than Count_Type'Last elements, so
1169 -- we must check the sum of the current length and the insertion count.
1170 -- Note: we cannot simply add these values, because of the possibility
1173 if Checks and then Old_Length > Count_Type'Last - Count then
1174 raise Constraint_Error with "Count is out of range";
1177 -- It is now safe compute the length of the new vector, without fear of
1180 New_Length := Old_Length + Count;
1182 -- The second constraint is that the new Last index value cannot exceed
1183 -- Index_Type'Last. In each branch below, we calculate the maximum
1184 -- length (computed from the range of values in Index_Type), and then
1185 -- compare the new length to the maximum length. If the new length is
1186 -- acceptable, then we compute the new last index from that.
1188 if Index_Type'Base'Last
>= Count_Type_Last
then
1190 -- We have to handle the case when there might be more values in the
1191 -- range of Index_Type than in the range of Count_Type.
1193 if Index_Type
'First <= 0 then
1195 -- We know that No_Index (the same as Index_Type'First - 1) is
1196 -- less than 0, so it is safe to compute the following sum without
1197 -- fear of overflow.
1199 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1201 if Index
<= Index_Type
'Last then
1203 -- We have determined that range of Index_Type has at least as
1204 -- many values as in Count_Type, so Count_Type'Last is the
1205 -- maximum number of items that are allowed.
1207 Max_Length
:= Count_Type
'Last;
1210 -- The range of Index_Type has fewer values than in Count_Type,
1211 -- so the maximum number of items is computed from the range of
1214 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1218 -- No_Index is equal or greater than 0, so we can safely compute
1219 -- the difference without fear of overflow (which we would have to
1220 -- worry about if No_Index were less than 0, but that case is
1223 if Index_Type
'Last - No_Index
>= Count_Type_Last
then
1224 -- We have determined that range of Index_Type has at least as
1225 -- many values as in Count_Type, so Count_Type'Last is the
1226 -- maximum number of items that are allowed.
1228 Max_Length
:= Count_Type
'Last;
1231 -- The range of Index_Type has fewer values than in Count_Type,
1232 -- so the maximum number of items is computed from the range of
1235 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1239 elsif Index_Type
'First <= 0 then
1241 -- We know that No_Index (the same as Index_Type'First - 1) is less
1242 -- than 0, so it is safe to compute the following sum without fear of
1245 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
1247 if J
<= Count_Type
'Base (Index_Type
'Last) then
1249 -- We have determined that range of Index_Type has at least as
1250 -- many values as in Count_Type, so Count_Type'Last is the maximum
1251 -- number of items that are allowed.
1253 Max_Length
:= Count_Type
'Last;
1256 -- The range of Index_Type has fewer values than Count_Type does,
1257 -- so the maximum number of items is computed from the range of
1261 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1265 -- No_Index is equal or greater than 0, so we can safely compute the
1266 -- difference without fear of overflow (which we would have to worry
1267 -- about if No_Index were less than 0, but that case is handled
1271 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
1274 -- We have just computed the maximum length (number of items). We must
1275 -- now compare the requested length to the maximum length, as we do not
1276 -- allow a vector expand beyond the maximum (because that would create
1277 -- an internal array with a last index value greater than
1278 -- Index_Type'Last, with no way to index those elements).
1280 if Checks
and then New_Length
> Max_Length
then
1281 raise Constraint_Error
with "Count is out of range";
1284 -- New_Last is the last index value of the items in the container after
1285 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1286 -- compute its value from the New_Length.
1288 if Index_Type
'Base'Last >= Count_Type_Last then
1289 New_Last := No_Index + Index_Type'Base (New_Length);
1291 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1294 if Container.Elements = null then
1295 pragma Assert (Container.Last = No_Index);
1297 -- This is the simplest case, with which we must always begin: we're
1298 -- inserting items into an empty vector that hasn't allocated an
1299 -- internal array yet. Note that we don't need to check the busy bit
1300 -- here, because an empty container cannot be busy.
1302 -- In an indefinite vector, elements are allocated individually, and
1303 -- stored as access values on the internal array (the length of which
1304 -- represents the vector "capacity"), which is separately allocated.
1306 Container.Elements := new Elements_Type (New_Last);
1308 -- The element backbone has been successfully allocated, so now we
1309 -- allocate the elements.
1311 for Idx in Container.Elements.EA'Range loop
1313 -- In order to preserve container invariants, we always attempt
1314 -- the element allocation first, before setting the Last index
1315 -- value, in case the allocation fails (either because there is no
1316 -- storage available, or because element initialization fails).
1319 -- The element allocator may need an accessibility check in the
1320 -- case actual type is class-wide or has access discriminants
1321 -- (see RM 4.8(10.1) and AI12-0035).
1323 pragma Unsuppress (Accessibility_Check);
1326 Container.Elements.EA (Idx) := new Element_Type'(New_Item
);
1329 -- The allocation of the element succeeded, so it is now safe to
1330 -- update the Last index, restoring container invariants.
1332 Container
.Last
:= Idx
;
1338 -- The tampering bits exist to prevent an item from being harmfully
1339 -- manipulated while it is being visited. Query, Update, and Iterate
1340 -- increment the busy count on entry, and decrement the count on
1341 -- exit. Insert checks the count to determine whether it is being called
1342 -- while the associated callback procedure is executing.
1344 TC_Check
(Container
.TC
);
1346 if New_Length
<= Container
.Elements
.EA
'Length then
1348 -- In this case, we're inserting elements into a vector that has
1349 -- already allocated an internal array, and the existing array has
1350 -- enough unused storage for the new items.
1353 E
: Elements_Array
renames Container
.Elements
.EA
;
1354 K
: Index_Type
'Base;
1357 if Before
> Container
.Last
then
1359 -- The new items are being appended to the vector, so no
1360 -- sliding of existing elements is required.
1362 for Idx
in Before
.. New_Last
loop
1364 -- In order to preserve container invariants, we always
1365 -- attempt the element allocation first, before setting the
1366 -- Last index value, in case the allocation fails (either
1367 -- because there is no storage available, or because element
1368 -- initialization fails).
1371 -- The element allocator may need an accessibility check
1372 -- in case the actual type is class-wide or has access
1373 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1375 pragma Unsuppress
(Accessibility_Check
);
1378 E
(Idx
) := new Element_Type
'(New_Item);
1381 -- The allocation of the element succeeded, so it is now
1382 -- safe to update the Last index, restoring container
1385 Container.Last := Idx;
1389 -- The new items are being inserted before some existing
1390 -- elements, so we must slide the existing elements up to their
1391 -- new home. We use the wider of Index_Type'Base and
1392 -- Count_Type'Base as the type for intermediate index values.
1394 if Index_Type'Base'Last
>= Count_Type_Last
then
1395 Index
:= Before
+ Index_Type
'Base (Count
);
1397 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
1400 -- The new items are being inserted in the middle of the array,
1401 -- in the range [Before, Index). Copy the existing elements to
1402 -- the end of the array, to make room for the new items.
1404 E
(Index
.. New_Last
) := E
(Before
.. Container
.Last
);
1405 Container
.Last
:= New_Last
;
1407 -- We have copied the existing items up to the end of the
1408 -- array, to make room for the new items in the middle of
1409 -- the array. Now we actually allocate the new items.
1411 -- Note: initialize K outside loop to make it clear that
1412 -- K always has a value if the exception handler triggers.
1417 -- The element allocator may need an accessibility check in
1418 -- the case the actual type is class-wide or has access
1419 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1421 pragma Unsuppress
(Accessibility_Check
);
1424 while K
< Index
loop
1425 E
(K
) := new Element_Type
'(New_Item);
1432 -- Values in the range [Before, K) were successfully
1433 -- allocated, but values in the range [K, Index) are
1434 -- stale (these array positions contain copies of the
1435 -- old items, that did not get assigned a new item,
1436 -- because the allocation failed). We must finish what
1437 -- we started by clearing out all of the stale values,
1438 -- leaving a "hole" in the middle of the array.
1440 E (K .. Index - 1) := (others => null);
1449 -- In this case, we're inserting elements into a vector that has already
1450 -- allocated an internal array, but the existing array does not have
1451 -- enough storage, so we must allocate a new, longer array. In order to
1452 -- guarantee that the amortized insertion cost is O(1), we always
1453 -- allocate an array whose length is some power-of-two factor of the
1454 -- current array length. (The new array cannot have a length less than
1455 -- the New_Length of the container, but its last index value cannot be
1456 -- greater than Index_Type'Last.)
1458 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1459 while New_Capacity < New_Length loop
1460 if New_Capacity > Count_Type'Last / 2 then
1461 New_Capacity := Count_Type'Last;
1465 New_Capacity := 2 * New_Capacity;
1468 if New_Capacity > Max_Length then
1470 -- We have reached the limit of capacity, so no further expansion
1471 -- will occur. (This is not a problem, as there is never a need to
1472 -- have more capacity than the maximum container length.)
1474 New_Capacity := Max_Length;
1477 -- We have computed the length of the new internal array (and this is
1478 -- what "vector capacity" means), so use that to compute its last index.
1480 if Index_Type'Base'Last
>= Count_Type_Last
then
1481 Dst_Last
:= No_Index
+ Index_Type
'Base (New_Capacity
);
1484 Index_Type
'Base (Count_Type
'Base (No_Index
) + New_Capacity
);
1487 -- Now we allocate the new, longer internal array. If the allocation
1488 -- fails, we have not changed any container state, so no side-effect
1489 -- will occur as a result of propagating the exception.
1491 Dst
:= new Elements_Type
(Dst_Last
);
1493 -- We have our new internal array. All that needs to be done now is to
1494 -- copy the existing items (if any) from the old array (the "source"
1495 -- array) to the new array (the "destination" array), and then
1496 -- deallocate the old array.
1499 Src
: Elements_Access
:= Container
.Elements
;
1502 Dst
.EA
(Index_Type
'First .. Before
- 1) :=
1503 Src
.EA
(Index_Type
'First .. Before
- 1);
1505 if Before
> Container
.Last
then
1507 -- The new items are being appended to the vector, so no
1508 -- sliding of existing elements is required.
1510 -- We have copied the elements from to the old source array to the
1511 -- new destination array, so we can now deallocate the old array.
1513 Container
.Elements
:= Dst
;
1516 -- Now we append the new items.
1518 for Idx
in Before
.. New_Last
loop
1520 -- In order to preserve container invariants, we always attempt
1521 -- the element allocation first, before setting the Last index
1522 -- value, in case the allocation fails (either because there
1523 -- is no storage available, or because element initialization
1527 -- The element allocator may need an accessibility check in
1528 -- the case the actual type is class-wide or has access
1529 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1531 pragma Unsuppress
(Accessibility_Check
);
1534 Dst
.EA
(Idx
) := new Element_Type
'(New_Item);
1537 -- The allocation of the element succeeded, so it is now safe
1538 -- to update the Last index, restoring container invariants.
1540 Container.Last := Idx;
1544 -- The new items are being inserted before some existing elements,
1545 -- so we must slide the existing elements up to their new home.
1547 if Index_Type'Base'Last
>= Count_Type_Last
then
1548 Index
:= Before
+ Index_Type
'Base (Count
);
1550 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
1553 Dst
.EA
(Index
.. New_Last
) := Src
.EA
(Before
.. Container
.Last
);
1555 -- We have copied the elements from to the old source array to the
1556 -- new destination array, so we can now deallocate the old array.
1558 Container
.Elements
:= Dst
;
1559 Container
.Last
:= New_Last
;
1562 -- The new array has a range in the middle containing null access
1563 -- values. Fill in that partition of the array with the new items.
1565 for Idx
in Before
.. Index
- 1 loop
1567 -- Note that container invariants have already been satisfied
1568 -- (in particular, the Last index value of the vector has
1569 -- already been updated), so if this allocation fails we simply
1570 -- let it propagate.
1573 -- The element allocator may need an accessibility check in
1574 -- the case the actual type is class-wide or has access
1575 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1577 pragma Unsuppress
(Accessibility_Check
);
1580 Dst
.EA
(Idx
) := new Element_Type
'(New_Item);
1588 (Container : in out Vector;
1589 Before : Extended_Index;
1592 N : constant Count_Type := Length (New_Item);
1593 J : Index_Type'Base;
1596 -- Use Insert_Space to create the "hole" (the destination slice) into
1597 -- which we copy the source items.
1599 Insert_Space (Container, Before, Count => N);
1603 -- There's nothing else to do here (vetting of parameters was
1604 -- performed already in Insert_Space), so we simply return.
1609 if Container'Address /= New_Item'Address then
1611 -- This is the simple case. New_Item denotes an object different
1612 -- from Container, so there's nothing special we need to do to copy
1613 -- the source items to their destination, because all of the source
1614 -- items are contiguous.
1617 subtype Src_Index_Subtype is Index_Type'Base range
1618 Index_Type'First .. New_Item.Last;
1620 Src : Elements_Array renames
1621 New_Item.Elements.EA (Src_Index_Subtype);
1623 Dst : Elements_Array renames Container.Elements.EA;
1625 Dst_Index : Index_Type'Base;
1628 Dst_Index := Before - 1;
1629 for Src_Index in Src'Range loop
1630 Dst_Index := Dst_Index + 1;
1632 if Src (Src_Index) /= null then
1633 Dst (Dst_Index) := new Element_Type'(Src
(Src_Index
).all);
1641 -- New_Item denotes the same object as Container, so an insertion has
1642 -- potentially split the source items. The first source slice is
1643 -- [Index_Type'First, Before), and the second source slice is
1644 -- [J, Container.Last], where index value J is the first index of the
1645 -- second slice. (J gets computed below, but only after we have
1646 -- determined that the second source slice is non-empty.) The
1647 -- destination slice is always the range [Before, J). We perform the
1648 -- copy in two steps, using each of the two slices of the source items.
1651 L
: constant Index_Type
'Base := Before
- 1;
1653 subtype Src_Index_Subtype
is Index_Type
'Base range
1654 Index_Type
'First .. L
;
1656 Src
: Elements_Array
renames
1657 Container
.Elements
.EA
(Src_Index_Subtype
);
1659 Dst
: Elements_Array
renames Container
.Elements
.EA
;
1661 Dst_Index
: Index_Type
'Base;
1664 -- We first copy the source items that precede the space we
1665 -- inserted. (If Before equals Index_Type'First, then this first
1666 -- source slice will be empty, which is harmless.)
1668 Dst_Index
:= Before
- 1;
1669 for Src_Index
in Src
'Range loop
1670 Dst_Index
:= Dst_Index
+ 1;
1672 if Src
(Src_Index
) /= null then
1673 Dst
(Dst_Index
) := new Element_Type
'(Src (Src_Index).all);
1677 if Src'Length = N then
1679 -- The new items were effectively appended to the container, so we
1680 -- have already copied all of the items that need to be copied.
1681 -- We return early here, even though the source slice below is
1682 -- empty (so the assignment would be harmless), because we want to
1683 -- avoid computing J, which will overflow if J is greater than
1684 -- Index_Type'Base'Last
.
1690 -- Index value J is the first index of the second source slice. (It is
1691 -- also 1 greater than the last index of the destination slice.) Note:
1692 -- avoid computing J if J is greater than Index_Type'Base'Last, in order
1693 -- to avoid overflow. Prevent that by returning early above, immediately
1694 -- after copying the first slice of the source, and determining that
1695 -- this second slice of the source is empty.
1697 if Index_Type
'Base'Last >= Count_Type_Last then
1698 J := Before + Index_Type'Base (N);
1700 J := Index_Type'Base (Count_Type'Base (Before) + N);
1704 subtype Src_Index_Subtype is Index_Type'Base range
1705 J .. Container.Last;
1707 Src : Elements_Array renames
1708 Container.Elements.EA (Src_Index_Subtype);
1710 Dst : Elements_Array renames Container.Elements.EA;
1712 Dst_Index : Index_Type'Base;
1715 -- We next copy the source items that follow the space we inserted.
1716 -- Index value Dst_Index is the first index of that portion of the
1717 -- destination that receives this slice of the source. (For the
1718 -- reasons given above, this slice is guaranteed to be non-empty.)
1720 if Index_Type'Base'Last
>= Count_Type_Last
then
1721 Dst_Index
:= J
- Index_Type
'Base (Src
'Length);
1723 Dst_Index
:= Index_Type
'Base (Count_Type
'Base (J
) - Src
'Length);
1726 for Src_Index
in Src
'Range loop
1727 if Src
(Src_Index
) /= null then
1728 Dst
(Dst_Index
) := new Element_Type
'(Src (Src_Index).all);
1731 Dst_Index := Dst_Index + 1;
1737 (Container : in out Vector;
1741 Index : Index_Type'Base;
1744 if Checks and then Before.Container /= null
1745 and then Before.Container /= Container'Unrestricted_Access
1747 raise Program_Error with "Before cursor denotes wrong container";
1750 if Is_Empty (New_Item) then
1754 if Before.Container = null or else Before.Index > Container.Last then
1755 if Checks and then Container.Last = Index_Type'Last then
1756 raise Constraint_Error with
1757 "vector is already at its maximum length";
1760 Index := Container.Last + 1;
1763 Index := Before.Index;
1766 Insert (Container, Index, New_Item);
1770 (Container : in out Vector;
1773 Position : out Cursor)
1775 Index : Index_Type'Base;
1778 if Checks and then Before.Container /= null
1779 and then Before.Container /= Container'Unrestricted_Access
1781 raise Program_Error with "Before cursor denotes wrong container";
1784 if Is_Empty (New_Item) then
1785 if Before.Container = null or else Before.Index > Container.Last then
1786 Position := No_Element;
1788 Position := (Container'Unrestricted_Access, Before.Index);
1794 if Before.Container = null or else Before.Index > Container.Last then
1795 if Checks and then Container.Last = Index_Type'Last then
1796 raise Constraint_Error with
1797 "vector is already at its maximum length";
1800 Index := Container.Last + 1;
1803 Index := Before.Index;
1806 Insert (Container, Index, New_Item);
1808 Position := (Container'Unrestricted_Access, Index);
1812 (Container : in out Vector;
1814 New_Item : Element_Type;
1815 Count : Count_Type := 1)
1817 Index : Index_Type'Base;
1820 if Checks and then Before.Container /= null
1821 and then Before.Container /= Container'Unrestricted_Access
1823 raise Program_Error with "Before cursor denotes wrong container";
1830 if Before.Container = null or else Before.Index > Container.Last then
1831 if Checks and then Container.Last = Index_Type'Last then
1832 raise Constraint_Error with
1833 "vector is already at its maximum length";
1836 Index := Container.Last + 1;
1839 Index := Before.Index;
1842 Insert (Container, Index, New_Item, Count);
1846 (Container : in out Vector;
1848 New_Item : Element_Type;
1849 Position : out Cursor;
1850 Count : Count_Type := 1)
1852 Index : Index_Type'Base;
1855 if Checks and then Before.Container /= null
1856 and then Before.Container /= Container'Unrestricted_Access
1858 raise Program_Error with "Before cursor denotes wrong container";
1862 if Before.Container = null or else Before.Index > Container.Last then
1863 Position := No_Element;
1865 Position := (Container'Unrestricted_Access, Before.Index);
1871 if Before.Container = null or else Before.Index > Container.Last then
1872 if Checks and then Container.Last = Index_Type'Last then
1873 raise Constraint_Error with
1874 "vector is already at its maximum length";
1877 Index := Container.Last + 1;
1880 Index := Before.Index;
1883 Insert (Container, Index, New_Item, Count);
1885 Position := (Container'Unrestricted_Access, Index);
1892 procedure Insert_Space
1893 (Container : in out Vector;
1894 Before : Extended_Index;
1895 Count : Count_Type := 1)
1897 Old_Length : constant Count_Type := Container.Length;
1899 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1900 New_Length : Count_Type'Base; -- sum of current length and Count
1901 New_Last : Index_Type'Base; -- last index of vector after insertion
1903 Index : Index_Type'Base; -- scratch for intermediate values
1904 J : Count_Type'Base; -- scratch
1906 New_Capacity : Count_Type'Base; -- length of new, expanded array
1907 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1908 Dst : Elements_Access; -- new, expanded internal array
1912 -- As a precondition on the generic actual Index_Type, the base type
1913 -- must include Index_Type'Pred (Index_Type'First); this is the value
1914 -- that Container.Last assumes when the vector is empty. However, we
1915 -- do not allow that as the value for Index when specifying where the
1916 -- new items should be inserted, so we must manually check. (That the
1917 -- user is allowed to specify the value at all here is a consequence
1918 -- of the declaration of the Extended_Index subtype, which includes
1919 -- the values in the base range that immediately precede and
1920 -- immediately follow the values in the Index_Type.)
1922 if Before < Index_Type'First then
1923 raise Constraint_Error with
1924 "Before index is out of range (too small)";
1927 -- We do allow a value greater than Container.Last to be specified as
1928 -- the Index, but only if it's immediately greater. This allows for
1929 -- the case of appending items to the back end of the vector. (It is
1930 -- assumed that specifying an index value greater than Last + 1
1931 -- indicates some deeper flaw in the caller's algorithm, so that case
1932 -- is treated as a proper error.)
1934 if Before > Container.Last + 1 then
1935 raise Constraint_Error with
1936 "Before index is out of range (too large)";
1940 -- We treat inserting 0 items into the container as a no-op, even when
1941 -- the container is busy, so we simply return.
1947 -- There are two constraints we need to satisfy. The first constraint is
1948 -- that a container cannot have more than Count_Type'Last elements, so
1949 -- we must check the sum of the current length and the insertion count.
1950 -- Note: we cannot simply add these values, because of the possibility
1953 if Checks and then Old_Length > Count_Type'Last - Count then
1954 raise Constraint_Error with "Count is out of range";
1957 -- It is now safe compute the length of the new vector, without fear of
1960 New_Length := Old_Length + Count;
1962 -- The second constraint is that the new Last index value cannot exceed
1963 -- Index_Type'Last. In each branch below, we calculate the maximum
1964 -- length (computed from the range of values in Index_Type), and then
1965 -- compare the new length to the maximum length. If the new length is
1966 -- acceptable, then we compute the new last index from that.
1968 if Index_Type'Base'Last
>= Count_Type_Last
then
1969 -- We have to handle the case when there might be more values in the
1970 -- range of Index_Type than in the range of Count_Type.
1972 if Index_Type
'First <= 0 then
1974 -- We know that No_Index (the same as Index_Type'First - 1) is
1975 -- less than 0, so it is safe to compute the following sum without
1976 -- fear of overflow.
1978 Index
:= No_Index
+ Index_Type
'Base (Count_Type
'Last);
1980 if Index
<= Index_Type
'Last then
1982 -- We have determined that range of Index_Type has at least as
1983 -- many values as in Count_Type, so Count_Type'Last is the
1984 -- maximum number of items that are allowed.
1986 Max_Length
:= Count_Type
'Last;
1989 -- The range of Index_Type has fewer values than in Count_Type,
1990 -- so the maximum number of items is computed from the range of
1993 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
1997 -- No_Index is equal or greater than 0, so we can safely compute
1998 -- the difference without fear of overflow (which we would have to
1999 -- worry about if No_Index were less than 0, but that case is
2002 if Index_Type
'Last - No_Index
>= Count_Type_Last
then
2003 -- We have determined that range of Index_Type has at least as
2004 -- many values as in Count_Type, so Count_Type'Last is the
2005 -- maximum number of items that are allowed.
2007 Max_Length
:= Count_Type
'Last;
2010 -- The range of Index_Type has fewer values than in Count_Type,
2011 -- so the maximum number of items is computed from the range of
2014 Max_Length
:= Count_Type
'Base (Index_Type
'Last - No_Index
);
2018 elsif Index_Type
'First <= 0 then
2020 -- We know that No_Index (the same as Index_Type'First - 1) is less
2021 -- than 0, so it is safe to compute the following sum without fear of
2024 J
:= Count_Type
'Base (No_Index
) + Count_Type
'Last;
2026 if J
<= Count_Type
'Base (Index_Type
'Last) then
2028 -- We have determined that range of Index_Type has at least as
2029 -- many values as in Count_Type, so Count_Type'Last is the maximum
2030 -- number of items that are allowed.
2032 Max_Length
:= Count_Type
'Last;
2035 -- The range of Index_Type has fewer values than Count_Type does,
2036 -- so the maximum number of items is computed from the range of
2040 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2044 -- No_Index is equal or greater than 0, so we can safely compute the
2045 -- difference without fear of overflow (which we would have to worry
2046 -- about if No_Index were less than 0, but that case is handled
2050 Count_Type
'Base (Index_Type
'Last) - Count_Type
'Base (No_Index
);
2053 -- We have just computed the maximum length (number of items). We must
2054 -- now compare the requested length to the maximum length, as we do not
2055 -- allow a vector expand beyond the maximum (because that would create
2056 -- an internal array with a last index value greater than
2057 -- Index_Type'Last, with no way to index those elements).
2059 if Checks
and then New_Length
> Max_Length
then
2060 raise Constraint_Error
with "Count is out of range";
2063 -- New_Last is the last index value of the items in the container after
2064 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2065 -- compute its value from the New_Length.
2067 if Index_Type
'Base'Last >= Count_Type_Last then
2068 New_Last := No_Index + Index_Type'Base (New_Length);
2070 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2073 if Container.Elements = null then
2074 pragma Assert (Container.Last = No_Index);
2076 -- This is the simplest case, with which we must always begin: we're
2077 -- inserting items into an empty vector that hasn't allocated an
2078 -- internal array yet. Note that we don't need to check the busy bit
2079 -- here, because an empty container cannot be busy.
2081 -- In an indefinite vector, elements are allocated individually, and
2082 -- stored as access values on the internal array (the length of which
2083 -- represents the vector "capacity"), which is separately allocated.
2084 -- We have no elements here (because we're inserting "space"), so all
2085 -- we need to do is allocate the backbone.
2087 Container.Elements := new Elements_Type (New_Last);
2088 Container.Last := New_Last;
2093 -- The tampering bits exist to prevent an item from being harmfully
2094 -- manipulated while it is being visited. Query, Update, and Iterate
2095 -- increment the busy count on entry, and decrement the count on exit.
2096 -- Insert checks the count to determine whether it is being called while
2097 -- the associated callback procedure is executing.
2099 TC_Check (Container.TC);
2101 if New_Length <= Container.Elements.EA'Length then
2103 -- In this case, we are inserting elements into a vector that has
2104 -- already allocated an internal array, and the existing array has
2105 -- enough unused storage for the new items.
2108 E : Elements_Array renames Container.Elements.EA;
2111 if Before <= Container.Last then
2113 -- The new space is being inserted before some existing
2114 -- elements, so we must slide the existing elements up to
2115 -- their new home. We use the wider of Index_Type'Base and
2116 -- Count_Type'Base as the type for intermediate index values.
2118 if Index_Type'Base'Last
>= Count_Type_Last
then
2119 Index
:= Before
+ Index_Type
'Base (Count
);
2121 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2124 E
(Index
.. New_Last
) := E
(Before
.. Container
.Last
);
2125 E
(Before
.. Index
- 1) := (others => null);
2129 Container
.Last
:= New_Last
;
2133 -- In this case, we're inserting elements into a vector that has already
2134 -- allocated an internal array, but the existing array does not have
2135 -- enough storage, so we must allocate a new, longer array. In order to
2136 -- guarantee that the amortized insertion cost is O(1), we always
2137 -- allocate an array whose length is some power-of-two factor of the
2138 -- current array length. (The new array cannot have a length less than
2139 -- the New_Length of the container, but its last index value cannot be
2140 -- greater than Index_Type'Last.)
2142 New_Capacity
:= Count_Type
'Max (1, Container
.Elements
.EA
'Length);
2143 while New_Capacity
< New_Length
loop
2144 if New_Capacity
> Count_Type
'Last / 2 then
2145 New_Capacity
:= Count_Type
'Last;
2149 New_Capacity
:= 2 * New_Capacity
;
2152 if New_Capacity
> Max_Length
then
2154 -- We have reached the limit of capacity, so no further expansion
2155 -- will occur. (This is not a problem, as there is never a need to
2156 -- have more capacity than the maximum container length.)
2158 New_Capacity
:= Max_Length
;
2161 -- We have computed the length of the new internal array (and this is
2162 -- what "vector capacity" means), so use that to compute its last index.
2164 if Index_Type
'Base'Last >= Count_Type_Last then
2165 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2168 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2171 -- Now we allocate the new, longer internal array. If the allocation
2172 -- fails, we have not changed any container state, so no side-effect
2173 -- will occur as a result of propagating the exception.
2175 Dst := new Elements_Type (Dst_Last);
2177 -- We have our new internal array. All that needs to be done now is to
2178 -- copy the existing items (if any) from the old array (the "source"
2179 -- array) to the new array (the "destination" array), and then
2180 -- deallocate the old array.
2183 Src : Elements_Access := Container.Elements;
2186 Dst.EA (Index_Type'First .. Before - 1) :=
2187 Src.EA (Index_Type'First .. Before - 1);
2189 if Before <= Container.Last then
2191 -- The new items are being inserted before some existing elements,
2192 -- so we must slide the existing elements up to their new home.
2194 if Index_Type'Base'Last
>= Count_Type_Last
then
2195 Index
:= Before
+ Index_Type
'Base (Count
);
2197 Index
:= Index_Type
'Base (Count_Type
'Base (Before
) + Count
);
2200 Dst
.EA
(Index
.. New_Last
) := Src
.EA
(Before
.. Container
.Last
);
2203 -- We have copied the elements from to the old, source array to the
2204 -- new, destination array, so we can now restore invariants, and
2205 -- deallocate the old array.
2207 Container
.Elements
:= Dst
;
2208 Container
.Last
:= New_Last
;
2213 procedure Insert_Space
2214 (Container
: in out Vector
;
2216 Position
: out Cursor
;
2217 Count
: Count_Type
:= 1)
2219 Index
: Index_Type
'Base;
2222 if Checks
and then Before
.Container
/= null
2223 and then Before
.Container
/= Container
'Unrestricted_Access
2225 raise Program_Error
with "Before cursor denotes wrong container";
2229 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2230 Position
:= No_Element
;
2232 Position
:= (Container
'Unrestricted_Access, Before
.Index
);
2238 if Before
.Container
= null or else Before
.Index
> Container
.Last
then
2239 if Checks
and then Container
.Last
= Index_Type
'Last then
2240 raise Constraint_Error
with
2241 "vector is already at its maximum length";
2244 Index
:= Container
.Last
+ 1;
2247 Index
:= Before
.Index
;
2250 Insert_Space
(Container
, Index
, Count
);
2252 Position
:= (Container
'Unrestricted_Access, Index
);
2259 function Is_Empty
(Container
: Vector
) return Boolean is
2261 return Container
.Last
< Index_Type
'First;
2269 (Container
: Vector
;
2270 Process
: not null access procedure (Position
: Cursor
))
2272 Busy
: With_Busy
(Container
.TC
'Unrestricted_Access);
2274 for Indx
in Index_Type
'First .. Container
.Last
loop
2275 Process
(Cursor
'(Container'Unrestricted_Access, Indx));
2280 (Container : Vector)
2281 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2283 V : constant Vector_Access := Container'Unrestricted_Access;
2285 -- The value of its Index component influences the behavior of the First
2286 -- and Last selector functions of the iterator object. When the Index
2287 -- component is No_Index (as is the case here), this means the iterator
2288 -- object was constructed without a start expression. This is a complete
2289 -- iterator, meaning that the iteration starts from the (logical)
2290 -- beginning of the sequence of items.
2292 -- Note: For a forward iterator, Container.First is the beginning, and
2293 -- for a reverse iterator, Container.Last is the beginning.
2295 return It : constant Iterator :=
2296 (Limited_Controlled with
2300 Busy (Container.TC'Unrestricted_Access.all);
2305 (Container : Vector;
2307 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2309 V : constant Vector_Access := Container'Unrestricted_Access;
2311 -- It was formerly the case that when Start = No_Element, the partial
2312 -- iterator was defined to behave the same as for a complete iterator,
2313 -- and iterate over the entire sequence of items. However, those
2314 -- semantics were unintuitive and arguably error-prone (it is too easy
2315 -- to accidentally create an endless loop), and so they were changed,
2316 -- per the ARG meeting in Denver on 2011/11. However, there was no
2317 -- consensus about what positive meaning this corner case should have,
2318 -- and so it was decided to simply raise an exception. This does imply,
2319 -- however, that it is not possible to use a partial iterator to specify
2320 -- an empty sequence of items.
2323 if Start.Container = null then
2324 raise Constraint_Error with
2325 "Start position for iterator equals No_Element";
2328 if Start.Container /= V then
2329 raise Program_Error with
2330 "Start cursor of Iterate designates wrong vector";
2333 if Start.Index > V.Last then
2334 raise Constraint_Error with
2335 "Start position for iterator equals No_Element";
2339 -- The value of its Index component influences the behavior of the First
2340 -- and Last selector functions of the iterator object. When the Index
2341 -- component is not No_Index (as is the case here), it means that this
2342 -- is a partial iteration, over a subset of the complete sequence of
2343 -- items. The iterator object was constructed with a start expression,
2344 -- indicating the position from which the iteration begins. Note that
2345 -- the start position has the same value irrespective of whether this
2346 -- is a forward or reverse iteration.
2348 return It : constant Iterator :=
2349 (Limited_Controlled with
2351 Index => Start.Index)
2353 Busy (Container.TC'Unrestricted_Access.all);
2361 function Last (Container : Vector) return Cursor is
2363 if Is_Empty (Container) then
2367 return (Container'Unrestricted_Access, Container.Last);
2370 function Last (Object : Iterator) return Cursor is
2372 -- The value of the iterator object's Index component influences the
2373 -- behavior of the Last (and First) selector function.
2375 -- When the Index component is No_Index, this means the iterator
2376 -- object was constructed without a start expression, in which case the
2377 -- (reverse) iteration starts from the (logical) beginning of the entire
2378 -- sequence (corresponding to Container.Last, for a reverse iterator).
2380 -- Otherwise, this is iteration over a partial sequence of items.
2381 -- When the Index component is not No_Index, the iterator object was
2382 -- constructed with a start expression, that specifies the position
2383 -- from which the (reverse) partial iteration begins.
2385 if Object.Index = No_Index then
2386 return Last (Object.Container.all);
2388 return Cursor'(Object
.Container
, Object
.Index
);
2396 function Last_Element
(Container
: Vector
) return Element_Type
is
2398 if Checks
and then Container
.Last
= No_Index
then
2399 raise Constraint_Error
with "Container is empty";
2403 EA
: constant Element_Access
:=
2404 Container
.Elements
.EA
(Container
.Last
);
2406 if Checks
and then EA
= null then
2407 raise Constraint_Error
with "last element is empty";
2418 function Last_Index
(Container
: Vector
) return Extended_Index
is
2420 return Container
.Last
;
2427 function Length
(Container
: Vector
) return Count_Type
is
2428 L
: constant Index_Type
'Base := Container
.Last
;
2429 F
: constant Index_Type
:= Index_Type
'First;
2432 -- The base range of the index type (Index_Type'Base) might not include
2433 -- all values for length (Count_Type). Contrariwise, the index type
2434 -- might include values outside the range of length. Hence we use
2435 -- whatever type is wider for intermediate values when calculating
2436 -- length. Note that no matter what the index type is, the maximum
2437 -- length to which a vector is allowed to grow is always the minimum
2438 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2440 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2441 -- to have a base range of -128 .. 127, but the corresponding vector
2442 -- would have lengths in the range 0 .. 255. In this case we would need
2443 -- to use Count_Type'Base for intermediate values.
2445 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2446 -- vector would have a maximum length of 10, but the index values lie
2447 -- outside the range of Count_Type (which is only 32 bits). In this
2448 -- case we would need to use Index_Type'Base for intermediate values.
2450 if Count_Type
'Base'Last >= Index_Type'Pos (Index_Type'Base'Last
) then
2451 return Count_Type
'Base (L
) - Count_Type
'Base (F
) + 1;
2453 return Count_Type
(L
- F
+ 1);
2462 (Target
: in out Vector
;
2463 Source
: in out Vector
)
2466 if Target
'Address = Source
'Address then
2470 TC_Check
(Source
.TC
);
2472 Clear
(Target
); -- Checks busy-bit
2475 Target_Elements
: constant Elements_Access
:= Target
.Elements
;
2477 Target
.Elements
:= Source
.Elements
;
2478 Source
.Elements
:= Target_Elements
;
2481 Target
.Last
:= Source
.Last
;
2482 Source
.Last
:= No_Index
;
2489 function Next
(Position
: Cursor
) return Cursor
is
2491 if Position
.Container
= null then
2493 elsif Position
.Index
< Position
.Container
.Last
then
2494 return (Position
.Container
, Position
.Index
+ 1);
2500 function Next
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
2502 if Position
.Container
= null then
2504 elsif Checks
and then Position
.Container
/= Object
.Container
then
2505 raise Program_Error
with
2506 "Position cursor of Next designates wrong vector";
2508 return Next
(Position
);
2512 procedure Next
(Position
: in out Cursor
) is
2514 if Position
.Container
= null then
2516 elsif Position
.Index
< Position
.Container
.Last
then
2517 Position
.Index
:= Position
.Index
+ 1;
2519 Position
:= No_Element
;
2527 procedure Prepend
(Container
: in out Vector
; New_Item
: Vector
) is
2529 Insert
(Container
, Index_Type
'First, New_Item
);
2533 (Container
: in out Vector
;
2534 New_Item
: Element_Type
;
2535 Count
: Count_Type
:= 1)
2538 Insert
(Container
, Index_Type
'First, New_Item
, Count
);
2545 function Previous
(Position
: Cursor
) return Cursor
is
2547 if Position
.Container
= null then
2549 elsif Position
.Index
> Index_Type
'First then
2550 return (Position
.Container
, Position
.Index
- 1);
2556 function Previous
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
2558 if Position
.Container
= null then
2560 elsif Checks
and then Position
.Container
/= Object
.Container
then
2561 raise Program_Error
with
2562 "Position cursor of Previous designates wrong vector";
2564 return Previous
(Position
);
2568 procedure Previous
(Position
: in out Cursor
) is
2570 if Position
.Container
= null then
2572 elsif Position
.Index
> Index_Type
'First then
2573 Position
.Index
:= Position
.Index
- 1;
2575 Position
:= No_Element
;
2579 ----------------------
2580 -- Pseudo_Reference --
2581 ----------------------
2583 function Pseudo_Reference
2584 (Container
: aliased Vector
'Class) return Reference_Control_Type
2586 TC
: constant Tamper_Counts_Access
:= Container
.TC
'Unrestricted_Access;
2588 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
2591 end Pseudo_Reference
;
2597 procedure Query_Element
2598 (Container
: Vector
;
2600 Process
: not null access procedure (Element
: Element_Type
))
2602 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
2603 V
: Vector
renames Container
'Unrestricted_Access.all;
2606 if Checks
and then Index
> Container
.Last
then
2607 raise Constraint_Error
with "Index is out of range";
2610 if Checks
and then V
.Elements
.EA
(Index
) = null then
2611 raise Constraint_Error
with "element is null";
2614 Process
(V
.Elements
.EA
(Index
).all);
2617 procedure Query_Element
2619 Process
: not null access procedure (Element
: Element_Type
))
2622 if Checks
and then Position
.Container
= null then
2623 raise Constraint_Error
with "Position cursor has no element";
2625 Query_Element
(Position
.Container
.all, Position
.Index
, Process
);
2634 (Stream
: not null access Root_Stream_Type
'Class;
2635 Container
: out Vector
)
2637 Length
: Count_Type
'Base;
2638 Last
: Index_Type
'Base := Index_Type
'Pred (Index_Type
'First);
2644 Count_Type
'Base'Read (Stream, Length);
2646 if Length > Capacity (Container) then
2647 Reserve_Capacity (Container, Capacity => Length);
2650 for J in Count_Type range 1 .. Length loop
2653 Boolean'Read (Stream, B);
2656 Container.Elements.EA (Last) :=
2657 new Element_Type'(Element_Type
'Input (Stream
));
2660 Container
.Last
:= Last
;
2665 (Stream
: not null access Root_Stream_Type
'Class;
2666 Position
: out Cursor
)
2669 raise Program_Error
with "attempt to stream vector cursor";
2673 (Stream
: not null access Root_Stream_Type
'Class;
2674 Item
: out Reference_Type
)
2677 raise Program_Error
with "attempt to stream reference";
2681 (Stream
: not null access Root_Stream_Type
'Class;
2682 Item
: out Constant_Reference_Type
)
2685 raise Program_Error
with "attempt to stream reference";
2693 (Container
: aliased in out Vector
;
2694 Position
: Cursor
) return Reference_Type
2698 if Position
.Container
= null then
2699 raise Constraint_Error
with "Position cursor has no element";
2702 if Position
.Container
/= Container
'Unrestricted_Access then
2703 raise Program_Error
with "Position cursor denotes wrong container";
2706 if Position
.Index
> Position
.Container
.Last
then
2707 raise Constraint_Error
with "Position cursor is out of range";
2712 TC
: constant Tamper_Counts_Access
:=
2713 Container
.TC
'Unrestricted_Access;
2715 -- The following will raise Constraint_Error if Element is null
2717 return R
: constant Reference_Type
:=
2718 (Element
=> Container
.Elements
.EA
(Position
.Index
),
2719 Control
=> (Controlled
with TC
))
2727 (Container
: aliased in out Vector
;
2728 Index
: Index_Type
) return Reference_Type
2731 if Checks
and then Index
> Container
.Last
then
2732 raise Constraint_Error
with "Index is out of range";
2736 TC
: constant Tamper_Counts_Access
:=
2737 Container
.TC
'Unrestricted_Access;
2739 -- The following will raise Constraint_Error if Element is null
2741 return R
: constant Reference_Type
:=
2742 (Element
=> Container
.Elements
.EA
(Index
),
2743 Control
=> (Controlled
with TC
))
2750 ---------------------
2751 -- Replace_Element --
2752 ---------------------
2754 procedure Replace_Element
2755 (Container
: in out Vector
;
2757 New_Item
: Element_Type
)
2760 if Checks
and then Index
> Container
.Last
then
2761 raise Constraint_Error
with "Index is out of range";
2764 TE_Check
(Container
.TC
);
2767 X
: Element_Access
:= Container
.Elements
.EA
(Index
);
2769 -- The element allocator may need an accessibility check in the case
2770 -- where the actual type is class-wide or has access discriminants
2771 -- (see RM 4.8(10.1) and AI12-0035).
2773 pragma Unsuppress
(Accessibility_Check
);
2776 Container
.Elements
.EA
(Index
) := new Element_Type
'(New_Item);
2779 end Replace_Element;
2781 procedure Replace_Element
2782 (Container : in out Vector;
2784 New_Item : Element_Type)
2788 if Position.Container = null then
2789 raise Constraint_Error with "Position cursor has no element";
2792 if Position.Container /= Container'Unrestricted_Access then
2793 raise Program_Error with "Position cursor denotes wrong container";
2796 if Position.Index > Container.Last then
2797 raise Constraint_Error with "Position cursor is out of range";
2801 TE_Check (Container.TC);
2804 X : Element_Access := Container.Elements.EA (Position.Index);
2806 -- The element allocator may need an accessibility check in the case
2807 -- where the actual type is class-wide or has access discriminants
2808 -- (see RM 4.8(10.1) and AI12-0035).
2810 pragma Unsuppress (Accessibility_Check);
2813 Container.Elements.EA (Position.Index) := new Element_Type'(New_Item
);
2816 end Replace_Element
;
2818 ----------------------
2819 -- Reserve_Capacity --
2820 ----------------------
2822 procedure Reserve_Capacity
2823 (Container
: in out Vector
;
2824 Capacity
: Count_Type
)
2826 N
: constant Count_Type
:= Length
(Container
);
2828 Index
: Count_Type
'Base;
2829 Last
: Index_Type
'Base;
2832 -- Reserve_Capacity can be used to either expand the storage available
2833 -- for elements (this would be its typical use, in anticipation of
2834 -- future insertion), or to trim back storage. In the latter case,
2835 -- storage can only be trimmed back to the limit of the container
2836 -- length. Note that Reserve_Capacity neither deletes (active) elements
2837 -- nor inserts elements; it only affects container capacity, never
2838 -- container length.
2840 if Capacity
= 0 then
2842 -- This is a request to trim back storage, to the minimum amount
2843 -- possible given the current state of the container.
2847 -- The container is empty, so in this unique case we can
2848 -- deallocate the entire internal array. Note that an empty
2849 -- container can never be busy, so there's no need to check the
2853 X
: Elements_Access
:= Container
.Elements
;
2856 -- First we remove the internal array from the container, to
2857 -- handle the case when the deallocation raises an exception
2858 -- (although that's unlikely, since this is simply an array of
2859 -- access values, all of which are null).
2861 Container
.Elements
:= null;
2863 -- Container invariants have been restored, so it is now safe
2864 -- to attempt to deallocate the internal array.
2869 elsif N
< Container
.Elements
.EA
'Length then
2871 -- The container is not empty, and the current length is less than
2872 -- the current capacity, so there's storage available to trim. In
2873 -- this case, we allocate a new internal array having a length
2874 -- that exactly matches the number of items in the
2875 -- container. (Reserve_Capacity does not delete active elements,
2876 -- so this is the best we can do with respect to minimizing
2879 TC_Check
(Container
.TC
);
2882 subtype Array_Index_Subtype
is Index_Type
'Base range
2883 Index_Type
'First .. Container
.Last
;
2885 Src
: Elements_Array
renames
2886 Container
.Elements
.EA
(Array_Index_Subtype
);
2888 X
: Elements_Access
:= Container
.Elements
;
2891 -- Although we have isolated the old internal array that we're
2892 -- going to deallocate, we don't deallocate it until we have
2893 -- successfully allocated a new one. If there is an exception
2894 -- during allocation (because there is not enough storage), we
2895 -- let it propagate without causing any side-effect.
2897 Container
.Elements
:= new Elements_Type
'(Container.Last, Src);
2899 -- We have successfully allocated a new internal array (with a
2900 -- smaller length than the old one, and containing a copy of
2901 -- just the active elements in the container), so we can
2902 -- deallocate the old array.
2911 -- Reserve_Capacity can be used to expand the storage available for
2912 -- elements, but we do not let the capacity grow beyond the number of
2913 -- values in Index_Type'Range. (Were it otherwise, there would be no way
2914 -- to refer to the elements with index values greater than
2915 -- Index_Type'Last, so that storage would be wasted.) Here we compute
2916 -- the Last index value of the new internal array, in a way that avoids
2917 -- any possibility of overflow.
2919 if Index_Type'Base'Last
>= Count_Type_Last
then
2921 -- We perform a two-part test. First we determine whether the
2922 -- computed Last value lies in the base range of the type, and then
2923 -- determine whether it lies in the range of the index (sub)type.
2925 -- Last must satisfy this relation:
2926 -- First + Length - 1 <= Last
2927 -- We regroup terms:
2928 -- First - 1 <= Last - Length
2929 -- Which can rewrite as:
2930 -- No_Index <= Last - Length
2933 Index_Type
'Base'Last - Index_Type'Base (Capacity) < No_Index
2935 raise Constraint_Error with "Capacity is out of range";
2938 -- We now know that the computed value of Last is within the base
2939 -- range of the type, so it is safe to compute its value:
2941 Last := No_Index + Index_Type'Base (Capacity);
2943 -- Finally we test whether the value is within the range of the
2944 -- generic actual index subtype:
2946 if Checks and then Last > Index_Type'Last then
2947 raise Constraint_Error with "Capacity is out of range";
2950 elsif Index_Type'First <= 0 then
2952 -- Here we can compute Last directly, in the normal way. We know that
2953 -- No_Index is less than 0, so there is no danger of overflow when
2954 -- adding the (positive) value of Capacity.
2956 Index := Count_Type'Base (No_Index) + Capacity; -- Last
2958 if Checks and then Index > Count_Type'Base (Index_Type'Last) then
2959 raise Constraint_Error with "Capacity is out of range";
2962 -- We know that the computed value (having type Count_Type) of Last
2963 -- is within the range of the generic actual index subtype, so it is
2964 -- safe to convert to Index_Type:
2966 Last := Index_Type'Base (Index);
2969 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2970 -- must test the length indirectly (by working backwards from the
2971 -- largest possible value of Last), in order to prevent overflow.
2973 Index := Count_Type'Base (Index_Type'Last) - Capacity; -- No_Index
2975 if Checks and then Index < Count_Type'Base (No_Index) then
2976 raise Constraint_Error with "Capacity is out of range";
2979 -- We have determined that the value of Capacity would not create a
2980 -- Last index value outside of the range of Index_Type, so we can now
2981 -- safely compute its value.
2983 Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
2986 -- The requested capacity is non-zero, but we don't know yet whether
2987 -- this is a request for expansion or contraction of storage.
2989 if Container.Elements = null then
2991 -- The container is empty (it doesn't even have an internal array),
2992 -- so this represents a request to allocate storage having the given
2995 Container.Elements := new Elements_Type (Last);
2999 if Capacity <= N then
3001 -- This is a request to trim back storage, but only to the limit of
3002 -- what's already in the container. (Reserve_Capacity never deletes
3003 -- active elements, it only reclaims excess storage.)
3005 if N < Container.Elements.EA'Length then
3007 -- The container is not empty (because the requested capacity is
3008 -- positive, and less than or equal to the container length), and
3009 -- the current length is less than the current capacity, so there
3010 -- is storage available to trim. In this case, we allocate a new
3011 -- internal array having a length that exactly matches the number
3012 -- of items in the container.
3014 TC_Check (Container.TC);
3017 subtype Array_Index_Subtype is Index_Type'Base range
3018 Index_Type'First .. Container.Last;
3020 Src : Elements_Array renames
3021 Container.Elements.EA (Array_Index_Subtype);
3023 X : Elements_Access := Container.Elements;
3026 -- Although we have isolated the old internal array that we're
3027 -- going to deallocate, we don't deallocate it until we have
3028 -- successfully allocated a new one. If there is an exception
3029 -- during allocation (because there is not enough storage), we
3030 -- let it propagate without causing any side-effect.
3032 Container.Elements := new Elements_Type'(Container
.Last
, Src
);
3034 -- We have successfully allocated a new internal array (with a
3035 -- smaller length than the old one, and containing a copy of
3036 -- just the active elements in the container), so it is now
3037 -- safe to deallocate the old array.
3046 -- The requested capacity is larger than the container length (the
3047 -- number of active elements). Whether this represents a request for
3048 -- expansion or contraction of the current capacity depends on what the
3049 -- current capacity is.
3051 if Capacity
= Container
.Elements
.EA
'Length then
3053 -- The requested capacity matches the existing capacity, so there's
3054 -- nothing to do here. We treat this case as a no-op, and simply
3055 -- return without checking the busy bit.
3060 -- There is a change in the capacity of a non-empty container, so a new
3061 -- internal array will be allocated. (The length of the new internal
3062 -- array could be less or greater than the old internal array. We know
3063 -- only that the length of the new internal array is greater than the
3064 -- number of active elements in the container.) We must check whether
3065 -- the container is busy before doing anything else.
3067 TC_Check
(Container
.TC
);
3069 -- We now allocate a new internal array, having a length different from
3070 -- its current value.
3073 X
: Elements_Access
:= Container
.Elements
;
3075 subtype Index_Subtype
is Index_Type
'Base range
3076 Index_Type
'First .. Container
.Last
;
3079 -- We now allocate a new internal array, having a length different
3080 -- from its current value.
3082 Container
.Elements
:= new Elements_Type
(Last
);
3084 -- We have successfully allocated the new internal array, so now we
3085 -- move the existing elements from the existing the old internal
3086 -- array onto the new one. Note that we're just copying access
3087 -- values, to this should not raise any exceptions.
3089 Container
.Elements
.EA
(Index_Subtype
) := X
.EA
(Index_Subtype
);
3091 -- We have moved the elements from the old internal array, so now we
3092 -- can deallocate it.
3096 end Reserve_Capacity
;
3098 ----------------------
3099 -- Reverse_Elements --
3100 ----------------------
3102 procedure Reverse_Elements
(Container
: in out Vector
) is
3104 if Container
.Length
<= 1 then
3108 -- The exception behavior for the vector container must match that for
3109 -- the list container, so we check for cursor tampering here (which will
3110 -- catch more things) instead of for element tampering (which will catch
3111 -- fewer things). It's true that the elements of this vector container
3112 -- could be safely moved around while (say) an iteration is taking place
3113 -- (iteration only increments the busy counter), and so technically all
3114 -- we would need here is a test for element tampering (indicated by the
3115 -- lock counter), that's simply an artifact of our array-based
3116 -- implementation. Logically Reverse_Elements requires a check for
3117 -- cursor tampering.
3119 TC_Check
(Container
.TC
);
3124 E
: Elements_Array
renames Container
.Elements
.EA
;
3127 I
:= Index_Type
'First;
3128 J
:= Container
.Last
;
3131 EI
: constant Element_Access
:= E
(I
);
3142 end Reverse_Elements
;
3148 function Reverse_Find
3149 (Container
: Vector
;
3150 Item
: Element_Type
;
3151 Position
: Cursor
:= No_Element
) return Cursor
3153 Last
: Index_Type
'Base;
3156 if Checks
and then Position
.Container
/= null
3157 and then Position
.Container
/= Container
'Unrestricted_Access
3159 raise Program_Error
with "Position cursor denotes wrong container";
3163 (if Position
.Container
= null or else Position
.Index
> Container
.Last
3165 else Position
.Index
);
3167 -- Per AI05-0022, the container implementation is required to detect
3168 -- element tampering by a generic actual subprogram.
3171 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
3173 for Indx
in reverse Index_Type
'First .. Last
loop
3174 if Container
.Elements
.EA
(Indx
) /= null
3175 and then Container
.Elements
.EA
(Indx
).all = Item
3177 return Cursor
'(Container'Unrestricted_Access, Indx);
3185 ------------------------
3186 -- Reverse_Find_Index --
3187 ------------------------
3189 function Reverse_Find_Index
3190 (Container : Vector;
3191 Item : Element_Type;
3192 Index : Index_Type := Index_Type'Last) return Extended_Index
3194 -- Per AI05-0022, the container implementation is required to detect
3195 -- element tampering by a generic actual subprogram.
3197 Lock : With_Lock (Container.TC'Unrestricted_Access);
3199 Last : constant Index_Type'Base :=
3200 Index_Type'Min (Container.Last, Index);
3203 for Indx in reverse Index_Type'First .. Last loop
3204 if Container.Elements.EA (Indx) /= null
3205 and then Container.Elements.EA (Indx).all = Item
3212 end Reverse_Find_Index;
3214 ---------------------
3215 -- Reverse_Iterate --
3216 ---------------------
3218 procedure Reverse_Iterate
3219 (Container : Vector;
3220 Process : not null access procedure (Position : Cursor))
3222 Busy : With_Busy (Container.TC'Unrestricted_Access);
3224 for Indx in reverse Index_Type'First .. Container.Last loop
3225 Process (Cursor'(Container
'Unrestricted_Access, Indx
));
3227 end Reverse_Iterate
;
3233 procedure Set_Length
(Container
: in out Vector
; Length
: Count_Type
) is
3234 Count
: constant Count_Type
'Base := Container
.Length
- Length
;
3237 -- Set_Length allows the user to set the length explicitly, instead of
3238 -- implicitly as a side-effect of deletion or insertion. If the
3239 -- requested length is less than the current length, this is equivalent
3240 -- to deleting items from the back end of the vector. If the requested
3241 -- length is greater than the current length, then this is equivalent to
3242 -- inserting "space" (nonce items) at the end.
3245 Container
.Delete_Last
(Count
);
3247 elsif Checks
and then Container
.Last
>= Index_Type
'Last then
3248 raise Constraint_Error
with "vector is already at its maximum length";
3251 Container
.Insert_Space
(Container
.Last
+ 1, -Count
);
3259 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
3262 if I
> Container
.Last
then
3263 raise Constraint_Error
with "I index is out of range";
3266 if J
> Container
.Last
then
3267 raise Constraint_Error
with "J index is out of range";
3275 TE_Check
(Container
.TC
);
3278 EI
: Element_Access
renames Container
.Elements
.EA
(I
);
3279 EJ
: Element_Access
renames Container
.Elements
.EA
(J
);
3281 EI_Copy
: constant Element_Access
:= EI
;
3290 (Container
: in out Vector
;
3295 if I
.Container
= null then
3296 raise Constraint_Error
with "I cursor has no element";
3299 if J
.Container
= null then
3300 raise Constraint_Error
with "J cursor has no element";
3303 if I
.Container
/= Container
'Unrestricted_Access then
3304 raise Program_Error
with "I cursor denotes wrong container";
3307 if J
.Container
/= Container
'Unrestricted_Access then
3308 raise Program_Error
with "J cursor denotes wrong container";
3312 Swap
(Container
, I
.Index
, J
.Index
);
3320 (Container
: Vector
;
3321 Index
: Extended_Index
) return Cursor
3324 if Index
not in Index_Type
'First .. Container
.Last
then
3328 return Cursor
'(Container'Unrestricted_Access, Index);
3335 function To_Index (Position : Cursor) return Extended_Index is
3337 if Position.Container = null then
3339 elsif Position.Index <= Position.Container.Last then
3340 return Position.Index;
3350 function To_Vector (Length : Count_Type) return Vector is
3351 Index : Count_Type'Base;
3352 Last : Index_Type'Base;
3353 Elements : Elements_Access;
3357 return Empty_Vector;
3360 -- We create a vector object with a capacity that matches the specified
3361 -- Length, but we do not allow the vector capacity (the length of the
3362 -- internal array) to exceed the number of values in Index_Type'Range
3363 -- (otherwise, there would be no way to refer to those components via an
3364 -- index). We must therefore check whether the specified Length would
3365 -- create a Last index value greater than Index_Type'Last.
3367 if Index_Type'Base'Last
>= Count_Type_Last
then
3369 -- We perform a two-part test. First we determine whether the
3370 -- computed Last value lies in the base range of the type, and then
3371 -- determine whether it lies in the range of the index (sub)type.
3373 -- Last must satisfy this relation:
3374 -- First + Length - 1 <= Last
3375 -- We regroup terms:
3376 -- First - 1 <= Last - Length
3377 -- Which can rewrite as:
3378 -- No_Index <= Last - Length
3381 Index_Type
'Base'Last - Index_Type'Base (Length) < No_Index
3383 raise Constraint_Error with "Length is out of range";
3386 -- We now know that the computed value of Last is within the base
3387 -- range of the type, so it is safe to compute its value:
3389 Last := No_Index + Index_Type'Base (Length);
3391 -- Finally we test whether the value is within the range of the
3392 -- generic actual index subtype:
3394 if Checks and then Last > Index_Type'Last then
3395 raise Constraint_Error with "Length is out of range";
3398 elsif Index_Type'First <= 0 then
3400 -- Here we can compute Last directly, in the normal way. We know that
3401 -- No_Index is less than 0, so there is no danger of overflow when
3402 -- adding the (positive) value of Length.
3404 Index := Count_Type'Base (No_Index) + Length; -- Last
3406 if Checks and then Index > Count_Type'Base (Index_Type'Last) then
3407 raise Constraint_Error with "Length is out of range";
3410 -- We know that the computed value (having type Count_Type) of Last
3411 -- is within the range of the generic actual index subtype, so it is
3412 -- safe to convert to Index_Type:
3414 Last := Index_Type'Base (Index);
3417 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3418 -- must test the length indirectly (by working backwards from the
3419 -- largest possible value of Last), in order to prevent overflow.
3421 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3423 if Checks and then Index < Count_Type'Base (No_Index) then
3424 raise Constraint_Error with "Length is out of range";
3427 -- We have determined that the value of Length would not create a
3428 -- Last index value outside of the range of Index_Type, so we can now
3429 -- safely compute its value.
3431 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3434 Elements := new Elements_Type (Last);
3436 return Vector'(Controlled
with Elements
, Last
, TC
=> <>);
3440 (New_Item
: Element_Type
;
3441 Length
: Count_Type
) return Vector
3443 Index
: Count_Type
'Base;
3444 Last
: Index_Type
'Base;
3445 Elements
: Elements_Access
;
3449 return Empty_Vector
;
3452 -- We create a vector object with a capacity that matches the specified
3453 -- Length, but we do not allow the vector capacity (the length of the
3454 -- internal array) to exceed the number of values in Index_Type'Range
3455 -- (otherwise, there would be no way to refer to those components via an
3456 -- index). We must therefore check whether the specified Length would
3457 -- create a Last index value greater than Index_Type'Last.
3459 if Index_Type
'Base'Last >= Count_Type_Last then
3461 -- We perform a two-part test. First we determine whether the
3462 -- computed Last value lies in the base range of the type, and then
3463 -- determine whether it lies in the range of the index (sub)type.
3465 -- Last must satisfy this relation:
3466 -- First + Length - 1 <= Last
3467 -- We regroup terms:
3468 -- First - 1 <= Last - Length
3469 -- Which can rewrite as:
3470 -- No_Index <= Last - Length
3473 Index_Type'Base'Last
- Index_Type
'Base (Length
) < No_Index
3475 raise Constraint_Error
with "Length is out of range";
3478 -- We now know that the computed value of Last is within the base
3479 -- range of the type, so it is safe to compute its value:
3481 Last
:= No_Index
+ Index_Type
'Base (Length
);
3483 -- Finally we test whether the value is within the range of the
3484 -- generic actual index subtype:
3486 if Checks
and then Last
> Index_Type
'Last then
3487 raise Constraint_Error
with "Length is out of range";
3490 elsif Index_Type
'First <= 0 then
3492 -- Here we can compute Last directly, in the normal way. We know that
3493 -- No_Index is less than 0, so there is no danger of overflow when
3494 -- adding the (positive) value of Length.
3496 Index
:= Count_Type
'Base (No_Index
) + Length
; -- Last
3498 if Checks
and then Index
> Count_Type
'Base (Index_Type
'Last) then
3499 raise Constraint_Error
with "Length is out of range";
3502 -- We know that the computed value (having type Count_Type) of Last
3503 -- is within the range of the generic actual index subtype, so it is
3504 -- safe to convert to Index_Type:
3506 Last
:= Index_Type
'Base (Index
);
3509 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3510 -- must test the length indirectly (by working backwards from the
3511 -- largest possible value of Last), in order to prevent overflow.
3513 Index
:= Count_Type
'Base (Index_Type
'Last) - Length
; -- No_Index
3515 if Checks
and then Index
< Count_Type
'Base (No_Index
) then
3516 raise Constraint_Error
with "Length is out of range";
3519 -- We have determined that the value of Length would not create a
3520 -- Last index value outside of the range of Index_Type, so we can now
3521 -- safely compute its value.
3523 Last
:= Index_Type
'Base (Count_Type
'Base (No_Index
) + Length
);
3526 Elements
:= new Elements_Type
(Last
);
3528 -- We use Last as the index of the loop used to populate the internal
3529 -- array with items. In general, we prefer to initialize the loop index
3530 -- immediately prior to entering the loop. However, Last is also used in
3531 -- the exception handler (to reclaim elements that have been allocated,
3532 -- before propagating the exception), and the initialization of Last
3533 -- after entering the block containing the handler confuses some static
3534 -- analysis tools, with respect to whether Last has been properly
3535 -- initialized when the handler executes. So here we initialize our loop
3536 -- variable earlier than we prefer, before entering the block, so there
3539 Last
:= Index_Type
'First;
3542 -- The element allocator may need an accessibility check in the case
3543 -- where the actual type is class-wide or has access discriminants
3544 -- (see RM 4.8(10.1) and AI12-0035).
3546 pragma Unsuppress
(Accessibility_Check
);
3550 Elements
.EA
(Last
) := new Element_Type
'(New_Item);
3551 exit when Last = Elements.Last;
3557 for J in Index_Type'First .. Last - 1 loop
3558 Free (Elements.EA (J));
3565 return (Controlled with Elements, Last, TC => <>);
3568 --------------------
3569 -- Update_Element --
3570 --------------------
3572 procedure Update_Element
3573 (Container : in out Vector;
3575 Process : not null access procedure (Element : in out Element_Type))
3577 Lock : With_Lock (Container.TC'Unchecked_Access);
3579 if Checks and then Index > Container.Last then
3580 raise Constraint_Error with "Index is out of range";
3583 if Checks and then Container.Elements.EA (Index) = null then
3584 raise Constraint_Error with "element is null";
3587 Process (Container.Elements.EA (Index).all);
3590 procedure Update_Element
3591 (Container : in out Vector;
3593 Process : not null access procedure (Element : in out Element_Type))
3597 if Position.Container = null then
3598 raise Constraint_Error with "Position cursor has no element";
3599 elsif Position.Container /= Container'Unrestricted_Access then
3600 raise Program_Error with "Position cursor denotes wrong container";
3604 Update_Element (Container, Position.Index, Process);
3612 (Stream : not null access Root_Stream_Type'Class;
3615 N : constant Count_Type := Length (Container);
3618 Count_Type'Base'Write
(Stream
, N
);
3625 E
: Elements_Array
renames Container
.Elements
.EA
;
3628 for Indx
in Index_Type
'First .. Container
.Last
loop
3629 if E
(Indx
) = null then
3630 Boolean'Write (Stream
, False);
3632 Boolean'Write (Stream
, True);
3633 Element_Type
'Output (Stream
, E
(Indx
).all);
3640 (Stream
: not null access Root_Stream_Type
'Class;
3644 raise Program_Error
with "attempt to stream vector cursor";
3648 (Stream
: not null access Root_Stream_Type
'Class;
3649 Item
: Reference_Type
)
3652 raise Program_Error
with "attempt to stream reference";
3656 (Stream
: not null access Root_Stream_Type
'Class;
3657 Item
: Constant_Reference_Type
)
3660 raise Program_Error
with "attempt to stream reference";
3663 end Ada
.Containers
.Indefinite_Vectors
;