Merge form mainline (hopefully)
[official-gcc.git] / gcc / ada / a-cohase.adb
blob05a2416c7b5af4e829890a4da53ef66886130007
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-2005 Free Software Foundation, Inc. --
10 -- --
11 -- This specification is derived from the Ada Reference Manual for use with --
12 -- GNAT. The copyright notice above, and the license provisions that follow --
13 -- apply solely to the contents of the part following the private keyword. --
14 -- --
15 -- GNAT is free software; you can redistribute it and/or modify it under --
16 -- terms of the GNU General Public License as published by the Free Soft- --
17 -- ware Foundation; either version 2, or (at your option) any later ver- --
18 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
19 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
20 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
21 -- for more details. You should have received a copy of the GNU General --
22 -- Public License distributed with GNAT; see file COPYING. If not, write --
23 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
24 -- Boston, MA 02110-1301, USA. --
25 -- --
26 -- As a special exception, if other files instantiate generics from this --
27 -- unit, or you link this unit with other files to produce an executable, --
28 -- this unit does not by itself cause the resulting executable to be --
29 -- covered by the GNU General Public License. This exception does not --
30 -- however invalidate any other reasons why the executable file might be --
31 -- covered by the GNU Public License. --
32 -- --
33 -- This unit has originally being developed by Matthew J Heaney. --
34 ------------------------------------------------------------------------------
36 with Ada.Unchecked_Deallocation;
38 with Ada.Containers.Hash_Tables.Generic_Operations;
39 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
41 with Ada.Containers.Hash_Tables.Generic_Keys;
42 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
44 with Ada.Containers.Prime_Numbers;
46 with System; use type System.Address;
48 package body Ada.Containers.Hashed_Sets is
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
54 function Copy_Node (Source : Node_Access) return Node_Access;
55 pragma Inline (Copy_Node);
57 function Equivalent_Keys
58 (Key : Element_Type;
59 Node : Node_Access) return Boolean;
60 pragma Inline (Equivalent_Keys);
62 function Find_Equal_Key
63 (R_HT : Hash_Table_Type;
64 L_Node : Node_Access) return Boolean;
66 function Find_Equivalent_Key
67 (R_HT : Hash_Table_Type;
68 L_Node : Node_Access) return Boolean;
70 procedure Free (X : in out Node_Access);
72 function Hash_Node (Node : Node_Access) return Hash_Type;
73 pragma Inline (Hash_Node);
75 function Is_In
76 (HT : Hash_Table_Type;
77 Key : Node_Access) return Boolean;
78 pragma Inline (Is_In);
80 function Next (Node : Node_Access) return Node_Access;
81 pragma Inline (Next);
83 function Read_Node (Stream : access Root_Stream_Type'Class)
84 return Node_Access;
85 pragma Inline (Read_Node);
87 procedure Replace_Element
88 (HT : in out Hash_Table_Type;
89 Node : Node_Access;
90 New_Item : Element_Type);
92 procedure Set_Next (Node : Node_Access; Next : Node_Access);
93 pragma Inline (Set_Next);
95 function Vet (Position : Cursor) return Boolean;
97 procedure Write_Node
98 (Stream : access Root_Stream_Type'Class;
99 Node : Node_Access);
100 pragma Inline (Write_Node);
102 --------------------------
103 -- Local Instantiations --
104 --------------------------
106 package HT_Ops is
107 new Hash_Tables.Generic_Operations
108 (HT_Types => HT_Types,
109 Hash_Node => Hash_Node,
110 Next => Next,
111 Set_Next => Set_Next,
112 Copy_Node => Copy_Node,
113 Free => Free);
115 package Element_Keys is
116 new Hash_Tables.Generic_Keys
117 (HT_Types => HT_Types,
118 Next => Next,
119 Set_Next => Set_Next,
120 Key_Type => Element_Type,
121 Hash => Hash,
122 Equivalent_Keys => Equivalent_Keys);
124 function Is_Equal is
125 new HT_Ops.Generic_Equal (Find_Equal_Key);
127 function Is_Equivalent is
128 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
130 procedure Read_Nodes is
131 new HT_Ops.Generic_Read (Read_Node);
133 procedure Write_Nodes is
134 new HT_Ops.Generic_Write (Write_Node);
136 ---------
137 -- "=" --
138 ---------
140 function "=" (Left, Right : Set) return Boolean is
141 begin
142 return Is_Equal (Left.HT, Right.HT);
143 end "=";
145 ------------
146 -- Adjust --
147 ------------
149 procedure Adjust (Container : in out Set) is
150 begin
151 HT_Ops.Adjust (Container.HT);
152 end Adjust;
154 --------------
155 -- Capacity --
156 --------------
158 function Capacity (Container : Set) return Count_Type is
159 begin
160 return HT_Ops.Capacity (Container.HT);
161 end Capacity;
163 -----------
164 -- Clear --
165 -----------
167 procedure Clear (Container : in out Set) is
168 begin
169 HT_Ops.Clear (Container.HT);
170 end Clear;
172 --------------
173 -- Contains --
174 --------------
176 function Contains (Container : Set; Item : Element_Type) return Boolean is
177 begin
178 return Find (Container, Item) /= No_Element;
179 end Contains;
181 ---------------
182 -- Copy_Node --
183 ---------------
185 function Copy_Node (Source : Node_Access) return Node_Access is
186 begin
187 return new Node_Type'(Element => Source.Element, Next => null);
188 end Copy_Node;
190 ------------
191 -- Delete --
192 ------------
194 procedure Delete
195 (Container : in out Set;
196 Item : Element_Type)
198 X : Node_Access;
200 begin
201 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
203 if X = null then
204 raise Constraint_Error;
205 end if;
207 Free (X);
208 end Delete;
210 procedure Delete
211 (Container : in out Set;
212 Position : in out Cursor)
214 begin
215 pragma Assert (Vet (Position), "bad cursor in Delete");
217 if Position.Node = null then
218 raise Constraint_Error;
219 end if;
221 if Position.Container /= Container'Unrestricted_Access then
222 raise Program_Error;
223 end if;
225 if Container.HT.Busy > 0 then
226 raise Program_Error;
227 end if;
229 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
231 Free (Position.Node);
232 Position.Container := null;
233 end Delete;
235 ----------------
236 -- Difference --
237 ----------------
239 procedure Difference
240 (Target : in out Set;
241 Source : Set)
243 Tgt_Node : Node_Access;
245 begin
246 if Target'Address = Source'Address then
247 Clear (Target);
248 return;
249 end if;
251 if Source.Length = 0 then
252 return;
253 end if;
255 if Target.HT.Busy > 0 then
256 raise Program_Error;
257 end if;
259 -- TODO: This can be written in terms of a loop instead as
260 -- active-iterator style, sort of like a passive iterator.
262 Tgt_Node := HT_Ops.First (Target.HT);
263 while Tgt_Node /= null loop
264 if Is_In (Source.HT, Tgt_Node) then
265 declare
266 X : Node_Access := Tgt_Node;
267 begin
268 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
269 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
270 Free (X);
271 end;
273 else
274 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
275 end if;
276 end loop;
277 end Difference;
279 function Difference (Left, Right : Set) return Set is
280 Buckets : HT_Types.Buckets_Access;
281 Length : Count_Type;
283 begin
284 if Left'Address = Right'Address then
285 return Empty_Set;
286 end if;
288 if Left.Length = 0 then
289 return Empty_Set;
290 end if;
292 if Right.Length = 0 then
293 return Left;
294 end if;
296 declare
297 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
298 begin
299 Buckets := new Buckets_Type (0 .. Size - 1);
300 end;
302 Length := 0;
304 Iterate_Left : declare
305 procedure Process (L_Node : Node_Access);
307 procedure Iterate is
308 new HT_Ops.Generic_Iteration (Process);
310 -------------
311 -- Process --
312 -------------
314 procedure Process (L_Node : Node_Access) is
315 begin
316 if not Is_In (Right.HT, L_Node) then
317 declare
318 J : constant Hash_Type :=
319 Hash (L_Node.Element) mod Buckets'Length;
321 Bucket : Node_Access renames Buckets (J);
323 begin
324 Bucket := new Node_Type'(L_Node.Element, Bucket);
325 end;
327 Length := Length + 1;
328 end if;
329 end Process;
331 -- Start of processing for Iterate_Left
333 begin
334 Iterate (Left.HT);
335 exception
336 when others =>
337 HT_Ops.Free_Hash_Table (Buckets);
338 raise;
339 end Iterate_Left;
341 return (Controlled with HT => (Buckets, Length, 0, 0));
342 end Difference;
344 -------------
345 -- Element --
346 -------------
348 function Element (Position : Cursor) return Element_Type is
349 begin
350 pragma Assert (Vet (Position), "bad cursor in function Element");
352 if Position.Node = null then
353 raise Constraint_Error;
354 end if;
356 return Position.Node.Element;
357 end Element;
359 ---------------------
360 -- Equivalent_Sets --
361 ---------------------
363 function Equivalent_Sets (Left, Right : Set) return Boolean is
364 begin
365 return Is_Equivalent (Left.HT, Right.HT);
366 end Equivalent_Sets;
368 -------------------------
369 -- Equivalent_Elements --
370 -------------------------
372 function Equivalent_Elements (Left, Right : Cursor)
373 return Boolean is
374 begin
375 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
376 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
378 if Left.Node = null
379 or else Right.Node = null
380 then
381 raise Constraint_Error;
382 end if;
384 return Equivalent_Elements (Left.Node.Element, Right.Node.Element);
385 end Equivalent_Elements;
387 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
388 return Boolean is
389 begin
390 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
392 if Left.Node = null then
393 raise Constraint_Error;
394 end if;
396 return Equivalent_Elements (Left.Node.Element, Right);
397 end Equivalent_Elements;
399 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
400 return Boolean is
401 begin
402 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
404 if Right.Node = null then
405 raise Constraint_Error;
406 end if;
408 return Equivalent_Elements (Left, Right.Node.Element);
409 end Equivalent_Elements;
411 ---------------------
412 -- Equivalent_Keys --
413 ---------------------
415 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
416 return Boolean is
417 begin
418 return Equivalent_Elements (Key, Node.Element);
419 end Equivalent_Keys;
421 -------------
422 -- Exclude --
423 -------------
425 procedure Exclude
426 (Container : in out Set;
427 Item : Element_Type)
429 X : Node_Access;
430 begin
431 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
432 Free (X);
433 end Exclude;
435 --------------
436 -- Finalize --
437 --------------
439 procedure Finalize (Container : in out Set) is
440 begin
441 HT_Ops.Finalize (Container.HT);
442 end Finalize;
444 ----------
445 -- Find --
446 ----------
448 function Find
449 (Container : Set;
450 Item : Element_Type) return Cursor
452 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
454 begin
455 if Node = null then
456 return No_Element;
457 end if;
459 return Cursor'(Container'Unrestricted_Access, Node);
460 end Find;
462 --------------------
463 -- Find_Equal_Key --
464 --------------------
466 function Find_Equal_Key
467 (R_HT : Hash_Table_Type;
468 L_Node : Node_Access) return Boolean
470 R_Index : constant Hash_Type :=
471 Element_Keys.Index (R_HT, L_Node.Element);
473 R_Node : Node_Access := R_HT.Buckets (R_Index);
475 begin
476 loop
477 if R_Node = null then
478 return False;
479 end if;
481 if L_Node.Element = R_Node.Element then
482 return True;
483 end if;
485 R_Node := Next (R_Node);
486 end loop;
487 end Find_Equal_Key;
489 -------------------------
490 -- Find_Equivalent_Key --
491 -------------------------
493 function Find_Equivalent_Key
494 (R_HT : Hash_Table_Type;
495 L_Node : Node_Access) return Boolean
497 R_Index : constant Hash_Type :=
498 Element_Keys.Index (R_HT, L_Node.Element);
500 R_Node : Node_Access := R_HT.Buckets (R_Index);
502 begin
503 loop
504 if R_Node = null then
505 return False;
506 end if;
508 if Equivalent_Elements (L_Node.Element, R_Node.Element) then
509 return True;
510 end if;
512 R_Node := Next (R_Node);
513 end loop;
514 end Find_Equivalent_Key;
516 -----------
517 -- First --
518 -----------
520 function First (Container : Set) return Cursor is
521 Node : constant Node_Access := HT_Ops.First (Container.HT);
523 begin
524 if Node = null then
525 return No_Element;
526 end if;
528 return Cursor'(Container'Unrestricted_Access, Node);
529 end First;
531 ----------
532 -- Free --
533 ----------
535 procedure Free (X : in out Node_Access) is
536 procedure Deallocate is
537 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
539 begin
540 if X /= null then
541 X.Next := X; -- detect mischief (in Vet)
542 Deallocate (X);
543 end if;
544 end Free;
546 -----------------
547 -- Has_Element --
548 -----------------
550 function Has_Element (Position : Cursor) return Boolean is
551 begin
552 pragma Assert (Vet (Position), "bad cursor in Has_Element");
553 return Position.Node /= null;
554 end Has_Element;
556 ---------------
557 -- Hash_Node --
558 ---------------
560 function Hash_Node (Node : Node_Access) return Hash_Type is
561 begin
562 return Hash (Node.Element);
563 end Hash_Node;
565 -------------
566 -- Include --
567 -------------
569 procedure Include
570 (Container : in out Set;
571 New_Item : Element_Type)
573 Position : Cursor;
574 Inserted : Boolean;
576 begin
577 Insert (Container, New_Item, Position, Inserted);
579 if not Inserted then
580 if Container.HT.Lock > 0 then
581 raise Program_Error;
582 end if;
584 Position.Node.Element := New_Item;
585 end if;
586 end Include;
588 ------------
589 -- Insert --
590 ------------
592 procedure Insert
593 (Container : in out Set;
594 New_Item : Element_Type;
595 Position : out Cursor;
596 Inserted : out Boolean)
598 function New_Node (Next : Node_Access) return Node_Access;
599 pragma Inline (New_Node);
601 procedure Local_Insert is
602 new Element_Keys.Generic_Conditional_Insert (New_Node);
604 --------------
605 -- New_Node --
606 --------------
608 function New_Node (Next : Node_Access) return Node_Access is
609 Node : constant Node_Access := new Node_Type'(New_Item, Next);
610 begin
611 return Node;
612 end New_Node;
614 HT : Hash_Table_Type renames Container.HT;
616 -- Start of processing for Insert
618 begin
619 if HT_Ops.Capacity (HT) = 0 then
620 HT_Ops.Reserve_Capacity (HT, 1);
621 end if;
623 Local_Insert (HT, New_Item, Position.Node, Inserted);
625 if Inserted
626 and then HT.Length > HT_Ops.Capacity (HT)
627 then
628 HT_Ops.Reserve_Capacity (HT, HT.Length);
629 end if;
631 Position.Container := Container'Unchecked_Access;
632 end Insert;
634 procedure Insert
635 (Container : in out Set;
636 New_Item : Element_Type)
638 Position : Cursor;
639 Inserted : Boolean;
641 begin
642 Insert (Container, New_Item, Position, Inserted);
644 if not Inserted then
645 raise Constraint_Error;
646 end if;
647 end Insert;
649 ------------------
650 -- Intersection --
651 ------------------
653 procedure Intersection
654 (Target : in out Set;
655 Source : Set)
657 Tgt_Node : Node_Access;
659 begin
660 if Target'Address = Source'Address then
661 return;
662 end if;
664 if Source.Length = 0 then
665 Clear (Target);
666 return;
667 end if;
669 if Target.HT.Busy > 0 then
670 raise Program_Error;
671 end if;
673 -- TODO: optimize this to use an explicit
674 -- loop instead of an active iterator
675 -- (similar to how a passive iterator is
676 -- implemented).
678 -- Another possibility is to test which
679 -- set is smaller, and iterate over the
680 -- smaller set.
682 Tgt_Node := HT_Ops.First (Target.HT);
683 while Tgt_Node /= null loop
684 if Is_In (Source.HT, Tgt_Node) then
685 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
687 else
688 declare
689 X : Node_Access := Tgt_Node;
690 begin
691 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
692 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
693 Free (X);
694 end;
695 end if;
696 end loop;
697 end Intersection;
699 function Intersection (Left, Right : Set) return Set is
700 Buckets : HT_Types.Buckets_Access;
701 Length : Count_Type;
703 begin
704 if Left'Address = Right'Address then
705 return Left;
706 end if;
708 Length := Count_Type'Min (Left.Length, Right.Length);
710 if Length = 0 then
711 return Empty_Set;
712 end if;
714 declare
715 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
716 begin
717 Buckets := new Buckets_Type (0 .. Size - 1);
718 end;
720 Length := 0;
722 Iterate_Left : declare
723 procedure Process (L_Node : Node_Access);
725 procedure Iterate is
726 new HT_Ops.Generic_Iteration (Process);
728 -------------
729 -- Process --
730 -------------
732 procedure Process (L_Node : Node_Access) is
733 begin
734 if Is_In (Right.HT, L_Node) then
735 declare
736 J : constant Hash_Type :=
737 Hash (L_Node.Element) mod Buckets'Length;
739 Bucket : Node_Access renames Buckets (J);
741 begin
742 Bucket := new Node_Type'(L_Node.Element, Bucket);
743 end;
745 Length := Length + 1;
746 end if;
747 end Process;
749 -- Start of processing for Iterate_Left
751 begin
752 Iterate (Left.HT);
753 exception
754 when others =>
755 HT_Ops.Free_Hash_Table (Buckets);
756 raise;
757 end Iterate_Left;
759 return (Controlled with HT => (Buckets, Length, 0, 0));
760 end Intersection;
762 --------------
763 -- Is_Empty --
764 --------------
766 function Is_Empty (Container : Set) return Boolean is
767 begin
768 return Container.HT.Length = 0;
769 end Is_Empty;
771 -----------
772 -- Is_In --
773 -----------
775 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
776 begin
777 return Element_Keys.Find (HT, Key.Element) /= null;
778 end Is_In;
780 ---------------
781 -- Is_Subset --
782 ---------------
784 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
785 Subset_Node : Node_Access;
787 begin
788 if Subset'Address = Of_Set'Address then
789 return True;
790 end if;
792 if Subset.Length > Of_Set.Length then
793 return False;
794 end if;
796 -- TODO: rewrite this to loop in the
797 -- style of a passive iterator.
799 Subset_Node := HT_Ops.First (Subset.HT);
800 while Subset_Node /= null loop
801 if not Is_In (Of_Set.HT, Subset_Node) then
802 return False;
803 end if;
804 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
805 end loop;
807 return True;
808 end Is_Subset;
810 -------------
811 -- Iterate --
812 -------------
814 procedure Iterate
815 (Container : Set;
816 Process : not null access procedure (Position : Cursor))
818 procedure Process_Node (Node : Node_Access);
819 pragma Inline (Process_Node);
821 procedure Iterate is
822 new HT_Ops.Generic_Iteration (Process_Node);
824 ------------------
825 -- Process_Node --
826 ------------------
828 procedure Process_Node (Node : Node_Access) is
829 begin
830 Process (Cursor'(Container'Unrestricted_Access, Node));
831 end Process_Node;
833 -- Start of processing for Iterate
835 begin
836 -- TODO: resolve whether HT_Ops.Generic_Iteration should
837 -- manipulate busy bit.
839 Iterate (Container.HT);
840 end Iterate;
842 ------------
843 -- Length --
844 ------------
846 function Length (Container : Set) return Count_Type is
847 begin
848 return Container.HT.Length;
849 end Length;
851 ----------
852 -- Move --
853 ----------
855 procedure Move (Target : in out Set; Source : in out Set) is
856 begin
857 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
858 end Move;
860 ----------
861 -- Next --
862 ----------
864 function Next (Node : Node_Access) return Node_Access is
865 begin
866 return Node.Next;
867 end Next;
869 function Next (Position : Cursor) return Cursor is
870 begin
871 pragma Assert (Vet (Position), "bad cursor in function Next");
873 if Position.Node = null then
874 return No_Element;
875 end if;
877 declare
878 HT : Hash_Table_Type renames Position.Container.HT;
879 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
881 begin
882 if Node = null then
883 return No_Element;
884 end if;
886 return Cursor'(Position.Container, Node);
887 end;
888 end Next;
890 procedure Next (Position : in out Cursor) is
891 begin
892 Position := Next (Position);
893 end Next;
895 -------------
896 -- Overlap --
897 -------------
899 function Overlap (Left, Right : Set) return Boolean is
900 Left_Node : Node_Access;
902 begin
903 if Right.Length = 0 then
904 return False;
905 end if;
907 if Left'Address = Right'Address then
908 return True;
909 end if;
911 Left_Node := HT_Ops.First (Left.HT);
912 while Left_Node /= null loop
913 if Is_In (Right.HT, Left_Node) then
914 return True;
915 end if;
916 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
917 end loop;
919 return False;
920 end Overlap;
922 -------------------
923 -- Query_Element --
924 -------------------
926 procedure Query_Element
927 (Position : Cursor;
928 Process : not null access procedure (Element : Element_Type))
930 begin
931 pragma Assert (Vet (Position), "bad cursor in Query_Element");
933 if Position.Node = null then
934 raise Constraint_Error;
935 end if;
937 declare
938 HT : Hash_Table_Type renames Position.Container.HT;
940 B : Natural renames HT.Busy;
941 L : Natural renames HT.Lock;
943 begin
944 B := B + 1;
945 L := L + 1;
947 begin
948 Process (Position.Node.Element);
949 exception
950 when others =>
951 L := L - 1;
952 B := B - 1;
953 raise;
954 end;
956 L := L - 1;
957 B := B - 1;
958 end;
959 end Query_Element;
961 ----------
962 -- Read --
963 ----------
965 procedure Read
966 (Stream : access Root_Stream_Type'Class;
967 Container : out Set)
969 begin
970 Read_Nodes (Stream, Container.HT);
971 end Read;
973 ---------------
974 -- Read_Node --
975 ---------------
977 function Read_Node (Stream : access Root_Stream_Type'Class)
978 return Node_Access
980 Node : Node_Access := new Node_Type;
982 begin
983 Element_Type'Read (Stream, Node.Element);
984 return Node;
985 exception
986 when others =>
987 Free (Node);
988 raise;
989 end Read_Node;
991 -------------
992 -- Replace --
993 -------------
995 procedure Replace
996 (Container : in out Set;
997 New_Item : Element_Type)
999 Node : constant Node_Access :=
1000 Element_Keys.Find (Container.HT, New_Item);
1002 begin
1003 if Node = null then
1004 raise Constraint_Error;
1005 end if;
1007 if Container.HT.Lock > 0 then
1008 raise Program_Error;
1009 end if;
1011 Node.Element := New_Item;
1012 end Replace;
1014 ---------------------
1015 -- Replace_Element --
1016 ---------------------
1018 procedure Replace_Element
1019 (HT : in out Hash_Table_Type;
1020 Node : Node_Access;
1021 New_Item : Element_Type)
1023 begin
1024 if Equivalent_Elements (Node.Element, New_Item) then
1025 pragma Assert (Hash (Node.Element) = Hash (New_Item));
1027 if HT.Lock > 0 then
1028 raise Program_Error;
1029 end if;
1031 Node.Element := New_Item; -- Note that this assignment can fail
1032 return;
1033 end if;
1035 if HT.Busy > 0 then
1036 raise Program_Error;
1037 end if;
1039 HT_Ops.Delete_Node_Sans_Free (HT, Node);
1041 Insert_New_Element : declare
1042 function New_Node (Next : Node_Access) return Node_Access;
1043 pragma Inline (New_Node);
1045 procedure Local_Insert is
1046 new Element_Keys.Generic_Conditional_Insert (New_Node);
1048 --------------
1049 -- New_Node --
1050 --------------
1052 function New_Node (Next : Node_Access) return Node_Access is
1053 begin
1054 Node.Element := New_Item; -- Note that this assignment can fail
1055 Node.Next := Next;
1056 return Node;
1057 end New_Node;
1059 Result : Node_Access;
1060 Inserted : Boolean;
1062 -- Start of processing for Insert_New_Element
1064 begin
1065 Local_Insert
1066 (HT => HT,
1067 Key => New_Item,
1068 Node => Result,
1069 Inserted => Inserted);
1071 if Inserted then
1072 return;
1073 end if;
1074 exception
1075 when others =>
1076 null; -- Assignment must have failed
1077 end Insert_New_Element;
1079 Reinsert_Old_Element : declare
1080 function New_Node (Next : Node_Access) return Node_Access;
1081 pragma Inline (New_Node);
1083 procedure Local_Insert is
1084 new Element_Keys.Generic_Conditional_Insert (New_Node);
1086 --------------
1087 -- New_Node --
1088 --------------
1090 function New_Node (Next : Node_Access) return Node_Access is
1091 begin
1092 Node.Next := Next;
1093 return Node;
1094 end New_Node;
1096 Result : Node_Access;
1097 Inserted : Boolean;
1099 -- Start of processing for Reinsert_Old_Element
1101 begin
1102 Local_Insert
1103 (HT => HT,
1104 Key => Node.Element,
1105 Node => Result,
1106 Inserted => Inserted);
1107 exception
1108 when others =>
1109 null;
1110 end Reinsert_Old_Element;
1112 raise Program_Error;
1113 end Replace_Element;
1115 procedure Replace_Element
1116 (Container : in out Set;
1117 Position : Cursor;
1118 New_Item : Element_Type)
1120 begin
1121 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1123 if Position.Node = null then
1124 raise Constraint_Error;
1125 end if;
1127 if Position.Container /= Container'Unrestricted_Access then
1128 raise Program_Error;
1129 end if;
1131 Replace_Element (Container.HT, Position.Node, New_Item);
1132 end Replace_Element;
1134 ----------------------
1135 -- Reserve_Capacity --
1136 ----------------------
1138 procedure Reserve_Capacity
1139 (Container : in out Set;
1140 Capacity : Count_Type)
1142 begin
1143 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1144 end Reserve_Capacity;
1146 --------------
1147 -- Set_Next --
1148 --------------
1150 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1151 begin
1152 Node.Next := Next;
1153 end Set_Next;
1155 --------------------------
1156 -- Symmetric_Difference --
1157 --------------------------
1159 procedure Symmetric_Difference
1160 (Target : in out Set;
1161 Source : Set)
1163 begin
1164 if Target'Address = Source'Address then
1165 Clear (Target);
1166 return;
1167 end if;
1169 if Target.HT.Busy > 0 then
1170 raise Program_Error;
1171 end if;
1173 declare
1174 N : constant Count_Type := Target.Length + Source.Length;
1175 begin
1176 if N > HT_Ops.Capacity (Target.HT) then
1177 HT_Ops.Reserve_Capacity (Target.HT, N);
1178 end if;
1179 end;
1181 if Target.Length = 0 then
1182 Iterate_Source_When_Empty_Target : declare
1183 procedure Process (Src_Node : Node_Access);
1185 procedure Iterate is
1186 new HT_Ops.Generic_Iteration (Process);
1188 -------------
1189 -- Process --
1190 -------------
1192 procedure Process (Src_Node : Node_Access) is
1193 E : Element_Type renames Src_Node.Element;
1194 B : Buckets_Type renames Target.HT.Buckets.all;
1195 J : constant Hash_Type := Hash (E) mod B'Length;
1196 N : Count_Type renames Target.HT.Length;
1198 begin
1199 B (J) := new Node_Type'(E, B (J));
1200 N := N + 1;
1201 end Process;
1203 -- Start of processing for Iterate_Source_When_Empty_Target
1205 begin
1206 Iterate (Source.HT);
1207 end Iterate_Source_When_Empty_Target;
1209 else
1210 Iterate_Source : declare
1211 procedure Process (Src_Node : Node_Access);
1213 procedure Iterate is
1214 new HT_Ops.Generic_Iteration (Process);
1216 -------------
1217 -- Process --
1218 -------------
1220 procedure Process (Src_Node : Node_Access) is
1221 E : Element_Type renames Src_Node.Element;
1222 B : Buckets_Type renames Target.HT.Buckets.all;
1223 J : constant Hash_Type := Hash (E) mod B'Length;
1224 N : Count_Type renames Target.HT.Length;
1226 begin
1227 if B (J) = null then
1228 B (J) := new Node_Type'(E, null);
1229 N := N + 1;
1231 elsif Equivalent_Elements (E, B (J).Element) then
1232 declare
1233 X : Node_Access := B (J);
1234 begin
1235 B (J) := B (J).Next;
1236 N := N - 1;
1237 Free (X);
1238 end;
1240 else
1241 declare
1242 Prev : Node_Access := B (J);
1243 Curr : Node_Access := Prev.Next;
1245 begin
1246 while Curr /= null loop
1247 if Equivalent_Elements (E, Curr.Element) then
1248 Prev.Next := Curr.Next;
1249 N := N - 1;
1250 Free (Curr);
1251 return;
1252 end if;
1254 Prev := Curr;
1255 Curr := Prev.Next;
1256 end loop;
1258 B (J) := new Node_Type'(E, B (J));
1259 N := N + 1;
1260 end;
1261 end if;
1262 end Process;
1264 -- Start of processing for Iterate_Source
1266 begin
1267 Iterate (Source.HT);
1268 end Iterate_Source;
1269 end if;
1270 end Symmetric_Difference;
1272 function Symmetric_Difference (Left, Right : Set) return Set is
1273 Buckets : HT_Types.Buckets_Access;
1274 Length : Count_Type;
1276 begin
1277 if Left'Address = Right'Address then
1278 return Empty_Set;
1279 end if;
1281 if Right.Length = 0 then
1282 return Left;
1283 end if;
1285 if Left.Length = 0 then
1286 return Right;
1287 end if;
1289 declare
1290 Size : constant Hash_Type :=
1291 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1292 begin
1293 Buckets := new Buckets_Type (0 .. Size - 1);
1294 end;
1296 Length := 0;
1298 Iterate_Left : declare
1299 procedure Process (L_Node : Node_Access);
1301 procedure Iterate is
1302 new HT_Ops.Generic_Iteration (Process);
1304 -------------
1305 -- Process --
1306 -------------
1308 procedure Process (L_Node : Node_Access) is
1309 begin
1310 if not Is_In (Right.HT, L_Node) then
1311 declare
1312 E : Element_Type renames L_Node.Element;
1313 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1315 begin
1316 Buckets (J) := new Node_Type'(E, Buckets (J));
1317 Length := Length + 1;
1318 end;
1319 end if;
1320 end Process;
1322 -- Start of processing for Iterate_Left
1324 begin
1325 Iterate (Left.HT);
1326 exception
1327 when others =>
1328 HT_Ops.Free_Hash_Table (Buckets);
1329 raise;
1330 end Iterate_Left;
1332 Iterate_Right : declare
1333 procedure Process (R_Node : Node_Access);
1335 procedure Iterate is
1336 new HT_Ops.Generic_Iteration (Process);
1338 -------------
1339 -- Process --
1340 -------------
1342 procedure Process (R_Node : Node_Access) is
1343 begin
1344 if not Is_In (Left.HT, R_Node) then
1345 declare
1346 E : Element_Type renames R_Node.Element;
1347 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1349 begin
1350 Buckets (J) := new Node_Type'(E, Buckets (J));
1351 Length := Length + 1;
1352 end;
1353 end if;
1354 end Process;
1356 -- Start of processing for Iterate_Right
1358 begin
1359 Iterate (Right.HT);
1360 exception
1361 when others =>
1362 HT_Ops.Free_Hash_Table (Buckets);
1363 raise;
1364 end Iterate_Right;
1366 return (Controlled with HT => (Buckets, Length, 0, 0));
1367 end Symmetric_Difference;
1369 -----------
1370 -- Union --
1371 -----------
1373 procedure Union
1374 (Target : in out Set;
1375 Source : Set)
1377 procedure Process (Src_Node : Node_Access);
1379 procedure Iterate is
1380 new HT_Ops.Generic_Iteration (Process);
1382 -------------
1383 -- Process --
1384 -------------
1386 procedure Process (Src_Node : Node_Access) is
1387 function New_Node (Next : Node_Access) return Node_Access;
1388 pragma Inline (New_Node);
1390 procedure Insert is
1391 new Element_Keys.Generic_Conditional_Insert (New_Node);
1393 --------------
1394 -- New_Node --
1395 --------------
1397 function New_Node (Next : Node_Access) return Node_Access is
1398 Node : constant Node_Access :=
1399 new Node_Type'(Src_Node.Element, Next);
1400 begin
1401 return Node;
1402 end New_Node;
1404 Tgt_Node : Node_Access;
1405 Success : Boolean;
1407 -- Start of processing for Process
1409 begin
1410 Insert (Target.HT, Src_Node.Element, Tgt_Node, Success);
1411 end Process;
1413 -- Start of processing for Union
1415 begin
1416 if Target'Address = Source'Address then
1417 return;
1418 end if;
1420 if Target.HT.Busy > 0 then
1421 raise Program_Error;
1422 end if;
1424 declare
1425 N : constant Count_Type := Target.Length + Source.Length;
1426 begin
1427 if N > HT_Ops.Capacity (Target.HT) then
1428 HT_Ops.Reserve_Capacity (Target.HT, N);
1429 end if;
1430 end;
1432 Iterate (Source.HT);
1433 end Union;
1435 function Union (Left, Right : Set) return Set is
1436 Buckets : HT_Types.Buckets_Access;
1437 Length : Count_Type;
1439 begin
1440 if Left'Address = Right'Address then
1441 return Left;
1442 end if;
1444 if Right.Length = 0 then
1445 return Left;
1446 end if;
1448 if Left.Length = 0 then
1449 return Right;
1450 end if;
1452 declare
1453 Size : constant Hash_Type :=
1454 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1455 begin
1456 Buckets := new Buckets_Type (0 .. Size - 1);
1457 end;
1459 Iterate_Left : declare
1460 procedure Process (L_Node : Node_Access);
1462 procedure Iterate is
1463 new HT_Ops.Generic_Iteration (Process);
1465 -------------
1466 -- Process --
1467 -------------
1469 procedure Process (L_Node : Node_Access) is
1470 J : constant Hash_Type :=
1471 Hash (L_Node.Element) mod Buckets'Length;
1473 begin
1474 Buckets (J) := new Node_Type'(L_Node.Element, Buckets (J));
1475 end Process;
1477 -- Start of processing for Iterate_Left
1479 begin
1480 Iterate (Left.HT);
1481 exception
1482 when others =>
1483 HT_Ops.Free_Hash_Table (Buckets);
1484 raise;
1485 end Iterate_Left;
1487 Length := Left.Length;
1489 Iterate_Right : declare
1490 procedure Process (Src_Node : Node_Access);
1492 procedure Iterate is
1493 new HT_Ops.Generic_Iteration (Process);
1495 -------------
1496 -- Process --
1497 -------------
1499 procedure Process (Src_Node : Node_Access) is
1500 J : constant Hash_Type :=
1501 Hash (Src_Node.Element) mod Buckets'Length;
1503 Tgt_Node : Node_Access := Buckets (J);
1505 begin
1506 while Tgt_Node /= null loop
1507 if Equivalent_Elements (Src_Node.Element, Tgt_Node.Element) then
1508 return;
1509 end if;
1511 Tgt_Node := Next (Tgt_Node);
1512 end loop;
1514 Buckets (J) := new Node_Type'(Src_Node.Element, Buckets (J));
1515 Length := Length + 1;
1516 end Process;
1518 -- Start of processing for Iterate_Right
1520 begin
1521 Iterate (Right.HT);
1522 exception
1523 when others =>
1524 HT_Ops.Free_Hash_Table (Buckets);
1525 raise;
1526 end Iterate_Right;
1528 return (Controlled with HT => (Buckets, Length, 0, 0));
1529 end Union;
1531 ---------
1532 -- Vet --
1533 ---------
1535 function Vet (Position : Cursor) return Boolean is
1536 begin
1537 if Position.Node = null then
1538 return Position.Container = null;
1539 end if;
1541 if Position.Container = null then
1542 return False;
1543 end if;
1545 if Position.Node.Next = Position.Node then
1546 return False;
1547 end if;
1549 declare
1550 HT : Hash_Table_Type renames Position.Container.HT;
1551 X : Node_Access;
1553 begin
1554 if HT.Length = 0 then
1555 return False;
1556 end if;
1558 if HT.Buckets = null
1559 or else HT.Buckets'Length = 0
1560 then
1561 return False;
1562 end if;
1564 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element));
1566 for J in 1 .. HT.Length loop
1567 if X = Position.Node then
1568 return True;
1569 end if;
1571 if X = null then
1572 return False;
1573 end if;
1575 if X = X.Next then -- to prevent unnecessary looping
1576 return False;
1577 end if;
1579 X := X.Next;
1580 end loop;
1582 return False;
1583 end;
1584 end Vet;
1586 -----------
1587 -- Write --
1588 -----------
1590 procedure Write
1591 (Stream : access Root_Stream_Type'Class;
1592 Container : Set)
1594 begin
1595 Write_Nodes (Stream, Container.HT);
1596 end Write;
1598 ----------------
1599 -- Write_Node --
1600 ----------------
1602 procedure Write_Node
1603 (Stream : access Root_Stream_Type'Class;
1604 Node : Node_Access)
1606 begin
1607 Element_Type'Write (Stream, Node.Element);
1608 end Write_Node;
1610 package body Generic_Keys is
1612 -----------------------
1613 -- Local Subprograms --
1614 -----------------------
1616 function Equivalent_Key_Node
1617 (Key : Key_Type;
1618 Node : Node_Access) return Boolean;
1619 pragma Inline (Equivalent_Key_Node);
1621 --------------------------
1622 -- Local Instantiations --
1623 --------------------------
1625 package Key_Keys is
1626 new Hash_Tables.Generic_Keys
1627 (HT_Types => HT_Types,
1628 Next => Next,
1629 Set_Next => Set_Next,
1630 Key_Type => Key_Type,
1631 Hash => Hash,
1632 Equivalent_Keys => Equivalent_Key_Node);
1634 --------------
1635 -- Contains --
1636 --------------
1638 function Contains
1639 (Container : Set;
1640 Key : Key_Type) return Boolean
1642 begin
1643 return Find (Container, Key) /= No_Element;
1644 end Contains;
1646 ------------
1647 -- Delete --
1648 ------------
1650 procedure Delete
1651 (Container : in out Set;
1652 Key : Key_Type)
1654 X : Node_Access;
1656 begin
1657 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1659 if X = null then
1660 raise Constraint_Error;
1661 end if;
1663 Free (X);
1664 end Delete;
1666 -------------
1667 -- Element --
1668 -------------
1670 function Element
1671 (Container : Set;
1672 Key : Key_Type) return Element_Type
1674 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1676 begin
1677 return Node.Element;
1678 end Element;
1680 -------------------------
1681 -- Equivalent_Key_Node --
1682 -------------------------
1684 function Equivalent_Key_Node
1685 (Key : Key_Type;
1686 Node : Node_Access) return Boolean
1688 begin
1689 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1690 end Equivalent_Key_Node;
1692 -------------
1693 -- Exclude --
1694 -------------
1696 procedure Exclude
1697 (Container : in out Set;
1698 Key : Key_Type)
1700 X : Node_Access;
1701 begin
1702 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1703 Free (X);
1704 end Exclude;
1706 ----------
1707 -- Find --
1708 ----------
1710 function Find
1711 (Container : Set;
1712 Key : Key_Type) return Cursor
1714 Node : constant Node_Access :=
1715 Key_Keys.Find (Container.HT, Key);
1717 begin
1718 if Node = null then
1719 return No_Element;
1720 end if;
1722 return Cursor'(Container'Unrestricted_Access, Node);
1723 end Find;
1725 ---------
1726 -- Key --
1727 ---------
1729 function Key (Position : Cursor) return Key_Type is
1730 begin
1731 pragma Assert (Vet (Position), "bad cursor in function Key");
1733 if Position.Node = null then
1734 raise Constraint_Error;
1735 end if;
1737 return Key (Position.Node.Element);
1738 end Key;
1740 -------------
1741 -- Replace --
1742 -------------
1744 procedure Replace
1745 (Container : in out Set;
1746 Key : Key_Type;
1747 New_Item : Element_Type)
1749 Node : constant Node_Access :=
1750 Key_Keys.Find (Container.HT, Key);
1752 begin
1753 if Node = null then
1754 raise Constraint_Error;
1755 end if;
1757 Replace_Element (Container.HT, Node, New_Item);
1758 end Replace;
1760 -----------------------------------
1761 -- Update_Element_Preserving_Key --
1762 -----------------------------------
1764 procedure Update_Element_Preserving_Key
1765 (Container : in out Set;
1766 Position : Cursor;
1767 Process : not null access
1768 procedure (Element : in out Element_Type))
1770 HT : Hash_Table_Type renames Container.HT;
1771 Indx : Hash_Type;
1773 begin
1774 pragma Assert
1775 (Vet (Position),
1776 "bad cursor in Update_Element_Preserving_Key");
1778 if Position.Node = null then
1779 raise Constraint_Error;
1780 end if;
1782 if Position.Container /= Container'Unrestricted_Access then
1783 raise Program_Error;
1784 end if;
1786 if HT.Buckets = null
1787 or else HT.Buckets'Length = 0
1788 or else HT.Length = 0
1789 or else Position.Node.Next = Position.Node
1790 then
1791 raise Program_Error;
1792 end if;
1794 Indx := HT_Ops.Index (HT, Position.Node);
1796 declare
1797 E : Element_Type renames Position.Node.Element;
1798 K : constant Key_Type := Key (E);
1800 B : Natural renames HT.Busy;
1801 L : Natural renames HT.Lock;
1803 begin
1804 B := B + 1;
1805 L := L + 1;
1807 begin
1808 Process (E);
1809 exception
1810 when others =>
1811 L := L - 1;
1812 B := B - 1;
1813 raise;
1814 end;
1816 L := L - 1;
1817 B := B - 1;
1819 if Equivalent_Keys (K, Key (E)) then
1820 pragma Assert (Hash (K) = Hash (E));
1821 return;
1822 end if;
1823 end;
1825 if HT.Buckets (Indx) = Position.Node then
1826 HT.Buckets (Indx) := Position.Node.Next;
1828 else
1829 declare
1830 Prev : Node_Access := HT.Buckets (Indx);
1832 begin
1833 while Prev.Next /= Position.Node loop
1834 Prev := Prev.Next;
1836 if Prev = null then
1837 raise Program_Error;
1838 end if;
1839 end loop;
1841 Prev.Next := Position.Node.Next;
1842 end;
1843 end if;
1845 HT.Length := HT.Length - 1;
1847 declare
1848 X : Node_Access := Position.Node;
1850 begin
1851 Free (X);
1852 end;
1854 raise Program_Error;
1855 end Update_Element_Preserving_Key;
1857 end Generic_Keys;
1859 end Ada.Containers.Hashed_Sets;