PR tree-optimization/43833
[official-gcc/alias-decl.git] / gcc / ada / a-cohase.adb
blob760605feb308d9a2e56a2c57a342ae7cb7e1fd09
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-2009, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Unchecked_Deallocation;
32 with Ada.Containers.Hash_Tables.Generic_Operations;
33 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
35 with Ada.Containers.Hash_Tables.Generic_Keys;
36 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
38 with Ada.Containers.Prime_Numbers;
40 with System; use type System.Address;
42 package body Ada.Containers.Hashed_Sets is
44 -----------------------
45 -- Local Subprograms --
46 -----------------------
48 procedure Assign (Node : Node_Access; Item : Element_Type);
49 pragma Inline (Assign);
51 function Copy_Node (Source : Node_Access) return Node_Access;
52 pragma Inline (Copy_Node);
54 function Equivalent_Keys
55 (Key : Element_Type;
56 Node : Node_Access) return Boolean;
57 pragma Inline (Equivalent_Keys);
59 function Find_Equal_Key
60 (R_HT : Hash_Table_Type;
61 L_Node : Node_Access) return Boolean;
63 function Find_Equivalent_Key
64 (R_HT : Hash_Table_Type;
65 L_Node : Node_Access) return Boolean;
67 procedure Free (X : in out Node_Access);
69 function Hash_Node (Node : Node_Access) return Hash_Type;
70 pragma Inline (Hash_Node);
72 procedure Insert
73 (HT : in out Hash_Table_Type;
74 New_Item : Element_Type;
75 Node : out Node_Access;
76 Inserted : out Boolean);
78 function Is_In
79 (HT : Hash_Table_Type;
80 Key : Node_Access) return Boolean;
81 pragma Inline (Is_In);
83 function Next (Node : Node_Access) return Node_Access;
84 pragma Inline (Next);
86 function Read_Node (Stream : not null access Root_Stream_Type'Class)
87 return Node_Access;
88 pragma Inline (Read_Node);
90 procedure Set_Next (Node : Node_Access; Next : Node_Access);
91 pragma Inline (Set_Next);
93 function Vet (Position : Cursor) return Boolean;
95 procedure Write_Node
96 (Stream : not null access Root_Stream_Type'Class;
97 Node : Node_Access);
98 pragma Inline (Write_Node);
100 --------------------------
101 -- Local Instantiations --
102 --------------------------
104 package HT_Ops is new Hash_Tables.Generic_Operations
105 (HT_Types => HT_Types,
106 Hash_Node => Hash_Node,
107 Next => Next,
108 Set_Next => Set_Next,
109 Copy_Node => Copy_Node,
110 Free => Free);
112 package Element_Keys is new Hash_Tables.Generic_Keys
113 (HT_Types => HT_Types,
114 Next => Next,
115 Set_Next => Set_Next,
116 Key_Type => Element_Type,
117 Hash => Hash,
118 Equivalent_Keys => Equivalent_Keys);
120 function Is_Equal is
121 new HT_Ops.Generic_Equal (Find_Equal_Key);
123 function Is_Equivalent is
124 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
126 procedure Read_Nodes is
127 new HT_Ops.Generic_Read (Read_Node);
129 procedure Replace_Element is
130 new Element_Keys.Generic_Replace_Element (Hash_Node, Assign);
132 procedure Write_Nodes is
133 new HT_Ops.Generic_Write (Write_Node);
135 ---------
136 -- "=" --
137 ---------
139 function "=" (Left, Right : Set) return Boolean is
140 begin
141 return Is_Equal (Left.HT, Right.HT);
142 end "=";
144 ------------
145 -- Adjust --
146 ------------
148 procedure Adjust (Container : in out Set) is
149 begin
150 HT_Ops.Adjust (Container.HT);
151 end Adjust;
153 ------------
154 -- Assign --
155 ------------
157 procedure Assign (Node : Node_Access; Item : Element_Type) is
158 begin
159 Node.Element := Item;
160 end Assign;
162 --------------
163 -- Capacity --
164 --------------
166 function Capacity (Container : Set) return Count_Type is
167 begin
168 return HT_Ops.Capacity (Container.HT);
169 end Capacity;
171 -----------
172 -- Clear --
173 -----------
175 procedure Clear (Container : in out Set) is
176 begin
177 HT_Ops.Clear (Container.HT);
178 end Clear;
180 --------------
181 -- Contains --
182 --------------
184 function Contains (Container : Set; Item : Element_Type) return Boolean is
185 begin
186 return Find (Container, Item) /= No_Element;
187 end Contains;
189 ---------------
190 -- Copy_Node --
191 ---------------
193 function Copy_Node (Source : Node_Access) return Node_Access is
194 begin
195 return new Node_Type'(Element => Source.Element, Next => null);
196 end Copy_Node;
198 ------------
199 -- Delete --
200 ------------
202 procedure Delete
203 (Container : in out Set;
204 Item : Element_Type)
206 X : Node_Access;
208 begin
209 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
211 if X = null then
212 raise Constraint_Error with "attempt to delete element not in set";
213 end if;
215 Free (X);
216 end Delete;
218 procedure Delete
219 (Container : in out Set;
220 Position : in out Cursor)
222 begin
223 if Position.Node = null then
224 raise Constraint_Error with "Position cursor equals No_Element";
225 end if;
227 if Position.Container /= Container'Unrestricted_Access then
228 raise Program_Error with "Position cursor designates wrong set";
229 end if;
231 if Container.HT.Busy > 0 then
232 raise Program_Error with
233 "attempt to tamper with elements (set is busy)";
234 end if;
236 pragma Assert (Vet (Position), "bad cursor in Delete");
238 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
240 Free (Position.Node);
241 Position.Container := null;
242 end Delete;
244 ----------------
245 -- Difference --
246 ----------------
248 procedure Difference
249 (Target : in out Set;
250 Source : Set)
252 Tgt_Node : Node_Access;
254 begin
255 if Target'Address = Source'Address then
256 Clear (Target);
257 return;
258 end if;
260 if Source.HT.Length = 0 then
261 return;
262 end if;
264 if Target.HT.Busy > 0 then
265 raise Program_Error with
266 "attempt to tamper with elements (set is busy)";
267 end if;
269 if Source.HT.Length < Target.HT.Length then
270 declare
271 Src_Node : Node_Access;
273 begin
274 Src_Node := HT_Ops.First (Source.HT);
275 while Src_Node /= null loop
276 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element);
278 if Tgt_Node /= null then
279 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
280 Free (Tgt_Node);
281 end if;
283 Src_Node := HT_Ops.Next (Source.HT, Src_Node);
284 end loop;
285 end;
287 else
288 Tgt_Node := HT_Ops.First (Target.HT);
289 while Tgt_Node /= null loop
290 if Is_In (Source.HT, Tgt_Node) then
291 declare
292 X : Node_Access := Tgt_Node;
293 begin
294 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
295 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
296 Free (X);
297 end;
299 else
300 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
301 end if;
302 end loop;
303 end if;
304 end Difference;
306 function Difference (Left, Right : Set) return Set is
307 Buckets : HT_Types.Buckets_Access;
308 Length : Count_Type;
310 begin
311 if Left'Address = Right'Address then
312 return Empty_Set;
313 end if;
315 if Left.HT.Length = 0 then
316 return Empty_Set;
317 end if;
319 if Right.HT.Length = 0 then
320 return Left;
321 end if;
323 declare
324 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
325 begin
326 Buckets := HT_Ops.New_Buckets (Length => Size);
327 end;
329 Length := 0;
331 Iterate_Left : declare
332 procedure Process (L_Node : Node_Access);
334 procedure Iterate is
335 new HT_Ops.Generic_Iteration (Process);
337 -------------
338 -- Process --
339 -------------
341 procedure Process (L_Node : Node_Access) is
342 begin
343 if not Is_In (Right.HT, L_Node) then
344 declare
345 J : constant Hash_Type :=
346 Hash (L_Node.Element) mod Buckets'Length;
348 Bucket : Node_Access renames Buckets (J);
350 begin
351 Bucket := new Node_Type'(L_Node.Element, Bucket);
352 end;
354 Length := Length + 1;
355 end if;
356 end Process;
358 -- Start of processing for Iterate_Left
360 begin
361 Iterate (Left.HT);
362 exception
363 when others =>
364 HT_Ops.Free_Hash_Table (Buckets);
365 raise;
366 end Iterate_Left;
368 return (Controlled with HT => (Buckets, Length, 0, 0));
369 end Difference;
371 -------------
372 -- Element --
373 -------------
375 function Element (Position : Cursor) return Element_Type is
376 begin
377 if Position.Node = null then
378 raise Constraint_Error with "Position cursor equals No_Element";
379 end if;
381 pragma Assert (Vet (Position), "bad cursor in function Element");
383 return Position.Node.Element;
384 end Element;
386 ---------------------
387 -- Equivalent_Sets --
388 ---------------------
390 function Equivalent_Sets (Left, Right : Set) return Boolean is
391 begin
392 return Is_Equivalent (Left.HT, Right.HT);
393 end Equivalent_Sets;
395 -------------------------
396 -- Equivalent_Elements --
397 -------------------------
399 function Equivalent_Elements (Left, Right : Cursor)
400 return Boolean is
401 begin
402 if Left.Node = null then
403 raise Constraint_Error with
404 "Left cursor of Equivalent_Elements equals No_Element";
405 end if;
407 if Right.Node = null then
408 raise Constraint_Error with
409 "Right cursor of Equivalent_Elements equals No_Element";
410 end if;
412 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
413 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
415 return Equivalent_Elements (Left.Node.Element, Right.Node.Element);
416 end Equivalent_Elements;
418 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
419 return Boolean is
420 begin
421 if Left.Node = null then
422 raise Constraint_Error with
423 "Left cursor of Equivalent_Elements equals No_Element";
424 end if;
426 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad");
428 return Equivalent_Elements (Left.Node.Element, Right);
429 end Equivalent_Elements;
431 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
432 return Boolean is
433 begin
434 if Right.Node = null then
435 raise Constraint_Error with
436 "Right cursor of Equivalent_Elements equals No_Element";
437 end if;
439 pragma Assert
440 (Vet (Right),
441 "Right cursor of Equivalent_Elements is bad");
443 return Equivalent_Elements (Left, Right.Node.Element);
444 end Equivalent_Elements;
446 ---------------------
447 -- Equivalent_Keys --
448 ---------------------
450 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
451 return Boolean is
452 begin
453 return Equivalent_Elements (Key, Node.Element);
454 end Equivalent_Keys;
456 -------------
457 -- Exclude --
458 -------------
460 procedure Exclude
461 (Container : in out Set;
462 Item : Element_Type)
464 X : Node_Access;
465 begin
466 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
467 Free (X);
468 end Exclude;
470 --------------
471 -- Finalize --
472 --------------
474 procedure Finalize (Container : in out Set) is
475 begin
476 HT_Ops.Finalize (Container.HT);
477 end Finalize;
479 ----------
480 -- Find --
481 ----------
483 function Find
484 (Container : Set;
485 Item : Element_Type) return Cursor
487 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
489 begin
490 if Node = null then
491 return No_Element;
492 end if;
494 return Cursor'(Container'Unrestricted_Access, Node);
495 end Find;
497 --------------------
498 -- Find_Equal_Key --
499 --------------------
501 function Find_Equal_Key
502 (R_HT : Hash_Table_Type;
503 L_Node : Node_Access) return Boolean
505 R_Index : constant Hash_Type :=
506 Element_Keys.Index (R_HT, L_Node.Element);
508 R_Node : Node_Access := R_HT.Buckets (R_Index);
510 begin
511 loop
512 if R_Node = null then
513 return False;
514 end if;
516 if L_Node.Element = R_Node.Element then
517 return True;
518 end if;
520 R_Node := Next (R_Node);
521 end loop;
522 end Find_Equal_Key;
524 -------------------------
525 -- Find_Equivalent_Key --
526 -------------------------
528 function Find_Equivalent_Key
529 (R_HT : Hash_Table_Type;
530 L_Node : Node_Access) return Boolean
532 R_Index : constant Hash_Type :=
533 Element_Keys.Index (R_HT, L_Node.Element);
535 R_Node : Node_Access := R_HT.Buckets (R_Index);
537 begin
538 loop
539 if R_Node = null then
540 return False;
541 end if;
543 if Equivalent_Elements (L_Node.Element, R_Node.Element) then
544 return True;
545 end if;
547 R_Node := Next (R_Node);
548 end loop;
549 end Find_Equivalent_Key;
551 -----------
552 -- First --
553 -----------
555 function First (Container : Set) return Cursor is
556 Node : constant Node_Access := HT_Ops.First (Container.HT);
558 begin
559 if Node = null then
560 return No_Element;
561 end if;
563 return Cursor'(Container'Unrestricted_Access, Node);
564 end First;
566 ----------
567 -- Free --
568 ----------
570 procedure Free (X : in out Node_Access) is
571 procedure Deallocate is
572 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
574 begin
575 if X /= null then
576 X.Next := X; -- detect mischief (in Vet)
577 Deallocate (X);
578 end if;
579 end Free;
581 -----------------
582 -- Has_Element --
583 -----------------
585 function Has_Element (Position : Cursor) return Boolean is
586 begin
587 pragma Assert (Vet (Position), "bad cursor in Has_Element");
588 return Position.Node /= null;
589 end Has_Element;
591 ---------------
592 -- Hash_Node --
593 ---------------
595 function Hash_Node (Node : Node_Access) return Hash_Type is
596 begin
597 return Hash (Node.Element);
598 end Hash_Node;
600 -------------
601 -- Include --
602 -------------
604 procedure Include
605 (Container : in out Set;
606 New_Item : Element_Type)
608 Position : Cursor;
609 Inserted : Boolean;
611 begin
612 Insert (Container, New_Item, Position, Inserted);
614 if not Inserted then
615 if Container.HT.Lock > 0 then
616 raise Program_Error with
617 "attempt to tamper with cursors (set is locked)";
618 end if;
620 Position.Node.Element := New_Item;
621 end if;
622 end Include;
624 ------------
625 -- Insert --
626 ------------
628 procedure Insert
629 (Container : in out Set;
630 New_Item : Element_Type;
631 Position : out Cursor;
632 Inserted : out Boolean)
634 begin
635 Insert (Container.HT, New_Item, Position.Node, Inserted);
636 Position.Container := Container'Unchecked_Access;
637 end Insert;
639 procedure Insert
640 (Container : in out Set;
641 New_Item : Element_Type)
643 Position : Cursor;
644 pragma Unreferenced (Position);
646 Inserted : Boolean;
648 begin
649 Insert (Container, New_Item, Position, Inserted);
651 if not Inserted then
652 raise Constraint_Error with
653 "attempt to insert element already in set";
654 end if;
655 end Insert;
657 procedure Insert
658 (HT : in out Hash_Table_Type;
659 New_Item : Element_Type;
660 Node : out Node_Access;
661 Inserted : out Boolean)
663 function New_Node (Next : Node_Access) return Node_Access;
664 pragma Inline (New_Node);
666 procedure Local_Insert is
667 new Element_Keys.Generic_Conditional_Insert (New_Node);
669 --------------
670 -- New_Node --
671 --------------
673 function New_Node (Next : Node_Access) return Node_Access is
674 begin
675 return new Node_Type'(New_Item, Next);
676 end New_Node;
678 -- Start of processing for Insert
680 begin
681 if HT_Ops.Capacity (HT) = 0 then
682 HT_Ops.Reserve_Capacity (HT, 1);
683 end if;
685 Local_Insert (HT, New_Item, Node, Inserted);
687 if Inserted
688 and then HT.Length > HT_Ops.Capacity (HT)
689 then
690 HT_Ops.Reserve_Capacity (HT, HT.Length);
691 end if;
692 end Insert;
694 ------------------
695 -- Intersection --
696 ------------------
698 procedure Intersection
699 (Target : in out Set;
700 Source : Set)
702 Tgt_Node : Node_Access;
704 begin
705 if Target'Address = Source'Address then
706 return;
707 end if;
709 if Source.HT.Length = 0 then
710 Clear (Target);
711 return;
712 end if;
714 if Target.HT.Busy > 0 then
715 raise Program_Error with
716 "attempt to tamper with elements (set is busy)";
717 end if;
719 Tgt_Node := HT_Ops.First (Target.HT);
720 while Tgt_Node /= null loop
721 if Is_In (Source.HT, Tgt_Node) then
722 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
724 else
725 declare
726 X : Node_Access := Tgt_Node;
727 begin
728 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
729 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
730 Free (X);
731 end;
732 end if;
733 end loop;
734 end Intersection;
736 function Intersection (Left, Right : Set) return Set is
737 Buckets : HT_Types.Buckets_Access;
738 Length : Count_Type;
740 begin
741 if Left'Address = Right'Address then
742 return Left;
743 end if;
745 Length := Count_Type'Min (Left.Length, Right.Length);
747 if Length = 0 then
748 return Empty_Set;
749 end if;
751 declare
752 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
753 begin
754 Buckets := HT_Ops.New_Buckets (Length => Size);
755 end;
757 Length := 0;
759 Iterate_Left : declare
760 procedure Process (L_Node : Node_Access);
762 procedure Iterate is
763 new HT_Ops.Generic_Iteration (Process);
765 -------------
766 -- Process --
767 -------------
769 procedure Process (L_Node : Node_Access) is
770 begin
771 if Is_In (Right.HT, L_Node) then
772 declare
773 J : constant Hash_Type :=
774 Hash (L_Node.Element) mod Buckets'Length;
776 Bucket : Node_Access renames Buckets (J);
778 begin
779 Bucket := new Node_Type'(L_Node.Element, Bucket);
780 end;
782 Length := Length + 1;
783 end if;
784 end Process;
786 -- Start of processing for Iterate_Left
788 begin
789 Iterate (Left.HT);
790 exception
791 when others =>
792 HT_Ops.Free_Hash_Table (Buckets);
793 raise;
794 end Iterate_Left;
796 return (Controlled with HT => (Buckets, Length, 0, 0));
797 end Intersection;
799 --------------
800 -- Is_Empty --
801 --------------
803 function Is_Empty (Container : Set) return Boolean is
804 begin
805 return Container.HT.Length = 0;
806 end Is_Empty;
808 -----------
809 -- Is_In --
810 -----------
812 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
813 begin
814 return Element_Keys.Find (HT, Key.Element) /= null;
815 end Is_In;
817 ---------------
818 -- Is_Subset --
819 ---------------
821 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
822 Subset_Node : Node_Access;
824 begin
825 if Subset'Address = Of_Set'Address then
826 return True;
827 end if;
829 if Subset.Length > Of_Set.Length then
830 return False;
831 end if;
833 Subset_Node := HT_Ops.First (Subset.HT);
834 while Subset_Node /= null loop
835 if not Is_In (Of_Set.HT, Subset_Node) then
836 return False;
837 end if;
838 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
839 end loop;
841 return True;
842 end Is_Subset;
844 -------------
845 -- Iterate --
846 -------------
848 procedure Iterate
849 (Container : Set;
850 Process : not null access procedure (Position : Cursor))
852 procedure Process_Node (Node : Node_Access);
853 pragma Inline (Process_Node);
855 procedure Iterate is
856 new HT_Ops.Generic_Iteration (Process_Node);
858 ------------------
859 -- Process_Node --
860 ------------------
862 procedure Process_Node (Node : Node_Access) is
863 begin
864 Process (Cursor'(Container'Unrestricted_Access, Node));
865 end Process_Node;
867 B : Natural renames Container'Unrestricted_Access.HT.Busy;
869 -- Start of processing for Iterate
871 begin
872 B := B + 1;
874 begin
875 Iterate (Container.HT);
876 exception
877 when others =>
878 B := B - 1;
879 raise;
880 end;
882 B := B - 1;
883 end Iterate;
885 ------------
886 -- Length --
887 ------------
889 function Length (Container : Set) return Count_Type is
890 begin
891 return Container.HT.Length;
892 end Length;
894 ----------
895 -- Move --
896 ----------
898 procedure Move (Target : in out Set; Source : in out Set) is
899 begin
900 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
901 end Move;
903 ----------
904 -- Next --
905 ----------
907 function Next (Node : Node_Access) return Node_Access is
908 begin
909 return Node.Next;
910 end Next;
912 function Next (Position : Cursor) return Cursor is
913 begin
914 if Position.Node = null then
915 return No_Element;
916 end if;
918 pragma Assert (Vet (Position), "bad cursor in Next");
920 declare
921 HT : Hash_Table_Type renames Position.Container.HT;
922 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
924 begin
925 if Node = null then
926 return No_Element;
927 end if;
929 return Cursor'(Position.Container, Node);
930 end;
931 end Next;
933 procedure Next (Position : in out Cursor) is
934 begin
935 Position := Next (Position);
936 end Next;
938 -------------
939 -- Overlap --
940 -------------
942 function Overlap (Left, Right : Set) return Boolean is
943 Left_Node : Node_Access;
945 begin
946 if Right.Length = 0 then
947 return False;
948 end if;
950 if Left'Address = Right'Address then
951 return True;
952 end if;
954 Left_Node := HT_Ops.First (Left.HT);
955 while Left_Node /= null loop
956 if Is_In (Right.HT, Left_Node) then
957 return True;
958 end if;
959 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
960 end loop;
962 return False;
963 end Overlap;
965 -------------------
966 -- Query_Element --
967 -------------------
969 procedure Query_Element
970 (Position : Cursor;
971 Process : not null access procedure (Element : Element_Type))
973 begin
974 if Position.Node = null then
975 raise Constraint_Error with
976 "Position cursor of Query_Element equals No_Element";
977 end if;
979 pragma Assert (Vet (Position), "bad cursor in Query_Element");
981 declare
982 HT : Hash_Table_Type renames Position.Container.HT;
984 B : Natural renames HT.Busy;
985 L : Natural renames HT.Lock;
987 begin
988 B := B + 1;
989 L := L + 1;
991 begin
992 Process (Position.Node.Element);
993 exception
994 when others =>
995 L := L - 1;
996 B := B - 1;
997 raise;
998 end;
1000 L := L - 1;
1001 B := B - 1;
1002 end;
1003 end Query_Element;
1005 ----------
1006 -- Read --
1007 ----------
1009 procedure Read
1010 (Stream : not null access Root_Stream_Type'Class;
1011 Container : out Set)
1013 begin
1014 Read_Nodes (Stream, Container.HT);
1015 end Read;
1017 procedure Read
1018 (Stream : not null access Root_Stream_Type'Class;
1019 Item : out Cursor)
1021 begin
1022 raise Program_Error with "attempt to stream set cursor";
1023 end Read;
1025 ---------------
1026 -- Read_Node --
1027 ---------------
1029 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1030 return Node_Access
1032 Node : Node_Access := new Node_Type;
1034 begin
1035 Element_Type'Read (Stream, Node.Element);
1036 return Node;
1037 exception
1038 when others =>
1039 Free (Node);
1040 raise;
1041 end Read_Node;
1043 -------------
1044 -- Replace --
1045 -------------
1047 procedure Replace
1048 (Container : in out Set;
1049 New_Item : Element_Type)
1051 Node : constant Node_Access :=
1052 Element_Keys.Find (Container.HT, New_Item);
1054 begin
1055 if Node = null then
1056 raise Constraint_Error with
1057 "attempt to replace element not in set";
1058 end if;
1060 if Container.HT.Lock > 0 then
1061 raise Program_Error with
1062 "attempt to tamper with cursors (set is locked)";
1063 end if;
1065 Node.Element := New_Item;
1066 end Replace;
1068 procedure Replace_Element
1069 (Container : in out Set;
1070 Position : Cursor;
1071 New_Item : Element_Type)
1073 begin
1074 if Position.Node = null then
1075 raise Constraint_Error with
1076 "Position cursor equals No_Element";
1077 end if;
1079 if Position.Container /= Container'Unrestricted_Access then
1080 raise Program_Error with
1081 "Position cursor designates wrong set";
1082 end if;
1084 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1086 Replace_Element (Container.HT, Position.Node, New_Item);
1087 end Replace_Element;
1089 ----------------------
1090 -- Reserve_Capacity --
1091 ----------------------
1093 procedure Reserve_Capacity
1094 (Container : in out Set;
1095 Capacity : Count_Type)
1097 begin
1098 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1099 end Reserve_Capacity;
1101 --------------
1102 -- Set_Next --
1103 --------------
1105 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1106 begin
1107 Node.Next := Next;
1108 end Set_Next;
1110 --------------------------
1111 -- Symmetric_Difference --
1112 --------------------------
1114 procedure Symmetric_Difference
1115 (Target : in out Set;
1116 Source : Set)
1118 begin
1119 if Target'Address = Source'Address then
1120 Clear (Target);
1121 return;
1122 end if;
1124 if Target.HT.Busy > 0 then
1125 raise Program_Error with
1126 "attempt to tamper with elements (set is busy)";
1127 end if;
1129 declare
1130 N : constant Count_Type := Target.Length + Source.Length;
1131 begin
1132 if N > HT_Ops.Capacity (Target.HT) then
1133 HT_Ops.Reserve_Capacity (Target.HT, N);
1134 end if;
1135 end;
1137 if Target.Length = 0 then
1138 Iterate_Source_When_Empty_Target : declare
1139 procedure Process (Src_Node : Node_Access);
1141 procedure Iterate is
1142 new HT_Ops.Generic_Iteration (Process);
1144 -------------
1145 -- Process --
1146 -------------
1148 procedure Process (Src_Node : Node_Access) is
1149 E : Element_Type renames Src_Node.Element;
1150 B : Buckets_Type renames Target.HT.Buckets.all;
1151 J : constant Hash_Type := Hash (E) mod B'Length;
1152 N : Count_Type renames Target.HT.Length;
1154 begin
1155 B (J) := new Node_Type'(E, B (J));
1156 N := N + 1;
1157 end Process;
1159 -- Start of processing for Iterate_Source_When_Empty_Target
1161 begin
1162 Iterate (Source.HT);
1163 end Iterate_Source_When_Empty_Target;
1165 else
1166 Iterate_Source : declare
1167 procedure Process (Src_Node : Node_Access);
1169 procedure Iterate is
1170 new HT_Ops.Generic_Iteration (Process);
1172 -------------
1173 -- Process --
1174 -------------
1176 procedure Process (Src_Node : Node_Access) is
1177 E : Element_Type renames Src_Node.Element;
1178 B : Buckets_Type renames Target.HT.Buckets.all;
1179 J : constant Hash_Type := Hash (E) mod B'Length;
1180 N : Count_Type renames Target.HT.Length;
1182 begin
1183 if B (J) = null then
1184 B (J) := new Node_Type'(E, null);
1185 N := N + 1;
1187 elsif Equivalent_Elements (E, B (J).Element) then
1188 declare
1189 X : Node_Access := B (J);
1190 begin
1191 B (J) := B (J).Next;
1192 N := N - 1;
1193 Free (X);
1194 end;
1196 else
1197 declare
1198 Prev : Node_Access := B (J);
1199 Curr : Node_Access := Prev.Next;
1201 begin
1202 while Curr /= null loop
1203 if Equivalent_Elements (E, Curr.Element) then
1204 Prev.Next := Curr.Next;
1205 N := N - 1;
1206 Free (Curr);
1207 return;
1208 end if;
1210 Prev := Curr;
1211 Curr := Prev.Next;
1212 end loop;
1214 B (J) := new Node_Type'(E, B (J));
1215 N := N + 1;
1216 end;
1217 end if;
1218 end Process;
1220 -- Start of processing for Iterate_Source
1222 begin
1223 Iterate (Source.HT);
1224 end Iterate_Source;
1225 end if;
1226 end Symmetric_Difference;
1228 function Symmetric_Difference (Left, Right : Set) return Set is
1229 Buckets : HT_Types.Buckets_Access;
1230 Length : Count_Type;
1232 begin
1233 if Left'Address = Right'Address then
1234 return Empty_Set;
1235 end if;
1237 if Right.Length = 0 then
1238 return Left;
1239 end if;
1241 if Left.Length = 0 then
1242 return Right;
1243 end if;
1245 declare
1246 Size : constant Hash_Type :=
1247 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1248 begin
1249 Buckets := HT_Ops.New_Buckets (Length => Size);
1250 end;
1252 Length := 0;
1254 Iterate_Left : declare
1255 procedure Process (L_Node : Node_Access);
1257 procedure Iterate is
1258 new HT_Ops.Generic_Iteration (Process);
1260 -------------
1261 -- Process --
1262 -------------
1264 procedure Process (L_Node : Node_Access) is
1265 begin
1266 if not Is_In (Right.HT, L_Node) then
1267 declare
1268 E : Element_Type renames L_Node.Element;
1269 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1271 begin
1272 Buckets (J) := new Node_Type'(E, Buckets (J));
1273 Length := Length + 1;
1274 end;
1275 end if;
1276 end Process;
1278 -- Start of processing for Iterate_Left
1280 begin
1281 Iterate (Left.HT);
1282 exception
1283 when others =>
1284 HT_Ops.Free_Hash_Table (Buckets);
1285 raise;
1286 end Iterate_Left;
1288 Iterate_Right : declare
1289 procedure Process (R_Node : Node_Access);
1291 procedure Iterate is
1292 new HT_Ops.Generic_Iteration (Process);
1294 -------------
1295 -- Process --
1296 -------------
1298 procedure Process (R_Node : Node_Access) is
1299 begin
1300 if not Is_In (Left.HT, R_Node) then
1301 declare
1302 E : Element_Type renames R_Node.Element;
1303 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1305 begin
1306 Buckets (J) := new Node_Type'(E, Buckets (J));
1307 Length := Length + 1;
1308 end;
1309 end if;
1310 end Process;
1312 -- Start of processing for Iterate_Right
1314 begin
1315 Iterate (Right.HT);
1316 exception
1317 when others =>
1318 HT_Ops.Free_Hash_Table (Buckets);
1319 raise;
1320 end Iterate_Right;
1322 return (Controlled with HT => (Buckets, Length, 0, 0));
1323 end Symmetric_Difference;
1325 ------------
1326 -- To_Set --
1327 ------------
1329 function To_Set (New_Item : Element_Type) return Set is
1330 HT : Hash_Table_Type;
1332 Node : Node_Access;
1333 Inserted : Boolean;
1334 pragma Unreferenced (Node, Inserted);
1336 begin
1337 Insert (HT, New_Item, Node, Inserted);
1338 return Set'(Controlled with HT);
1339 end To_Set;
1341 -----------
1342 -- Union --
1343 -----------
1345 procedure Union
1346 (Target : in out Set;
1347 Source : Set)
1349 procedure Process (Src_Node : Node_Access);
1351 procedure Iterate is
1352 new HT_Ops.Generic_Iteration (Process);
1354 -------------
1355 -- Process --
1356 -------------
1358 procedure Process (Src_Node : Node_Access) is
1359 function New_Node (Next : Node_Access) return Node_Access;
1360 pragma Inline (New_Node);
1362 procedure Insert is
1363 new Element_Keys.Generic_Conditional_Insert (New_Node);
1365 --------------
1366 -- New_Node --
1367 --------------
1369 function New_Node (Next : Node_Access) return Node_Access is
1370 Node : constant Node_Access :=
1371 new Node_Type'(Src_Node.Element, Next);
1372 begin
1373 return Node;
1374 end New_Node;
1376 Tgt_Node : Node_Access;
1377 Success : Boolean;
1378 pragma Unreferenced (Tgt_Node, Success);
1380 -- Start of processing for Process
1382 begin
1383 Insert (Target.HT, Src_Node.Element, Tgt_Node, Success);
1384 end Process;
1386 -- Start of processing for Union
1388 begin
1389 if Target'Address = Source'Address then
1390 return;
1391 end if;
1393 if Target.HT.Busy > 0 then
1394 raise Program_Error with
1395 "attempt to tamper with elements (set is busy)";
1396 end if;
1398 declare
1399 N : constant Count_Type := Target.Length + Source.Length;
1400 begin
1401 if N > HT_Ops.Capacity (Target.HT) then
1402 HT_Ops.Reserve_Capacity (Target.HT, N);
1403 end if;
1404 end;
1406 Iterate (Source.HT);
1407 end Union;
1409 function Union (Left, Right : Set) return Set is
1410 Buckets : HT_Types.Buckets_Access;
1411 Length : Count_Type;
1413 begin
1414 if Left'Address = Right'Address then
1415 return Left;
1416 end if;
1418 if Right.Length = 0 then
1419 return Left;
1420 end if;
1422 if Left.Length = 0 then
1423 return Right;
1424 end if;
1426 declare
1427 Size : constant Hash_Type :=
1428 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1429 begin
1430 Buckets := HT_Ops.New_Buckets (Length => Size);
1431 end;
1433 Iterate_Left : declare
1434 procedure Process (L_Node : Node_Access);
1436 procedure Iterate is
1437 new HT_Ops.Generic_Iteration (Process);
1439 -------------
1440 -- Process --
1441 -------------
1443 procedure Process (L_Node : Node_Access) is
1444 J : constant Hash_Type :=
1445 Hash (L_Node.Element) mod Buckets'Length;
1447 begin
1448 Buckets (J) := new Node_Type'(L_Node.Element, Buckets (J));
1449 end Process;
1451 -- Start of processing for Iterate_Left
1453 begin
1454 Iterate (Left.HT);
1455 exception
1456 when others =>
1457 HT_Ops.Free_Hash_Table (Buckets);
1458 raise;
1459 end Iterate_Left;
1461 Length := Left.Length;
1463 Iterate_Right : declare
1464 procedure Process (Src_Node : Node_Access);
1466 procedure Iterate is
1467 new HT_Ops.Generic_Iteration (Process);
1469 -------------
1470 -- Process --
1471 -------------
1473 procedure Process (Src_Node : Node_Access) is
1474 J : constant Hash_Type :=
1475 Hash (Src_Node.Element) mod Buckets'Length;
1477 Tgt_Node : Node_Access := Buckets (J);
1479 begin
1480 while Tgt_Node /= null loop
1481 if Equivalent_Elements (Src_Node.Element, Tgt_Node.Element) then
1482 return;
1483 end if;
1485 Tgt_Node := Next (Tgt_Node);
1486 end loop;
1488 Buckets (J) := new Node_Type'(Src_Node.Element, Buckets (J));
1489 Length := Length + 1;
1490 end Process;
1492 -- Start of processing for Iterate_Right
1494 begin
1495 Iterate (Right.HT);
1496 exception
1497 when others =>
1498 HT_Ops.Free_Hash_Table (Buckets);
1499 raise;
1500 end Iterate_Right;
1502 return (Controlled with HT => (Buckets, Length, 0, 0));
1503 end Union;
1505 ---------
1506 -- Vet --
1507 ---------
1509 function Vet (Position : Cursor) return Boolean is
1510 begin
1511 if Position.Node = null then
1512 return Position.Container = null;
1513 end if;
1515 if Position.Container = null then
1516 return False;
1517 end if;
1519 if Position.Node.Next = Position.Node then
1520 return False;
1521 end if;
1523 declare
1524 HT : Hash_Table_Type renames Position.Container.HT;
1525 X : Node_Access;
1527 begin
1528 if HT.Length = 0 then
1529 return False;
1530 end if;
1532 if HT.Buckets = null
1533 or else HT.Buckets'Length = 0
1534 then
1535 return False;
1536 end if;
1538 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element));
1540 for J in 1 .. HT.Length loop
1541 if X = Position.Node then
1542 return True;
1543 end if;
1545 if X = null then
1546 return False;
1547 end if;
1549 if X = X.Next then -- to prevent unnecessary looping
1550 return False;
1551 end if;
1553 X := X.Next;
1554 end loop;
1556 return False;
1557 end;
1558 end Vet;
1560 -----------
1561 -- Write --
1562 -----------
1564 procedure Write
1565 (Stream : not null access Root_Stream_Type'Class;
1566 Container : Set)
1568 begin
1569 Write_Nodes (Stream, Container.HT);
1570 end Write;
1572 procedure Write
1573 (Stream : not null access Root_Stream_Type'Class;
1574 Item : Cursor)
1576 begin
1577 raise Program_Error with "attempt to stream set cursor";
1578 end Write;
1580 ----------------
1581 -- Write_Node --
1582 ----------------
1584 procedure Write_Node
1585 (Stream : not null access Root_Stream_Type'Class;
1586 Node : Node_Access)
1588 begin
1589 Element_Type'Write (Stream, Node.Element);
1590 end Write_Node;
1592 package body Generic_Keys is
1594 -----------------------
1595 -- Local Subprograms --
1596 -----------------------
1598 function Equivalent_Key_Node
1599 (Key : Key_Type;
1600 Node : Node_Access) return Boolean;
1601 pragma Inline (Equivalent_Key_Node);
1603 --------------------------
1604 -- Local Instantiations --
1605 --------------------------
1607 package Key_Keys is
1608 new Hash_Tables.Generic_Keys
1609 (HT_Types => HT_Types,
1610 Next => Next,
1611 Set_Next => Set_Next,
1612 Key_Type => Key_Type,
1613 Hash => Hash,
1614 Equivalent_Keys => Equivalent_Key_Node);
1616 --------------
1617 -- Contains --
1618 --------------
1620 function Contains
1621 (Container : Set;
1622 Key : Key_Type) return Boolean
1624 begin
1625 return Find (Container, Key) /= No_Element;
1626 end Contains;
1628 ------------
1629 -- Delete --
1630 ------------
1632 procedure Delete
1633 (Container : in out Set;
1634 Key : Key_Type)
1636 X : Node_Access;
1638 begin
1639 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1641 if X = null then
1642 raise Constraint_Error with "attempt to delete key not in set";
1643 end if;
1645 Free (X);
1646 end Delete;
1648 -------------
1649 -- Element --
1650 -------------
1652 function Element
1653 (Container : Set;
1654 Key : Key_Type) return Element_Type
1656 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1658 begin
1659 if Node = null then
1660 raise Constraint_Error with "key not in map";
1661 end if;
1663 return Node.Element;
1664 end Element;
1666 -------------------------
1667 -- Equivalent_Key_Node --
1668 -------------------------
1670 function Equivalent_Key_Node
1671 (Key : Key_Type;
1672 Node : Node_Access) return Boolean
1674 begin
1675 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1676 end Equivalent_Key_Node;
1678 -------------
1679 -- Exclude --
1680 -------------
1682 procedure Exclude
1683 (Container : in out Set;
1684 Key : Key_Type)
1686 X : Node_Access;
1687 begin
1688 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1689 Free (X);
1690 end Exclude;
1692 ----------
1693 -- Find --
1694 ----------
1696 function Find
1697 (Container : Set;
1698 Key : Key_Type) return Cursor
1700 Node : constant Node_Access :=
1701 Key_Keys.Find (Container.HT, Key);
1703 begin
1704 if Node = null then
1705 return No_Element;
1706 end if;
1708 return Cursor'(Container'Unrestricted_Access, Node);
1709 end Find;
1711 ---------
1712 -- Key --
1713 ---------
1715 function Key (Position : Cursor) return Key_Type is
1716 begin
1717 if Position.Node = null then
1718 raise Constraint_Error with
1719 "Position cursor equals No_Element";
1720 end if;
1722 pragma Assert (Vet (Position), "bad cursor in function Key");
1724 return Key (Position.Node.Element);
1725 end Key;
1727 -------------
1728 -- Replace --
1729 -------------
1731 procedure Replace
1732 (Container : in out Set;
1733 Key : Key_Type;
1734 New_Item : Element_Type)
1736 Node : constant Node_Access :=
1737 Key_Keys.Find (Container.HT, Key);
1739 begin
1740 if Node = null then
1741 raise Constraint_Error with
1742 "attempt to replace key not in set";
1743 end if;
1745 Replace_Element (Container.HT, Node, New_Item);
1746 end Replace;
1748 -----------------------------------
1749 -- Update_Element_Preserving_Key --
1750 -----------------------------------
1752 procedure Update_Element_Preserving_Key
1753 (Container : in out Set;
1754 Position : Cursor;
1755 Process : not null access
1756 procedure (Element : in out Element_Type))
1758 HT : Hash_Table_Type renames Container.HT;
1759 Indx : Hash_Type;
1761 begin
1762 if Position.Node = null then
1763 raise Constraint_Error with
1764 "Position cursor equals No_Element";
1765 end if;
1767 if Position.Container /= Container'Unrestricted_Access then
1768 raise Program_Error with
1769 "Position cursor designates wrong set";
1770 end if;
1772 if HT.Buckets = null
1773 or else HT.Buckets'Length = 0
1774 or else HT.Length = 0
1775 or else Position.Node.Next = Position.Node
1776 then
1777 raise Program_Error with "Position cursor is bad (set is empty)";
1778 end if;
1780 pragma Assert
1781 (Vet (Position),
1782 "bad cursor in Update_Element_Preserving_Key");
1784 Indx := HT_Ops.Index (HT, Position.Node);
1786 declare
1787 E : Element_Type renames Position.Node.Element;
1788 K : constant Key_Type := Key (E);
1790 B : Natural renames HT.Busy;
1791 L : Natural renames HT.Lock;
1793 begin
1794 B := B + 1;
1795 L := L + 1;
1797 begin
1798 Process (E);
1799 exception
1800 when others =>
1801 L := L - 1;
1802 B := B - 1;
1803 raise;
1804 end;
1806 L := L - 1;
1807 B := B - 1;
1809 if Equivalent_Keys (K, Key (E)) then
1810 pragma Assert (Hash (K) = Hash (E));
1811 return;
1812 end if;
1813 end;
1815 if HT.Buckets (Indx) = Position.Node then
1816 HT.Buckets (Indx) := Position.Node.Next;
1818 else
1819 declare
1820 Prev : Node_Access := HT.Buckets (Indx);
1822 begin
1823 while Prev.Next /= Position.Node loop
1824 Prev := Prev.Next;
1826 if Prev = null then
1827 raise Program_Error with
1828 "Position cursor is bad (node not found)";
1829 end if;
1830 end loop;
1832 Prev.Next := Position.Node.Next;
1833 end;
1834 end if;
1836 HT.Length := HT.Length - 1;
1838 declare
1839 X : Node_Access := Position.Node;
1841 begin
1842 Free (X);
1843 end;
1845 raise Program_Error with "key was modified";
1846 end Update_Element_Preserving_Key;
1848 end Generic_Keys;
1850 end Ada.Containers.Hashed_Sets;