PR target/81369
[official-gcc.git] / gcc / ada / a-cofove.adb
blob63cbebbe74f2889f3830ef3d3aba1e5da3f4b026
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . F O R M A L _ V E C T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2010-2017, 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 ------------------------------------------------------------------------------
28 with Ada.Containers.Generic_Array_Sort;
29 with Ada.Unchecked_Deallocation;
31 with System; use type System.Address;
33 package body Ada.Containers.Formal_Vectors with
34 SPARK_Mode => Off
37 Growth_Factor : constant := 2;
38 -- When growing a container, multiply current capacity by this. Doubling
39 -- leads to amortized linear-time copying.
41 type Int is range System.Min_Int .. System.Max_Int;
43 procedure Free is
44 new Ada.Unchecked_Deallocation (Elements_Array, Elements_Array_Ptr);
46 type Maximal_Array_Ptr is access all Elements_Array (Array_Index)
47 with Storage_Size => 0;
48 type Maximal_Array_Ptr_Const is access constant Elements_Array (Array_Index)
49 with Storage_Size => 0;
51 function Elems (Container : in out Vector) return Maximal_Array_Ptr;
52 function Elemsc
53 (Container : Vector) return Maximal_Array_Ptr_Const;
54 -- Returns a pointer to the Elements array currently in use -- either
55 -- Container.Elements_Ptr or a pointer to Container.Elements. We work with
56 -- pointers to a bogus array subtype that is constrained with the maximum
57 -- possible bounds. This means that the pointer is a thin pointer. This is
58 -- necessary because 'Unrestricted_Access doesn't work when it produces
59 -- access-to-unconstrained and is returned from a function.
61 -- Note that this is dangerous: make sure calls to this use an indexed
62 -- component or slice that is within the bounds 1 .. Length (Container).
64 function Get_Element
65 (Container : Vector;
66 Position : Capacity_Range) return Element_Type;
68 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base;
70 function Current_Capacity (Container : Vector) return Capacity_Range;
72 procedure Insert_Space
73 (Container : in out Vector;
74 Before : Extended_Index;
75 Count : Count_Type := 1);
77 ---------
78 -- "=" --
79 ---------
81 function "=" (Left : Vector; Right : Vector) return Boolean is
82 begin
83 if Left'Address = Right'Address then
84 return True;
85 end if;
87 if Length (Left) /= Length (Right) then
88 return False;
89 end if;
91 for J in 1 .. Length (Left) loop
92 if Get_Element (Left, J) /= Get_Element (Right, J) then
93 return False;
94 end if;
95 end loop;
97 return True;
98 end "=";
100 ------------
101 -- Append --
102 ------------
104 procedure Append (Container : in out Vector; New_Item : Vector) is
105 begin
106 if Is_Empty (New_Item) then
107 return;
108 end if;
110 if Container.Last >= Index_Type'Last then
111 raise Constraint_Error with "vector is already at its maximum length";
112 end if;
114 Insert (Container, Container.Last + 1, New_Item);
115 end Append;
117 procedure Append (Container : in out Vector; New_Item : Element_Type) is
118 begin
119 Append (Container, New_Item, 1);
120 end Append;
122 procedure Append
123 (Container : in out Vector;
124 New_Item : Element_Type;
125 Count : Count_Type)
127 begin
128 if Count = 0 then
129 return;
130 end if;
132 if Container.Last >= Index_Type'Last then
133 raise Constraint_Error with "vector is already at its maximum length";
134 end if;
136 Insert (Container, Container.Last + 1, New_Item, Count);
137 end Append;
139 ------------
140 -- Assign --
141 ------------
143 procedure Assign (Target : in out Vector; Source : Vector) is
144 LS : constant Capacity_Range := Length (Source);
146 begin
147 if Target'Address = Source'Address then
148 return;
149 end if;
151 if Bounded and then Target.Capacity < LS then
152 raise Constraint_Error;
153 end if;
155 Clear (Target);
156 Append (Target, Source);
157 end Assign;
159 --------------
160 -- Capacity --
161 --------------
163 function Capacity (Container : Vector) return Capacity_Range is
164 begin
165 return
166 (if Bounded then
167 Container.Capacity
168 else
169 Capacity_Range'Last);
170 end Capacity;
172 -----------
173 -- Clear --
174 -----------
176 procedure Clear (Container : in out Vector) is
177 begin
178 Container.Last := No_Index;
180 -- Free element, note that this is OK if Elements_Ptr is null
182 Free (Container.Elements_Ptr);
183 end Clear;
185 --------------
186 -- Contains --
187 --------------
189 function Contains
190 (Container : Vector;
191 Item : Element_Type) return Boolean
193 begin
194 return Find_Index (Container, Item) /= No_Index;
195 end Contains;
197 ----------
198 -- Copy --
199 ----------
201 function Copy
202 (Source : Vector;
203 Capacity : Capacity_Range := 0) return Vector
205 LS : constant Capacity_Range := Length (Source);
206 C : Capacity_Range;
208 begin
209 if Capacity = 0 then
210 C := LS;
211 elsif Capacity >= LS then
212 C := Capacity;
213 else
214 raise Capacity_Error;
215 end if;
217 return Target : Vector (C) do
218 Elems (Target) (1 .. LS) := Elemsc (Source) (1 .. LS);
219 Target.Last := Source.Last;
220 end return;
221 end Copy;
223 ----------------------
224 -- Current_Capacity --
225 ----------------------
227 function Current_Capacity (Container : Vector) return Capacity_Range is
228 begin
229 return
230 (if Container.Elements_Ptr = null then
231 Container.Elements'Length
232 else
233 Container.Elements_Ptr.all'Length);
234 end Current_Capacity;
236 ------------
237 -- Delete --
238 ------------
240 procedure Delete (Container : in out Vector; Index : Extended_Index) is
241 begin
242 Delete (Container, Index, 1);
243 end Delete;
245 procedure Delete
246 (Container : in out Vector;
247 Index : Extended_Index;
248 Count : Count_Type)
250 Old_Last : constant Index_Type'Base := Container.Last;
251 Old_Len : constant Count_Type := Length (Container);
252 New_Last : Index_Type'Base;
253 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
254 Off : Count_Type'Base; -- Index expressed as offset from IT'First
256 begin
257 -- Delete removes items from the vector, the number of which is the
258 -- minimum of the specified Count and the items (if any) that exist from
259 -- Index to Container.Last. There are no constraints on the specified
260 -- value of Count (it can be larger than what's available at this
261 -- position in the vector, for example), but there are constraints on
262 -- the allowed values of the Index.
264 -- As a precondition on the generic actual Index_Type, the base type
265 -- must include Index_Type'Pred (Index_Type'First); this is the value
266 -- that Container.Last assumes when the vector is empty. However, we do
267 -- not allow that as the value for Index when specifying which items
268 -- should be deleted, so we must manually check. (That the user is
269 -- allowed to specify the value at all here is a consequence of the
270 -- declaration of the Extended_Index subtype, which includes the values
271 -- in the base range that immediately precede and immediately follow the
272 -- values in the Index_Type.)
274 if Index < Index_Type'First then
275 raise Constraint_Error with "Index is out of range (too small)";
276 end if;
278 -- We do allow a value greater than Container.Last to be specified as
279 -- the Index, but only if it's immediately greater. This allows the
280 -- corner case of deleting no items from the back end of the vector to
281 -- be treated as a no-op. (It is assumed that specifying an index value
282 -- greater than Last + 1 indicates some deeper flaw in the caller's
283 -- algorithm, so that case is treated as a proper error.)
285 if Index > Old_Last then
286 if Index > Old_Last + 1 then
287 raise Constraint_Error with "Index is out of range (too large)";
288 end if;
290 return;
291 end if;
293 if Count = 0 then
294 return;
295 end if;
297 -- We first calculate what's available for deletion starting at
298 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
299 -- Count_Type'Base as the type for intermediate values. (See function
300 -- Length for more information.)
302 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
303 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
304 else
305 Count2 := Count_Type'Base (Old_Last - Index + 1);
306 end if;
308 -- If more elements are requested (Count) for deletion than are
309 -- available (Count2) for deletion beginning at Index, then everything
310 -- from Index is deleted. There are no elements to slide down, and so
311 -- all we need to do is set the value of Container.Last.
313 if Count >= Count2 then
314 Container.Last := Index - 1;
315 return;
316 end if;
318 -- There are some elements aren't being deleted (the requested count was
319 -- less than the available count), so we must slide them down to Index.
320 -- We first calculate the index values of the respective array slices,
321 -- using the wider of Index_Type'Base and Count_Type'Base as the type
322 -- for intermediate calculations.
324 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
325 Off := Count_Type'Base (Index - Index_Type'First);
326 New_Last := Old_Last - Index_Type'Base (Count);
327 else
328 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
329 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
330 end if;
332 -- The array index values for each slice have already been determined,
333 -- so we just slide down to Index the elements that weren't deleted.
335 declare
336 EA : Maximal_Array_Ptr renames Elems (Container);
337 Idx : constant Count_Type := EA'First + Off;
338 begin
339 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
340 Container.Last := New_Last;
341 end;
342 end Delete;
344 ------------------
345 -- Delete_First --
346 ------------------
348 procedure Delete_First (Container : in out Vector) is
349 begin
350 Delete_First (Container, 1);
351 end Delete_First;
353 procedure Delete_First (Container : in out Vector; Count : Count_Type) is
354 begin
355 if Count = 0 then
356 return;
358 elsif Count >= Length (Container) then
359 Clear (Container);
360 return;
362 else
363 Delete (Container, Index_Type'First, Count);
364 end if;
365 end Delete_First;
367 -----------------
368 -- Delete_Last --
369 -----------------
371 procedure Delete_Last (Container : in out Vector) is
372 begin
373 Delete_Last (Container, 1);
374 end Delete_Last;
376 procedure Delete_Last (Container : in out Vector; Count : Count_Type) is
377 begin
378 if Count = 0 then
379 return;
380 end if;
382 -- There is no restriction on how large Count can be when deleting
383 -- items. If it is equal or greater than the current length, then this
384 -- is equivalent to clearing the vector. (In particular, there's no need
385 -- for us to actually calculate the new value for Last.)
387 -- If the requested count is less than the current length, then we must
388 -- calculate the new value for Last. For the type we use the widest of
389 -- Index_Type'Base and Count_Type'Base for the intermediate values of
390 -- our calculation. (See the comments in Length for more information.)
392 if Count >= Length (Container) then
393 Container.Last := No_Index;
395 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
396 Container.Last := Container.Last - Index_Type'Base (Count);
398 else
399 Container.Last :=
400 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
401 end if;
402 end Delete_Last;
404 -------------
405 -- Element --
406 -------------
408 function Element
409 (Container : Vector;
410 Index : Index_Type) return Element_Type
412 begin
413 if Index > Container.Last then
414 raise Constraint_Error with "Index is out of range";
415 end if;
417 declare
418 II : constant Int'Base := Int (Index) - Int (No_Index);
419 I : constant Capacity_Range := Capacity_Range (II);
420 begin
421 return Get_Element (Container, I);
422 end;
423 end Element;
425 --------------
426 -- Elements --
427 --------------
429 function Elems (Container : in out Vector) return Maximal_Array_Ptr is
430 begin
431 return
432 (if Container.Elements_Ptr = null then
433 Container.Elements'Unrestricted_Access
434 else
435 Container.Elements_Ptr.all'Unrestricted_Access);
436 end Elems;
438 function Elemsc (Container : Vector) return Maximal_Array_Ptr_Const is
439 begin
440 return
441 (if Container.Elements_Ptr = null then
442 Container.Elements'Unrestricted_Access
443 else
444 Container.Elements_Ptr.all'Unrestricted_Access);
445 end Elemsc;
447 ----------------
448 -- Find_Index --
449 ----------------
451 function Find_Index
452 (Container : Vector;
453 Item : Element_Type;
454 Index : Index_Type := Index_Type'First) return Extended_Index
456 K : Capacity_Range;
457 Last : constant Index_Type := Last_Index (Container);
459 begin
460 K := Capacity_Range (Int (Index) - Int (No_Index));
461 for Indx in Index .. Last loop
462 if Get_Element (Container, K) = Item then
463 return Indx;
464 end if;
466 K := K + 1;
467 end loop;
469 return No_Index;
470 end Find_Index;
472 -------------------
473 -- First_Element --
474 -------------------
476 function First_Element (Container : Vector) return Element_Type is
477 begin
478 if Is_Empty (Container) then
479 raise Constraint_Error with "Container is empty";
480 else
481 return Get_Element (Container, 1);
482 end if;
483 end First_Element;
485 -----------------
486 -- First_Index --
487 -----------------
489 function First_Index (Container : Vector) return Index_Type is
490 pragma Unreferenced (Container);
491 begin
492 return Index_Type'First;
493 end First_Index;
495 ------------------
496 -- Formal_Model --
497 ------------------
499 package body Formal_Model is
501 -------------------------
502 -- M_Elements_In_Union --
503 -------------------------
505 function M_Elements_In_Union
506 (Container : M.Sequence;
507 Left : M.Sequence;
508 Right : M.Sequence) return Boolean
510 Elem : Element_Type;
512 begin
513 for Index in Index_Type'First .. M.Last (Container) loop
514 Elem := Element (Container, Index);
516 if not M.Contains (Left, Index_Type'First, M.Last (Left), Elem)
517 and then
518 not M.Contains (Right, Index_Type'First, M.Last (Right), Elem)
519 then
520 return False;
521 end if;
522 end loop;
524 return True;
525 end M_Elements_In_Union;
527 -------------------------
528 -- M_Elements_Included --
529 -------------------------
531 function M_Elements_Included
532 (Left : M.Sequence;
533 L_Fst : Index_Type := Index_Type'First;
534 L_Lst : Extended_Index;
535 Right : M.Sequence;
536 R_Fst : Index_Type := Index_Type'First;
537 R_Lst : Extended_Index) return Boolean
539 begin
540 for I in L_Fst .. L_Lst loop
541 declare
542 Found : Boolean := False;
543 J : Extended_Index := R_Fst - 1;
545 begin
546 while not Found and J < R_Lst loop
547 J := J + 1;
548 if Element (Left, I) = Element (Right, J) then
549 Found := True;
550 end if;
551 end loop;
553 if not Found then
554 return False;
555 end if;
556 end;
557 end loop;
559 return True;
560 end M_Elements_Included;
562 -------------------------
563 -- M_Elements_Reversed --
564 -------------------------
566 function M_Elements_Reversed
567 (Left : M.Sequence;
568 Right : M.Sequence) return Boolean
570 L : constant Index_Type := M.Last (Left);
572 begin
573 if L /= M.Last (Right) then
574 return False;
575 end if;
577 for I in Index_Type'First .. L loop
578 if Element (Left, I) /= Element (Right, L - I + 1)
579 then
580 return False;
581 end if;
582 end loop;
584 return True;
585 end M_Elements_Reversed;
587 ------------------------
588 -- M_Elements_Swapted --
589 ------------------------
591 function M_Elements_Swapped
592 (Left : M.Sequence;
593 Right : M.Sequence;
594 X : Index_Type;
595 Y : Index_Type) return Boolean
597 begin
598 if M.Length (Left) /= M.Length (Right)
599 or else Element (Left, X) /= Element (Right, Y)
600 or else Element (Left, Y) /= Element (Right, X)
601 then
602 return False;
603 end if;
605 for I in Index_Type'First .. M.Last (Left) loop
606 if I /= X and then I /= Y
607 and then Element (Left, I) /= Element (Right, I)
608 then
609 return False;
610 end if;
611 end loop;
613 return True;
614 end M_Elements_Swapped;
616 -----------
617 -- Model --
618 -----------
620 function Model (Container : Vector) return M.Sequence is
621 R : M.Sequence;
623 begin
624 for Position in 1 .. Length (Container) loop
625 R := M.Add (R, Elemsc (Container) (Position));
626 end loop;
628 return R;
629 end Model;
631 end Formal_Model;
633 ---------------------
634 -- Generic_Sorting --
635 ---------------------
637 package body Generic_Sorting with SPARK_Mode => Off is
639 ------------------
640 -- Formal_Model --
641 ------------------
643 package body Formal_Model is
645 -----------------------
646 -- M_Elements_Sorted --
647 -----------------------
649 function M_Elements_Sorted (Container : M.Sequence) return Boolean is
650 begin
651 if M.Length (Container) = 0 then
652 return True;
653 end if;
655 declare
656 E1 : Element_Type := Element (Container, Index_Type'First);
658 begin
659 for I in Index_Type'First + 1 .. M.Last (Container) loop
660 declare
661 E2 : constant Element_Type := Element (Container, I);
663 begin
664 if E2 < E1 then
665 return False;
666 end if;
668 E1 := E2;
669 end;
670 end loop;
671 end;
673 return True;
674 end M_Elements_Sorted;
676 end Formal_Model;
678 ---------------
679 -- Is_Sorted --
680 ---------------
682 function Is_Sorted (Container : Vector) return Boolean is
683 L : constant Capacity_Range := Length (Container);
685 begin
686 for J in 1 .. L - 1 loop
687 if Get_Element (Container, J + 1) <
688 Get_Element (Container, J)
689 then
690 return False;
691 end if;
692 end loop;
694 return True;
695 end Is_Sorted;
697 ----------
698 -- Sort --
699 ----------
701 procedure Sort (Container : in out Vector) is
702 procedure Sort is
703 new Generic_Array_Sort
704 (Index_Type => Array_Index,
705 Element_Type => Element_Type,
706 Array_Type => Elements_Array,
707 "<" => "<");
709 Len : constant Capacity_Range := Length (Container);
711 begin
712 if Container.Last <= Index_Type'First then
713 return;
714 else
715 Sort (Elems (Container) (1 .. Len));
716 end if;
717 end Sort;
719 -----------
720 -- Merge --
721 -----------
723 procedure Merge (Target : in out Vector; Source : in out Vector) is
724 I : Count_Type;
725 J : Count_Type;
727 begin
728 if Target'Address = Source'Address then
729 raise Program_Error with "Target and Source denote same container";
730 end if;
732 if Length (Source) = 0 then
733 return;
734 end if;
736 if Length (Target) = 0 then
737 Move (Target => Target, Source => Source);
738 return;
739 end if;
741 I := Length (Target);
743 declare
744 New_Length : constant Count_Type := I + Length (Source);
746 begin
747 if not Bounded
748 and then Current_Capacity (Target) < Capacity_Range (New_Length)
749 then
750 Reserve_Capacity
751 (Target,
752 Capacity_Range'Max
753 (Current_Capacity (Target) * Growth_Factor,
754 Capacity_Range (New_Length)));
755 end if;
757 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
758 Target.Last := No_Index + Index_Type'Base (New_Length);
760 else
761 Target.Last :=
762 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
763 end if;
764 end;
766 declare
767 TA : Maximal_Array_Ptr renames Elems (Target);
768 SA : Maximal_Array_Ptr renames Elems (Source);
770 begin
771 J := Length (Target);
772 while Length (Source) /= 0 loop
773 if I = 0 then
774 TA (1 .. J) := SA (1 .. Length (Source));
775 Source.Last := No_Index;
776 exit;
777 end if;
779 if SA (Length (Source)) < TA (I) then
780 TA (J) := TA (I);
781 I := I - 1;
783 else
784 TA (J) := SA (Length (Source));
785 Source.Last := Source.Last - 1;
786 end if;
788 J := J - 1;
789 end loop;
790 end;
791 end Merge;
793 end Generic_Sorting;
795 -----------------
796 -- Get_Element --
797 -----------------
799 function Get_Element
800 (Container : Vector;
801 Position : Capacity_Range) return Element_Type
803 begin
804 return Elemsc (Container) (Position);
805 end Get_Element;
807 -----------------
808 -- Has_Element --
809 -----------------
811 function Has_Element
812 (Container : Vector;
813 Position : Extended_Index) return Boolean
815 begin
816 return Position in First_Index (Container) .. Last_Index (Container);
817 end Has_Element;
819 ------------
820 -- Insert --
821 ------------
823 procedure Insert
824 (Container : in out Vector;
825 Before : Extended_Index;
826 New_Item : Element_Type)
828 begin
829 Insert (Container, Before, New_Item, 1);
830 end Insert;
832 procedure Insert
833 (Container : in out Vector;
834 Before : Extended_Index;
835 New_Item : Element_Type;
836 Count : Count_Type)
838 J : Count_Type'Base; -- scratch
840 begin
841 -- Use Insert_Space to create the "hole" (the destination slice)
843 Insert_Space (Container, Before, Count);
845 J := To_Array_Index (Before);
847 Elems (Container) (J .. J - 1 + Count) := (others => New_Item);
848 end Insert;
850 procedure Insert
851 (Container : in out Vector;
852 Before : Extended_Index;
853 New_Item : Vector)
855 N : constant Count_Type := Length (New_Item);
856 B : Count_Type; -- index Before converted to Count_Type
858 begin
859 if Container'Address = New_Item'Address then
860 raise Program_Error with
861 "Container and New_Item denote same container";
862 end if;
864 -- Use Insert_Space to create the "hole" (the destination slice) into
865 -- which we copy the source items.
867 Insert_Space (Container, Before, Count => N);
869 if N = 0 then
871 -- There's nothing else to do here (vetting of parameters was
872 -- performed already in Insert_Space), so we simply return.
874 return;
875 end if;
877 B := To_Array_Index (Before);
879 Elems (Container) (B .. B + N - 1) := Elemsc (New_Item) (1 .. N);
880 end Insert;
882 ------------------
883 -- Insert_Space --
884 ------------------
886 procedure Insert_Space
887 (Container : in out Vector;
888 Before : Extended_Index;
889 Count : Count_Type := 1)
891 Old_Length : constant Count_Type := Length (Container);
893 Max_Length : Count_Type'Base; -- determined from range of Index_Type
894 New_Length : Count_Type'Base; -- sum of current length and Count
896 Index : Index_Type'Base; -- scratch for intermediate values
897 J : Count_Type'Base; -- scratch
899 begin
900 -- As a precondition on the generic actual Index_Type, the base type
901 -- must include Index_Type'Pred (Index_Type'First); this is the value
902 -- that Container.Last assumes when the vector is empty. However, we do
903 -- not allow that as the value for Index when specifying where the new
904 -- items should be inserted, so we must manually check. (That the user
905 -- is allowed to specify the value at all here is a consequence of the
906 -- declaration of the Extended_Index subtype, which includes the values
907 -- in the base range that immediately precede and immediately follow the
908 -- values in the Index_Type.)
910 if Before < Index_Type'First then
911 raise Constraint_Error with
912 "Before index is out of range (too small)";
913 end if;
915 -- We do allow a value greater than Container.Last to be specified as
916 -- the Index, but only if it's immediately greater. This allows for the
917 -- case of appending items to the back end of the vector. (It is assumed
918 -- that specifying an index value greater than Last + 1 indicates some
919 -- deeper flaw in the caller's algorithm, so that case is treated as a
920 -- proper error.)
922 if Before > Container.Last
923 and then Before - 1 > Container.Last
924 then
925 raise Constraint_Error with
926 "Before index is out of range (too large)";
927 end if;
929 -- We treat inserting 0 items into the container as a no-op, so we
930 -- simply return.
932 if Count = 0 then
933 return;
934 end if;
936 -- There are two constraints we need to satisfy. The first constraint is
937 -- that a container cannot have more than Count_Type'Last elements, so
938 -- we must check the sum of the current length and the insertion count.
939 -- Note that the value cannot be simply added because the result may
940 -- overflow.
942 if Old_Length > Count_Type'Last - Count then
943 raise Constraint_Error with "Count is out of range";
944 end if;
946 -- It is now safe compute the length of the new vector, without fear of
947 -- overflow.
949 New_Length := Old_Length + Count;
951 -- The second constraint is that the new Last index value cannot exceed
952 -- Index_Type'Last. In each branch below, we calculate the maximum
953 -- length (computed from the range of values in Index_Type), and then
954 -- compare the new length to the maximum length. If the new length is
955 -- acceptable, then we compute the new last index from that.
957 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
959 -- We have to handle the case when there might be more values in the
960 -- range of Index_Type than in the range of Count_Type.
962 if Index_Type'First <= 0 then
964 -- We know that No_Index (the same as Index_Type'First - 1) is
965 -- less than 0, so it is safe to compute the following sum without
966 -- fear of overflow.
968 Index := No_Index + Index_Type'Base (Count_Type'Last);
970 if Index <= Index_Type'Last then
972 -- We have determined that range of Index_Type has at least as
973 -- many values as in Count_Type, so Count_Type'Last is the
974 -- maximum number of items that are allowed.
976 Max_Length := Count_Type'Last;
978 else
979 -- The range of Index_Type has fewer values than in Count_Type,
980 -- so the maximum number of items is computed from the range of
981 -- the Index_Type.
983 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
984 end if;
986 else
987 -- No_Index is equal or greater than 0, so we can safely compute
988 -- the difference without fear of overflow (which we would have to
989 -- worry about if No_Index were less than 0, but that case is
990 -- handled above).
992 if Index_Type'Last - No_Index >= Count_Type'Pos (Count_Type'Last)
993 then
994 -- We have determined that range of Index_Type has at least as
995 -- many values as in Count_Type, so Count_Type'Last is the
996 -- maximum number of items that are allowed.
998 Max_Length := Count_Type'Last;
1000 else
1001 -- The range of Index_Type has fewer values than in Count_Type,
1002 -- so the maximum number of items is computed from the range of
1003 -- the Index_Type.
1005 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1006 end if;
1007 end if;
1009 elsif Index_Type'First <= 0 then
1011 -- We know that No_Index (the same as Index_Type'First - 1) is less
1012 -- than 0, so it is safe to compute the following sum without fear of
1013 -- overflow.
1015 J := Count_Type'Base (No_Index) + Count_Type'Last;
1017 if J <= Count_Type'Base (Index_Type'Last) then
1019 -- We have determined that range of Index_Type has at least as
1020 -- many values as in Count_Type, so Count_Type'Last is the maximum
1021 -- number of items that are allowed.
1023 Max_Length := Count_Type'Last;
1025 else
1026 -- The range of Index_Type has fewer values than Count_Type does,
1027 -- so the maximum number of items is computed from the range of
1028 -- the Index_Type.
1030 Max_Length :=
1031 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1032 end if;
1034 else
1035 -- No_Index is equal or greater than 0, so we can safely compute the
1036 -- difference without fear of overflow (which we would have to worry
1037 -- about if No_Index were less than 0, but that case is handled
1038 -- above).
1040 Max_Length :=
1041 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1042 end if;
1044 -- We have just computed the maximum length (number of items). We must
1045 -- now compare the requested length to the maximum length, as we do not
1046 -- allow a vector expand beyond the maximum (because that would create
1047 -- an internal array with a last index value greater than
1048 -- Index_Type'Last, with no way to index those elements).
1050 if New_Length > Max_Length then
1051 raise Constraint_Error with "Count is out of range";
1052 end if;
1054 J := To_Array_Index (Before);
1056 -- Increase the capacity of container if needed
1058 if not Bounded
1059 and then Current_Capacity (Container) < Capacity_Range (New_Length)
1060 then
1061 Reserve_Capacity
1062 (Container,
1063 Capacity_Range'Max (Current_Capacity (Container) * Growth_Factor,
1064 Capacity_Range (New_Length)));
1065 end if;
1067 declare
1068 EA : Maximal_Array_Ptr renames Elems (Container);
1070 begin
1071 if Before <= Container.Last then
1073 -- The new items are being inserted before some existing
1074 -- elements, so we must slide the existing elements up to their
1075 -- new home.
1077 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1078 end if;
1079 end;
1081 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1082 Container.Last := No_Index + Index_Type'Base (New_Length);
1084 else
1085 Container.Last :=
1086 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1087 end if;
1088 end Insert_Space;
1090 --------------
1091 -- Is_Empty --
1092 --------------
1094 function Is_Empty (Container : Vector) return Boolean is
1095 begin
1096 return Last_Index (Container) < Index_Type'First;
1097 end Is_Empty;
1099 ------------------
1100 -- Last_Element --
1101 ------------------
1103 function Last_Element (Container : Vector) return Element_Type is
1104 begin
1105 if Is_Empty (Container) then
1106 raise Constraint_Error with "Container is empty";
1107 else
1108 return Get_Element (Container, Length (Container));
1109 end if;
1110 end Last_Element;
1112 ----------------
1113 -- Last_Index --
1114 ----------------
1116 function Last_Index (Container : Vector) return Extended_Index is
1117 begin
1118 return Container.Last;
1119 end Last_Index;
1121 ------------
1122 -- Length --
1123 ------------
1125 function Length (Container : Vector) return Capacity_Range is
1126 L : constant Int := Int (Container.Last);
1127 F : constant Int := Int (Index_Type'First);
1128 N : constant Int'Base := L - F + 1;
1130 begin
1131 return Capacity_Range (N);
1132 end Length;
1134 ----------
1135 -- Move --
1136 ----------
1138 procedure Move (Target : in out Vector; Source : in out Vector) is
1139 LS : constant Capacity_Range := Length (Source);
1141 begin
1142 if Target'Address = Source'Address then
1143 return;
1144 end if;
1146 if Bounded and then Target.Capacity < LS then
1147 raise Constraint_Error;
1148 end if;
1150 Clear (Target);
1151 Append (Target, Source);
1152 Clear (Source);
1153 end Move;
1155 ------------
1156 -- Prepend --
1157 ------------
1159 procedure Prepend (Container : in out Vector; New_Item : Vector) is
1160 begin
1161 Insert (Container, Index_Type'First, New_Item);
1162 end Prepend;
1164 procedure Prepend (Container : in out Vector; New_Item : Element_Type) is
1165 begin
1166 Prepend (Container, New_Item, 1);
1167 end Prepend;
1169 procedure Prepend
1170 (Container : in out Vector;
1171 New_Item : Element_Type;
1172 Count : Count_Type)
1174 begin
1175 Insert (Container, Index_Type'First, New_Item, Count);
1176 end Prepend;
1178 ---------------------
1179 -- Replace_Element --
1180 ---------------------
1182 procedure Replace_Element
1183 (Container : in out Vector;
1184 Index : Index_Type;
1185 New_Item : Element_Type)
1187 begin
1188 if Index > Container.Last then
1189 raise Constraint_Error with "Index is out of range";
1190 end if;
1192 declare
1193 II : constant Int'Base := Int (Index) - Int (No_Index);
1194 I : constant Capacity_Range := Capacity_Range (II);
1196 begin
1197 Elems (Container) (I) := New_Item;
1198 end;
1199 end Replace_Element;
1201 ----------------------
1202 -- Reserve_Capacity --
1203 ----------------------
1205 procedure Reserve_Capacity
1206 (Container : in out Vector;
1207 Capacity : Capacity_Range)
1209 begin
1210 if Bounded then
1211 if Capacity > Container.Capacity then
1212 raise Constraint_Error with "Capacity is out of range";
1213 end if;
1215 else
1216 if Capacity > Formal_Vectors.Current_Capacity (Container) then
1217 declare
1218 New_Elements : constant Elements_Array_Ptr :=
1219 new Elements_Array (1 .. Capacity);
1220 L : constant Capacity_Range := Length (Container);
1222 begin
1223 New_Elements (1 .. L) := Elemsc (Container) (1 .. L);
1224 Free (Container.Elements_Ptr);
1225 Container.Elements_Ptr := New_Elements;
1226 end;
1227 end if;
1228 end if;
1229 end Reserve_Capacity;
1231 ----------------------
1232 -- Reverse_Elements --
1233 ----------------------
1235 procedure Reverse_Elements (Container : in out Vector) is
1236 begin
1237 if Length (Container) <= 1 then
1238 return;
1239 end if;
1241 declare
1242 I, J : Capacity_Range;
1243 E : Elements_Array renames
1244 Elems (Container) (1 .. Length (Container));
1246 begin
1247 I := 1;
1248 J := Length (Container);
1249 while I < J loop
1250 declare
1251 EI : constant Element_Type := E (I);
1253 begin
1254 E (I) := E (J);
1255 E (J) := EI;
1256 end;
1258 I := I + 1;
1259 J := J - 1;
1260 end loop;
1261 end;
1262 end Reverse_Elements;
1264 ------------------------
1265 -- Reverse_Find_Index --
1266 ------------------------
1268 function Reverse_Find_Index
1269 (Container : Vector;
1270 Item : Element_Type;
1271 Index : Index_Type := Index_Type'Last) return Extended_Index
1273 Last : Index_Type'Base;
1274 K : Capacity_Range;
1276 begin
1277 if Index > Last_Index (Container) then
1278 Last := Last_Index (Container);
1279 else
1280 Last := Index;
1281 end if;
1283 K := Capacity_Range (Int (Last) - Int (No_Index));
1284 for Indx in reverse Index_Type'First .. Last loop
1285 if Get_Element (Container, K) = Item then
1286 return Indx;
1287 end if;
1289 K := K - 1;
1290 end loop;
1292 return No_Index;
1293 end Reverse_Find_Index;
1295 ----------
1296 -- Swap --
1297 ----------
1299 procedure Swap
1300 (Container : in out Vector;
1301 I : Index_Type;
1302 J : Index_Type)
1304 begin
1305 if I > Container.Last then
1306 raise Constraint_Error with "I index is out of range";
1307 end if;
1309 if J > Container.Last then
1310 raise Constraint_Error with "J index is out of range";
1311 end if;
1313 if I = J then
1314 return;
1315 end if;
1317 declare
1318 II : constant Int'Base := Int (I) - Int (No_Index);
1319 JJ : constant Int'Base := Int (J) - Int (No_Index);
1321 EI : Element_Type renames Elems (Container) (Capacity_Range (II));
1322 EJ : Element_Type renames Elems (Container) (Capacity_Range (JJ));
1324 EI_Copy : constant Element_Type := EI;
1326 begin
1327 EI := EJ;
1328 EJ := EI_Copy;
1329 end;
1330 end Swap;
1332 --------------------
1333 -- To_Array_Index --
1334 --------------------
1336 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is
1337 Offset : Count_Type'Base;
1339 begin
1340 -- We know that
1341 -- Index >= Index_Type'First
1342 -- hence we also know that
1343 -- Index - Index_Type'First >= 0
1345 -- The issue is that even though 0 is guaranteed to be a value in
1346 -- the type Index_Type'Base, there's no guarantee that the difference
1347 -- is a value in that type. To prevent overflow we use the wider
1348 -- of Count_Type'Base and Index_Type'Base to perform intermediate
1349 -- calculations.
1351 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1352 Offset := Count_Type'Base (Index - Index_Type'First);
1354 else
1355 Offset :=
1356 Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
1357 end if;
1359 -- The array index subtype for all container element arrays always
1360 -- starts with 1.
1362 return 1 + Offset;
1363 end To_Array_Index;
1365 ---------------
1366 -- To_Vector --
1367 ---------------
1369 function To_Vector
1370 (New_Item : Element_Type;
1371 Length : Capacity_Range) return Vector
1373 begin
1374 if Length = 0 then
1375 return Empty_Vector;
1376 end if;
1378 declare
1379 First : constant Int := Int (Index_Type'First);
1380 Last_As_Int : constant Int'Base := First + Int (Length) - 1;
1381 Last : Index_Type;
1383 begin
1384 if Last_As_Int > Index_Type'Pos (Index_Type'Last) then
1385 raise Constraint_Error with "Length is out of range"; -- ???
1386 end if;
1388 Last := Index_Type (Last_As_Int);
1390 return
1391 (Capacity => Length,
1392 Last => Last,
1393 Elements_Ptr => <>,
1394 Elements => (others => New_Item));
1395 end;
1396 end To_Vector;
1398 end Ada.Containers.Formal_Vectors;