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-2019, 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 28with Ada.Containers.Generic_Array_Sort; 29with Ada.Unchecked_Deallocation; 30 31with System; use type System.Address; 32 33package body Ada.Containers.Formal_Vectors with 34 SPARK_Mode => Off 35is 36 37 Growth_Factor : constant := 2; 38 -- When growing a container, multiply current capacity by this. Doubling 39 -- leads to amortized linear-time copying. 40 41 type Int is range System.Min_Int .. System.Max_Int; 42 43 procedure Free is 44 new Ada.Unchecked_Deallocation (Elements_Array, Elements_Array_Ptr); 45 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; 50 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. 60 -- 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). 63 64 function Get_Element 65 (Container : Vector; 66 Position : Capacity_Range) return Element_Type; 67 68 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base; 69 70 function Current_Capacity (Container : Vector) return Capacity_Range; 71 72 procedure Insert_Space 73 (Container : in out Vector; 74 Before : Extended_Index; 75 Count : Count_Type := 1); 76 77 --------- 78 -- "=" -- 79 --------- 80 81 function "=" (Left : Vector; Right : Vector) return Boolean is 82 begin 83 if Left'Address = Right'Address then 84 return True; 85 end if; 86 87 if Length (Left) /= Length (Right) then 88 return False; 89 end if; 90 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; 96 97 return True; 98 end "="; 99 100 ------------ 101 -- Append -- 102 ------------ 103 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; 109 110 if Container.Last >= Index_Type'Last then 111 raise Constraint_Error with "vector is already at its maximum length"; 112 end if; 113 114 Insert (Container, Container.Last + 1, New_Item); 115 end Append; 116 117 procedure Append (Container : in out Vector; New_Item : Element_Type) is 118 begin 119 Append (Container, New_Item, 1); 120 end Append; 121 122 procedure Append 123 (Container : in out Vector; 124 New_Item : Element_Type; 125 Count : Count_Type) 126 is 127 begin 128 if Count = 0 then 129 return; 130 end if; 131 132 if Container.Last >= Index_Type'Last then 133 raise Constraint_Error with "vector is already at its maximum length"; 134 end if; 135 136 Insert (Container, Container.Last + 1, New_Item, Count); 137 end Append; 138 139 ------------ 140 -- Assign -- 141 ------------ 142 143 procedure Assign (Target : in out Vector; Source : Vector) is 144 LS : constant Capacity_Range := Length (Source); 145 146 begin 147 if Target'Address = Source'Address then 148 return; 149 end if; 150 151 if Bounded and then Target.Capacity < LS then 152 raise Constraint_Error; 153 end if; 154 155 Clear (Target); 156 Append (Target, Source); 157 end Assign; 158 159 -------------- 160 -- Capacity -- 161 -------------- 162 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; 171 172 ----------- 173 -- Clear -- 174 ----------- 175 176 procedure Clear (Container : in out Vector) is 177 begin 178 Container.Last := No_Index; 179 180 -- Free element, note that this is OK if Elements_Ptr is null 181 182 Free (Container.Elements_Ptr); 183 end Clear; 184 185 -------------- 186 -- Contains -- 187 -------------- 188 189 function Contains 190 (Container : Vector; 191 Item : Element_Type) return Boolean 192 is 193 begin 194 return Find_Index (Container, Item) /= No_Index; 195 end Contains; 196 197 ---------- 198 -- Copy -- 199 ---------- 200 201 function Copy 202 (Source : Vector; 203 Capacity : Capacity_Range := 0) return Vector 204 is 205 LS : constant Capacity_Range := Length (Source); 206 C : Capacity_Range; 207 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; 216 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; 222 223 ---------------------- 224 -- Current_Capacity -- 225 ---------------------- 226 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; 235 236 ------------ 237 -- Delete -- 238 ------------ 239 240 procedure Delete (Container : in out Vector; Index : Extended_Index) is 241 begin 242 Delete (Container, Index, 1); 243 end Delete; 244 245 procedure Delete 246 (Container : in out Vector; 247 Index : Extended_Index; 248 Count : Count_Type) 249 is 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 255 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. 263 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.) 273 274 if Index < Index_Type'First then 275 raise Constraint_Error with "Index is out of range (too small)"; 276 end if; 277 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.) 284 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; 289 290 return; 291 end if; 292 293 if Count = 0 then 294 return; 295 end if; 296 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.) 301 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; 307 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. 312 313 if Count >= Count2 then 314 Container.Last := Index - 1; 315 return; 316 end if; 317 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. 323 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; 331 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. 334 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; 343 344 ------------------ 345 -- Delete_First -- 346 ------------------ 347 348 procedure Delete_First (Container : in out Vector) is 349 begin 350 Delete_First (Container, 1); 351 end Delete_First; 352 353 procedure Delete_First (Container : in out Vector; Count : Count_Type) is 354 begin 355 if Count = 0 then 356 return; 357 358 elsif Count >= Length (Container) then 359 Clear (Container); 360 return; 361 362 else 363 Delete (Container, Index_Type'First, Count); 364 end if; 365 end Delete_First; 366 367 ----------------- 368 -- Delete_Last -- 369 ----------------- 370 371 procedure Delete_Last (Container : in out Vector) is 372 begin 373 Delete_Last (Container, 1); 374 end Delete_Last; 375 376 procedure Delete_Last (Container : in out Vector; Count : Count_Type) is 377 begin 378 if Count = 0 then 379 return; 380 end if; 381 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.) 386 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.) 391 392 if Count >= Length (Container) then 393 Container.Last := No_Index; 394 395 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then 396 Container.Last := Container.Last - Index_Type'Base (Count); 397 398 else 399 Container.Last := 400 Index_Type'Base (Count_Type'Base (Container.Last) - Count); 401 end if; 402 end Delete_Last; 403 404 ------------- 405 -- Element -- 406 ------------- 407 408 function Element 409 (Container : Vector; 410 Index : Index_Type) return Element_Type 411 is 412 begin 413 if Index > Container.Last then 414 raise Constraint_Error with "Index is out of range"; 415 end if; 416 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; 424 425 ----------- 426 -- Elems -- 427 ----------- 428 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; 437 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; 446 447 ---------------- 448 -- Find_Index -- 449 ---------------- 450 451 function Find_Index 452 (Container : Vector; 453 Item : Element_Type; 454 Index : Index_Type := Index_Type'First) return Extended_Index 455 is 456 K : Capacity_Range; 457 Last : constant Index_Type := Last_Index (Container); 458 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; 465 466 K := K + 1; 467 end loop; 468 469 return No_Index; 470 end Find_Index; 471 472 ------------------- 473 -- First_Element -- 474 ------------------- 475 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; 484 485 ----------------- 486 -- First_Index -- 487 ----------------- 488 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; 494 495 ------------------ 496 -- Formal_Model -- 497 ------------------ 498 499 package body Formal_Model is 500 501 ------------------------- 502 -- M_Elements_In_Union -- 503 ------------------------- 504 505 function M_Elements_In_Union 506 (Container : M.Sequence; 507 Left : M.Sequence; 508 Right : M.Sequence) return Boolean 509 is 510 Elem : Element_Type; 511 512 begin 513 for Index in Index_Type'First .. M.Last (Container) loop 514 Elem := Element (Container, Index); 515 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; 523 524 return True; 525 end M_Elements_In_Union; 526 527 ------------------------- 528 -- M_Elements_Included -- 529 ------------------------- 530 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 538 is 539 begin 540 for I in L_Fst .. L_Lst loop 541 declare 542 Found : Boolean := False; 543 J : Extended_Index := R_Fst - 1; 544 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; 552 553 if not Found then 554 return False; 555 end if; 556 end; 557 end loop; 558 559 return True; 560 end M_Elements_Included; 561 562 ------------------------- 563 -- M_Elements_Reversed -- 564 ------------------------- 565 566 function M_Elements_Reversed 567 (Left : M.Sequence; 568 Right : M.Sequence) return Boolean 569 is 570 L : constant Index_Type := M.Last (Left); 571 572 begin 573 if L /= M.Last (Right) then 574 return False; 575 end if; 576 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; 583 584 return True; 585 end M_Elements_Reversed; 586 587 ------------------------ 588 -- M_Elements_Swapped -- 589 ------------------------ 590 591 function M_Elements_Swapped 592 (Left : M.Sequence; 593 Right : M.Sequence; 594 X : Index_Type; 595 Y : Index_Type) return Boolean 596 is 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; 604 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; 612 613 return True; 614 end M_Elements_Swapped; 615 616 ----------- 617 -- Model -- 618 ----------- 619 620 function Model (Container : Vector) return M.Sequence is 621 R : M.Sequence; 622 623 begin 624 for Position in 1 .. Length (Container) loop 625 R := M.Add (R, Elemsc (Container) (Position)); 626 end loop; 627 628 return R; 629 end Model; 630 631 end Formal_Model; 632 633 --------------------- 634 -- Generic_Sorting -- 635 --------------------- 636 637 package body Generic_Sorting with SPARK_Mode => Off is 638 639 ------------------ 640 -- Formal_Model -- 641 ------------------ 642 643 package body Formal_Model is 644 645 ----------------------- 646 -- M_Elements_Sorted -- 647 ----------------------- 648 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; 654 655 declare 656 E1 : Element_Type := Element (Container, Index_Type'First); 657 658 begin 659 for I in Index_Type'First + 1 .. M.Last (Container) loop 660 declare 661 E2 : constant Element_Type := Element (Container, I); 662 663 begin 664 if E2 < E1 then 665 return False; 666 end if; 667 668 E1 := E2; 669 end; 670 end loop; 671 end; 672 673 return True; 674 end M_Elements_Sorted; 675 676 end Formal_Model; 677 678 --------------- 679 -- Is_Sorted -- 680 --------------- 681 682 function Is_Sorted (Container : Vector) return Boolean is 683 L : constant Capacity_Range := Length (Container); 684 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; 693 694 return True; 695 end Is_Sorted; 696 697 ---------- 698 -- Sort -- 699 ---------- 700 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 "<" => "<"); 708 709 Len : constant Capacity_Range := Length (Container); 710 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; 718 719 ----------- 720 -- Merge -- 721 ----------- 722 723 procedure Merge (Target : in out Vector; Source : in out Vector) is 724 I : Count_Type; 725 J : Count_Type; 726 727 begin 728 if Target'Address = Source'Address then 729 raise Program_Error with "Target and Source denote same container"; 730 end if; 731 732 if Length (Source) = 0 then 733 return; 734 end if; 735 736 if Length (Target) = 0 then 737 Move (Target => Target, Source => Source); 738 return; 739 end if; 740 741 I := Length (Target); 742 743 declare 744 New_Length : constant Count_Type := I + Length (Source); 745 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; 756 757 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then 758 Target.Last := No_Index + Index_Type'Base (New_Length); 759 760 else 761 Target.Last := 762 Index_Type'Base (Count_Type'Base (No_Index) + New_Length); 763 end if; 764 end; 765 766 declare 767 TA : Maximal_Array_Ptr renames Elems (Target); 768 SA : Maximal_Array_Ptr renames Elems (Source); 769 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; 778 779 if SA (Length (Source)) < TA (I) then 780 TA (J) := TA (I); 781 I := I - 1; 782 783 else 784 TA (J) := SA (Length (Source)); 785 Source.Last := Source.Last - 1; 786 end if; 787 788 J := J - 1; 789 end loop; 790 end; 791 end Merge; 792 793 end Generic_Sorting; 794 795 ----------------- 796 -- Get_Element -- 797 ----------------- 798 799 function Get_Element 800 (Container : Vector; 801 Position : Capacity_Range) return Element_Type 802 is 803 begin 804 return Elemsc (Container) (Position); 805 end Get_Element; 806 807 ----------------- 808 -- Has_Element -- 809 ----------------- 810 811 function Has_Element 812 (Container : Vector; 813 Position : Extended_Index) return Boolean 814 is 815 begin 816 return Position in First_Index (Container) .. Last_Index (Container); 817 end Has_Element; 818 819 ------------ 820 -- Insert -- 821 ------------ 822 823 procedure Insert 824 (Container : in out Vector; 825 Before : Extended_Index; 826 New_Item : Element_Type) 827 is 828 begin 829 Insert (Container, Before, New_Item, 1); 830 end Insert; 831 832 procedure Insert 833 (Container : in out Vector; 834 Before : Extended_Index; 835 New_Item : Element_Type; 836 Count : Count_Type) 837 is 838 J : Count_Type'Base; -- scratch 839 840 begin 841 -- Use Insert_Space to create the "hole" (the destination slice) 842 843 Insert_Space (Container, Before, Count); 844 845 J := To_Array_Index (Before); 846 847 Elems (Container) (J .. J - 1 + Count) := (others => New_Item); 848 end Insert; 849 850 procedure Insert 851 (Container : in out Vector; 852 Before : Extended_Index; 853 New_Item : Vector) 854 is 855 N : constant Count_Type := Length (New_Item); 856 B : Count_Type; -- index Before converted to Count_Type 857 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; 863 864 -- Use Insert_Space to create the "hole" (the destination slice) into 865 -- which we copy the source items. 866 867 Insert_Space (Container, Before, Count => N); 868 869 if N = 0 then 870 871 -- There's nothing else to do here (vetting of parameters was 872 -- performed already in Insert_Space), so we simply return. 873 874 return; 875 end if; 876 877 B := To_Array_Index (Before); 878 879 Elems (Container) (B .. B + N - 1) := Elemsc (New_Item) (1 .. N); 880 end Insert; 881 882 ------------------ 883 -- Insert_Space -- 884 ------------------ 885 886 procedure Insert_Space 887 (Container : in out Vector; 888 Before : Extended_Index; 889 Count : Count_Type := 1) 890 is 891 Old_Length : constant Count_Type := Length (Container); 892 893 Max_Length : Count_Type'Base; -- determined from range of Index_Type 894 New_Length : Count_Type'Base; -- sum of current length and Count 895 896 Index : Index_Type'Base; -- scratch for intermediate values 897 J : Count_Type'Base; -- scratch 898 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.) 909 910 if Before < Index_Type'First then 911 raise Constraint_Error with 912 "Before index is out of range (too small)"; 913 end if; 914 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.) 921 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; 928 929 -- We treat inserting 0 items into the container as a no-op, so we 930 -- simply return. 931 932 if Count = 0 then 933 return; 934 end if; 935 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. 941 942 if Old_Length > Count_Type'Last - Count then 943 raise Constraint_Error with "Count is out of range"; 944 end if; 945 946 -- It is now safe compute the length of the new vector, without fear of 947 -- overflow. 948 949 New_Length := Old_Length + Count; 950 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. 956 957 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then 958 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. 961 962 if Index_Type'First <= 0 then 963 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. 967 968 Index := No_Index + Index_Type'Base (Count_Type'Last); 969 970 if Index <= Index_Type'Last then 971 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. 975 976 Max_Length := Count_Type'Last; 977 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. 982 983 Max_Length := Count_Type'Base (Index_Type'Last - No_Index); 984 end if; 985 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). 991 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. 997 998 Max_Length := Count_Type'Last; 999 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. 1004 1005 Max_Length := Count_Type'Base (Index_Type'Last - No_Index); 1006 end if; 1007 end if; 1008 1009 elsif Index_Type'First <= 0 then 1010 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. 1014 1015 J := Count_Type'Base (No_Index) + Count_Type'Last; 1016 1017 if J <= Count_Type'Base (Index_Type'Last) then 1018 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. 1022 1023 Max_Length := Count_Type'Last; 1024 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. 1029 1030 Max_Length := 1031 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index); 1032 end if; 1033 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). 1039 1040 Max_Length := 1041 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index); 1042 end if; 1043 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). 1049 1050 if New_Length > Max_Length then 1051 raise Constraint_Error with "Count is out of range"; 1052 end if; 1053 1054 J := To_Array_Index (Before); 1055 1056 -- Increase the capacity of container if needed 1057 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; 1066 1067 declare 1068 EA : Maximal_Array_Ptr renames Elems (Container); 1069 1070 begin 1071 if Before <= Container.Last then 1072 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. 1076 1077 EA (J + Count .. New_Length) := EA (J .. Old_Length); 1078 end if; 1079 end; 1080 1081 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then 1082 Container.Last := No_Index + Index_Type'Base (New_Length); 1083 1084 else 1085 Container.Last := 1086 Index_Type'Base (Count_Type'Base (No_Index) + New_Length); 1087 end if; 1088 end Insert_Space; 1089 1090 -------------- 1091 -- Is_Empty -- 1092 -------------- 1093 1094 function Is_Empty (Container : Vector) return Boolean is 1095 begin 1096 return Last_Index (Container) < Index_Type'First; 1097 end Is_Empty; 1098 1099 ------------------ 1100 -- Last_Element -- 1101 ------------------ 1102 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; 1111 1112 ---------------- 1113 -- Last_Index -- 1114 ---------------- 1115 1116 function Last_Index (Container : Vector) return Extended_Index is 1117 begin 1118 return Container.Last; 1119 end Last_Index; 1120 1121 ------------ 1122 -- Length -- 1123 ------------ 1124 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; 1129 1130 begin 1131 return Capacity_Range (N); 1132 end Length; 1133 1134 ---------- 1135 -- Move -- 1136 ---------- 1137 1138 procedure Move (Target : in out Vector; Source : in out Vector) is 1139 LS : constant Capacity_Range := Length (Source); 1140 1141 begin 1142 if Target'Address = Source'Address then 1143 return; 1144 end if; 1145 1146 if Bounded and then Target.Capacity < LS then 1147 raise Constraint_Error; 1148 end if; 1149 1150 Clear (Target); 1151 Append (Target, Source); 1152 Clear (Source); 1153 end Move; 1154 1155 ------------ 1156 -- Prepend -- 1157 ------------ 1158 1159 procedure Prepend (Container : in out Vector; New_Item : Vector) is 1160 begin 1161 Insert (Container, Index_Type'First, New_Item); 1162 end Prepend; 1163 1164 procedure Prepend (Container : in out Vector; New_Item : Element_Type) is 1165 begin 1166 Prepend (Container, New_Item, 1); 1167 end Prepend; 1168 1169 procedure Prepend 1170 (Container : in out Vector; 1171 New_Item : Element_Type; 1172 Count : Count_Type) 1173 is 1174 begin 1175 Insert (Container, Index_Type'First, New_Item, Count); 1176 end Prepend; 1177 1178 --------------------- 1179 -- Replace_Element -- 1180 --------------------- 1181 1182 procedure Replace_Element 1183 (Container : in out Vector; 1184 Index : Index_Type; 1185 New_Item : Element_Type) 1186 is 1187 begin 1188 if Index > Container.Last then 1189 raise Constraint_Error with "Index is out of range"; 1190 end if; 1191 1192 declare 1193 II : constant Int'Base := Int (Index) - Int (No_Index); 1194 I : constant Capacity_Range := Capacity_Range (II); 1195 1196 begin 1197 Elems (Container) (I) := New_Item; 1198 end; 1199 end Replace_Element; 1200 1201 ---------------------- 1202 -- Reserve_Capacity -- 1203 ---------------------- 1204 1205 procedure Reserve_Capacity 1206 (Container : in out Vector; 1207 Capacity : Capacity_Range) 1208 is 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; 1214 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); 1221 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; 1230 1231 ---------------------- 1232 -- Reverse_Elements -- 1233 ---------------------- 1234 1235 procedure Reverse_Elements (Container : in out Vector) is 1236 begin 1237 if Length (Container) <= 1 then 1238 return; 1239 end if; 1240 1241 declare 1242 I, J : Capacity_Range; 1243 E : Elements_Array renames 1244 Elems (Container) (1 .. Length (Container)); 1245 1246 begin 1247 I := 1; 1248 J := Length (Container); 1249 while I < J loop 1250 declare 1251 EI : constant Element_Type := E (I); 1252 1253 begin 1254 E (I) := E (J); 1255 E (J) := EI; 1256 end; 1257 1258 I := I + 1; 1259 J := J - 1; 1260 end loop; 1261 end; 1262 end Reverse_Elements; 1263 1264 ------------------------ 1265 -- Reverse_Find_Index -- 1266 ------------------------ 1267 1268 function Reverse_Find_Index 1269 (Container : Vector; 1270 Item : Element_Type; 1271 Index : Index_Type := Index_Type'Last) return Extended_Index 1272 is 1273 Last : Index_Type'Base; 1274 K : Capacity_Range; 1275 1276 begin 1277 if Index > Last_Index (Container) then 1278 Last := Last_Index (Container); 1279 else 1280 Last := Index; 1281 end if; 1282 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; 1288 1289 K := K - 1; 1290 end loop; 1291 1292 return No_Index; 1293 end Reverse_Find_Index; 1294 1295 ---------- 1296 -- Swap -- 1297 ---------- 1298 1299 procedure Swap 1300 (Container : in out Vector; 1301 I : Index_Type; 1302 J : Index_Type) 1303 is 1304 begin 1305 if I > Container.Last then 1306 raise Constraint_Error with "I index is out of range"; 1307 end if; 1308 1309 if J > Container.Last then 1310 raise Constraint_Error with "J index is out of range"; 1311 end if; 1312 1313 if I = J then 1314 return; 1315 end if; 1316 1317 declare 1318 II : constant Int'Base := Int (I) - Int (No_Index); 1319 JJ : constant Int'Base := Int (J) - Int (No_Index); 1320 1321 EI : Element_Type renames Elems (Container) (Capacity_Range (II)); 1322 EJ : Element_Type renames Elems (Container) (Capacity_Range (JJ)); 1323 1324 EI_Copy : constant Element_Type := EI; 1325 1326 begin 1327 EI := EJ; 1328 EJ := EI_Copy; 1329 end; 1330 end Swap; 1331 1332 -------------------- 1333 -- To_Array_Index -- 1334 -------------------- 1335 1336 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is 1337 Offset : Count_Type'Base; 1338 1339 begin 1340 -- We know that 1341 -- Index >= Index_Type'First 1342 -- hence we also know that 1343 -- Index - Index_Type'First >= 0 1344 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. 1350 1351 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then 1352 Offset := Count_Type'Base (Index - Index_Type'First); 1353 1354 else 1355 Offset := 1356 Count_Type'Base (Index) - Count_Type'Base (Index_Type'First); 1357 end if; 1358 1359 -- The array index subtype for all container element arrays always 1360 -- starts with 1. 1361 1362 return 1 + Offset; 1363 end To_Array_Index; 1364 1365 --------------- 1366 -- To_Vector -- 1367 --------------- 1368 1369 function To_Vector 1370 (New_Item : Element_Type; 1371 Length : Capacity_Range) return Vector 1372 is 1373 begin 1374 if Length = 0 then 1375 return Empty_Vector; 1376 end if; 1377 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; 1382 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; 1387 1388 Last := Index_Type (Last_As_Int); 1389 1390 return 1391 (Capacity => Length, 1392 Last => Last, 1393 Elements_Ptr => <>, 1394 Elements => (others => New_Item)); 1395 end; 1396 end To_Vector; 1397 1398end Ada.Containers.Formal_Vectors; 1399