1------------------------------------------------------------------------------ 2-- -- 3-- GNAT LIBRARY COMPONENTS -- 4-- -- 5-- A D A . C O N T A I N E R S . H A S H E D _ S E T S -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 2004-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-- This unit was originally developed by Matthew J Heaney. -- 28------------------------------------------------------------------------------ 29 30with Ada.Unchecked_Deallocation; 31 32with Ada.Containers.Hash_Tables.Generic_Operations; 33pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations); 34 35with Ada.Containers.Hash_Tables.Generic_Keys; 36pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys); 37 38with Ada.Containers.Helpers; use Ada.Containers.Helpers; 39 40with Ada.Containers.Prime_Numbers; 41 42with System; use type System.Address; 43 44package body Ada.Containers.Hashed_Sets is 45 46 pragma Warnings (Off, "variable ""Busy*"" is not referenced"); 47 pragma Warnings (Off, "variable ""Lock*"" is not referenced"); 48 -- See comment in Ada.Containers.Helpers 49 50 ----------------------- 51 -- Local Subprograms -- 52 ----------------------- 53 54 procedure Assign (Node : Node_Access; Item : Element_Type); 55 pragma Inline (Assign); 56 57 function Copy_Node (Source : Node_Access) return Node_Access; 58 pragma Inline (Copy_Node); 59 60 function Equivalent_Keys 61 (Key : Element_Type; 62 Node : Node_Access) return Boolean; 63 pragma Inline (Equivalent_Keys); 64 65 function Find_Equal_Key 66 (R_HT : Hash_Table_Type; 67 L_Node : Node_Access) return Boolean; 68 69 function Find_Equivalent_Key 70 (R_HT : Hash_Table_Type; 71 L_Node : Node_Access) return Boolean; 72 73 procedure Free (X : in out Node_Access); 74 75 function Hash_Node (Node : Node_Access) return Hash_Type; 76 pragma Inline (Hash_Node); 77 78 procedure Insert 79 (HT : in out Hash_Table_Type; 80 New_Item : Element_Type; 81 Node : out Node_Access; 82 Inserted : out Boolean); 83 84 function Is_In 85 (HT : aliased in out Hash_Table_Type; 86 Key : Node_Access) return Boolean; 87 pragma Inline (Is_In); 88 89 function Next (Node : Node_Access) return Node_Access; 90 pragma Inline (Next); 91 92 function Read_Node (Stream : not null access Root_Stream_Type'Class) 93 return Node_Access; 94 pragma Inline (Read_Node); 95 96 procedure Set_Next (Node : Node_Access; Next : Node_Access); 97 pragma Inline (Set_Next); 98 99 function Vet (Position : Cursor) return Boolean; 100 101 procedure Write_Node 102 (Stream : not null access Root_Stream_Type'Class; 103 Node : Node_Access); 104 pragma Inline (Write_Node); 105 106 -------------------------- 107 -- Local Instantiations -- 108 -------------------------- 109 110 package HT_Ops is new Hash_Tables.Generic_Operations 111 (HT_Types => HT_Types, 112 Hash_Node => Hash_Node, 113 Next => Next, 114 Set_Next => Set_Next, 115 Copy_Node => Copy_Node, 116 Free => Free); 117 118 package Element_Keys is new Hash_Tables.Generic_Keys 119 (HT_Types => HT_Types, 120 Next => Next, 121 Set_Next => Set_Next, 122 Key_Type => Element_Type, 123 Hash => Hash, 124 Equivalent_Keys => Equivalent_Keys); 125 126 function Is_Equal is 127 new HT_Ops.Generic_Equal (Find_Equal_Key); 128 129 function Is_Equivalent is 130 new HT_Ops.Generic_Equal (Find_Equivalent_Key); 131 132 procedure Read_Nodes is 133 new HT_Ops.Generic_Read (Read_Node); 134 135 procedure Replace_Element is 136 new Element_Keys.Generic_Replace_Element (Hash_Node, Assign); 137 138 procedure Write_Nodes is 139 new HT_Ops.Generic_Write (Write_Node); 140 141 --------- 142 -- "=" -- 143 --------- 144 145 function "=" (Left, Right : Set) return Boolean is 146 begin 147 return Is_Equal (Left.HT, Right.HT); 148 end "="; 149 150 ------------ 151 -- Adjust -- 152 ------------ 153 154 procedure Adjust (Container : in out Set) is 155 begin 156 HT_Ops.Adjust (Container.HT); 157 end Adjust; 158 159 ------------ 160 -- Assign -- 161 ------------ 162 163 procedure Assign (Node : Node_Access; Item : Element_Type) is 164 begin 165 Node.Element := Item; 166 end Assign; 167 168 procedure Assign (Target : in out Set; Source : Set) is 169 begin 170 if Target'Address = Source'Address then 171 return; 172 end if; 173 174 Target.Clear; 175 Target.Union (Source); 176 end Assign; 177 178 -------------- 179 -- Capacity -- 180 -------------- 181 182 function Capacity (Container : Set) return Count_Type is 183 begin 184 return HT_Ops.Capacity (Container.HT); 185 end Capacity; 186 187 ----------- 188 -- Clear -- 189 ----------- 190 191 procedure Clear (Container : in out Set) is 192 begin 193 HT_Ops.Clear (Container.HT); 194 end Clear; 195 196 ------------------------ 197 -- Constant_Reference -- 198 ------------------------ 199 200 function Constant_Reference 201 (Container : aliased Set; 202 Position : Cursor) return Constant_Reference_Type 203 is 204 begin 205 if Checks and then Position.Container = null then 206 raise Constraint_Error with "Position cursor has no element"; 207 end if; 208 209 if Checks and then Position.Container /= Container'Unrestricted_Access 210 then 211 raise Program_Error with 212 "Position cursor designates wrong container"; 213 end if; 214 215 pragma Assert (Vet (Position), "bad cursor in Constant_Reference"); 216 217 declare 218 HT : Hash_Table_Type renames Position.Container.all.HT; 219 TC : constant Tamper_Counts_Access := 220 HT.TC'Unrestricted_Access; 221 begin 222 return R : constant Constant_Reference_Type := 223 (Element => Position.Node.Element'Access, 224 Control => (Controlled with TC)) 225 do 226 Lock (TC.all); 227 end return; 228 end; 229 end Constant_Reference; 230 231 -------------- 232 -- Contains -- 233 -------------- 234 235 function Contains (Container : Set; Item : Element_Type) return Boolean is 236 begin 237 return Find (Container, Item) /= No_Element; 238 end Contains; 239 240 ---------- 241 -- Copy -- 242 ---------- 243 244 function Copy 245 (Source : Set; 246 Capacity : Count_Type := 0) return Set 247 is 248 C : Count_Type; 249 250 begin 251 if Capacity < Source.Length then 252 if Checks and then Capacity /= 0 then 253 raise Capacity_Error 254 with "Requested capacity is less than Source length"; 255 end if; 256 257 C := Source.Length; 258 else 259 C := Capacity; 260 end if; 261 262 return Target : Set do 263 Target.Reserve_Capacity (C); 264 Target.Assign (Source); 265 end return; 266 end Copy; 267 268 --------------- 269 -- Copy_Node -- 270 --------------- 271 272 function Copy_Node (Source : Node_Access) return Node_Access is 273 begin 274 return new Node_Type'(Element => Source.Element, Next => null); 275 end Copy_Node; 276 277 ------------ 278 -- Delete -- 279 ------------ 280 281 procedure Delete 282 (Container : in out Set; 283 Item : Element_Type) 284 is 285 X : Node_Access; 286 287 begin 288 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X); 289 290 if Checks and then X = null then 291 raise Constraint_Error with "attempt to delete element not in set"; 292 end if; 293 294 Free (X); 295 end Delete; 296 297 procedure Delete 298 (Container : in out Set; 299 Position : in out Cursor) 300 is 301 begin 302 if Checks and then Position.Node = null then 303 raise Constraint_Error with "Position cursor equals No_Element"; 304 end if; 305 306 if Checks and then Position.Container /= Container'Unrestricted_Access 307 then 308 raise Program_Error with "Position cursor designates wrong set"; 309 end if; 310 311 TC_Check (Container.HT.TC); 312 313 pragma Assert (Vet (Position), "bad cursor in Delete"); 314 315 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node); 316 317 Free (Position.Node); 318 Position.Container := null; 319 end Delete; 320 321 ---------------- 322 -- Difference -- 323 ---------------- 324 325 procedure Difference 326 (Target : in out Set; 327 Source : Set) 328 is 329 Tgt_Node : Node_Access; 330 Src_HT : Hash_Table_Type renames Source'Unrestricted_Access.HT; 331 332 begin 333 if Target'Address = Source'Address then 334 Clear (Target); 335 return; 336 end if; 337 338 if Src_HT.Length = 0 then 339 return; 340 end if; 341 342 TC_Check (Target.HT.TC); 343 344 if Src_HT.Length < Target.HT.Length then 345 declare 346 Src_Node : Node_Access; 347 348 begin 349 Src_Node := HT_Ops.First (Src_HT); 350 while Src_Node /= null loop 351 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element); 352 353 if Tgt_Node /= null then 354 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node); 355 Free (Tgt_Node); 356 end if; 357 358 Src_Node := HT_Ops.Next (Src_HT, Src_Node); 359 end loop; 360 end; 361 362 else 363 Tgt_Node := HT_Ops.First (Target.HT); 364 while Tgt_Node /= null loop 365 if Is_In (Src_HT, Tgt_Node) then 366 declare 367 X : Node_Access := Tgt_Node; 368 begin 369 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node); 370 HT_Ops.Delete_Node_Sans_Free (Target.HT, X); 371 Free (X); 372 end; 373 374 else 375 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node); 376 end if; 377 end loop; 378 end if; 379 end Difference; 380 381 function Difference (Left, Right : Set) return Set is 382 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT; 383 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT; 384 Buckets : HT_Types.Buckets_Access; 385 Length : Count_Type; 386 387 begin 388 if Left'Address = Right'Address then 389 return Empty_Set; 390 end if; 391 392 if Left_HT.Length = 0 then 393 return Empty_Set; 394 end if; 395 396 if Right_HT.Length = 0 then 397 return Left; 398 end if; 399 400 declare 401 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length); 402 begin 403 Buckets := HT_Ops.New_Buckets (Length => Size); 404 end; 405 406 Length := 0; 407 408 Iterate_Left : declare 409 procedure Process (L_Node : Node_Access); 410 411 procedure Iterate is 412 new HT_Ops.Generic_Iteration (Process); 413 414 ------------- 415 -- Process -- 416 ------------- 417 418 procedure Process (L_Node : Node_Access) is 419 begin 420 if not Is_In (Right_HT, L_Node) then 421 declare 422 -- Per AI05-0022, the container implementation is required 423 -- to detect element tampering by a generic actual 424 -- subprogram, hence the use of Checked_Index instead of a 425 -- simple invocation of generic formal Hash. 426 427 J : constant Hash_Type := 428 HT_Ops.Checked_Index (Left_HT, Buckets.all, L_Node); 429 430 Bucket : Node_Access renames Buckets (J); 431 432 begin 433 Bucket := new Node_Type'(L_Node.Element, Bucket); 434 end; 435 436 Length := Length + 1; 437 end if; 438 end Process; 439 440 -- Start of processing for Iterate_Left 441 442 begin 443 Iterate (Left_HT); 444 exception 445 when others => 446 HT_Ops.Free_Hash_Table (Buckets); 447 raise; 448 end Iterate_Left; 449 450 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0))); 451 end Difference; 452 453 ------------- 454 -- Element -- 455 ------------- 456 457 function Element (Position : Cursor) return Element_Type is 458 begin 459 if Checks and then Position.Node = null then 460 raise Constraint_Error with "Position cursor equals No_Element"; 461 end if; 462 463 pragma Assert (Vet (Position), "bad cursor in function Element"); 464 465 return Position.Node.Element; 466 end Element; 467 468 --------------------- 469 -- Equivalent_Sets -- 470 --------------------- 471 472 function Equivalent_Sets (Left, Right : Set) return Boolean is 473 begin 474 return Is_Equivalent (Left.HT, Right.HT); 475 end Equivalent_Sets; 476 477 ------------------------- 478 -- Equivalent_Elements -- 479 ------------------------- 480 481 function Equivalent_Elements (Left, Right : Cursor) 482 return Boolean is 483 begin 484 if Checks and then Left.Node = null then 485 raise Constraint_Error with 486 "Left cursor of Equivalent_Elements equals No_Element"; 487 end if; 488 489 if Checks and then Right.Node = null then 490 raise Constraint_Error with 491 "Right cursor of Equivalent_Elements equals No_Element"; 492 end if; 493 494 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements"); 495 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements"); 496 497 -- AI05-0022 requires that a container implementation detect element 498 -- tampering by a generic actual subprogram. However, the following case 499 -- falls outside the scope of that AI. Randy Brukardt explained on the 500 -- ARG list on 2013/02/07 that: 501 502 -- (Begin Quote): 503 -- But for an operation like "<" [the ordered set analog of 504 -- Equivalent_Elements], there is no need to "dereference" a cursor 505 -- after the call to the generic formal parameter function, so nothing 506 -- bad could happen if tampering is undetected. And the operation can 507 -- safely return a result without a problem even if an element is 508 -- deleted from the container. 509 -- (End Quote). 510 511 return Equivalent_Elements (Left.Node.Element, Right.Node.Element); 512 end Equivalent_Elements; 513 514 function Equivalent_Elements (Left : Cursor; Right : Element_Type) 515 return Boolean is 516 begin 517 if Checks and then Left.Node = null then 518 raise Constraint_Error with 519 "Left cursor of Equivalent_Elements equals No_Element"; 520 end if; 521 522 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad"); 523 524 return Equivalent_Elements (Left.Node.Element, Right); 525 end Equivalent_Elements; 526 527 function Equivalent_Elements (Left : Element_Type; Right : Cursor) 528 return Boolean is 529 begin 530 if Checks and then Right.Node = null then 531 raise Constraint_Error with 532 "Right cursor of Equivalent_Elements equals No_Element"; 533 end if; 534 535 pragma Assert 536 (Vet (Right), 537 "Right cursor of Equivalent_Elements is bad"); 538 539 return Equivalent_Elements (Left, Right.Node.Element); 540 end Equivalent_Elements; 541 542 --------------------- 543 -- Equivalent_Keys -- 544 --------------------- 545 546 function Equivalent_Keys (Key : Element_Type; Node : Node_Access) 547 return Boolean is 548 begin 549 return Equivalent_Elements (Key, Node.Element); 550 end Equivalent_Keys; 551 552 ------------- 553 -- Exclude -- 554 ------------- 555 556 procedure Exclude 557 (Container : in out Set; 558 Item : Element_Type) 559 is 560 X : Node_Access; 561 begin 562 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X); 563 Free (X); 564 end Exclude; 565 566 -------------- 567 -- Finalize -- 568 -------------- 569 570 procedure Finalize (Container : in out Set) is 571 begin 572 HT_Ops.Finalize (Container.HT); 573 end Finalize; 574 575 procedure Finalize (Object : in out Iterator) is 576 begin 577 if Object.Container /= null then 578 Unbusy (Object.Container.HT.TC); 579 end if; 580 end Finalize; 581 582 ---------- 583 -- Find -- 584 ---------- 585 586 function Find 587 (Container : Set; 588 Item : Element_Type) return Cursor 589 is 590 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT; 591 Node : constant Node_Access := Element_Keys.Find (HT, Item); 592 593 begin 594 if Node = null then 595 return No_Element; 596 end if; 597 598 return Cursor'(Container'Unrestricted_Access, Node, Hash_Type'Last); 599 end Find; 600 601 -------------------- 602 -- Find_Equal_Key -- 603 -------------------- 604 605 function Find_Equal_Key 606 (R_HT : Hash_Table_Type; 607 L_Node : Node_Access) return Boolean 608 is 609 R_Index : constant Hash_Type := 610 Element_Keys.Index (R_HT, L_Node.Element); 611 612 R_Node : Node_Access := R_HT.Buckets (R_Index); 613 614 begin 615 loop 616 if R_Node = null then 617 return False; 618 end if; 619 620 if L_Node.Element = R_Node.Element then 621 return True; 622 end if; 623 624 R_Node := Next (R_Node); 625 end loop; 626 end Find_Equal_Key; 627 628 ------------------------- 629 -- Find_Equivalent_Key -- 630 ------------------------- 631 632 function Find_Equivalent_Key 633 (R_HT : Hash_Table_Type; 634 L_Node : Node_Access) return Boolean 635 is 636 R_Index : constant Hash_Type := 637 Element_Keys.Index (R_HT, L_Node.Element); 638 639 R_Node : Node_Access := R_HT.Buckets (R_Index); 640 641 begin 642 loop 643 if R_Node = null then 644 return False; 645 end if; 646 647 if Equivalent_Elements (L_Node.Element, R_Node.Element) then 648 return True; 649 end if; 650 651 R_Node := Next (R_Node); 652 end loop; 653 end Find_Equivalent_Key; 654 655 ----------- 656 -- First -- 657 ----------- 658 659 function First (Container : Set) return Cursor is 660 Pos : Hash_Type; 661 Node : constant Node_Access := HT_Ops.First (Container.HT, Pos); 662 begin 663 if Node = null then 664 return No_Element; 665 end if; 666 667 return Cursor'(Container'Unrestricted_Access, Node, Pos); 668 end First; 669 670 function First (Object : Iterator) return Cursor is 671 begin 672 return Object.Container.First; 673 end First; 674 675 ---------- 676 -- Free -- 677 ---------- 678 679 procedure Free (X : in out Node_Access) is 680 procedure Deallocate is 681 new Ada.Unchecked_Deallocation (Node_Type, Node_Access); 682 683 begin 684 if X /= null then 685 X.Next := X; -- detect mischief (in Vet) 686 Deallocate (X); 687 end if; 688 end Free; 689 690 ------------------------ 691 -- Get_Element_Access -- 692 ------------------------ 693 694 function Get_Element_Access 695 (Position : Cursor) return not null Element_Access is 696 begin 697 return Position.Node.Element'Access; 698 end Get_Element_Access; 699 700 ----------------- 701 -- Has_Element -- 702 ----------------- 703 704 function Has_Element (Position : Cursor) return Boolean is 705 begin 706 pragma Assert (Vet (Position), "bad cursor in Has_Element"); 707 return Position.Node /= null; 708 end Has_Element; 709 710 --------------- 711 -- Hash_Node -- 712 --------------- 713 714 function Hash_Node (Node : Node_Access) return Hash_Type is 715 begin 716 return Hash (Node.Element); 717 end Hash_Node; 718 719 ------------- 720 -- Include -- 721 ------------- 722 723 procedure Include 724 (Container : in out Set; 725 New_Item : Element_Type) 726 is 727 Position : Cursor; 728 Inserted : Boolean; 729 730 begin 731 Insert (Container, New_Item, Position, Inserted); 732 733 if not Inserted then 734 TE_Check (Container.HT.TC); 735 736 Position.Node.Element := New_Item; 737 end if; 738 end Include; 739 740 ------------ 741 -- Insert -- 742 ------------ 743 744 procedure Insert 745 (Container : in out Set; 746 New_Item : Element_Type; 747 Position : out Cursor; 748 Inserted : out Boolean) 749 is 750 begin 751 Insert (Container.HT, New_Item, Position.Node, Inserted); 752 Position.Container := Container'Unchecked_Access; 753 end Insert; 754 755 procedure Insert 756 (Container : in out Set; 757 New_Item : Element_Type) 758 is 759 Position : Cursor; 760 pragma Unreferenced (Position); 761 762 Inserted : Boolean; 763 764 begin 765 Insert (Container, New_Item, Position, Inserted); 766 767 if Checks and then not Inserted then 768 raise Constraint_Error with 769 "attempt to insert element already in set"; 770 end if; 771 end Insert; 772 773 procedure Insert 774 (HT : in out Hash_Table_Type; 775 New_Item : Element_Type; 776 Node : out Node_Access; 777 Inserted : out Boolean) 778 is 779 function New_Node (Next : Node_Access) return Node_Access; 780 pragma Inline (New_Node); 781 782 procedure Local_Insert is 783 new Element_Keys.Generic_Conditional_Insert (New_Node); 784 785 -------------- 786 -- New_Node -- 787 -------------- 788 789 function New_Node (Next : Node_Access) return Node_Access is 790 begin 791 return new Node_Type'(New_Item, Next); 792 end New_Node; 793 794 -- Start of processing for Insert 795 796 begin 797 if HT_Ops.Capacity (HT) = 0 then 798 HT_Ops.Reserve_Capacity (HT, 1); 799 end if; 800 801 TC_Check (HT.TC); 802 803 Local_Insert (HT, New_Item, Node, Inserted); 804 805 if Inserted 806 and then HT.Length > HT_Ops.Capacity (HT) 807 then 808 HT_Ops.Reserve_Capacity (HT, HT.Length); 809 end if; 810 end Insert; 811 812 ------------------ 813 -- Intersection -- 814 ------------------ 815 816 procedure Intersection 817 (Target : in out Set; 818 Source : Set) 819 is 820 Src_HT : Hash_Table_Type renames Source'Unrestricted_Access.HT; 821 Tgt_Node : Node_Access; 822 823 begin 824 if Target'Address = Source'Address then 825 return; 826 end if; 827 828 if Source.HT.Length = 0 then 829 Clear (Target); 830 return; 831 end if; 832 833 TC_Check (Target.HT.TC); 834 835 Tgt_Node := HT_Ops.First (Target.HT); 836 while Tgt_Node /= null loop 837 if Is_In (Src_HT, Tgt_Node) then 838 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node); 839 840 else 841 declare 842 X : Node_Access := Tgt_Node; 843 begin 844 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node); 845 HT_Ops.Delete_Node_Sans_Free (Target.HT, X); 846 Free (X); 847 end; 848 end if; 849 end loop; 850 end Intersection; 851 852 function Intersection (Left, Right : Set) return Set is 853 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT; 854 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT; 855 Buckets : HT_Types.Buckets_Access; 856 Length : Count_Type; 857 858 begin 859 if Left'Address = Right'Address then 860 return Left; 861 end if; 862 863 Length := Count_Type'Min (Left.Length, Right.Length); 864 865 if Length = 0 then 866 return Empty_Set; 867 end if; 868 869 declare 870 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length); 871 begin 872 Buckets := HT_Ops.New_Buckets (Length => Size); 873 end; 874 875 Length := 0; 876 877 Iterate_Left : declare 878 procedure Process (L_Node : Node_Access); 879 880 procedure Iterate is 881 new HT_Ops.Generic_Iteration (Process); 882 883 ------------- 884 -- Process -- 885 ------------- 886 887 procedure Process (L_Node : Node_Access) is 888 begin 889 if Is_In (Right_HT, L_Node) then 890 declare 891 -- Per AI05-0022, the container implementation is required 892 -- to detect element tampering by a generic actual 893 -- subprogram, hence the use of Checked_Index instead of a 894 -- simple invocation of generic formal Hash. 895 896 J : constant Hash_Type := 897 HT_Ops.Checked_Index (Left_HT, Buckets.all, L_Node); 898 899 Bucket : Node_Access renames Buckets (J); 900 901 begin 902 Bucket := new Node_Type'(L_Node.Element, Bucket); 903 end; 904 905 Length := Length + 1; 906 end if; 907 end Process; 908 909 -- Start of processing for Iterate_Left 910 911 begin 912 Iterate (Left_HT); 913 exception 914 when others => 915 HT_Ops.Free_Hash_Table (Buckets); 916 raise; 917 end Iterate_Left; 918 919 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0))); 920 end Intersection; 921 922 -------------- 923 -- Is_Empty -- 924 -------------- 925 926 function Is_Empty (Container : Set) return Boolean is 927 begin 928 return Container.HT.Length = 0; 929 end Is_Empty; 930 931 ----------- 932 -- Is_In -- 933 ----------- 934 935 function Is_In 936 (HT : aliased in out Hash_Table_Type; 937 Key : Node_Access) return Boolean 938 is 939 begin 940 return Element_Keys.Find (HT, Key.Element) /= null; 941 end Is_In; 942 943 --------------- 944 -- Is_Subset -- 945 --------------- 946 947 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is 948 Subset_HT : Hash_Table_Type renames Subset'Unrestricted_Access.HT; 949 Of_Set_HT : Hash_Table_Type renames Of_Set'Unrestricted_Access.HT; 950 Subset_Node : Node_Access; 951 952 begin 953 if Subset'Address = Of_Set'Address then 954 return True; 955 end if; 956 957 if Subset.Length > Of_Set.Length then 958 return False; 959 end if; 960 961 Subset_Node := HT_Ops.First (Subset_HT); 962 while Subset_Node /= null loop 963 if not Is_In (Of_Set_HT, Subset_Node) then 964 return False; 965 end if; 966 Subset_Node := HT_Ops.Next (Subset_HT, Subset_Node); 967 end loop; 968 969 return True; 970 end Is_Subset; 971 972 ------------- 973 -- Iterate -- 974 ------------- 975 976 procedure Iterate 977 (Container : Set; 978 Process : not null access procedure (Position : Cursor)) 979 is 980 procedure Process_Node (Node : Node_Access; Position : Hash_Type); 981 pragma Inline (Process_Node); 982 983 procedure Iterate is 984 new HT_Ops.Generic_Iteration_With_Position (Process_Node); 985 986 ------------------ 987 -- Process_Node -- 988 ------------------ 989 990 procedure Process_Node (Node : Node_Access; Position : Hash_Type) is 991 begin 992 Process (Cursor'(Container'Unrestricted_Access, Node, Position)); 993 end Process_Node; 994 995 Busy : With_Busy (Container.HT.TC'Unrestricted_Access); 996 997 -- Start of processing for Iterate 998 999 begin 1000 Iterate (Container.HT); 1001 end Iterate; 1002 1003 function Iterate 1004 (Container : Set) return Set_Iterator_Interfaces.Forward_Iterator'Class 1005 is 1006 begin 1007 Busy (Container.HT.TC'Unrestricted_Access.all); 1008 return It : constant Iterator := 1009 Iterator'(Limited_Controlled with 1010 Container => Container'Unrestricted_Access); 1011 end Iterate; 1012 1013 ------------ 1014 -- Length -- 1015 ------------ 1016 1017 function Length (Container : Set) return Count_Type is 1018 begin 1019 return Container.HT.Length; 1020 end Length; 1021 1022 ---------- 1023 -- Move -- 1024 ---------- 1025 1026 procedure Move (Target : in out Set; Source : in out Set) is 1027 begin 1028 HT_Ops.Move (Target => Target.HT, Source => Source.HT); 1029 end Move; 1030 1031 ---------- 1032 -- Next -- 1033 ---------- 1034 1035 function Next (Node : Node_Access) return Node_Access is 1036 begin 1037 return Node.Next; 1038 end Next; 1039 1040 function Next (Position : Cursor) return Cursor is 1041 Node : Node_Access; 1042 Pos : Hash_Type; 1043 begin 1044 if Position.Node = null then 1045 return No_Element; 1046 end if; 1047 1048 pragma Assert (Vet (Position), "bad cursor in Next"); 1049 1050 Pos := Position.Position; 1051 Node := HT_Ops.Next (Position.Container.HT, Position.Node, Pos); 1052 1053 if Node = null then 1054 return No_Element; 1055 end if; 1056 1057 return Cursor'(Position.Container, Node, Pos); 1058 end Next; 1059 1060 procedure Next (Position : in out Cursor) is 1061 begin 1062 Position := Next (Position); 1063 end Next; 1064 1065 function Next 1066 (Object : Iterator; 1067 Position : Cursor) return Cursor 1068 is 1069 begin 1070 if Position.Container = null then 1071 return No_Element; 1072 end if; 1073 1074 if Checks and then Position.Container /= Object.Container then 1075 raise Program_Error with 1076 "Position cursor of Next designates wrong set"; 1077 end if; 1078 1079 return Next (Position); 1080 end Next; 1081 1082 ------------- 1083 -- Overlap -- 1084 ------------- 1085 1086 function Overlap (Left, Right : Set) return Boolean is 1087 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT; 1088 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT; 1089 Left_Node : Node_Access; 1090 1091 begin 1092 if Right.Length = 0 then 1093 return False; 1094 end if; 1095 1096 if Left'Address = Right'Address then 1097 return True; 1098 end if; 1099 1100 Left_Node := HT_Ops.First (Left_HT); 1101 while Left_Node /= null loop 1102 if Is_In (Right_HT, Left_Node) then 1103 return True; 1104 end if; 1105 Left_Node := HT_Ops.Next (Left_HT, Left_Node); 1106 end loop; 1107 1108 return False; 1109 end Overlap; 1110 1111 ---------------------- 1112 -- Pseudo_Reference -- 1113 ---------------------- 1114 1115 function Pseudo_Reference 1116 (Container : aliased Set'Class) return Reference_Control_Type 1117 is 1118 TC : constant Tamper_Counts_Access := 1119 Container.HT.TC'Unrestricted_Access; 1120 begin 1121 return R : constant Reference_Control_Type := (Controlled with TC) do 1122 Lock (TC.all); 1123 end return; 1124 end Pseudo_Reference; 1125 1126 ------------------- 1127 -- Query_Element -- 1128 ------------------- 1129 1130 procedure Query_Element 1131 (Position : Cursor; 1132 Process : not null access procedure (Element : Element_Type)) 1133 is 1134 begin 1135 if Checks and then Position.Node = null then 1136 raise Constraint_Error with 1137 "Position cursor of Query_Element equals No_Element"; 1138 end if; 1139 1140 pragma Assert (Vet (Position), "bad cursor in Query_Element"); 1141 1142 declare 1143 HT : Hash_Table_Type renames Position.Container.HT; 1144 Lock : With_Lock (HT.TC'Unrestricted_Access); 1145 begin 1146 Process (Position.Node.Element); 1147 end; 1148 end Query_Element; 1149 1150 ---------- 1151 -- Read -- 1152 ---------- 1153 1154 procedure Read 1155 (Stream : not null access Root_Stream_Type'Class; 1156 Container : out Set) 1157 is 1158 begin 1159 Read_Nodes (Stream, Container.HT); 1160 end Read; 1161 1162 procedure Read 1163 (Stream : not null access Root_Stream_Type'Class; 1164 Item : out Cursor) 1165 is 1166 begin 1167 raise Program_Error with "attempt to stream set cursor"; 1168 end Read; 1169 1170 procedure Read 1171 (Stream : not null access Root_Stream_Type'Class; 1172 Item : out Constant_Reference_Type) 1173 is 1174 begin 1175 raise Program_Error with "attempt to stream reference"; 1176 end Read; 1177 1178 --------------- 1179 -- Read_Node -- 1180 --------------- 1181 1182 function Read_Node (Stream : not null access Root_Stream_Type'Class) 1183 return Node_Access 1184 is 1185 Node : Node_Access := new Node_Type; 1186 begin 1187 Element_Type'Read (Stream, Node.Element); 1188 return Node; 1189 exception 1190 when others => 1191 Free (Node); 1192 raise; 1193 end Read_Node; 1194 1195 ------------- 1196 -- Replace -- 1197 ------------- 1198 1199 procedure Replace 1200 (Container : in out Set; 1201 New_Item : Element_Type) 1202 is 1203 Node : constant Node_Access := 1204 Element_Keys.Find (Container.HT, New_Item); 1205 1206 begin 1207 if Checks and then Node = null then 1208 raise Constraint_Error with 1209 "attempt to replace element not in set"; 1210 end if; 1211 1212 TE_Check (Container.HT.TC); 1213 1214 Node.Element := New_Item; 1215 end Replace; 1216 1217 procedure Replace_Element 1218 (Container : in out Set; 1219 Position : Cursor; 1220 New_Item : Element_Type) 1221 is 1222 begin 1223 if Checks and then Position.Node = null then 1224 raise Constraint_Error with 1225 "Position cursor equals No_Element"; 1226 end if; 1227 1228 if Checks and then Position.Container /= Container'Unrestricted_Access 1229 then 1230 raise Program_Error with 1231 "Position cursor designates wrong set"; 1232 end if; 1233 1234 pragma Assert (Vet (Position), "bad cursor in Replace_Element"); 1235 1236 Replace_Element (Container.HT, Position.Node, New_Item); 1237 end Replace_Element; 1238 1239 ---------------------- 1240 -- Reserve_Capacity -- 1241 ---------------------- 1242 1243 procedure Reserve_Capacity 1244 (Container : in out Set; 1245 Capacity : Count_Type) 1246 is 1247 begin 1248 HT_Ops.Reserve_Capacity (Container.HT, Capacity); 1249 end Reserve_Capacity; 1250 1251 -------------- 1252 -- Set_Next -- 1253 -------------- 1254 1255 procedure Set_Next (Node : Node_Access; Next : Node_Access) is 1256 begin 1257 Node.Next := Next; 1258 end Set_Next; 1259 1260 -------------------------- 1261 -- Symmetric_Difference -- 1262 -------------------------- 1263 1264 procedure Symmetric_Difference 1265 (Target : in out Set; 1266 Source : Set) 1267 is 1268 Tgt_HT : Hash_Table_Type renames Target.HT; 1269 Src_HT : Hash_Table_Type renames Source.HT'Unrestricted_Access.all; 1270 begin 1271 if Target'Address = Source'Address then 1272 Clear (Target); 1273 return; 1274 end if; 1275 1276 TC_Check (Tgt_HT.TC); 1277 1278 declare 1279 N : constant Count_Type := Target.Length + Source.Length; 1280 begin 1281 if N > HT_Ops.Capacity (Tgt_HT) then 1282 HT_Ops.Reserve_Capacity (Tgt_HT, N); 1283 end if; 1284 end; 1285 1286 if Target.Length = 0 then 1287 Iterate_Source_When_Empty_Target : declare 1288 procedure Process (Src_Node : Node_Access); 1289 1290 procedure Iterate is new HT_Ops.Generic_Iteration (Process); 1291 1292 ------------- 1293 -- Process -- 1294 ------------- 1295 1296 procedure Process (Src_Node : Node_Access) is 1297 E : Element_Type renames Src_Node.Element; 1298 B : Buckets_Type renames Tgt_HT.Buckets.all; 1299 J : constant Hash_Type := Hash (E) mod B'Length; 1300 N : Count_Type renames Tgt_HT.Length; 1301 1302 begin 1303 B (J) := new Node_Type'(E, B (J)); 1304 N := N + 1; 1305 end Process; 1306 1307 -- Per AI05-0022, the container implementation is required to 1308 -- detect element tampering by a generic actual subprogram. 1309 1310 Lock_Tgt : With_Lock (Tgt_HT.TC'Unrestricted_Access); 1311 Lock_Src : With_Lock (Src_HT.TC'Unrestricted_Access); 1312 1313 -- Start of processing for Iterate_Source_When_Empty_Target 1314 1315 begin 1316 Iterate (Src_HT); 1317 end Iterate_Source_When_Empty_Target; 1318 1319 else 1320 Iterate_Source : declare 1321 procedure Process (Src_Node : Node_Access); 1322 1323 procedure Iterate is 1324 new HT_Ops.Generic_Iteration (Process); 1325 1326 ------------- 1327 -- Process -- 1328 ------------- 1329 1330 procedure Process (Src_Node : Node_Access) is 1331 E : Element_Type renames Src_Node.Element; 1332 B : Buckets_Type renames Tgt_HT.Buckets.all; 1333 J : constant Hash_Type := Hash (E) mod B'Length; 1334 N : Count_Type renames Tgt_HT.Length; 1335 1336 begin 1337 if B (J) = null then 1338 B (J) := new Node_Type'(E, null); 1339 N := N + 1; 1340 1341 elsif Equivalent_Elements (E, B (J).Element) then 1342 declare 1343 X : Node_Access := B (J); 1344 begin 1345 B (J) := B (J).Next; 1346 N := N - 1; 1347 Free (X); 1348 end; 1349 1350 else 1351 declare 1352 Prev : Node_Access := B (J); 1353 Curr : Node_Access := Prev.Next; 1354 1355 begin 1356 while Curr /= null loop 1357 if Equivalent_Elements (E, Curr.Element) then 1358 Prev.Next := Curr.Next; 1359 N := N - 1; 1360 Free (Curr); 1361 return; 1362 end if; 1363 1364 Prev := Curr; 1365 Curr := Prev.Next; 1366 end loop; 1367 1368 B (J) := new Node_Type'(E, B (J)); 1369 N := N + 1; 1370 end; 1371 end if; 1372 end Process; 1373 1374 -- Per AI05-0022, the container implementation is required to 1375 -- detect element tampering by a generic actual subprogram. 1376 1377 Lock_Tgt : With_Lock (Tgt_HT.TC'Unrestricted_Access); 1378 Lock_Src : With_Lock (Src_HT.TC'Unrestricted_Access); 1379 1380 -- Start of processing for Iterate_Source 1381 1382 begin 1383 Iterate (Src_HT); 1384 end Iterate_Source; 1385 end if; 1386 end Symmetric_Difference; 1387 1388 function Symmetric_Difference (Left, Right : Set) return Set is 1389 Left_HT : Hash_Table_Type renames Left'Unrestricted_Access.HT; 1390 Right_HT : Hash_Table_Type renames Right'Unrestricted_Access.HT; 1391 Buckets : HT_Types.Buckets_Access; 1392 Length : Count_Type; 1393 1394 begin 1395 if Left'Address = Right'Address then 1396 return Empty_Set; 1397 end if; 1398 1399 if Right.Length = 0 then 1400 return Left; 1401 end if; 1402 1403 if Left.Length = 0 then 1404 return Right; 1405 end if; 1406 1407 declare 1408 Size : constant Hash_Type := 1409 Prime_Numbers.To_Prime (Left.Length + Right.Length); 1410 begin 1411 Buckets := HT_Ops.New_Buckets (Length => Size); 1412 end; 1413 1414 Length := 0; 1415 1416 Iterate_Left : declare 1417 procedure Process (L_Node : Node_Access); 1418 1419 procedure Iterate is 1420 new HT_Ops.Generic_Iteration (Process); 1421 1422 ------------- 1423 -- Process -- 1424 ------------- 1425 1426 procedure Process (L_Node : Node_Access) is 1427 begin 1428 if not Is_In (Right_HT, L_Node) then 1429 declare 1430 E : Element_Type renames L_Node.Element; 1431 1432 -- Per AI05-0022, the container implementation is required 1433 -- to detect element tampering by a generic actual 1434 -- subprogram, hence the use of Checked_Index instead of a 1435 -- simple invocation of generic formal Hash. 1436 1437 J : constant Hash_Type := 1438 HT_Ops.Checked_Index (Left_HT, Buckets.all, L_Node); 1439 1440 begin 1441 Buckets (J) := new Node_Type'(E, Buckets (J)); 1442 Length := Length + 1; 1443 end; 1444 end if; 1445 end Process; 1446 1447 -- Start of processing for Iterate_Left 1448 1449 begin 1450 Iterate (Left_HT); 1451 1452 exception 1453 when others => 1454 HT_Ops.Free_Hash_Table (Buckets); 1455 raise; 1456 end Iterate_Left; 1457 1458 Iterate_Right : declare 1459 procedure Process (R_Node : Node_Access); 1460 1461 procedure Iterate is 1462 new HT_Ops.Generic_Iteration (Process); 1463 1464 ------------- 1465 -- Process -- 1466 ------------- 1467 1468 procedure Process (R_Node : Node_Access) is 1469 begin 1470 if not Is_In (Left_HT, R_Node) then 1471 declare 1472 E : Element_Type renames R_Node.Element; 1473 1474 -- Per AI05-0022, the container implementation is required 1475 -- to detect element tampering by a generic actual 1476 -- subprogram, hence the use of Checked_Index instead of a 1477 -- simple invocation of generic formal Hash. 1478 1479 J : constant Hash_Type := 1480 HT_Ops.Checked_Index (Right_HT, Buckets.all, R_Node); 1481 1482 begin 1483 Buckets (J) := new Node_Type'(E, Buckets (J)); 1484 Length := Length + 1; 1485 end; 1486 end if; 1487 end Process; 1488 1489 -- Start of processing for Iterate_Right 1490 1491 begin 1492 Iterate (Right_HT); 1493 1494 exception 1495 when others => 1496 HT_Ops.Free_Hash_Table (Buckets); 1497 raise; 1498 end Iterate_Right; 1499 1500 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0))); 1501 end Symmetric_Difference; 1502 1503 ------------ 1504 -- To_Set -- 1505 ------------ 1506 1507 function To_Set (New_Item : Element_Type) return Set is 1508 HT : Hash_Table_Type; 1509 1510 Node : Node_Access; 1511 Inserted : Boolean; 1512 pragma Unreferenced (Node, Inserted); 1513 1514 begin 1515 Insert (HT, New_Item, Node, Inserted); 1516 return Set'(Controlled with HT); 1517 end To_Set; 1518 1519 ----------- 1520 -- Union -- 1521 ----------- 1522 1523 procedure Union 1524 (Target : in out Set; 1525 Source : Set) 1526 is 1527 procedure Process (Src_Node : Node_Access); 1528 1529 procedure Iterate is 1530 new HT_Ops.Generic_Iteration (Process); 1531 1532 ------------- 1533 -- Process -- 1534 ------------- 1535 1536 procedure Process (Src_Node : Node_Access) is 1537 function New_Node (Next : Node_Access) return Node_Access; 1538 pragma Inline (New_Node); 1539 1540 procedure Insert is 1541 new Element_Keys.Generic_Conditional_Insert (New_Node); 1542 1543 -------------- 1544 -- New_Node -- 1545 -------------- 1546 1547 function New_Node (Next : Node_Access) return Node_Access is 1548 Node : constant Node_Access := 1549 new Node_Type'(Src_Node.Element, Next); 1550 begin 1551 return Node; 1552 end New_Node; 1553 1554 Tgt_Node : Node_Access; 1555 Success : Boolean; 1556 pragma Unreferenced (Tgt_Node, Success); 1557 1558 -- Start of processing for Process 1559 1560 begin 1561 Insert (Target.HT, Src_Node.Element, Tgt_Node, Success); 1562 end Process; 1563 1564 -- Start of processing for Union 1565 1566 begin 1567 if Target'Address = Source'Address then 1568 return; 1569 end if; 1570 1571 TC_Check (Target.HT.TC); 1572 1573 declare 1574 N : constant Count_Type := Target.Length + Source.Length; 1575 begin 1576 if N > HT_Ops.Capacity (Target.HT) then 1577 HT_Ops.Reserve_Capacity (Target.HT, N); 1578 end if; 1579 end; 1580 1581 Iterate (Source.HT); 1582 end Union; 1583 1584 function Union (Left, Right : Set) return Set is 1585 Left_HT : Hash_Table_Type renames Left.HT'Unrestricted_Access.all; 1586 Right_HT : Hash_Table_Type renames Right.HT'Unrestricted_Access.all; 1587 Buckets : HT_Types.Buckets_Access; 1588 Length : Count_Type; 1589 1590 begin 1591 if Left'Address = Right'Address then 1592 return Left; 1593 end if; 1594 1595 if Right.Length = 0 then 1596 return Left; 1597 end if; 1598 1599 if Left.Length = 0 then 1600 return Right; 1601 end if; 1602 1603 declare 1604 Size : constant Hash_Type := 1605 Prime_Numbers.To_Prime (Left.Length + Right.Length); 1606 begin 1607 Buckets := HT_Ops.New_Buckets (Length => Size); 1608 end; 1609 1610 Iterate_Left : declare 1611 procedure Process (L_Node : Node_Access); 1612 1613 procedure Iterate is 1614 new HT_Ops.Generic_Iteration (Process); 1615 1616 ------------- 1617 -- Process -- 1618 ------------- 1619 1620 procedure Process (L_Node : Node_Access) is 1621 J : constant Hash_Type := 1622 Hash (L_Node.Element) mod Buckets'Length; 1623 1624 begin 1625 Buckets (J) := new Node_Type'(L_Node.Element, Buckets (J)); 1626 end Process; 1627 1628 -- Per AI05-0022, the container implementation is required to detect 1629 -- element tampering by a generic actual subprogram, hence the use of 1630 -- Checked_Index instead of a simple invocation of generic formal 1631 -- Hash. 1632 1633 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access); 1634 1635 -- Start of processing for Iterate_Left 1636 1637 begin 1638 Iterate (Left_HT); 1639 exception 1640 when others => 1641 HT_Ops.Free_Hash_Table (Buckets); 1642 raise; 1643 end Iterate_Left; 1644 1645 Length := Left.Length; 1646 1647 Iterate_Right : declare 1648 procedure Process (Src_Node : Node_Access); 1649 1650 procedure Iterate is 1651 new HT_Ops.Generic_Iteration (Process); 1652 1653 ------------- 1654 -- Process -- 1655 ------------- 1656 1657 procedure Process (Src_Node : Node_Access) is 1658 J : constant Hash_Type := 1659 Hash (Src_Node.Element) mod Buckets'Length; 1660 1661 Tgt_Node : Node_Access := Buckets (J); 1662 1663 begin 1664 while Tgt_Node /= null loop 1665 if Equivalent_Elements (Src_Node.Element, Tgt_Node.Element) then 1666 return; 1667 end if; 1668 1669 Tgt_Node := Next (Tgt_Node); 1670 end loop; 1671 1672 Buckets (J) := new Node_Type'(Src_Node.Element, Buckets (J)); 1673 Length := Length + 1; 1674 end Process; 1675 1676 -- Per AI05-0022, the container implementation is required to detect 1677 -- element tampering by a generic actual subprogram, hence the use of 1678 -- Checked_Index instead of a simple invocation of generic formal 1679 -- Hash. 1680 1681 Lock_Left : With_Lock (Left_HT.TC'Unrestricted_Access); 1682 Lock_Right : With_Lock (Right_HT.TC'Unrestricted_Access); 1683 1684 -- Start of processing for Iterate_Right 1685 1686 begin 1687 Iterate (Right_HT); 1688 exception 1689 when others => 1690 HT_Ops.Free_Hash_Table (Buckets); 1691 raise; 1692 end Iterate_Right; 1693 1694 return (Controlled with HT => (Buckets, Length, (Busy => 0, Lock => 0))); 1695 end Union; 1696 1697 --------- 1698 -- Vet -- 1699 --------- 1700 1701 function Vet (Position : Cursor) return Boolean is 1702 begin 1703 if Position.Node = null then 1704 return Position.Container = null; 1705 end if; 1706 1707 if Position.Container = null then 1708 return False; 1709 end if; 1710 1711 if Position.Node.Next = Position.Node then 1712 return False; 1713 end if; 1714 1715 declare 1716 HT : Hash_Table_Type renames Position.Container.HT; 1717 X : Node_Access; 1718 1719 begin 1720 if HT.Length = 0 then 1721 return False; 1722 end if; 1723 1724 if HT.Buckets = null 1725 or else HT.Buckets'Length = 0 1726 then 1727 return False; 1728 end if; 1729 1730 X := HT.Buckets (Element_Keys.Checked_Index 1731 (HT, 1732 Position.Node.Element)); 1733 1734 for J in 1 .. HT.Length loop 1735 if X = Position.Node then 1736 return True; 1737 end if; 1738 1739 if X = null then 1740 return False; 1741 end if; 1742 1743 if X = X.Next then -- to prevent unnecessary looping 1744 return False; 1745 end if; 1746 1747 X := X.Next; 1748 end loop; 1749 1750 return False; 1751 end; 1752 end Vet; 1753 1754 ----------- 1755 -- Write -- 1756 ----------- 1757 1758 procedure Write 1759 (Stream : not null access Root_Stream_Type'Class; 1760 Container : Set) 1761 is 1762 begin 1763 Write_Nodes (Stream, Container.HT); 1764 end Write; 1765 1766 procedure Write 1767 (Stream : not null access Root_Stream_Type'Class; 1768 Item : Cursor) 1769 is 1770 begin 1771 raise Program_Error with "attempt to stream set cursor"; 1772 end Write; 1773 1774 procedure Write 1775 (Stream : not null access Root_Stream_Type'Class; 1776 Item : Constant_Reference_Type) 1777 is 1778 begin 1779 raise Program_Error with "attempt to stream reference"; 1780 end Write; 1781 1782 ---------------- 1783 -- Write_Node -- 1784 ---------------- 1785 1786 procedure Write_Node 1787 (Stream : not null access Root_Stream_Type'Class; 1788 Node : Node_Access) 1789 is 1790 begin 1791 Element_Type'Write (Stream, Node.Element); 1792 end Write_Node; 1793 1794 package body Generic_Keys is 1795 1796 ----------------------- 1797 -- Local Subprograms -- 1798 ----------------------- 1799 1800 function Equivalent_Key_Node 1801 (Key : Key_Type; 1802 Node : Node_Access) return Boolean; 1803 pragma Inline (Equivalent_Key_Node); 1804 1805 -------------------------- 1806 -- Local Instantiations -- 1807 -------------------------- 1808 1809 package Key_Keys is 1810 new Hash_Tables.Generic_Keys 1811 (HT_Types => HT_Types, 1812 Next => Next, 1813 Set_Next => Set_Next, 1814 Key_Type => Key_Type, 1815 Hash => Hash, 1816 Equivalent_Keys => Equivalent_Key_Node); 1817 1818 ------------------------ 1819 -- Constant_Reference -- 1820 ------------------------ 1821 1822 function Constant_Reference 1823 (Container : aliased Set; 1824 Key : Key_Type) return Constant_Reference_Type 1825 is 1826 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT; 1827 Node : constant Node_Access := Key_Keys.Find (HT, Key); 1828 1829 begin 1830 if Checks and then Node = null then 1831 raise Constraint_Error with "Key not in set"; 1832 end if; 1833 1834 declare 1835 TC : constant Tamper_Counts_Access := 1836 HT.TC'Unrestricted_Access; 1837 begin 1838 return R : constant Constant_Reference_Type := 1839 (Element => Node.Element'Access, 1840 Control => (Controlled with TC)) 1841 do 1842 Lock (TC.all); 1843 end return; 1844 end; 1845 end Constant_Reference; 1846 1847 -------------- 1848 -- Contains -- 1849 -------------- 1850 1851 function Contains 1852 (Container : Set; 1853 Key : Key_Type) return Boolean 1854 is 1855 begin 1856 return Find (Container, Key) /= No_Element; 1857 end Contains; 1858 1859 ------------ 1860 -- Delete -- 1861 ------------ 1862 1863 procedure Delete 1864 (Container : in out Set; 1865 Key : Key_Type) 1866 is 1867 X : Node_Access; 1868 1869 begin 1870 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X); 1871 1872 if Checks and then X = null then 1873 raise Constraint_Error with "attempt to delete key not in set"; 1874 end if; 1875 1876 Free (X); 1877 end Delete; 1878 1879 ------------- 1880 -- Element -- 1881 ------------- 1882 1883 function Element 1884 (Container : Set; 1885 Key : Key_Type) return Element_Type 1886 is 1887 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT; 1888 Node : constant Node_Access := Key_Keys.Find (HT, Key); 1889 1890 begin 1891 if Checks and then Node = null then 1892 raise Constraint_Error with "key not in set"; 1893 end if; 1894 1895 return Node.Element; 1896 end Element; 1897 1898 ------------------------- 1899 -- Equivalent_Key_Node -- 1900 ------------------------- 1901 1902 function Equivalent_Key_Node 1903 (Key : Key_Type; 1904 Node : Node_Access) return Boolean 1905 is 1906 begin 1907 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element)); 1908 end Equivalent_Key_Node; 1909 1910 ------------- 1911 -- Exclude -- 1912 ------------- 1913 1914 procedure Exclude 1915 (Container : in out Set; 1916 Key : Key_Type) 1917 is 1918 X : Node_Access; 1919 begin 1920 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X); 1921 Free (X); 1922 end Exclude; 1923 1924 -------------- 1925 -- Finalize -- 1926 -------------- 1927 1928 procedure Finalize (Control : in out Reference_Control_Type) is 1929 begin 1930 if Control.Container /= null then 1931 Impl.Reference_Control_Type (Control).Finalize; 1932 1933 if Checks and then 1934 Hash (Key (Element (Control.Old_Pos))) /= Control.Old_Hash 1935 then 1936 HT_Ops.Delete_Node_At_Index 1937 (Control.Container.HT, Control.Index, Control.Old_Pos.Node); 1938 raise Program_Error with "key not preserved in reference"; 1939 end if; 1940 1941 Control.Container := null; 1942 end if; 1943 end Finalize; 1944 1945 ---------- 1946 -- Find -- 1947 ---------- 1948 1949 function Find 1950 (Container : Set; 1951 Key : Key_Type) return Cursor 1952 is 1953 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT; 1954 Node : constant Node_Access := Key_Keys.Find (HT, Key); 1955 begin 1956 if Node = null then 1957 return No_Element; 1958 else 1959 return Cursor' 1960 (Container'Unrestricted_Access, Node, Hash_Type'Last); 1961 end if; 1962 end Find; 1963 1964 --------- 1965 -- Key -- 1966 --------- 1967 1968 function Key (Position : Cursor) return Key_Type is 1969 begin 1970 if Checks and then Position.Node = null then 1971 raise Constraint_Error with 1972 "Position cursor equals No_Element"; 1973 end if; 1974 1975 pragma Assert (Vet (Position), "bad cursor in function Key"); 1976 1977 return Key (Position.Node.Element); 1978 end Key; 1979 1980 ---------- 1981 -- Read -- 1982 ---------- 1983 1984 procedure Read 1985 (Stream : not null access Root_Stream_Type'Class; 1986 Item : out Reference_Type) 1987 is 1988 begin 1989 raise Program_Error with "attempt to stream reference"; 1990 end Read; 1991 1992 ------------------------------ 1993 -- Reference_Preserving_Key -- 1994 ------------------------------ 1995 1996 function Reference_Preserving_Key 1997 (Container : aliased in out Set; 1998 Position : Cursor) return Reference_Type 1999 is 2000 begin 2001 if Checks and then Position.Container = null then 2002 raise Constraint_Error with "Position cursor has no element"; 2003 end if; 2004 2005 if Checks and then Position.Container /= Container'Unrestricted_Access 2006 then 2007 raise Program_Error with 2008 "Position cursor designates wrong container"; 2009 end if; 2010 2011 pragma Assert 2012 (Vet (Position), 2013 "bad cursor in function Reference_Preserving_Key"); 2014 2015 declare 2016 HT : Hash_Table_Type renames Position.Container.all.HT; 2017 begin 2018 return R : constant Reference_Type := 2019 (Element => Position.Node.Element'Access, 2020 Control => 2021 (Controlled with 2022 HT.TC'Unrestricted_Access, 2023 Container'Unrestricted_Access, 2024 Index => HT_Ops.Index (HT, Position.Node), 2025 Old_Pos => Position, 2026 Old_Hash => Hash (Key (Position)))) 2027 do 2028 Lock (HT.TC); 2029 end return; 2030 end; 2031 end Reference_Preserving_Key; 2032 2033 function Reference_Preserving_Key 2034 (Container : aliased in out Set; 2035 Key : Key_Type) return Reference_Type 2036 is 2037 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key); 2038 2039 begin 2040 if Checks and then Node = null then 2041 raise Constraint_Error with "key not in set"; 2042 end if; 2043 2044 declare 2045 HT : Hash_Table_Type renames Container.HT; 2046 P : constant Cursor := Find (Container, Key); 2047 begin 2048 return R : constant Reference_Type := 2049 (Element => Node.Element'Access, 2050 Control => 2051 (Controlled with 2052 HT.TC'Unrestricted_Access, 2053 Container'Unrestricted_Access, 2054 Index => HT_Ops.Index (HT, P.Node), 2055 Old_Pos => P, 2056 Old_Hash => Hash (Key))) 2057 do 2058 Lock (HT.TC); 2059 end return; 2060 end; 2061 end Reference_Preserving_Key; 2062 2063 ------------- 2064 -- Replace -- 2065 ------------- 2066 2067 procedure Replace 2068 (Container : in out Set; 2069 Key : Key_Type; 2070 New_Item : Element_Type) 2071 is 2072 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key); 2073 2074 begin 2075 if Checks and then Node = null then 2076 raise Constraint_Error with 2077 "attempt to replace key not in set"; 2078 end if; 2079 2080 Replace_Element (Container.HT, Node, New_Item); 2081 end Replace; 2082 2083 ----------------------------------- 2084 -- Update_Element_Preserving_Key -- 2085 ----------------------------------- 2086 2087 procedure Update_Element_Preserving_Key 2088 (Container : in out Set; 2089 Position : Cursor; 2090 Process : not null access 2091 procedure (Element : in out Element_Type)) 2092 is 2093 HT : Hash_Table_Type renames Container.HT; 2094 Indx : Hash_Type; 2095 2096 begin 2097 if Checks and then Position.Node = null then 2098 raise Constraint_Error with 2099 "Position cursor equals No_Element"; 2100 end if; 2101 2102 if Checks and then Position.Container /= Container'Unrestricted_Access 2103 then 2104 raise Program_Error with 2105 "Position cursor designates wrong set"; 2106 end if; 2107 2108 if Checks and then 2109 (HT.Buckets = null 2110 or else HT.Buckets'Length = 0 2111 or else HT.Length = 0 2112 or else Position.Node.Next = Position.Node) 2113 then 2114 raise Program_Error with "Position cursor is bad (set is empty)"; 2115 end if; 2116 2117 pragma Assert 2118 (Vet (Position), 2119 "bad cursor in Update_Element_Preserving_Key"); 2120 2121 -- Per AI05-0022, the container implementation is required to detect 2122 -- element tampering by a generic actual subprogram. 2123 2124 declare 2125 E : Element_Type renames Position.Node.Element; 2126 K : constant Key_Type := Key (E); 2127 Lock : With_Lock (HT.TC'Unrestricted_Access); 2128 begin 2129 Indx := HT_Ops.Index (HT, Position.Node); 2130 Process (E); 2131 2132 if Equivalent_Keys (K, Key (E)) then 2133 return; 2134 end if; 2135 end; 2136 2137 if HT.Buckets (Indx) = Position.Node then 2138 HT.Buckets (Indx) := Position.Node.Next; 2139 2140 else 2141 declare 2142 Prev : Node_Access := HT.Buckets (Indx); 2143 2144 begin 2145 while Prev.Next /= Position.Node loop 2146 Prev := Prev.Next; 2147 2148 if Checks and then Prev = null then 2149 raise Program_Error with 2150 "Position cursor is bad (node not found)"; 2151 end if; 2152 end loop; 2153 2154 Prev.Next := Position.Node.Next; 2155 end; 2156 end if; 2157 2158 HT.Length := HT.Length - 1; 2159 2160 declare 2161 X : Node_Access := Position.Node; 2162 2163 begin 2164 Free (X); 2165 end; 2166 2167 raise Program_Error with "key was modified"; 2168 end Update_Element_Preserving_Key; 2169 2170 ----------- 2171 -- Write -- 2172 ----------- 2173 2174 procedure Write 2175 (Stream : not null access Root_Stream_Type'Class; 2176 Item : Reference_Type) 2177 is 2178 begin 2179 raise Program_Error with "attempt to stream reference"; 2180 end Write; 2181 2182 end Generic_Keys; 2183 2184end Ada.Containers.Hashed_Sets; 2185