PR rtl-optimization/79386
[official-gcc.git] / gcc / ada / a-cobove.adb
blob59d6c27350a34b810d270323ed39ec7042022d36
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ V E C T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2015, Free Software Foundation, Inc. --
10 -- --
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. --
17 -- --
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. --
21 -- --
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/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Generic_Array_Sort;
32 with System; use type System.Address;
34 package body Ada.Containers.Bounded_Vectors is
36 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
37 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
38 -- See comment in Ada.Containers.Helpers
40 -----------------------
41 -- Local Subprograms --
42 -----------------------
44 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base;
46 ---------
47 -- "&" --
48 ---------
50 function "&" (Left, Right : Vector) return Vector is
51 LN : constant Count_Type := Length (Left);
52 RN : constant Count_Type := Length (Right);
53 N : Count_Type'Base; -- length of result
54 J : Count_Type'Base; -- for computing intermediate index values
55 Last : Index_Type'Base; -- Last index of result
57 begin
58 -- We decide that the capacity of the result is the sum of the lengths
59 -- of the vector parameters. We could decide to make it larger, but we
60 -- have no basis for knowing how much larger, so we just allocate the
61 -- minimum amount of storage.
63 -- Here we handle the easy cases first, when one of the vector
64 -- parameters is empty. (We say "easy" because there's nothing to
65 -- compute, that can potentially overflow.)
67 if LN = 0 then
68 if RN = 0 then
69 return Empty_Vector;
70 end if;
72 return Vector'(Capacity => RN,
73 Elements => Right.Elements (1 .. RN),
74 Last => Right.Last,
75 others => <>);
76 end if;
78 if RN = 0 then
79 return Vector'(Capacity => LN,
80 Elements => Left.Elements (1 .. LN),
81 Last => Left.Last,
82 others => <>);
83 end if;
85 -- Neither of the vector parameters is empty, so must compute the length
86 -- of the result vector and its last index. (This is the harder case,
87 -- because our computations must avoid overflow.)
89 -- There are two constraints we need to satisfy. The first constraint is
90 -- that a container cannot have more than Count_Type'Last elements, so
91 -- we must check the sum of the combined lengths. Note that we cannot
92 -- simply add the lengths, because of the possibility of overflow.
94 if Checks and then LN > Count_Type'Last - RN then
95 raise Constraint_Error with "new length is out of range";
96 end if;
98 -- It is now safe to compute the length of the new vector, without fear
99 -- of overflow.
101 N := LN + RN;
103 -- The second constraint is that the new Last index value cannot
104 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
105 -- Count_Type'Base as the type for intermediate values.
107 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
109 -- We perform a two-part test. First we determine whether the
110 -- computed Last value lies in the base range of the type, and then
111 -- determine whether it lies in the range of the index (sub)type.
113 -- Last must satisfy this relation:
114 -- First + Length - 1 <= Last
115 -- We regroup terms:
116 -- First - 1 <= Last - Length
117 -- Which can rewrite as:
118 -- No_Index <= Last - Length
120 if Checks and then
121 Index_Type'Base'Last - Index_Type'Base (N) < No_Index
122 then
123 raise Constraint_Error with "new length is out of range";
124 end if;
126 -- We now know that the computed value of Last is within the base
127 -- range of the type, so it is safe to compute its value:
129 Last := No_Index + Index_Type'Base (N);
131 -- Finally we test whether the value is within the range of the
132 -- generic actual index subtype:
134 if Checks and then Last > Index_Type'Last then
135 raise Constraint_Error with "new length is out of range";
136 end if;
138 elsif Index_Type'First <= 0 then
140 -- Here we can compute Last directly, in the normal way. We know that
141 -- No_Index is less than 0, so there is no danger of overflow when
142 -- adding the (positive) value of length.
144 J := Count_Type'Base (No_Index) + N; -- Last
146 if Checks and then J > Count_Type'Base (Index_Type'Last) then
147 raise Constraint_Error with "new length is out of range";
148 end if;
150 -- We know that the computed value (having type Count_Type) of Last
151 -- is within the range of the generic actual index subtype, so it is
152 -- safe to convert to Index_Type:
154 Last := Index_Type'Base (J);
156 else
157 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
158 -- must test the length indirectly (by working backwards from the
159 -- largest possible value of Last), in order to prevent overflow.
161 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
163 if Checks and then J < Count_Type'Base (No_Index) then
164 raise Constraint_Error with "new length is out of range";
165 end if;
167 -- We have determined that the result length would not create a Last
168 -- index value outside of the range of Index_Type, so we can now
169 -- safely compute its value.
171 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
172 end if;
174 declare
175 LE : Elements_Array renames Left.Elements (1 .. LN);
176 RE : Elements_Array renames Right.Elements (1 .. RN);
178 begin
179 return Vector'(Capacity => N,
180 Elements => LE & RE,
181 Last => Last,
182 others => <>);
183 end;
184 end "&";
186 function "&" (Left : Vector; Right : Element_Type) return Vector is
187 LN : constant Count_Type := Length (Left);
189 begin
190 -- We decide that the capacity of the result is the sum of the lengths
191 -- of the parameters. We could decide to make it larger, but we have no
192 -- basis for knowing how much larger, so we just allocate the minimum
193 -- amount of storage.
195 -- We must compute the length of the result vector and its last index,
196 -- but in such a way that overflow is avoided. We must satisfy two
197 -- constraints: the new length cannot exceed Count_Type'Last, and the
198 -- new Last index cannot exceed Index_Type'Last.
200 if Checks and then LN = Count_Type'Last then
201 raise Constraint_Error with "new length is out of range";
202 end if;
204 if Checks and then Left.Last >= Index_Type'Last then
205 raise Constraint_Error with "new length is out of range";
206 end if;
208 return Vector'(Capacity => LN + 1,
209 Elements => Left.Elements (1 .. LN) & Right,
210 Last => Left.Last + 1,
211 others => <>);
212 end "&";
214 function "&" (Left : Element_Type; Right : Vector) return Vector is
215 RN : constant Count_Type := Length (Right);
217 begin
218 -- We decide that the capacity of the result is the sum of the lengths
219 -- of the parameters. We could decide to make it larger, but we have no
220 -- basis for knowing how much larger, so we just allocate the minimum
221 -- amount of storage.
223 -- We compute the length of the result vector and its last index, but in
224 -- such a way that overflow is avoided. We must satisfy two constraints:
225 -- the new length cannot exceed Count_Type'Last, and the new Last index
226 -- cannot exceed Index_Type'Last.
228 if Checks and then RN = Count_Type'Last then
229 raise Constraint_Error with "new length is out of range";
230 end if;
232 if Checks and then Right.Last >= Index_Type'Last then
233 raise Constraint_Error with "new length is out of range";
234 end if;
236 return Vector'(Capacity => 1 + RN,
237 Elements => Left & Right.Elements (1 .. RN),
238 Last => Right.Last + 1,
239 others => <>);
240 end "&";
242 function "&" (Left, Right : Element_Type) return Vector is
243 begin
244 -- We decide that the capacity of the result is the sum of the lengths
245 -- of the parameters. We could decide to make it larger, but we have no
246 -- basis for knowing how much larger, so we just allocate the minimum
247 -- amount of storage.
249 -- We must compute the length of the result vector and its last index,
250 -- but in such a way that overflow is avoided. We must satisfy two
251 -- constraints: the new length cannot exceed Count_Type'Last (here, we
252 -- know that that condition is satisfied), and the new Last index cannot
253 -- exceed Index_Type'Last.
255 if Checks and then Index_Type'First >= Index_Type'Last then
256 raise Constraint_Error with "new length is out of range";
257 end if;
259 return Vector'(Capacity => 2,
260 Elements => (Left, Right),
261 Last => Index_Type'First + 1,
262 others => <>);
263 end "&";
265 ---------
266 -- "=" --
267 ---------
269 overriding function "=" (Left, Right : Vector) return Boolean is
270 begin
271 if Left.Last /= Right.Last then
272 return False;
273 end if;
275 if Left.Length = 0 then
276 return True;
277 end if;
279 declare
280 -- Per AI05-0022, the container implementation is required to detect
281 -- element tampering by a generic actual subprogram.
283 Lock_Left : With_Lock (Left.TC'Unrestricted_Access);
284 Lock_Right : With_Lock (Right.TC'Unrestricted_Access);
285 begin
286 for J in Count_Type range 1 .. Left.Length loop
287 if Left.Elements (J) /= Right.Elements (J) then
288 return False;
289 end if;
290 end loop;
291 end;
293 return True;
294 end "=";
296 ------------
297 -- Assign --
298 ------------
300 procedure Assign (Target : in out Vector; Source : Vector) is
301 begin
302 if Target'Address = Source'Address then
303 return;
304 end if;
306 if Checks and then Target.Capacity < Source.Length then
307 raise Capacity_Error -- ???
308 with "Target capacity is less than Source length";
309 end if;
311 Target.Clear;
313 Target.Elements (1 .. Source.Length) :=
314 Source.Elements (1 .. Source.Length);
316 Target.Last := Source.Last;
317 end Assign;
319 ------------
320 -- Append --
321 ------------
323 procedure Append (Container : in out Vector; New_Item : Vector) is
324 begin
325 if New_Item.Is_Empty then
326 return;
327 end if;
329 if Checks and then Container.Last >= Index_Type'Last then
330 raise Constraint_Error with "vector is already at its maximum length";
331 end if;
333 Container.Insert (Container.Last + 1, New_Item);
334 end Append;
336 procedure Append
337 (Container : in out Vector;
338 New_Item : Element_Type;
339 Count : Count_Type := 1)
341 begin
342 if Count = 0 then
343 return;
344 end if;
346 if Checks and then Container.Last >= Index_Type'Last then
347 raise Constraint_Error with "vector is already at its maximum length";
348 end if;
350 Container.Insert (Container.Last + 1, New_Item, Count);
351 end Append;
353 --------------
354 -- Capacity --
355 --------------
357 function Capacity (Container : Vector) return Count_Type is
358 begin
359 return Container.Elements'Length;
360 end Capacity;
362 -----------
363 -- Clear --
364 -----------
366 procedure Clear (Container : in out Vector) is
367 begin
368 TC_Check (Container.TC);
370 Container.Last := No_Index;
371 end Clear;
373 ------------------------
374 -- Constant_Reference --
375 ------------------------
377 function Constant_Reference
378 (Container : aliased Vector;
379 Position : Cursor) return Constant_Reference_Type
381 begin
382 if Checks and then Position.Container = null then
383 raise Constraint_Error with "Position cursor has no element";
384 end if;
386 if Checks and then Position.Container /= Container'Unrestricted_Access
387 then
388 raise Program_Error with "Position cursor denotes wrong container";
389 end if;
391 if Checks and then Position.Index > Position.Container.Last then
392 raise Constraint_Error with "Position cursor is out of range";
393 end if;
395 declare
396 A : Elements_Array renames Container.Elements;
397 J : constant Count_Type := To_Array_Index (Position.Index);
398 TC : constant Tamper_Counts_Access :=
399 Container.TC'Unrestricted_Access;
400 begin
401 return R : constant Constant_Reference_Type :=
402 (Element => A (J)'Access,
403 Control => (Controlled with TC))
405 Lock (TC.all);
406 end return;
407 end;
408 end Constant_Reference;
410 function Constant_Reference
411 (Container : aliased Vector;
412 Index : Index_Type) return Constant_Reference_Type
414 begin
415 if Checks and then Index > Container.Last then
416 raise Constraint_Error with "Index is out of range";
417 end if;
419 declare
420 A : Elements_Array renames Container.Elements;
421 J : constant Count_Type := To_Array_Index (Index);
422 TC : constant Tamper_Counts_Access :=
423 Container.TC'Unrestricted_Access;
424 begin
425 return R : constant Constant_Reference_Type :=
426 (Element => A (J)'Access,
427 Control => (Controlled with TC))
429 Lock (TC.all);
430 end return;
431 end;
432 end Constant_Reference;
434 --------------
435 -- Contains --
436 --------------
438 function Contains
439 (Container : Vector;
440 Item : Element_Type) return Boolean
442 begin
443 return Find_Index (Container, Item) /= No_Index;
444 end Contains;
446 ----------
447 -- Copy --
448 ----------
450 function Copy
451 (Source : Vector;
452 Capacity : Count_Type := 0) return Vector
454 C : Count_Type;
456 begin
457 if Capacity = 0 then
458 C := Source.Length;
460 elsif Capacity >= Source.Length then
461 C := Capacity;
463 elsif Checks then
464 raise Capacity_Error
465 with "Requested capacity is less than Source length";
466 end if;
468 return Target : Vector (C) do
469 Target.Elements (1 .. Source.Length) :=
470 Source.Elements (1 .. Source.Length);
472 Target.Last := Source.Last;
473 end return;
474 end Copy;
476 ------------
477 -- Delete --
478 ------------
480 procedure Delete
481 (Container : in out Vector;
482 Index : Extended_Index;
483 Count : Count_Type := 1)
485 Old_Last : constant Index_Type'Base := Container.Last;
486 Old_Len : constant Count_Type := Container.Length;
487 New_Last : Index_Type'Base;
488 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
489 Off : Count_Type'Base; -- Index expressed as offset from IT'First
491 begin
492 -- Delete removes items from the vector, the number of which is the
493 -- minimum of the specified Count and the items (if any) that exist from
494 -- Index to Container.Last. There are no constraints on the specified
495 -- value of Count (it can be larger than what's available at this
496 -- position in the vector, for example), but there are constraints on
497 -- the allowed values of the Index.
499 -- As a precondition on the generic actual Index_Type, the base type
500 -- must include Index_Type'Pred (Index_Type'First); this is the value
501 -- that Container.Last assumes when the vector is empty. However, we do
502 -- not allow that as the value for Index when specifying which items
503 -- should be deleted, so we must manually check. (That the user is
504 -- allowed to specify the value at all here is a consequence of the
505 -- declaration of the Extended_Index subtype, which includes the values
506 -- in the base range that immediately precede and immediately follow the
507 -- values in the Index_Type.)
509 if Checks and then Index < Index_Type'First then
510 raise Constraint_Error with "Index is out of range (too small)";
511 end if;
513 -- We do allow a value greater than Container.Last to be specified as
514 -- the Index, but only if it's immediately greater. This allows the
515 -- corner case of deleting no items from the back end of the vector to
516 -- be treated as a no-op. (It is assumed that specifying an index value
517 -- greater than Last + 1 indicates some deeper flaw in the caller's
518 -- algorithm, so that case is treated as a proper error.)
520 if Index > Old_Last then
521 if Checks and then Index > Old_Last + 1 then
522 raise Constraint_Error with "Index is out of range (too large)";
523 end if;
525 return;
526 end if;
528 -- Here and elsewhere we treat deleting 0 items from the container as a
529 -- no-op, even when the container is busy, so we simply return.
531 if Count = 0 then
532 return;
533 end if;
535 -- The tampering bits exist to prevent an item from being deleted (or
536 -- otherwise harmfully manipulated) while it is being visited. Query,
537 -- Update, and Iterate increment the busy count on entry, and decrement
538 -- the count on exit. Delete checks the count to determine whether it is
539 -- being called while the associated callback procedure is executing.
541 TC_Check (Container.TC);
543 -- We first calculate what's available for deletion starting at
544 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
545 -- Count_Type'Base as the type for intermediate values. (See function
546 -- Length for more information.)
548 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
549 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
550 else
551 Count2 := Count_Type'Base (Old_Last - Index + 1);
552 end if;
554 -- If more elements are requested (Count) for deletion than are
555 -- available (Count2) for deletion beginning at Index, then everything
556 -- from Index is deleted. There are no elements to slide down, and so
557 -- all we need to do is set the value of Container.Last.
559 if Count >= Count2 then
560 Container.Last := Index - 1;
561 return;
562 end if;
564 -- There are some elements aren't being deleted (the requested count was
565 -- less than the available count), so we must slide them down to
566 -- Index. We first calculate the index values of the respective array
567 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
568 -- type for intermediate calculations.
570 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
571 Off := Count_Type'Base (Index - Index_Type'First);
572 New_Last := Old_Last - Index_Type'Base (Count);
573 else
574 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
575 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
576 end if;
578 -- The array index values for each slice have already been determined,
579 -- so we just slide down to Index the elements that weren't deleted.
581 declare
582 EA : Elements_Array renames Container.Elements;
583 Idx : constant Count_Type := EA'First + Off;
584 begin
585 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
586 Container.Last := New_Last;
587 end;
588 end Delete;
590 procedure Delete
591 (Container : in out Vector;
592 Position : in out Cursor;
593 Count : Count_Type := 1)
595 pragma Warnings (Off, Position);
597 begin
598 if Checks and then Position.Container = null then
599 raise Constraint_Error with "Position cursor has no element";
600 end if;
602 if Checks and then Position.Container /= Container'Unrestricted_Access
603 then
604 raise Program_Error with "Position cursor denotes wrong container";
605 end if;
607 if Checks and then Position.Index > Container.Last then
608 raise Program_Error with "Position index is out of range";
609 end if;
611 Delete (Container, Position.Index, Count);
612 Position := No_Element;
613 end Delete;
615 ------------------
616 -- Delete_First --
617 ------------------
619 procedure Delete_First
620 (Container : in out Vector;
621 Count : Count_Type := 1)
623 begin
624 if Count = 0 then
625 return;
627 elsif Count >= Length (Container) then
628 Clear (Container);
629 return;
631 else
632 Delete (Container, Index_Type'First, Count);
633 end if;
634 end Delete_First;
636 -----------------
637 -- Delete_Last --
638 -----------------
640 procedure Delete_Last
641 (Container : in out Vector;
642 Count : Count_Type := 1)
644 begin
645 -- It is not permitted to delete items while the container is busy (for
646 -- example, we're in the middle of a passive iteration). However, we
647 -- always treat deleting 0 items as a no-op, even when we're busy, so we
648 -- simply return without checking.
650 if Count = 0 then
651 return;
652 end if;
654 -- The tampering bits exist to prevent an item from being deleted (or
655 -- otherwise harmfully manipulated) while it is being visited. Query,
656 -- Update, and Iterate increment the busy count on entry, and decrement
657 -- the count on exit. Delete_Last checks the count to determine whether
658 -- it is being called while the associated callback procedure is
659 -- executing.
661 TC_Check (Container.TC);
663 -- There is no restriction on how large Count can be when deleting
664 -- items. If it is equal or greater than the current length, then this
665 -- is equivalent to clearing the vector. (In particular, there's no need
666 -- for us to actually calculate the new value for Last.)
668 -- If the requested count is less than the current length, then we must
669 -- calculate the new value for Last. For the type we use the widest of
670 -- Index_Type'Base and Count_Type'Base for the intermediate values of
671 -- our calculation. (See the comments in Length for more information.)
673 if Count >= Container.Length then
674 Container.Last := No_Index;
676 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
677 Container.Last := Container.Last - Index_Type'Base (Count);
679 else
680 Container.Last :=
681 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
682 end if;
683 end Delete_Last;
685 -------------
686 -- Element --
687 -------------
689 function Element
690 (Container : Vector;
691 Index : Index_Type) return Element_Type
693 begin
694 if Checks and then Index > Container.Last then
695 raise Constraint_Error with "Index is out of range";
696 else
697 return Container.Elements (To_Array_Index (Index));
698 end if;
699 end Element;
701 function Element (Position : Cursor) return Element_Type is
702 begin
703 if Checks and then Position.Container = null then
704 raise Constraint_Error with "Position cursor has no element";
705 else
706 return Position.Container.Element (Position.Index);
707 end if;
708 end Element;
710 --------------
711 -- Finalize --
712 --------------
714 procedure Finalize (Object : in out Iterator) is
715 begin
716 Unbusy (Object.Container.TC);
717 end Finalize;
719 ----------
720 -- Find --
721 ----------
723 function Find
724 (Container : Vector;
725 Item : Element_Type;
726 Position : Cursor := No_Element) return Cursor
728 begin
729 if Position.Container /= null then
730 if Checks and then Position.Container /= Container'Unrestricted_Access
731 then
732 raise Program_Error with "Position cursor denotes wrong container";
733 end if;
735 if Checks and then Position.Index > Container.Last then
736 raise Program_Error with "Position index is out of range";
737 end if;
738 end if;
740 -- Per AI05-0022, the container implementation is required to detect
741 -- element tampering by a generic actual subprogram.
743 declare
744 Lock : With_Lock (Container.TC'Unrestricted_Access);
745 begin
746 for J in Position.Index .. Container.Last loop
747 if Container.Elements (To_Array_Index (J)) = Item then
748 return Cursor'(Container'Unrestricted_Access, J);
749 end if;
750 end loop;
752 return No_Element;
753 end;
754 end Find;
756 ----------------
757 -- Find_Index --
758 ----------------
760 function Find_Index
761 (Container : Vector;
762 Item : Element_Type;
763 Index : Index_Type := Index_Type'First) return Extended_Index
765 -- Per AI05-0022, the container implementation is required to detect
766 -- element tampering by a generic actual subprogram.
768 Lock : With_Lock (Container.TC'Unrestricted_Access);
769 begin
770 for Indx in Index .. Container.Last loop
771 if Container.Elements (To_Array_Index (Indx)) = Item then
772 return Indx;
773 end if;
774 end loop;
776 return No_Index;
777 end Find_Index;
779 -----------
780 -- First --
781 -----------
783 function First (Container : Vector) return Cursor is
784 begin
785 if Is_Empty (Container) then
786 return No_Element;
787 else
788 return (Container'Unrestricted_Access, Index_Type'First);
789 end if;
790 end First;
792 function First (Object : Iterator) return Cursor is
793 begin
794 -- The value of the iterator object's Index component influences the
795 -- behavior of the First (and Last) selector function.
797 -- When the Index component is No_Index, this means the iterator
798 -- object was constructed without a start expression, in which case the
799 -- (forward) iteration starts from the (logical) beginning of the entire
800 -- sequence of items (corresponding to Container.First, for a forward
801 -- iterator).
803 -- Otherwise, this is iteration over a partial sequence of items.
804 -- When the Index component isn't No_Index, the iterator object was
805 -- constructed with a start expression, that specifies the position
806 -- from which the (forward) partial iteration begins.
808 if Object.Index = No_Index then
809 return First (Object.Container.all);
810 else
811 return Cursor'(Object.Container, Object.Index);
812 end if;
813 end First;
815 -------------------
816 -- First_Element --
817 -------------------
819 function First_Element (Container : Vector) return Element_Type is
820 begin
821 if Checks and then Container.Last = No_Index then
822 raise Constraint_Error with "Container is empty";
823 end if;
825 return Container.Elements (To_Array_Index (Index_Type'First));
826 end First_Element;
828 -----------------
829 -- First_Index --
830 -----------------
832 function First_Index (Container : Vector) return Index_Type is
833 pragma Unreferenced (Container);
834 begin
835 return Index_Type'First;
836 end First_Index;
838 ---------------------
839 -- Generic_Sorting --
840 ---------------------
842 package body Generic_Sorting is
844 ---------------
845 -- Is_Sorted --
846 ---------------
848 function Is_Sorted (Container : Vector) return Boolean is
849 begin
850 if Container.Last <= Index_Type'First then
851 return True;
852 end if;
854 -- Per AI05-0022, the container implementation is required to detect
855 -- element tampering by a generic actual subprogram.
857 declare
858 Lock : With_Lock (Container.TC'Unrestricted_Access);
859 EA : Elements_Array renames Container.Elements;
860 begin
861 for J in 1 .. Container.Length - 1 loop
862 if EA (J + 1) < EA (J) then
863 return False;
864 end if;
865 end loop;
867 return True;
868 end;
869 end Is_Sorted;
871 -----------
872 -- Merge --
873 -----------
875 procedure Merge (Target, Source : in out Vector) is
876 I, J : Count_Type;
878 begin
879 -- The semantics of Merge changed slightly per AI05-0021. It was
880 -- originally the case that if Target and Source denoted the same
881 -- container object, then the GNAT implementation of Merge did
882 -- nothing. However, it was argued that RM05 did not precisely
883 -- specify the semantics for this corner case. The decision of the
884 -- ARG was that if Target and Source denote the same non-empty
885 -- container object, then Program_Error is raised.
887 if Source.Is_Empty then
888 return;
889 end if;
891 if Checks and then Target'Address = Source'Address then
892 raise Program_Error with
893 "Target and Source denote same non-empty container";
894 end if;
896 if Target.Is_Empty then
897 Move (Target => Target, Source => Source);
898 return;
899 end if;
901 TC_Check (Source.TC);
903 I := Target.Length;
904 Target.Set_Length (I + Source.Length);
906 -- Per AI05-0022, the container implementation is required to detect
907 -- element tampering by a generic actual subprogram.
909 declare
910 TA : Elements_Array renames Target.Elements;
911 SA : Elements_Array renames Source.Elements;
913 Lock_Target : With_Lock (Target.TC'Unchecked_Access);
914 Lock_Source : With_Lock (Source.TC'Unchecked_Access);
915 begin
916 J := Target.Length;
917 while not Source.Is_Empty loop
918 pragma Assert (Source.Length <= 1
919 or else not (SA (Source.Length) < SA (Source.Length - 1)));
921 if I = 0 then
922 TA (1 .. J) := SA (1 .. Source.Length);
923 Source.Last := No_Index;
924 exit;
925 end if;
927 pragma Assert (I <= 1
928 or else not (TA (I) < TA (I - 1)));
930 if SA (Source.Length) < TA (I) then
931 TA (J) := TA (I);
932 I := I - 1;
934 else
935 TA (J) := SA (Source.Length);
936 Source.Last := Source.Last - 1;
937 end if;
939 J := J - 1;
940 end loop;
941 end;
942 end Merge;
944 ----------
945 -- Sort --
946 ----------
948 procedure Sort (Container : in out Vector) is
949 procedure Sort is
950 new Generic_Array_Sort
951 (Index_Type => Count_Type,
952 Element_Type => Element_Type,
953 Array_Type => Elements_Array,
954 "<" => "<");
956 begin
957 if Container.Last <= Index_Type'First then
958 return;
959 end if;
961 -- The exception behavior for the vector container must match that
962 -- for the list container, so we check for cursor tampering here
963 -- (which will catch more things) instead of for element tampering
964 -- (which will catch fewer things). It's true that the elements of
965 -- this vector container could be safely moved around while (say) an
966 -- iteration is taking place (iteration only increments the busy
967 -- counter), and so technically all we would need here is a test for
968 -- element tampering (indicated by the lock counter), that's simply
969 -- an artifact of our array-based implementation. Logically Sort
970 -- requires a check for cursor tampering.
972 TC_Check (Container.TC);
974 -- Per AI05-0022, the container implementation is required to detect
975 -- element tampering by a generic actual subprogram.
977 declare
978 Lock : With_Lock (Container.TC'Unchecked_Access);
979 begin
980 Sort (Container.Elements (1 .. Container.Length));
981 end;
982 end Sort;
984 end Generic_Sorting;
986 ------------------------
987 -- Get_Element_Access --
988 ------------------------
990 function Get_Element_Access
991 (Position : Cursor) return not null Element_Access is
992 begin
993 return Position.Container.Elements
994 (To_Array_Index (Position.Index))'Access;
995 end Get_Element_Access;
997 -----------------
998 -- Has_Element --
999 -----------------
1001 function Has_Element (Position : Cursor) return Boolean is
1002 begin
1003 if Position.Container = null then
1004 return False;
1005 end if;
1007 return Position.Index <= Position.Container.Last;
1008 end Has_Element;
1010 ------------
1011 -- Insert --
1012 ------------
1014 procedure Insert
1015 (Container : in out Vector;
1016 Before : Extended_Index;
1017 New_Item : Element_Type;
1018 Count : Count_Type := 1)
1020 EA : Elements_Array renames Container.Elements;
1021 Old_Length : constant Count_Type := Container.Length;
1023 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1024 New_Length : Count_Type'Base; -- sum of current length and Count
1026 Index : Index_Type'Base; -- scratch for intermediate values
1027 J : Count_Type'Base; -- scratch
1029 begin
1030 -- As a precondition on the generic actual Index_Type, the base type
1031 -- must include Index_Type'Pred (Index_Type'First); this is the value
1032 -- that Container.Last assumes when the vector is empty. However, we do
1033 -- not allow that as the value for Index when specifying where the new
1034 -- items should be inserted, so we must manually check. (That the user
1035 -- is allowed to specify the value at all here is a consequence of the
1036 -- declaration of the Extended_Index subtype, which includes the values
1037 -- in the base range that immediately precede and immediately follow the
1038 -- values in the Index_Type.)
1040 if Checks and then Before < Index_Type'First then
1041 raise Constraint_Error with
1042 "Before index is out of range (too small)";
1043 end if;
1045 -- We do allow a value greater than Container.Last to be specified as
1046 -- the Index, but only if it's immediately greater. This allows for the
1047 -- case of appending items to the back end of the vector. (It is assumed
1048 -- that specifying an index value greater than Last + 1 indicates some
1049 -- deeper flaw in the caller's algorithm, so that case is treated as a
1050 -- proper error.)
1052 if Checks and then Before > Container.Last
1053 and then Before > Container.Last + 1
1054 then
1055 raise Constraint_Error with
1056 "Before index is out of range (too large)";
1057 end if;
1059 -- We treat inserting 0 items into the container as a no-op, even when
1060 -- the container is busy, so we simply return.
1062 if Count = 0 then
1063 return;
1064 end if;
1066 -- There are two constraints we need to satisfy. The first constraint is
1067 -- that a container cannot have more than Count_Type'Last elements, so
1068 -- we must check the sum of the current length and the insertion
1069 -- count. Note that we cannot simply add these values, because of the
1070 -- possibility of overflow.
1072 if Checks and then Old_Length > Count_Type'Last - Count then
1073 raise Constraint_Error with "Count is out of range";
1074 end if;
1076 -- It is now safe compute the length of the new vector, without fear of
1077 -- overflow.
1079 New_Length := Old_Length + Count;
1081 -- The second constraint is that the new Last index value cannot exceed
1082 -- Index_Type'Last. In each branch below, we calculate the maximum
1083 -- length (computed from the range of values in Index_Type), and then
1084 -- compare the new length to the maximum length. If the new length is
1085 -- acceptable, then we compute the new last index from that.
1087 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1089 -- We have to handle the case when there might be more values in the
1090 -- range of Index_Type than in the range of Count_Type.
1092 if Index_Type'First <= 0 then
1094 -- We know that No_Index (the same as Index_Type'First - 1) is
1095 -- less than 0, so it is safe to compute the following sum without
1096 -- fear of overflow.
1098 Index := No_Index + Index_Type'Base (Count_Type'Last);
1100 if Index <= Index_Type'Last then
1102 -- We have determined that range of Index_Type has at least as
1103 -- many values as in Count_Type, so Count_Type'Last is the
1104 -- maximum number of items that are allowed.
1106 Max_Length := Count_Type'Last;
1108 else
1109 -- The range of Index_Type has fewer values than in Count_Type,
1110 -- so the maximum number of items is computed from the range of
1111 -- the Index_Type.
1113 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1114 end if;
1116 else
1117 -- No_Index is equal or greater than 0, so we can safely compute
1118 -- the difference without fear of overflow (which we would have to
1119 -- worry about if No_Index were less than 0, but that case is
1120 -- handled above).
1122 if Index_Type'Last - No_Index >=
1123 Count_Type'Pos (Count_Type'Last)
1124 then
1125 -- We have determined that range of Index_Type has at least as
1126 -- many values as in Count_Type, so Count_Type'Last is the
1127 -- maximum number of items that are allowed.
1129 Max_Length := Count_Type'Last;
1131 else
1132 -- The range of Index_Type has fewer values than in Count_Type,
1133 -- so the maximum number of items is computed from the range of
1134 -- the Index_Type.
1136 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1137 end if;
1138 end if;
1140 elsif Index_Type'First <= 0 then
1142 -- We know that No_Index (the same as Index_Type'First - 1) is less
1143 -- than 0, so it is safe to compute the following sum without fear of
1144 -- overflow.
1146 J := Count_Type'Base (No_Index) + Count_Type'Last;
1148 if J <= Count_Type'Base (Index_Type'Last) then
1150 -- We have determined that range of Index_Type has at least as
1151 -- many values as in Count_Type, so Count_Type'Last is the maximum
1152 -- number of items that are allowed.
1154 Max_Length := Count_Type'Last;
1156 else
1157 -- The range of Index_Type has fewer values than Count_Type does,
1158 -- so the maximum number of items is computed from the range of
1159 -- the Index_Type.
1161 Max_Length :=
1162 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1163 end if;
1165 else
1166 -- No_Index is equal or greater than 0, so we can safely compute the
1167 -- difference without fear of overflow (which we would have to worry
1168 -- about if No_Index were less than 0, but that case is handled
1169 -- above).
1171 Max_Length :=
1172 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1173 end if;
1175 -- We have just computed the maximum length (number of items). We must
1176 -- now compare the requested length to the maximum length, as we do not
1177 -- allow a vector expand beyond the maximum (because that would create
1178 -- an internal array with a last index value greater than
1179 -- Index_Type'Last, with no way to index those elements).
1181 if Checks and then New_Length > Max_Length then
1182 raise Constraint_Error with "Count is out of range";
1183 end if;
1185 -- The tampering bits exist to prevent an item from being harmfully
1186 -- manipulated while it is being visited. Query, Update, and Iterate
1187 -- increment the busy count on entry, and decrement the count on
1188 -- exit. Insert checks the count to determine whether it is being called
1189 -- while the associated callback procedure is executing.
1191 TC_Check (Container.TC);
1193 if Checks and then New_Length > Container.Capacity then
1194 raise Capacity_Error with "New length is larger than capacity";
1195 end if;
1197 J := To_Array_Index (Before);
1199 if Before > Container.Last then
1201 -- The new items are being appended to the vector, so no
1202 -- sliding of existing elements is required.
1204 EA (J .. New_Length) := (others => New_Item);
1206 else
1207 -- The new items are being inserted before some existing
1208 -- elements, so we must slide the existing elements up to their
1209 -- new home.
1211 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1212 EA (J .. J + Count - 1) := (others => New_Item);
1213 end if;
1215 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1216 Container.Last := No_Index + Index_Type'Base (New_Length);
1218 else
1219 Container.Last :=
1220 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1221 end if;
1222 end Insert;
1224 procedure Insert
1225 (Container : in out Vector;
1226 Before : Extended_Index;
1227 New_Item : Vector)
1229 N : constant Count_Type := Length (New_Item);
1230 B : Count_Type; -- index Before converted to Count_Type
1232 begin
1233 -- Use Insert_Space to create the "hole" (the destination slice) into
1234 -- which we copy the source items.
1236 Insert_Space (Container, Before, Count => N);
1238 if N = 0 then
1239 -- There's nothing else to do here (vetting of parameters was
1240 -- performed already in Insert_Space), so we simply return.
1242 return;
1243 end if;
1245 B := To_Array_Index (Before);
1247 if Container'Address /= New_Item'Address then
1248 -- This is the simple case. New_Item denotes an object different
1249 -- from Container, so there's nothing special we need to do to copy
1250 -- the source items to their destination, because all of the source
1251 -- items are contiguous.
1253 Container.Elements (B .. B + N - 1) := New_Item.Elements (1 .. N);
1254 return;
1255 end if;
1257 -- We refer to array index value Before + N - 1 as J. This is the last
1258 -- index value of the destination slice.
1260 -- New_Item denotes the same object as Container, so an insertion has
1261 -- potentially split the source items. The destination is always the
1262 -- range [Before, J], but the source is [Index_Type'First, Before) and
1263 -- (J, Container.Last]. We perform the copy in two steps, using each of
1264 -- the two slices of the source items.
1266 declare
1267 subtype Src_Index_Subtype is Count_Type'Base range 1 .. B - 1;
1269 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1271 begin
1272 -- We first copy the source items that precede the space we
1273 -- inserted. (If Before equals Index_Type'First, then this first
1274 -- source slice will be empty, which is harmless.)
1276 Container.Elements (B .. B + Src'Length - 1) := Src;
1277 end;
1279 declare
1280 subtype Src_Index_Subtype is Count_Type'Base range
1281 B + N .. Container.Length;
1283 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1285 begin
1286 -- We next copy the source items that follow the space we inserted.
1288 Container.Elements (B + N - Src'Length .. B + N - 1) := Src;
1289 end;
1290 end Insert;
1292 procedure Insert
1293 (Container : in out Vector;
1294 Before : Cursor;
1295 New_Item : Vector)
1297 Index : Index_Type'Base;
1299 begin
1300 if Checks and then Before.Container /= null
1301 and then Before.Container /= Container'Unchecked_Access
1302 then
1303 raise Program_Error with "Before cursor denotes wrong container";
1304 end if;
1306 if Is_Empty (New_Item) then
1307 return;
1308 end if;
1310 if Before.Container = null
1311 or else Before.Index > Container.Last
1312 then
1313 if Checks and then Container.Last = Index_Type'Last then
1314 raise Constraint_Error with
1315 "vector is already at its maximum length";
1316 end if;
1318 Index := Container.Last + 1;
1320 else
1321 Index := Before.Index;
1322 end if;
1324 Insert (Container, Index, New_Item);
1325 end Insert;
1327 procedure Insert
1328 (Container : in out Vector;
1329 Before : Cursor;
1330 New_Item : Vector;
1331 Position : out Cursor)
1333 Index : Index_Type'Base;
1335 begin
1336 if Checks and then Before.Container /= null
1337 and then Before.Container /= Container'Unchecked_Access
1338 then
1339 raise Program_Error with "Before cursor denotes wrong container";
1340 end if;
1342 if Is_Empty (New_Item) then
1343 if Before.Container = null
1344 or else Before.Index > Container.Last
1345 then
1346 Position := No_Element;
1347 else
1348 Position := (Container'Unchecked_Access, Before.Index);
1349 end if;
1351 return;
1352 end if;
1354 if Before.Container = null
1355 or else Before.Index > Container.Last
1356 then
1357 if Checks and then Container.Last = Index_Type'Last then
1358 raise Constraint_Error with
1359 "vector is already at its maximum length";
1360 end if;
1362 Index := Container.Last + 1;
1364 else
1365 Index := Before.Index;
1366 end if;
1368 Insert (Container, Index, New_Item);
1370 Position := Cursor'(Container'Unchecked_Access, Index);
1371 end Insert;
1373 procedure Insert
1374 (Container : in out Vector;
1375 Before : Cursor;
1376 New_Item : Element_Type;
1377 Count : Count_Type := 1)
1379 Index : Index_Type'Base;
1381 begin
1382 if Checks and then Before.Container /= null
1383 and then Before.Container /= Container'Unchecked_Access
1384 then
1385 raise Program_Error with "Before cursor denotes wrong container";
1386 end if;
1388 if Count = 0 then
1389 return;
1390 end if;
1392 if Before.Container = null
1393 or else Before.Index > Container.Last
1394 then
1395 if Checks and then Container.Last = Index_Type'Last then
1396 raise Constraint_Error with
1397 "vector is already at its maximum length";
1398 end if;
1400 Index := Container.Last + 1;
1402 else
1403 Index := Before.Index;
1404 end if;
1406 Insert (Container, Index, New_Item, Count);
1407 end Insert;
1409 procedure Insert
1410 (Container : in out Vector;
1411 Before : Cursor;
1412 New_Item : Element_Type;
1413 Position : out Cursor;
1414 Count : Count_Type := 1)
1416 Index : Index_Type'Base;
1418 begin
1419 if Checks and then Before.Container /= null
1420 and then Before.Container /= Container'Unchecked_Access
1421 then
1422 raise Program_Error with "Before cursor denotes wrong container";
1423 end if;
1425 if Count = 0 then
1426 if Before.Container = null
1427 or else Before.Index > Container.Last
1428 then
1429 Position := No_Element;
1430 else
1431 Position := (Container'Unchecked_Access, Before.Index);
1432 end if;
1434 return;
1435 end if;
1437 if Before.Container = null
1438 or else Before.Index > Container.Last
1439 then
1440 if Checks and then Container.Last = Index_Type'Last then
1441 raise Constraint_Error with
1442 "vector is already at its maximum length";
1443 end if;
1445 Index := Container.Last + 1;
1447 else
1448 Index := Before.Index;
1449 end if;
1451 Insert (Container, Index, New_Item, Count);
1453 Position := Cursor'(Container'Unchecked_Access, Index);
1454 end Insert;
1456 procedure Insert
1457 (Container : in out Vector;
1458 Before : Extended_Index;
1459 Count : Count_Type := 1)
1461 New_Item : Element_Type; -- Default-initialized value
1462 pragma Warnings (Off, New_Item);
1464 begin
1465 Insert (Container, Before, New_Item, Count);
1466 end Insert;
1468 procedure Insert
1469 (Container : in out Vector;
1470 Before : Cursor;
1471 Position : out Cursor;
1472 Count : Count_Type := 1)
1474 New_Item : Element_Type; -- Default-initialized value
1475 pragma Warnings (Off, New_Item);
1477 begin
1478 Insert (Container, Before, New_Item, Position, Count);
1479 end Insert;
1481 ------------------
1482 -- Insert_Space --
1483 ------------------
1485 procedure Insert_Space
1486 (Container : in out Vector;
1487 Before : Extended_Index;
1488 Count : Count_Type := 1)
1490 EA : Elements_Array renames Container.Elements;
1491 Old_Length : constant Count_Type := Container.Length;
1493 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1494 New_Length : Count_Type'Base; -- sum of current length and Count
1496 Index : Index_Type'Base; -- scratch for intermediate values
1497 J : Count_Type'Base; -- scratch
1499 begin
1500 -- As a precondition on the generic actual Index_Type, the base type
1501 -- must include Index_Type'Pred (Index_Type'First); this is the value
1502 -- that Container.Last assumes when the vector is empty. However, we do
1503 -- not allow that as the value for Index when specifying where the new
1504 -- items should be inserted, so we must manually check. (That the user
1505 -- is allowed to specify the value at all here is a consequence of the
1506 -- declaration of the Extended_Index subtype, which includes the values
1507 -- in the base range that immediately precede and immediately follow the
1508 -- values in the Index_Type.)
1510 if Checks and then Before < Index_Type'First then
1511 raise Constraint_Error with
1512 "Before index is out of range (too small)";
1513 end if;
1515 -- We do allow a value greater than Container.Last to be specified as
1516 -- the Index, but only if it's immediately greater. This allows for the
1517 -- case of appending items to the back end of the vector. (It is assumed
1518 -- that specifying an index value greater than Last + 1 indicates some
1519 -- deeper flaw in the caller's algorithm, so that case is treated as a
1520 -- proper error.)
1522 if Checks and then Before > Container.Last
1523 and then Before > Container.Last + 1
1524 then
1525 raise Constraint_Error with
1526 "Before index is out of range (too large)";
1527 end if;
1529 -- We treat inserting 0 items into the container as a no-op, even when
1530 -- the container is busy, so we simply return.
1532 if Count = 0 then
1533 return;
1534 end if;
1536 -- There are two constraints we need to satisfy. The first constraint is
1537 -- that a container cannot have more than Count_Type'Last elements, so
1538 -- we must check the sum of the current length and the insertion count.
1539 -- Note that we cannot simply add these values, because of the
1540 -- possibility of overflow.
1542 if Checks and then Old_Length > Count_Type'Last - Count then
1543 raise Constraint_Error with "Count is out of range";
1544 end if;
1546 -- It is now safe compute the length of the new vector, without fear of
1547 -- overflow.
1549 New_Length := Old_Length + Count;
1551 -- The second constraint is that the new Last index value cannot exceed
1552 -- Index_Type'Last. In each branch below, we calculate the maximum
1553 -- length (computed from the range of values in Index_Type), and then
1554 -- compare the new length to the maximum length. If the new length is
1555 -- acceptable, then we compute the new last index from that.
1557 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1559 -- We have to handle the case when there might be more values in the
1560 -- range of Index_Type than in the range of Count_Type.
1562 if Index_Type'First <= 0 then
1564 -- We know that No_Index (the same as Index_Type'First - 1) is
1565 -- less than 0, so it is safe to compute the following sum without
1566 -- fear of overflow.
1568 Index := No_Index + Index_Type'Base (Count_Type'Last);
1570 if Index <= Index_Type'Last then
1572 -- We have determined that range of Index_Type has at least as
1573 -- many values as in Count_Type, so Count_Type'Last is the
1574 -- maximum number of items that are allowed.
1576 Max_Length := Count_Type'Last;
1578 else
1579 -- The range of Index_Type has fewer values than in Count_Type,
1580 -- so the maximum number of items is computed from the range of
1581 -- the Index_Type.
1583 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1584 end if;
1586 else
1587 -- No_Index is equal or greater than 0, so we can safely compute
1588 -- the difference without fear of overflow (which we would have to
1589 -- worry about if No_Index were less than 0, but that case is
1590 -- handled above).
1592 if Index_Type'Last - No_Index >=
1593 Count_Type'Pos (Count_Type'Last)
1594 then
1595 -- We have determined that range of Index_Type has at least as
1596 -- many values as in Count_Type, so Count_Type'Last is the
1597 -- maximum number of items that are allowed.
1599 Max_Length := Count_Type'Last;
1601 else
1602 -- The range of Index_Type has fewer values than in Count_Type,
1603 -- so the maximum number of items is computed from the range of
1604 -- the Index_Type.
1606 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1607 end if;
1608 end if;
1610 elsif Index_Type'First <= 0 then
1612 -- We know that No_Index (the same as Index_Type'First - 1) is less
1613 -- than 0, so it is safe to compute the following sum without fear of
1614 -- overflow.
1616 J := Count_Type'Base (No_Index) + Count_Type'Last;
1618 if J <= Count_Type'Base (Index_Type'Last) then
1620 -- We have determined that range of Index_Type has at least as
1621 -- many values as in Count_Type, so Count_Type'Last is the maximum
1622 -- number of items that are allowed.
1624 Max_Length := Count_Type'Last;
1626 else
1627 -- The range of Index_Type has fewer values than Count_Type does,
1628 -- so the maximum number of items is computed from the range of
1629 -- the Index_Type.
1631 Max_Length :=
1632 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1633 end if;
1635 else
1636 -- No_Index is equal or greater than 0, so we can safely compute the
1637 -- difference without fear of overflow (which we would have to worry
1638 -- about if No_Index were less than 0, but that case is handled
1639 -- above).
1641 Max_Length :=
1642 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1643 end if;
1645 -- We have just computed the maximum length (number of items). We must
1646 -- now compare the requested length to the maximum length, as we do not
1647 -- allow a vector expand beyond the maximum (because that would create
1648 -- an internal array with a last index value greater than
1649 -- Index_Type'Last, with no way to index those elements).
1651 if Checks and then New_Length > Max_Length then
1652 raise Constraint_Error with "Count is out of range";
1653 end if;
1655 -- The tampering bits exist to prevent an item from being harmfully
1656 -- manipulated while it is being visited. Query, Update, and Iterate
1657 -- increment the busy count on entry, and decrement the count on
1658 -- exit. Insert checks the count to determine whether it is being called
1659 -- while the associated callback procedure is executing.
1661 TC_Check (Container.TC);
1663 -- An internal array has already been allocated, so we need to check
1664 -- whether there is enough unused storage for the new items.
1666 if Checks and then New_Length > Container.Capacity then
1667 raise Capacity_Error with "New length is larger than capacity";
1668 end if;
1670 -- In this case, we're inserting space into a vector that has already
1671 -- allocated an internal array, and the existing array has enough
1672 -- unused storage for the new items.
1674 if Before <= Container.Last then
1676 -- The space is being inserted before some existing elements,
1677 -- so we must slide the existing elements up to their new home.
1679 J := To_Array_Index (Before);
1680 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1681 end if;
1683 -- New_Last is the last index value of the items in the container after
1684 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1685 -- compute its value from the New_Length.
1687 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1688 Container.Last := No_Index + Index_Type'Base (New_Length);
1690 else
1691 Container.Last :=
1692 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1693 end if;
1694 end Insert_Space;
1696 procedure Insert_Space
1697 (Container : in out Vector;
1698 Before : Cursor;
1699 Position : out Cursor;
1700 Count : Count_Type := 1)
1702 Index : Index_Type'Base;
1704 begin
1705 if Checks and then Before.Container /= null
1706 and then Before.Container /= Container'Unchecked_Access
1707 then
1708 raise Program_Error with "Before cursor denotes wrong container";
1709 end if;
1711 if Count = 0 then
1712 if Before.Container = null
1713 or else Before.Index > Container.Last
1714 then
1715 Position := No_Element;
1716 else
1717 Position := (Container'Unchecked_Access, Before.Index);
1718 end if;
1720 return;
1721 end if;
1723 if Before.Container = null
1724 or else Before.Index > Container.Last
1725 then
1726 if Checks and then Container.Last = Index_Type'Last then
1727 raise Constraint_Error with
1728 "vector is already at its maximum length";
1729 end if;
1731 Index := Container.Last + 1;
1733 else
1734 Index := Before.Index;
1735 end if;
1737 Insert_Space (Container, Index, Count => Count);
1739 Position := Cursor'(Container'Unchecked_Access, Index);
1740 end Insert_Space;
1742 --------------
1743 -- Is_Empty --
1744 --------------
1746 function Is_Empty (Container : Vector) return Boolean is
1747 begin
1748 return Container.Last < Index_Type'First;
1749 end Is_Empty;
1751 -------------
1752 -- Iterate --
1753 -------------
1755 procedure Iterate
1756 (Container : Vector;
1757 Process : not null access procedure (Position : Cursor))
1759 Busy : With_Busy (Container.TC'Unrestricted_Access);
1760 begin
1761 for Indx in Index_Type'First .. Container.Last loop
1762 Process (Cursor'(Container'Unrestricted_Access, Indx));
1763 end loop;
1764 end Iterate;
1766 function Iterate
1767 (Container : Vector)
1768 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1770 V : constant Vector_Access := Container'Unrestricted_Access;
1771 begin
1772 -- The value of its Index component influences the behavior of the First
1773 -- and Last selector functions of the iterator object. When the Index
1774 -- component is No_Index (as is the case here), this means the iterator
1775 -- object was constructed without a start expression. This is a complete
1776 -- iterator, meaning that the iteration starts from the (logical)
1777 -- beginning of the sequence of items.
1779 -- Note: For a forward iterator, Container.First is the beginning, and
1780 -- for a reverse iterator, Container.Last is the beginning.
1782 return It : constant Iterator :=
1783 (Limited_Controlled with
1784 Container => V,
1785 Index => No_Index)
1787 Busy (Container.TC'Unrestricted_Access.all);
1788 end return;
1789 end Iterate;
1791 function Iterate
1792 (Container : Vector;
1793 Start : Cursor)
1794 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1796 V : constant Vector_Access := Container'Unrestricted_Access;
1797 begin
1798 -- It was formerly the case that when Start = No_Element, the partial
1799 -- iterator was defined to behave the same as for a complete iterator,
1800 -- and iterate over the entire sequence of items. However, those
1801 -- semantics were unintuitive and arguably error-prone (it is too easy
1802 -- to accidentally create an endless loop), and so they were changed,
1803 -- per the ARG meeting in Denver on 2011/11. However, there was no
1804 -- consensus about what positive meaning this corner case should have,
1805 -- and so it was decided to simply raise an exception. This does imply,
1806 -- however, that it is not possible to use a partial iterator to specify
1807 -- an empty sequence of items.
1809 if Checks and then Start.Container = null then
1810 raise Constraint_Error with
1811 "Start position for iterator equals No_Element";
1812 end if;
1814 if Checks and then Start.Container /= V then
1815 raise Program_Error with
1816 "Start cursor of Iterate designates wrong vector";
1817 end if;
1819 if Checks and then Start.Index > V.Last then
1820 raise Constraint_Error with
1821 "Start position for iterator equals No_Element";
1822 end if;
1824 -- The value of its Index component influences the behavior of the First
1825 -- and Last selector functions of the iterator object. When the Index
1826 -- component is not No_Index (as is the case here), it means that this
1827 -- is a partial iteration, over a subset of the complete sequence of
1828 -- items. The iterator object was constructed with a start expression,
1829 -- indicating the position from which the iteration begins. Note that
1830 -- the start position has the same value irrespective of whether this is
1831 -- a forward or reverse iteration.
1833 return It : constant Iterator :=
1834 (Limited_Controlled with
1835 Container => V,
1836 Index => Start.Index)
1838 Busy (Container.TC'Unrestricted_Access.all);
1839 end return;
1840 end Iterate;
1842 ----------
1843 -- Last --
1844 ----------
1846 function Last (Container : Vector) return Cursor is
1847 begin
1848 if Is_Empty (Container) then
1849 return No_Element;
1850 else
1851 return (Container'Unrestricted_Access, Container.Last);
1852 end if;
1853 end Last;
1855 function Last (Object : Iterator) return Cursor is
1856 begin
1857 -- The value of the iterator object's Index component influences the
1858 -- behavior of the Last (and First) selector function.
1860 -- When the Index component is No_Index, this means the iterator object
1861 -- was constructed without a start expression, in which case the
1862 -- (reverse) iteration starts from the (logical) beginning of the entire
1863 -- sequence (corresponding to Container.Last, for a reverse iterator).
1865 -- Otherwise, this is iteration over a partial sequence of items. When
1866 -- the Index component is not No_Index, the iterator object was
1867 -- constructed with a start expression, that specifies the position from
1868 -- which the (reverse) partial iteration begins.
1870 if Object.Index = No_Index then
1871 return Last (Object.Container.all);
1872 else
1873 return Cursor'(Object.Container, Object.Index);
1874 end if;
1875 end Last;
1877 ------------------
1878 -- Last_Element --
1879 ------------------
1881 function Last_Element (Container : Vector) return Element_Type is
1882 begin
1883 if Checks and then Container.Last = No_Index then
1884 raise Constraint_Error with "Container is empty";
1885 end if;
1887 return Container.Elements (Container.Length);
1888 end Last_Element;
1890 ----------------
1891 -- Last_Index --
1892 ----------------
1894 function Last_Index (Container : Vector) return Extended_Index is
1895 begin
1896 return Container.Last;
1897 end Last_Index;
1899 ------------
1900 -- Length --
1901 ------------
1903 function Length (Container : Vector) return Count_Type is
1904 L : constant Index_Type'Base := Container.Last;
1905 F : constant Index_Type := Index_Type'First;
1907 begin
1908 -- The base range of the index type (Index_Type'Base) might not include
1909 -- all values for length (Count_Type). Contrariwise, the index type
1910 -- might include values outside the range of length. Hence we use
1911 -- whatever type is wider for intermediate values when calculating
1912 -- length. Note that no matter what the index type is, the maximum
1913 -- length to which a vector is allowed to grow is always the minimum
1914 -- of Count_Type'Last and (IT'Last - IT'First + 1).
1916 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
1917 -- to have a base range of -128 .. 127, but the corresponding vector
1918 -- would have lengths in the range 0 .. 255. In this case we would need
1919 -- to use Count_Type'Base for intermediate values.
1921 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
1922 -- vector would have a maximum length of 10, but the index values lie
1923 -- outside the range of Count_Type (which is only 32 bits). In this
1924 -- case we would need to use Index_Type'Base for intermediate values.
1926 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
1927 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
1928 else
1929 return Count_Type (L - F + 1);
1930 end if;
1931 end Length;
1933 ----------
1934 -- Move --
1935 ----------
1937 procedure Move
1938 (Target : in out Vector;
1939 Source : in out Vector)
1941 begin
1942 if Target'Address = Source'Address then
1943 return;
1944 end if;
1946 if Checks and then Target.Capacity < Source.Length then
1947 raise Capacity_Error -- ???
1948 with "Target capacity is less than Source length";
1949 end if;
1951 TC_Check (Target.TC);
1952 TC_Check (Source.TC);
1954 -- Clear Target now, in case element assignment fails
1956 Target.Last := No_Index;
1958 Target.Elements (1 .. Source.Length) :=
1959 Source.Elements (1 .. Source.Length);
1961 Target.Last := Source.Last;
1962 Source.Last := No_Index;
1963 end Move;
1965 ----------
1966 -- Next --
1967 ----------
1969 function Next (Position : Cursor) return Cursor is
1970 begin
1971 if Position.Container = null then
1972 return No_Element;
1973 elsif Position.Index < Position.Container.Last then
1974 return (Position.Container, Position.Index + 1);
1975 else
1976 return No_Element;
1977 end if;
1978 end Next;
1980 function Next (Object : Iterator; Position : Cursor) return Cursor is
1981 begin
1982 if Position.Container = null then
1983 return No_Element;
1984 end if;
1986 if Checks and then Position.Container /= Object.Container then
1987 raise Program_Error with
1988 "Position cursor of Next designates wrong vector";
1989 end if;
1991 return Next (Position);
1992 end Next;
1994 procedure Next (Position : in out Cursor) is
1995 begin
1996 if Position.Container = null then
1997 return;
1998 elsif Position.Index < Position.Container.Last then
1999 Position.Index := Position.Index + 1;
2000 else
2001 Position := No_Element;
2002 end if;
2003 end Next;
2005 -------------
2006 -- Prepend --
2007 -------------
2009 procedure Prepend (Container : in out Vector; New_Item : Vector) is
2010 begin
2011 Insert (Container, Index_Type'First, New_Item);
2012 end Prepend;
2014 procedure Prepend
2015 (Container : in out Vector;
2016 New_Item : Element_Type;
2017 Count : Count_Type := 1)
2019 begin
2020 Insert (Container,
2021 Index_Type'First,
2022 New_Item,
2023 Count);
2024 end Prepend;
2026 --------------
2027 -- Previous --
2028 --------------
2030 procedure Previous (Position : in out Cursor) is
2031 begin
2032 if Position.Container = null then
2033 return;
2034 elsif Position.Index > Index_Type'First then
2035 Position.Index := Position.Index - 1;
2036 else
2037 Position := No_Element;
2038 end if;
2039 end Previous;
2041 function Previous (Position : Cursor) return Cursor is
2042 begin
2043 if Position.Container = null then
2044 return No_Element;
2045 elsif Position.Index > Index_Type'First then
2046 return (Position.Container, Position.Index - 1);
2047 else
2048 return No_Element;
2049 end if;
2050 end Previous;
2052 function Previous (Object : Iterator; Position : Cursor) return Cursor is
2053 begin
2054 if Position.Container = null then
2055 return No_Element;
2056 end if;
2058 if Checks and then Position.Container /= Object.Container then
2059 raise Program_Error with
2060 "Position cursor of Previous designates wrong vector";
2061 end if;
2063 return Previous (Position);
2064 end Previous;
2066 ----------------------
2067 -- Pseudo_Reference --
2068 ----------------------
2070 function Pseudo_Reference
2071 (Container : aliased Vector'Class) return Reference_Control_Type
2073 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
2074 begin
2075 return R : constant Reference_Control_Type := (Controlled with TC) do
2076 Lock (TC.all);
2077 end return;
2078 end Pseudo_Reference;
2080 -------------------
2081 -- Query_Element --
2082 -------------------
2084 procedure Query_Element
2085 (Container : Vector;
2086 Index : Index_Type;
2087 Process : not null access procedure (Element : Element_Type))
2089 Lock : With_Lock (Container.TC'Unrestricted_Access);
2090 V : Vector renames Container'Unrestricted_Access.all;
2091 begin
2092 if Checks and then Index > Container.Last then
2093 raise Constraint_Error with "Index is out of range";
2094 end if;
2096 Process (V.Elements (To_Array_Index (Index)));
2097 end Query_Element;
2099 procedure Query_Element
2100 (Position : Cursor;
2101 Process : not null access procedure (Element : Element_Type))
2103 begin
2104 if Checks and then Position.Container = null then
2105 raise Constraint_Error with "Position cursor has no element";
2106 end if;
2108 Query_Element (Position.Container.all, Position.Index, Process);
2109 end Query_Element;
2111 ----------
2112 -- Read --
2113 ----------
2115 procedure Read
2116 (Stream : not null access Root_Stream_Type'Class;
2117 Container : out Vector)
2119 Length : Count_Type'Base;
2120 Last : Index_Type'Base := No_Index;
2122 begin
2123 Clear (Container);
2125 Count_Type'Base'Read (Stream, Length);
2127 Reserve_Capacity (Container, Capacity => Length);
2129 for Idx in Count_Type range 1 .. Length loop
2130 Last := Last + 1;
2131 Element_Type'Read (Stream, Container.Elements (Idx));
2132 Container.Last := Last;
2133 end loop;
2134 end Read;
2136 procedure Read
2137 (Stream : not null access Root_Stream_Type'Class;
2138 Position : out Cursor)
2140 begin
2141 raise Program_Error with "attempt to stream vector cursor";
2142 end Read;
2144 procedure Read
2145 (Stream : not null access Root_Stream_Type'Class;
2146 Item : out Reference_Type)
2148 begin
2149 raise Program_Error with "attempt to stream reference";
2150 end Read;
2152 procedure Read
2153 (Stream : not null access Root_Stream_Type'Class;
2154 Item : out Constant_Reference_Type)
2156 begin
2157 raise Program_Error with "attempt to stream reference";
2158 end Read;
2160 ---------------
2161 -- Reference --
2162 ---------------
2164 function Reference
2165 (Container : aliased in out Vector;
2166 Position : Cursor) return Reference_Type
2168 begin
2169 if Checks and then Position.Container = null then
2170 raise Constraint_Error with "Position cursor has no element";
2171 end if;
2173 if Checks and then Position.Container /= Container'Unrestricted_Access
2174 then
2175 raise Program_Error with "Position cursor denotes wrong container";
2176 end if;
2178 if Checks and then Position.Index > Position.Container.Last then
2179 raise Constraint_Error with "Position cursor is out of range";
2180 end if;
2182 declare
2183 A : Elements_Array renames Container.Elements;
2184 J : constant Count_Type := To_Array_Index (Position.Index);
2185 TC : constant Tamper_Counts_Access :=
2186 Container.TC'Unrestricted_Access;
2187 begin
2188 return R : constant Reference_Type :=
2189 (Element => A (J)'Access,
2190 Control => (Controlled with TC))
2192 Lock (TC.all);
2193 end return;
2194 end;
2195 end Reference;
2197 function Reference
2198 (Container : aliased in out Vector;
2199 Index : Index_Type) return Reference_Type
2201 begin
2202 if Checks and then Index > Container.Last then
2203 raise Constraint_Error with "Index is out of range";
2204 end if;
2206 declare
2207 A : Elements_Array renames Container.Elements;
2208 J : constant Count_Type := To_Array_Index (Index);
2209 TC : constant Tamper_Counts_Access :=
2210 Container.TC'Unrestricted_Access;
2211 begin
2212 return R : constant Reference_Type :=
2213 (Element => A (J)'Access,
2214 Control => (Controlled with TC))
2216 Lock (TC.all);
2217 end return;
2218 end;
2219 end Reference;
2221 ---------------------
2222 -- Replace_Element --
2223 ---------------------
2225 procedure Replace_Element
2226 (Container : in out Vector;
2227 Index : Index_Type;
2228 New_Item : Element_Type)
2230 begin
2231 if Checks and then Index > Container.Last then
2232 raise Constraint_Error with "Index is out of range";
2233 end if;
2235 TE_Check (Container.TC);
2237 Container.Elements (To_Array_Index (Index)) := New_Item;
2238 end Replace_Element;
2240 procedure Replace_Element
2241 (Container : in out Vector;
2242 Position : Cursor;
2243 New_Item : Element_Type)
2245 begin
2246 if Checks and then Position.Container = null then
2247 raise Constraint_Error with "Position cursor has no element";
2248 end if;
2250 if Checks and then Position.Container /= Container'Unrestricted_Access
2251 then
2252 raise Program_Error with "Position cursor denotes wrong container";
2253 end if;
2255 if Checks and then Position.Index > Container.Last then
2256 raise Constraint_Error with "Position cursor is out of range";
2257 end if;
2259 TE_Check (Container.TC);
2261 Container.Elements (To_Array_Index (Position.Index)) := New_Item;
2262 end Replace_Element;
2264 ----------------------
2265 -- Reserve_Capacity --
2266 ----------------------
2268 procedure Reserve_Capacity
2269 (Container : in out Vector;
2270 Capacity : Count_Type)
2272 begin
2273 if Checks and then Capacity > Container.Capacity then
2274 raise Capacity_Error with "Capacity is out of range";
2275 end if;
2276 end Reserve_Capacity;
2278 ----------------------
2279 -- Reverse_Elements --
2280 ----------------------
2282 procedure Reverse_Elements (Container : in out Vector) is
2283 E : Elements_Array renames Container.Elements;
2284 Idx : Count_Type;
2285 Jdx : Count_Type;
2287 begin
2288 if Container.Length <= 1 then
2289 return;
2290 end if;
2292 -- The exception behavior for the vector container must match that for
2293 -- the list container, so we check for cursor tampering here (which will
2294 -- catch more things) instead of for element tampering (which will catch
2295 -- fewer things). It's true that the elements of this vector container
2296 -- could be safely moved around while (say) an iteration is taking place
2297 -- (iteration only increments the busy counter), and so technically
2298 -- all we would need here is a test for element tampering (indicated
2299 -- by the lock counter), that's simply an artifact of our array-based
2300 -- implementation. Logically Reverse_Elements requires a check for
2301 -- cursor tampering.
2303 TC_Check (Container.TC);
2305 Idx := 1;
2306 Jdx := Container.Length;
2307 while Idx < Jdx loop
2308 declare
2309 EI : constant Element_Type := E (Idx);
2311 begin
2312 E (Idx) := E (Jdx);
2313 E (Jdx) := EI;
2314 end;
2316 Idx := Idx + 1;
2317 Jdx := Jdx - 1;
2318 end loop;
2319 end Reverse_Elements;
2321 ------------------
2322 -- Reverse_Find --
2323 ------------------
2325 function Reverse_Find
2326 (Container : Vector;
2327 Item : Element_Type;
2328 Position : Cursor := No_Element) return Cursor
2330 Last : Index_Type'Base;
2332 begin
2333 if Checks and then Position.Container /= null
2334 and then Position.Container /= Container'Unrestricted_Access
2335 then
2336 raise Program_Error with "Position cursor denotes wrong container";
2337 end if;
2339 Last :=
2340 (if Position.Container = null or else Position.Index > Container.Last
2341 then Container.Last
2342 else Position.Index);
2344 -- Per AI05-0022, the container implementation is required to detect
2345 -- element tampering by a generic actual subprogram.
2347 declare
2348 Lock : With_Lock (Container.TC'Unrestricted_Access);
2349 begin
2350 for Indx in reverse Index_Type'First .. Last loop
2351 if Container.Elements (To_Array_Index (Indx)) = Item then
2352 return Cursor'(Container'Unrestricted_Access, Indx);
2353 end if;
2354 end loop;
2356 return No_Element;
2357 end;
2358 end Reverse_Find;
2360 ------------------------
2361 -- Reverse_Find_Index --
2362 ------------------------
2364 function Reverse_Find_Index
2365 (Container : Vector;
2366 Item : Element_Type;
2367 Index : Index_Type := Index_Type'Last) return Extended_Index
2369 -- Per AI05-0022, the container implementation is required to detect
2370 -- element tampering by a generic actual subprogram.
2372 Lock : With_Lock (Container.TC'Unrestricted_Access);
2374 Last : constant Index_Type'Base :=
2375 Index_Type'Min (Container.Last, Index);
2377 begin
2378 for Indx in reverse Index_Type'First .. Last loop
2379 if Container.Elements (To_Array_Index (Indx)) = Item then
2380 return Indx;
2381 end if;
2382 end loop;
2384 return No_Index;
2385 end Reverse_Find_Index;
2387 ---------------------
2388 -- Reverse_Iterate --
2389 ---------------------
2391 procedure Reverse_Iterate
2392 (Container : Vector;
2393 Process : not null access procedure (Position : Cursor))
2395 Busy : With_Busy (Container.TC'Unrestricted_Access);
2396 begin
2397 for Indx in reverse Index_Type'First .. Container.Last loop
2398 Process (Cursor'(Container'Unrestricted_Access, Indx));
2399 end loop;
2400 end Reverse_Iterate;
2402 ----------------
2403 -- Set_Length --
2404 ----------------
2406 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2407 Count : constant Count_Type'Base := Container.Length - Length;
2409 begin
2410 -- Set_Length allows the user to set the length explicitly, instead of
2411 -- implicitly as a side-effect of deletion or insertion. If the
2412 -- requested length is less than the current length, this is equivalent
2413 -- to deleting items from the back end of the vector. If the requested
2414 -- length is greater than the current length, then this is equivalent to
2415 -- inserting "space" (nonce items) at the end.
2417 if Count >= 0 then
2418 Container.Delete_Last (Count);
2419 elsif Checks and then Container.Last >= Index_Type'Last then
2420 raise Constraint_Error with "vector is already at its maximum length";
2421 else
2422 Container.Insert_Space (Container.Last + 1, -Count);
2423 end if;
2424 end Set_Length;
2426 ----------
2427 -- Swap --
2428 ----------
2430 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2431 E : Elements_Array renames Container.Elements;
2433 begin
2434 if Checks and then I > Container.Last then
2435 raise Constraint_Error with "I index is out of range";
2436 end if;
2438 if Checks and then J > Container.Last then
2439 raise Constraint_Error with "J index is out of range";
2440 end if;
2442 if I = J then
2443 return;
2444 end if;
2446 TE_Check (Container.TC);
2448 declare
2449 EI_Copy : constant Element_Type := E (To_Array_Index (I));
2450 begin
2451 E (To_Array_Index (I)) := E (To_Array_Index (J));
2452 E (To_Array_Index (J)) := EI_Copy;
2453 end;
2454 end Swap;
2456 procedure Swap (Container : in out Vector; I, J : Cursor) is
2457 begin
2458 if Checks and then I.Container = null then
2459 raise Constraint_Error with "I cursor has no element";
2460 end if;
2462 if Checks and then J.Container = null then
2463 raise Constraint_Error with "J cursor has no element";
2464 end if;
2466 if Checks and then I.Container /= Container'Unrestricted_Access then
2467 raise Program_Error with "I cursor denotes wrong container";
2468 end if;
2470 if Checks and then J.Container /= Container'Unrestricted_Access then
2471 raise Program_Error with "J cursor denotes wrong container";
2472 end if;
2474 Swap (Container, I.Index, J.Index);
2475 end Swap;
2477 --------------------
2478 -- To_Array_Index --
2479 --------------------
2481 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is
2482 Offset : Count_Type'Base;
2484 begin
2485 -- We know that
2486 -- Index >= Index_Type'First
2487 -- hence we also know that
2488 -- Index - Index_Type'First >= 0
2490 -- The issue is that even though 0 is guaranteed to be a value in
2491 -- the type Index_Type'Base, there's no guarantee that the difference
2492 -- is a value in that type. To prevent overflow we use the wider
2493 -- of Count_Type'Base and Index_Type'Base to perform intermediate
2494 -- calculations.
2496 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2497 Offset := Count_Type'Base (Index - Index_Type'First);
2499 else
2500 Offset := Count_Type'Base (Index) -
2501 Count_Type'Base (Index_Type'First);
2502 end if;
2504 -- The array index subtype for all container element arrays
2505 -- always starts with 1.
2507 return 1 + Offset;
2508 end To_Array_Index;
2510 ---------------
2511 -- To_Cursor --
2512 ---------------
2514 function To_Cursor
2515 (Container : Vector;
2516 Index : Extended_Index) return Cursor
2518 begin
2519 if Index not in Index_Type'First .. Container.Last then
2520 return No_Element;
2521 end if;
2523 return Cursor'(Container'Unrestricted_Access, Index);
2524 end To_Cursor;
2526 --------------
2527 -- To_Index --
2528 --------------
2530 function To_Index (Position : Cursor) return Extended_Index is
2531 begin
2532 if Position.Container = null then
2533 return No_Index;
2534 end if;
2536 if Position.Index <= Position.Container.Last then
2537 return Position.Index;
2538 end if;
2540 return No_Index;
2541 end To_Index;
2543 ---------------
2544 -- To_Vector --
2545 ---------------
2547 function To_Vector (Length : Count_Type) return Vector is
2548 Index : Count_Type'Base;
2549 Last : Index_Type'Base;
2551 begin
2552 if Length = 0 then
2553 return Empty_Vector;
2554 end if;
2556 -- We create a vector object with a capacity that matches the specified
2557 -- Length, but we do not allow the vector capacity (the length of the
2558 -- internal array) to exceed the number of values in Index_Type'Range
2559 -- (otherwise, there would be no way to refer to those components via an
2560 -- index). We must therefore check whether the specified Length would
2561 -- create a Last index value greater than Index_Type'Last.
2563 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2564 -- We perform a two-part test. First we determine whether the
2565 -- computed Last value lies in the base range of the type, and then
2566 -- determine whether it lies in the range of the index (sub)type.
2568 -- Last must satisfy this relation:
2569 -- First + Length - 1 <= Last
2570 -- We regroup terms:
2571 -- First - 1 <= Last - Length
2572 -- Which can rewrite as:
2573 -- No_Index <= Last - Length
2575 if Checks and then
2576 Index_Type'Base'Last - Index_Type'Base (Length) < No_Index
2577 then
2578 raise Constraint_Error with "Length is out of range";
2579 end if;
2581 -- We now know that the computed value of Last is within the base
2582 -- range of the type, so it is safe to compute its value:
2584 Last := No_Index + Index_Type'Base (Length);
2586 -- Finally we test whether the value is within the range of the
2587 -- generic actual index subtype:
2589 if Checks and then Last > Index_Type'Last then
2590 raise Constraint_Error with "Length is out of range";
2591 end if;
2593 elsif Index_Type'First <= 0 then
2595 -- Here we can compute Last directly, in the normal way. We know that
2596 -- No_Index is less than 0, so there is no danger of overflow when
2597 -- adding the (positive) value of Length.
2599 Index := Count_Type'Base (No_Index) + Length; -- Last
2601 if Checks and then Index > Count_Type'Base (Index_Type'Last) then
2602 raise Constraint_Error with "Length is out of range";
2603 end if;
2605 -- We know that the computed value (having type Count_Type) of Last
2606 -- is within the range of the generic actual index subtype, so it is
2607 -- safe to convert to Index_Type:
2609 Last := Index_Type'Base (Index);
2611 else
2612 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2613 -- must test the length indirectly (by working backwards from the
2614 -- largest possible value of Last), in order to prevent overflow.
2616 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2618 if Checks and then Index < Count_Type'Base (No_Index) then
2619 raise Constraint_Error with "Length is out of range";
2620 end if;
2622 -- We have determined that the value of Length would not create a
2623 -- Last index value outside of the range of Index_Type, so we can now
2624 -- safely compute its value.
2626 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2627 end if;
2629 return V : Vector (Capacity => Length) do
2630 V.Last := Last;
2631 end return;
2632 end To_Vector;
2634 function To_Vector
2635 (New_Item : Element_Type;
2636 Length : Count_Type) return Vector
2638 Index : Count_Type'Base;
2639 Last : Index_Type'Base;
2641 begin
2642 if Length = 0 then
2643 return Empty_Vector;
2644 end if;
2646 -- We create a vector object with a capacity that matches the specified
2647 -- Length, but we do not allow the vector capacity (the length of the
2648 -- internal array) to exceed the number of values in Index_Type'Range
2649 -- (otherwise, there would be no way to refer to those components via an
2650 -- index). We must therefore check whether the specified Length would
2651 -- create a Last index value greater than Index_Type'Last.
2653 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2655 -- We perform a two-part test. First we determine whether the
2656 -- computed Last value lies in the base range of the type, and then
2657 -- determine whether it lies in the range of the index (sub)type.
2659 -- Last must satisfy this relation:
2660 -- First + Length - 1 <= Last
2661 -- We regroup terms:
2662 -- First - 1 <= Last - Length
2663 -- Which can rewrite as:
2664 -- No_Index <= Last - Length
2666 if Checks and then
2667 Index_Type'Base'Last - Index_Type'Base (Length) < No_Index
2668 then
2669 raise Constraint_Error with "Length is out of range";
2670 end if;
2672 -- We now know that the computed value of Last is within the base
2673 -- range of the type, so it is safe to compute its value:
2675 Last := No_Index + Index_Type'Base (Length);
2677 -- Finally we test whether the value is within the range of the
2678 -- generic actual index subtype:
2680 if Checks and then Last > Index_Type'Last then
2681 raise Constraint_Error with "Length is out of range";
2682 end if;
2684 elsif Index_Type'First <= 0 then
2686 -- Here we can compute Last directly, in the normal way. We know that
2687 -- No_Index is less than 0, so there is no danger of overflow when
2688 -- adding the (positive) value of Length.
2690 Index := Count_Type'Base (No_Index) + Length; -- same value as V.Last
2692 if Checks and then Index > Count_Type'Base (Index_Type'Last) then
2693 raise Constraint_Error with "Length is out of range";
2694 end if;
2696 -- We know that the computed value (having type Count_Type) of Last
2697 -- is within the range of the generic actual index subtype, so it is
2698 -- safe to convert to Index_Type:
2700 Last := Index_Type'Base (Index);
2702 else
2703 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2704 -- must test the length indirectly (by working backwards from the
2705 -- largest possible value of Last), in order to prevent overflow.
2707 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2709 if Checks and then Index < Count_Type'Base (No_Index) then
2710 raise Constraint_Error with "Length is out of range";
2711 end if;
2713 -- We have determined that the value of Length would not create a
2714 -- Last index value outside of the range of Index_Type, so we can now
2715 -- safely compute its value.
2717 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2718 end if;
2720 return V : Vector (Capacity => Length) do
2721 V.Elements := (others => New_Item);
2722 V.Last := Last;
2723 end return;
2724 end To_Vector;
2726 --------------------
2727 -- Update_Element --
2728 --------------------
2730 procedure Update_Element
2731 (Container : in out Vector;
2732 Index : Index_Type;
2733 Process : not null access procedure (Element : in out Element_Type))
2735 Lock : With_Lock (Container.TC'Unchecked_Access);
2736 begin
2737 if Checks and then Index > Container.Last then
2738 raise Constraint_Error with "Index is out of range";
2739 end if;
2741 Process (Container.Elements (To_Array_Index (Index)));
2742 end Update_Element;
2744 procedure Update_Element
2745 (Container : in out Vector;
2746 Position : Cursor;
2747 Process : not null access procedure (Element : in out Element_Type))
2749 begin
2750 if Checks and then Position.Container = null then
2751 raise Constraint_Error with "Position cursor has no element";
2752 end if;
2754 if Checks and then Position.Container /= Container'Unrestricted_Access
2755 then
2756 raise Program_Error with "Position cursor denotes wrong container";
2757 end if;
2759 Update_Element (Container, Position.Index, Process);
2760 end Update_Element;
2762 -----------
2763 -- Write --
2764 -----------
2766 procedure Write
2767 (Stream : not null access Root_Stream_Type'Class;
2768 Container : Vector)
2770 N : Count_Type;
2772 begin
2773 N := Container.Length;
2774 Count_Type'Base'Write (Stream, N);
2776 for J in 1 .. N loop
2777 Element_Type'Write (Stream, Container.Elements (J));
2778 end loop;
2779 end Write;
2781 procedure Write
2782 (Stream : not null access Root_Stream_Type'Class;
2783 Position : Cursor)
2785 begin
2786 raise Program_Error with "attempt to stream vector cursor";
2787 end Write;
2789 procedure Write
2790 (Stream : not null access Root_Stream_Type'Class;
2791 Item : Reference_Type)
2793 begin
2794 raise Program_Error with "attempt to stream reference";
2795 end Write;
2797 procedure Write
2798 (Stream : not null access Root_Stream_Type'Class;
2799 Item : Constant_Reference_Type)
2801 begin
2802 raise Program_Error with "attempt to stream reference";
2803 end Write;
2805 end Ada.Containers.Bounded_Vectors;