Dead
[official-gcc.git] / gomp-20050608-branch / gcc / ada / a-cohase.adb
bloba54683e36ff392d28e3ee30729e320fa4c2d9b26
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 procedure Insert
76 (HT : in out Hash_Table_Type;
77 New_Item : Element_Type;
78 Node : out Node_Access;
79 Inserted : out Boolean);
81 function Is_In
82 (HT : Hash_Table_Type;
83 Key : Node_Access) return Boolean;
84 pragma Inline (Is_In);
86 function Next (Node : Node_Access) return Node_Access;
87 pragma Inline (Next);
89 function Read_Node (Stream : access Root_Stream_Type'Class)
90 return Node_Access;
91 pragma Inline (Read_Node);
93 procedure Replace_Element
94 (HT : in out Hash_Table_Type;
95 Node : Node_Access;
96 New_Item : Element_Type);
98 procedure Set_Next (Node : Node_Access; Next : Node_Access);
99 pragma Inline (Set_Next);
101 function Vet (Position : Cursor) return Boolean;
103 procedure Write_Node
104 (Stream : access Root_Stream_Type'Class;
105 Node : Node_Access);
106 pragma Inline (Write_Node);
108 --------------------------
109 -- Local Instantiations --
110 --------------------------
112 package HT_Ops is
113 new Hash_Tables.Generic_Operations
114 (HT_Types => HT_Types,
115 Hash_Node => Hash_Node,
116 Next => Next,
117 Set_Next => Set_Next,
118 Copy_Node => Copy_Node,
119 Free => Free);
121 package Element_Keys is
122 new Hash_Tables.Generic_Keys
123 (HT_Types => HT_Types,
124 Next => Next,
125 Set_Next => Set_Next,
126 Key_Type => Element_Type,
127 Hash => Hash,
128 Equivalent_Keys => Equivalent_Keys);
130 function Is_Equal is
131 new HT_Ops.Generic_Equal (Find_Equal_Key);
133 function Is_Equivalent is
134 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
136 procedure Read_Nodes is
137 new HT_Ops.Generic_Read (Read_Node);
139 procedure Write_Nodes is
140 new HT_Ops.Generic_Write (Write_Node);
142 ---------
143 -- "=" --
144 ---------
146 function "=" (Left, Right : Set) return Boolean is
147 begin
148 return Is_Equal (Left.HT, Right.HT);
149 end "=";
151 ------------
152 -- Adjust --
153 ------------
155 procedure Adjust (Container : in out Set) is
156 begin
157 HT_Ops.Adjust (Container.HT);
158 end Adjust;
160 --------------
161 -- Capacity --
162 --------------
164 function Capacity (Container : Set) return Count_Type is
165 begin
166 return HT_Ops.Capacity (Container.HT);
167 end Capacity;
169 -----------
170 -- Clear --
171 -----------
173 procedure Clear (Container : in out Set) is
174 begin
175 HT_Ops.Clear (Container.HT);
176 end Clear;
178 --------------
179 -- Contains --
180 --------------
182 function Contains (Container : Set; Item : Element_Type) return Boolean is
183 begin
184 return Find (Container, Item) /= No_Element;
185 end Contains;
187 ---------------
188 -- Copy_Node --
189 ---------------
191 function Copy_Node (Source : Node_Access) return Node_Access is
192 begin
193 return new Node_Type'(Element => Source.Element, Next => null);
194 end Copy_Node;
196 ------------
197 -- Delete --
198 ------------
200 procedure Delete
201 (Container : in out Set;
202 Item : Element_Type)
204 X : Node_Access;
206 begin
207 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
209 if X = null then
210 raise Constraint_Error with "attempt to delete element not in set";
211 end if;
213 Free (X);
214 end Delete;
216 procedure Delete
217 (Container : in out Set;
218 Position : in out Cursor)
220 begin
221 if Position.Node = null then
222 raise Constraint_Error with "Position cursor equals No_Element";
223 end if;
225 if Position.Container /= Container'Unrestricted_Access then
226 raise Program_Error with "Position cursor designates wrong set";
227 end if;
229 if Container.HT.Busy > 0 then
230 raise Program_Error with
231 "attempt to tamper with elements (set is busy)";
232 end if;
234 pragma Assert (Vet (Position), "bad cursor in Delete");
236 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
238 Free (Position.Node);
239 Position.Container := null;
240 end Delete;
242 ----------------
243 -- Difference --
244 ----------------
246 procedure Difference
247 (Target : in out Set;
248 Source : Set)
250 Tgt_Node : Node_Access;
252 begin
253 if Target'Address = Source'Address then
254 Clear (Target);
255 return;
256 end if;
258 if Source.HT.Length = 0 then
259 return;
260 end if;
262 if Target.HT.Busy > 0 then
263 raise Program_Error with
264 "attempt to tamper with elements (set is busy)";
265 end if;
267 -- TODO: This can be written in terms of a loop instead as
268 -- active-iterator style, sort of like a passive iterator.
270 Tgt_Node := HT_Ops.First (Target.HT);
271 while Tgt_Node /= null loop
272 if Is_In (Source.HT, Tgt_Node) then
273 declare
274 X : Node_Access := Tgt_Node;
275 begin
276 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
277 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
278 Free (X);
279 end;
281 else
282 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
283 end if;
284 end loop;
285 end Difference;
287 function Difference (Left, Right : Set) return Set is
288 Buckets : HT_Types.Buckets_Access;
289 Length : Count_Type;
291 begin
292 if Left'Address = Right'Address then
293 return Empty_Set;
294 end if;
296 if Left.HT.Length = 0 then
297 return Empty_Set;
298 end if;
300 if Right.HT.Length = 0 then
301 return Left;
302 end if;
304 declare
305 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
306 begin
307 Buckets := new Buckets_Type (0 .. Size - 1);
308 end;
310 Length := 0;
312 Iterate_Left : declare
313 procedure Process (L_Node : Node_Access);
315 procedure Iterate is
316 new HT_Ops.Generic_Iteration (Process);
318 -------------
319 -- Process --
320 -------------
322 procedure Process (L_Node : Node_Access) is
323 begin
324 if not Is_In (Right.HT, L_Node) then
325 declare
326 J : constant Hash_Type :=
327 Hash (L_Node.Element) mod Buckets'Length;
329 Bucket : Node_Access renames Buckets (J);
331 begin
332 Bucket := new Node_Type'(L_Node.Element, Bucket);
333 end;
335 Length := Length + 1;
336 end if;
337 end Process;
339 -- Start of processing for Iterate_Left
341 begin
342 Iterate (Left.HT);
343 exception
344 when others =>
345 HT_Ops.Free_Hash_Table (Buckets);
346 raise;
347 end Iterate_Left;
349 return (Controlled with HT => (Buckets, Length, 0, 0));
350 end Difference;
352 -------------
353 -- Element --
354 -------------
356 function Element (Position : Cursor) return Element_Type is
357 begin
358 if Position.Node = null then
359 raise Constraint_Error with "Position cursor equals No_Element";
360 end if;
362 pragma Assert (Vet (Position), "bad cursor in function Element");
364 return Position.Node.Element;
365 end Element;
367 ---------------------
368 -- Equivalent_Sets --
369 ---------------------
371 function Equivalent_Sets (Left, Right : Set) return Boolean is
372 begin
373 return Is_Equivalent (Left.HT, Right.HT);
374 end Equivalent_Sets;
376 -------------------------
377 -- Equivalent_Elements --
378 -------------------------
380 function Equivalent_Elements (Left, Right : Cursor)
381 return Boolean is
382 begin
383 if Left.Node = null then
384 raise Constraint_Error with
385 "Left cursor of Equivalent_Elements equals No_Element";
386 end if;
388 if Right.Node = null then
389 raise Constraint_Error with
390 "Right cursor of Equivalent_Elements equals No_Element";
391 end if;
393 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
394 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
396 return Equivalent_Elements (Left.Node.Element, Right.Node.Element);
397 end Equivalent_Elements;
399 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
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 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad");
409 return Equivalent_Elements (Left.Node.Element, Right);
410 end Equivalent_Elements;
412 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
413 return Boolean is
414 begin
415 if Right.Node = null then
416 raise Constraint_Error with
417 "Right cursor of Equivalent_Elements equals No_Element";
418 end if;
420 pragma Assert
421 (Vet (Right),
422 "Right cursor of Equivalent_Elements is bad");
424 return Equivalent_Elements (Left, Right.Node.Element);
425 end Equivalent_Elements;
427 ---------------------
428 -- Equivalent_Keys --
429 ---------------------
431 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
432 return Boolean is
433 begin
434 return Equivalent_Elements (Key, Node.Element);
435 end Equivalent_Keys;
437 -------------
438 -- Exclude --
439 -------------
441 procedure Exclude
442 (Container : in out Set;
443 Item : Element_Type)
445 X : Node_Access;
446 begin
447 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
448 Free (X);
449 end Exclude;
451 --------------
452 -- Finalize --
453 --------------
455 procedure Finalize (Container : in out Set) is
456 begin
457 HT_Ops.Finalize (Container.HT);
458 end Finalize;
460 ----------
461 -- Find --
462 ----------
464 function Find
465 (Container : Set;
466 Item : Element_Type) return Cursor
468 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
470 begin
471 if Node = null then
472 return No_Element;
473 end if;
475 return Cursor'(Container'Unrestricted_Access, Node);
476 end Find;
478 --------------------
479 -- Find_Equal_Key --
480 --------------------
482 function Find_Equal_Key
483 (R_HT : Hash_Table_Type;
484 L_Node : Node_Access) return Boolean
486 R_Index : constant Hash_Type :=
487 Element_Keys.Index (R_HT, L_Node.Element);
489 R_Node : Node_Access := R_HT.Buckets (R_Index);
491 begin
492 loop
493 if R_Node = null then
494 return False;
495 end if;
497 if L_Node.Element = R_Node.Element then
498 return True;
499 end if;
501 R_Node := Next (R_Node);
502 end loop;
503 end Find_Equal_Key;
505 -------------------------
506 -- Find_Equivalent_Key --
507 -------------------------
509 function Find_Equivalent_Key
510 (R_HT : Hash_Table_Type;
511 L_Node : Node_Access) return Boolean
513 R_Index : constant Hash_Type :=
514 Element_Keys.Index (R_HT, L_Node.Element);
516 R_Node : Node_Access := R_HT.Buckets (R_Index);
518 begin
519 loop
520 if R_Node = null then
521 return False;
522 end if;
524 if Equivalent_Elements (L_Node.Element, R_Node.Element) then
525 return True;
526 end if;
528 R_Node := Next (R_Node);
529 end loop;
530 end Find_Equivalent_Key;
532 -----------
533 -- First --
534 -----------
536 function First (Container : Set) return Cursor is
537 Node : constant Node_Access := HT_Ops.First (Container.HT);
539 begin
540 if Node = null then
541 return No_Element;
542 end if;
544 return Cursor'(Container'Unrestricted_Access, Node);
545 end First;
547 ----------
548 -- Free --
549 ----------
551 procedure Free (X : in out Node_Access) is
552 procedure Deallocate is
553 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
555 begin
556 if X /= null then
557 X.Next := X; -- detect mischief (in Vet)
558 Deallocate (X);
559 end if;
560 end Free;
562 -----------------
563 -- Has_Element --
564 -----------------
566 function Has_Element (Position : Cursor) return Boolean is
567 begin
568 pragma Assert (Vet (Position), "bad cursor in Has_Element");
569 return Position.Node /= null;
570 end Has_Element;
572 ---------------
573 -- Hash_Node --
574 ---------------
576 function Hash_Node (Node : Node_Access) return Hash_Type is
577 begin
578 return Hash (Node.Element);
579 end Hash_Node;
581 -------------
582 -- Include --
583 -------------
585 procedure Include
586 (Container : in out Set;
587 New_Item : Element_Type)
589 Position : Cursor;
590 Inserted : Boolean;
592 begin
593 Insert (Container, New_Item, Position, Inserted);
595 if not Inserted then
596 if Container.HT.Lock > 0 then
597 raise Program_Error with
598 "attempt to tamper with cursors (set is locked)";
599 end if;
601 Position.Node.Element := New_Item;
602 end if;
603 end Include;
605 ------------
606 -- Insert --
607 ------------
609 procedure Insert
610 (Container : in out Set;
611 New_Item : Element_Type;
612 Position : out Cursor;
613 Inserted : out Boolean)
615 begin
616 Insert (Container.HT, New_Item, Position.Node, Inserted);
617 Position.Container := Container'Unchecked_Access;
618 end Insert;
620 procedure Insert
621 (Container : in out Set;
622 New_Item : Element_Type)
624 Position : Cursor;
625 Inserted : Boolean;
627 begin
628 Insert (Container, New_Item, Position, Inserted);
630 if not Inserted then
631 raise Constraint_Error with
632 "attempt to insert element already in set";
633 end if;
634 end Insert;
636 procedure Insert
637 (HT : in out Hash_Table_Type;
638 New_Item : Element_Type;
639 Node : out Node_Access;
640 Inserted : out Boolean)
642 function New_Node (Next : Node_Access) return Node_Access;
643 pragma Inline (New_Node);
645 procedure Local_Insert is
646 new Element_Keys.Generic_Conditional_Insert (New_Node);
648 --------------
649 -- New_Node --
650 --------------
652 function New_Node (Next : Node_Access) return Node_Access is
653 begin
654 return new Node_Type'(New_Item, Next);
655 end New_Node;
657 -- Start of processing for Insert
659 begin
660 if HT_Ops.Capacity (HT) = 0 then
661 HT_Ops.Reserve_Capacity (HT, 1);
662 end if;
664 Local_Insert (HT, New_Item, Node, Inserted);
666 if Inserted
667 and then HT.Length > HT_Ops.Capacity (HT)
668 then
669 HT_Ops.Reserve_Capacity (HT, HT.Length);
670 end if;
671 end Insert;
673 ------------------
674 -- Intersection --
675 ------------------
677 procedure Intersection
678 (Target : in out Set;
679 Source : Set)
681 Tgt_Node : Node_Access;
683 begin
684 if Target'Address = Source'Address then
685 return;
686 end if;
688 if Source.Length = 0 then
689 Clear (Target);
690 return;
691 end if;
693 if Target.HT.Busy > 0 then
694 raise Program_Error with
695 "attempt to tamper with elements (set is busy)";
696 end if;
698 -- TODO: optimize this to use an explicit
699 -- loop instead of an active iterator
700 -- (similar to how a passive iterator is
701 -- implemented).
703 -- Another possibility is to test which
704 -- set is smaller, and iterate over the
705 -- smaller set.
707 Tgt_Node := HT_Ops.First (Target.HT);
708 while Tgt_Node /= null loop
709 if Is_In (Source.HT, Tgt_Node) then
710 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
712 else
713 declare
714 X : Node_Access := Tgt_Node;
715 begin
716 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
717 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
718 Free (X);
719 end;
720 end if;
721 end loop;
722 end Intersection;
724 function Intersection (Left, Right : Set) return Set is
725 Buckets : HT_Types.Buckets_Access;
726 Length : Count_Type;
728 begin
729 if Left'Address = Right'Address then
730 return Left;
731 end if;
733 Length := Count_Type'Min (Left.Length, Right.Length);
735 if Length = 0 then
736 return Empty_Set;
737 end if;
739 declare
740 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
741 begin
742 Buckets := new Buckets_Type (0 .. Size - 1);
743 end;
745 Length := 0;
747 Iterate_Left : declare
748 procedure Process (L_Node : Node_Access);
750 procedure Iterate is
751 new HT_Ops.Generic_Iteration (Process);
753 -------------
754 -- Process --
755 -------------
757 procedure Process (L_Node : Node_Access) is
758 begin
759 if Is_In (Right.HT, L_Node) then
760 declare
761 J : constant Hash_Type :=
762 Hash (L_Node.Element) mod Buckets'Length;
764 Bucket : Node_Access renames Buckets (J);
766 begin
767 Bucket := new Node_Type'(L_Node.Element, Bucket);
768 end;
770 Length := Length + 1;
771 end if;
772 end Process;
774 -- Start of processing for Iterate_Left
776 begin
777 Iterate (Left.HT);
778 exception
779 when others =>
780 HT_Ops.Free_Hash_Table (Buckets);
781 raise;
782 end Iterate_Left;
784 return (Controlled with HT => (Buckets, Length, 0, 0));
785 end Intersection;
787 --------------
788 -- Is_Empty --
789 --------------
791 function Is_Empty (Container : Set) return Boolean is
792 begin
793 return Container.HT.Length = 0;
794 end Is_Empty;
796 -----------
797 -- Is_In --
798 -----------
800 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
801 begin
802 return Element_Keys.Find (HT, Key.Element) /= null;
803 end Is_In;
805 ---------------
806 -- Is_Subset --
807 ---------------
809 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
810 Subset_Node : Node_Access;
812 begin
813 if Subset'Address = Of_Set'Address then
814 return True;
815 end if;
817 if Subset.Length > Of_Set.Length then
818 return False;
819 end if;
821 -- TODO: rewrite this to loop in the
822 -- style of a passive iterator.
824 Subset_Node := HT_Ops.First (Subset.HT);
825 while Subset_Node /= null loop
826 if not Is_In (Of_Set.HT, Subset_Node) then
827 return False;
828 end if;
829 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
830 end loop;
832 return True;
833 end Is_Subset;
835 -------------
836 -- Iterate --
837 -------------
839 procedure Iterate
840 (Container : Set;
841 Process : not null access procedure (Position : Cursor))
843 procedure Process_Node (Node : Node_Access);
844 pragma Inline (Process_Node);
846 procedure Iterate is
847 new HT_Ops.Generic_Iteration (Process_Node);
849 ------------------
850 -- Process_Node --
851 ------------------
853 procedure Process_Node (Node : Node_Access) is
854 begin
855 Process (Cursor'(Container'Unrestricted_Access, Node));
856 end Process_Node;
858 -- Start of processing for Iterate
860 begin
861 -- TODO: resolve whether HT_Ops.Generic_Iteration should
862 -- manipulate busy bit.
864 Iterate (Container.HT);
865 end Iterate;
867 ------------
868 -- Length --
869 ------------
871 function Length (Container : Set) return Count_Type is
872 begin
873 return Container.HT.Length;
874 end Length;
876 ----------
877 -- Move --
878 ----------
880 procedure Move (Target : in out Set; Source : in out Set) is
881 begin
882 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
883 end Move;
885 ----------
886 -- Next --
887 ----------
889 function Next (Node : Node_Access) return Node_Access is
890 begin
891 return Node.Next;
892 end Next;
894 function Next (Position : Cursor) return Cursor is
895 begin
896 if Position.Node = null then
897 return No_Element;
898 end if;
900 pragma Assert (Vet (Position), "bad cursor in Next");
902 declare
903 HT : Hash_Table_Type renames Position.Container.HT;
904 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
906 begin
907 if Node = null then
908 return No_Element;
909 end if;
911 return Cursor'(Position.Container, Node);
912 end;
913 end Next;
915 procedure Next (Position : in out Cursor) is
916 begin
917 Position := Next (Position);
918 end Next;
920 -------------
921 -- Overlap --
922 -------------
924 function Overlap (Left, Right : Set) return Boolean is
925 Left_Node : Node_Access;
927 begin
928 if Right.Length = 0 then
929 return False;
930 end if;
932 if Left'Address = Right'Address then
933 return True;
934 end if;
936 Left_Node := HT_Ops.First (Left.HT);
937 while Left_Node /= null loop
938 if Is_In (Right.HT, Left_Node) then
939 return True;
940 end if;
941 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
942 end loop;
944 return False;
945 end Overlap;
947 -------------------
948 -- Query_Element --
949 -------------------
951 procedure Query_Element
952 (Position : Cursor;
953 Process : not null access procedure (Element : Element_Type))
955 begin
956 if Position.Node = null then
957 raise Constraint_Error with
958 "Position cursor of Query_Element equals No_Element";
959 end if;
961 pragma Assert (Vet (Position), "bad cursor in Query_Element");
963 declare
964 HT : Hash_Table_Type renames Position.Container.HT;
966 B : Natural renames HT.Busy;
967 L : Natural renames HT.Lock;
969 begin
970 B := B + 1;
971 L := L + 1;
973 begin
974 Process (Position.Node.Element);
975 exception
976 when others =>
977 L := L - 1;
978 B := B - 1;
979 raise;
980 end;
982 L := L - 1;
983 B := B - 1;
984 end;
985 end Query_Element;
987 ----------
988 -- Read --
989 ----------
991 procedure Read
992 (Stream : access Root_Stream_Type'Class;
993 Container : out Set)
995 begin
996 Read_Nodes (Stream, Container.HT);
997 end Read;
999 procedure Read
1000 (Stream : access Root_Stream_Type'Class;
1001 Item : out Cursor)
1003 begin
1004 raise Program_Error with "attempt to stream set cursor";
1005 end Read;
1007 ---------------
1008 -- Read_Node --
1009 ---------------
1011 function Read_Node (Stream : access Root_Stream_Type'Class)
1012 return Node_Access
1014 Node : Node_Access := new Node_Type;
1016 begin
1017 Element_Type'Read (Stream, Node.Element);
1018 return Node;
1019 exception
1020 when others =>
1021 Free (Node);
1022 raise;
1023 end Read_Node;
1025 -------------
1026 -- Replace --
1027 -------------
1029 procedure Replace
1030 (Container : in out Set;
1031 New_Item : Element_Type)
1033 Node : constant Node_Access :=
1034 Element_Keys.Find (Container.HT, New_Item);
1036 begin
1037 if Node = null then
1038 raise Constraint_Error with
1039 "attempt to replace element not in set";
1040 end if;
1042 if Container.HT.Lock > 0 then
1043 raise Program_Error with
1044 "attempt to tamper with cursors (set is locked)";
1045 end if;
1047 Node.Element := New_Item;
1048 end Replace;
1050 ---------------------
1051 -- Replace_Element --
1052 ---------------------
1054 procedure Replace_Element
1055 (HT : in out Hash_Table_Type;
1056 Node : Node_Access;
1057 New_Item : Element_Type)
1059 begin
1060 if Equivalent_Elements (Node.Element, New_Item) then
1061 pragma Assert (Hash (Node.Element) = Hash (New_Item));
1063 if HT.Lock > 0 then
1064 raise Program_Error with
1065 "attempt to tamper with cursors (set is locked)";
1066 end if;
1068 Node.Element := New_Item; -- Note that this assignment can fail
1069 return;
1070 end if;
1072 if HT.Busy > 0 then
1073 raise Program_Error with
1074 "attempt to tamper with elements (set is busy)";
1075 end if;
1077 HT_Ops.Delete_Node_Sans_Free (HT, Node);
1079 Insert_New_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.Element := New_Item; -- Note that this assignment can fail
1093 Node.Next := Next;
1094 return Node;
1095 end New_Node;
1097 Result : Node_Access;
1098 Inserted : Boolean;
1100 -- Start of processing for Insert_New_Element
1102 begin
1103 Local_Insert
1104 (HT => HT,
1105 Key => New_Item,
1106 Node => Result,
1107 Inserted => Inserted);
1109 if Inserted then
1110 return;
1111 end if;
1112 exception
1113 when others =>
1114 null; -- Assignment must have failed
1115 end Insert_New_Element;
1117 Reinsert_Old_Element : declare
1118 function New_Node (Next : Node_Access) return Node_Access;
1119 pragma Inline (New_Node);
1121 procedure Local_Insert is
1122 new Element_Keys.Generic_Conditional_Insert (New_Node);
1124 --------------
1125 -- New_Node --
1126 --------------
1128 function New_Node (Next : Node_Access) return Node_Access is
1129 begin
1130 Node.Next := Next;
1131 return Node;
1132 end New_Node;
1134 Result : Node_Access;
1135 Inserted : Boolean;
1137 -- Start of processing for Reinsert_Old_Element
1139 begin
1140 Local_Insert
1141 (HT => HT,
1142 Key => Node.Element,
1143 Node => Result,
1144 Inserted => Inserted);
1145 exception
1146 when others =>
1147 null;
1148 end Reinsert_Old_Element;
1150 raise Program_Error with "attempt to replace existing element";
1151 end Replace_Element;
1153 procedure Replace_Element
1154 (Container : in out Set;
1155 Position : Cursor;
1156 New_Item : Element_Type)
1158 begin
1159 if Position.Node = null then
1160 raise Constraint_Error with
1161 "Position cursor equals No_Element";
1162 end if;
1164 if Position.Container /= Container'Unrestricted_Access then
1165 raise Program_Error with
1166 "Position cursor designates wrong set";
1167 end if;
1169 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1171 Replace_Element (Container.HT, Position.Node, New_Item);
1172 end Replace_Element;
1174 ----------------------
1175 -- Reserve_Capacity --
1176 ----------------------
1178 procedure Reserve_Capacity
1179 (Container : in out Set;
1180 Capacity : Count_Type)
1182 begin
1183 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1184 end Reserve_Capacity;
1186 --------------
1187 -- Set_Next --
1188 --------------
1190 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1191 begin
1192 Node.Next := Next;
1193 end Set_Next;
1195 --------------------------
1196 -- Symmetric_Difference --
1197 --------------------------
1199 procedure Symmetric_Difference
1200 (Target : in out Set;
1201 Source : Set)
1203 begin
1204 if Target'Address = Source'Address then
1205 Clear (Target);
1206 return;
1207 end if;
1209 if Target.HT.Busy > 0 then
1210 raise Program_Error with
1211 "attempt to tamper with elements (set is busy)";
1212 end if;
1214 declare
1215 N : constant Count_Type := Target.Length + Source.Length;
1216 begin
1217 if N > HT_Ops.Capacity (Target.HT) then
1218 HT_Ops.Reserve_Capacity (Target.HT, N);
1219 end if;
1220 end;
1222 if Target.Length = 0 then
1223 Iterate_Source_When_Empty_Target : declare
1224 procedure Process (Src_Node : Node_Access);
1226 procedure Iterate is
1227 new HT_Ops.Generic_Iteration (Process);
1229 -------------
1230 -- Process --
1231 -------------
1233 procedure Process (Src_Node : Node_Access) is
1234 E : Element_Type renames Src_Node.Element;
1235 B : Buckets_Type renames Target.HT.Buckets.all;
1236 J : constant Hash_Type := Hash (E) mod B'Length;
1237 N : Count_Type renames Target.HT.Length;
1239 begin
1240 B (J) := new Node_Type'(E, B (J));
1241 N := N + 1;
1242 end Process;
1244 -- Start of processing for Iterate_Source_When_Empty_Target
1246 begin
1247 Iterate (Source.HT);
1248 end Iterate_Source_When_Empty_Target;
1250 else
1251 Iterate_Source : declare
1252 procedure Process (Src_Node : Node_Access);
1254 procedure Iterate is
1255 new HT_Ops.Generic_Iteration (Process);
1257 -------------
1258 -- Process --
1259 -------------
1261 procedure Process (Src_Node : Node_Access) is
1262 E : Element_Type renames Src_Node.Element;
1263 B : Buckets_Type renames Target.HT.Buckets.all;
1264 J : constant Hash_Type := Hash (E) mod B'Length;
1265 N : Count_Type renames Target.HT.Length;
1267 begin
1268 if B (J) = null then
1269 B (J) := new Node_Type'(E, null);
1270 N := N + 1;
1272 elsif Equivalent_Elements (E, B (J).Element) then
1273 declare
1274 X : Node_Access := B (J);
1275 begin
1276 B (J) := B (J).Next;
1277 N := N - 1;
1278 Free (X);
1279 end;
1281 else
1282 declare
1283 Prev : Node_Access := B (J);
1284 Curr : Node_Access := Prev.Next;
1286 begin
1287 while Curr /= null loop
1288 if Equivalent_Elements (E, Curr.Element) then
1289 Prev.Next := Curr.Next;
1290 N := N - 1;
1291 Free (Curr);
1292 return;
1293 end if;
1295 Prev := Curr;
1296 Curr := Prev.Next;
1297 end loop;
1299 B (J) := new Node_Type'(E, B (J));
1300 N := N + 1;
1301 end;
1302 end if;
1303 end Process;
1305 -- Start of processing for Iterate_Source
1307 begin
1308 Iterate (Source.HT);
1309 end Iterate_Source;
1310 end if;
1311 end Symmetric_Difference;
1313 function Symmetric_Difference (Left, Right : Set) return Set is
1314 Buckets : HT_Types.Buckets_Access;
1315 Length : Count_Type;
1317 begin
1318 if Left'Address = Right'Address then
1319 return Empty_Set;
1320 end if;
1322 if Right.Length = 0 then
1323 return Left;
1324 end if;
1326 if Left.Length = 0 then
1327 return Right;
1328 end if;
1330 declare
1331 Size : constant Hash_Type :=
1332 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1333 begin
1334 Buckets := new Buckets_Type (0 .. Size - 1);
1335 end;
1337 Length := 0;
1339 Iterate_Left : declare
1340 procedure Process (L_Node : Node_Access);
1342 procedure Iterate is
1343 new HT_Ops.Generic_Iteration (Process);
1345 -------------
1346 -- Process --
1347 -------------
1349 procedure Process (L_Node : Node_Access) is
1350 begin
1351 if not Is_In (Right.HT, L_Node) then
1352 declare
1353 E : Element_Type renames L_Node.Element;
1354 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1356 begin
1357 Buckets (J) := new Node_Type'(E, Buckets (J));
1358 Length := Length + 1;
1359 end;
1360 end if;
1361 end Process;
1363 -- Start of processing for Iterate_Left
1365 begin
1366 Iterate (Left.HT);
1367 exception
1368 when others =>
1369 HT_Ops.Free_Hash_Table (Buckets);
1370 raise;
1371 end Iterate_Left;
1373 Iterate_Right : declare
1374 procedure Process (R_Node : Node_Access);
1376 procedure Iterate is
1377 new HT_Ops.Generic_Iteration (Process);
1379 -------------
1380 -- Process --
1381 -------------
1383 procedure Process (R_Node : Node_Access) is
1384 begin
1385 if not Is_In (Left.HT, R_Node) then
1386 declare
1387 E : Element_Type renames R_Node.Element;
1388 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1390 begin
1391 Buckets (J) := new Node_Type'(E, Buckets (J));
1392 Length := Length + 1;
1393 end;
1394 end if;
1395 end Process;
1397 -- Start of processing for Iterate_Right
1399 begin
1400 Iterate (Right.HT);
1401 exception
1402 when others =>
1403 HT_Ops.Free_Hash_Table (Buckets);
1404 raise;
1405 end Iterate_Right;
1407 return (Controlled with HT => (Buckets, Length, 0, 0));
1408 end Symmetric_Difference;
1410 ------------
1411 -- To_Set --
1412 ------------
1414 function To_Set (New_Item : Element_Type) return Set is
1415 HT : Hash_Table_Type;
1416 Node : Node_Access;
1417 Inserted : Boolean;
1419 begin
1420 Insert (HT, New_Item, Node, Inserted);
1421 return Set'(Controlled with HT);
1422 end To_Set;
1424 -----------
1425 -- Union --
1426 -----------
1428 procedure Union
1429 (Target : in out Set;
1430 Source : Set)
1432 procedure Process (Src_Node : Node_Access);
1434 procedure Iterate is
1435 new HT_Ops.Generic_Iteration (Process);
1437 -------------
1438 -- Process --
1439 -------------
1441 procedure Process (Src_Node : Node_Access) is
1442 function New_Node (Next : Node_Access) return Node_Access;
1443 pragma Inline (New_Node);
1445 procedure Insert is
1446 new Element_Keys.Generic_Conditional_Insert (New_Node);
1448 --------------
1449 -- New_Node --
1450 --------------
1452 function New_Node (Next : Node_Access) return Node_Access is
1453 Node : constant Node_Access :=
1454 new Node_Type'(Src_Node.Element, Next);
1455 begin
1456 return Node;
1457 end New_Node;
1459 Tgt_Node : Node_Access;
1460 Success : Boolean;
1462 -- Start of processing for Process
1464 begin
1465 Insert (Target.HT, Src_Node.Element, Tgt_Node, Success);
1466 end Process;
1468 -- Start of processing for Union
1470 begin
1471 if Target'Address = Source'Address then
1472 return;
1473 end if;
1475 if Target.HT.Busy > 0 then
1476 raise Program_Error with
1477 "attempt to tamper with elements (set is busy)";
1478 end if;
1480 declare
1481 N : constant Count_Type := Target.Length + Source.Length;
1482 begin
1483 if N > HT_Ops.Capacity (Target.HT) then
1484 HT_Ops.Reserve_Capacity (Target.HT, N);
1485 end if;
1486 end;
1488 Iterate (Source.HT);
1489 end Union;
1491 function Union (Left, Right : Set) return Set is
1492 Buckets : HT_Types.Buckets_Access;
1493 Length : Count_Type;
1495 begin
1496 if Left'Address = Right'Address then
1497 return Left;
1498 end if;
1500 if Right.Length = 0 then
1501 return Left;
1502 end if;
1504 if Left.Length = 0 then
1505 return Right;
1506 end if;
1508 declare
1509 Size : constant Hash_Type :=
1510 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1511 begin
1512 Buckets := new Buckets_Type (0 .. Size - 1);
1513 end;
1515 Iterate_Left : declare
1516 procedure Process (L_Node : Node_Access);
1518 procedure Iterate is
1519 new HT_Ops.Generic_Iteration (Process);
1521 -------------
1522 -- Process --
1523 -------------
1525 procedure Process (L_Node : Node_Access) is
1526 J : constant Hash_Type :=
1527 Hash (L_Node.Element) mod Buckets'Length;
1529 begin
1530 Buckets (J) := new Node_Type'(L_Node.Element, Buckets (J));
1531 end Process;
1533 -- Start of processing for Iterate_Left
1535 begin
1536 Iterate (Left.HT);
1537 exception
1538 when others =>
1539 HT_Ops.Free_Hash_Table (Buckets);
1540 raise;
1541 end Iterate_Left;
1543 Length := Left.Length;
1545 Iterate_Right : declare
1546 procedure Process (Src_Node : Node_Access);
1548 procedure Iterate is
1549 new HT_Ops.Generic_Iteration (Process);
1551 -------------
1552 -- Process --
1553 -------------
1555 procedure Process (Src_Node : Node_Access) is
1556 J : constant Hash_Type :=
1557 Hash (Src_Node.Element) mod Buckets'Length;
1559 Tgt_Node : Node_Access := Buckets (J);
1561 begin
1562 while Tgt_Node /= null loop
1563 if Equivalent_Elements (Src_Node.Element, Tgt_Node.Element) then
1564 return;
1565 end if;
1567 Tgt_Node := Next (Tgt_Node);
1568 end loop;
1570 Buckets (J) := new Node_Type'(Src_Node.Element, Buckets (J));
1571 Length := Length + 1;
1572 end Process;
1574 -- Start of processing for Iterate_Right
1576 begin
1577 Iterate (Right.HT);
1578 exception
1579 when others =>
1580 HT_Ops.Free_Hash_Table (Buckets);
1581 raise;
1582 end Iterate_Right;
1584 return (Controlled with HT => (Buckets, Length, 0, 0));
1585 end Union;
1587 ---------
1588 -- Vet --
1589 ---------
1591 function Vet (Position : Cursor) return Boolean is
1592 begin
1593 if Position.Node = null then
1594 return Position.Container = null;
1595 end if;
1597 if Position.Container = null then
1598 return False;
1599 end if;
1601 if Position.Node.Next = Position.Node then
1602 return False;
1603 end if;
1605 declare
1606 HT : Hash_Table_Type renames Position.Container.HT;
1607 X : Node_Access;
1609 begin
1610 if HT.Length = 0 then
1611 return False;
1612 end if;
1614 if HT.Buckets = null
1615 or else HT.Buckets'Length = 0
1616 then
1617 return False;
1618 end if;
1620 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element));
1622 for J in 1 .. HT.Length loop
1623 if X = Position.Node then
1624 return True;
1625 end if;
1627 if X = null then
1628 return False;
1629 end if;
1631 if X = X.Next then -- to prevent unnecessary looping
1632 return False;
1633 end if;
1635 X := X.Next;
1636 end loop;
1638 return False;
1639 end;
1640 end Vet;
1642 -----------
1643 -- Write --
1644 -----------
1646 procedure Write
1647 (Stream : access Root_Stream_Type'Class;
1648 Container : Set)
1650 begin
1651 Write_Nodes (Stream, Container.HT);
1652 end Write;
1654 procedure Write
1655 (Stream : access Root_Stream_Type'Class;
1656 Item : Cursor)
1658 begin
1659 raise Program_Error with "attempt to stream set cursor";
1660 end Write;
1662 ----------------
1663 -- Write_Node --
1664 ----------------
1666 procedure Write_Node
1667 (Stream : access Root_Stream_Type'Class;
1668 Node : Node_Access)
1670 begin
1671 Element_Type'Write (Stream, Node.Element);
1672 end Write_Node;
1674 package body Generic_Keys is
1676 -----------------------
1677 -- Local Subprograms --
1678 -----------------------
1680 function Equivalent_Key_Node
1681 (Key : Key_Type;
1682 Node : Node_Access) return Boolean;
1683 pragma Inline (Equivalent_Key_Node);
1685 --------------------------
1686 -- Local Instantiations --
1687 --------------------------
1689 package Key_Keys is
1690 new Hash_Tables.Generic_Keys
1691 (HT_Types => HT_Types,
1692 Next => Next,
1693 Set_Next => Set_Next,
1694 Key_Type => Key_Type,
1695 Hash => Hash,
1696 Equivalent_Keys => Equivalent_Key_Node);
1698 --------------
1699 -- Contains --
1700 --------------
1702 function Contains
1703 (Container : Set;
1704 Key : Key_Type) return Boolean
1706 begin
1707 return Find (Container, Key) /= No_Element;
1708 end Contains;
1710 ------------
1711 -- Delete --
1712 ------------
1714 procedure Delete
1715 (Container : in out Set;
1716 Key : Key_Type)
1718 X : Node_Access;
1720 begin
1721 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1723 if X = null then
1724 raise Constraint_Error with "attempt to delete key not in set";
1725 end if;
1727 Free (X);
1728 end Delete;
1730 -------------
1731 -- Element --
1732 -------------
1734 function Element
1735 (Container : Set;
1736 Key : Key_Type) return Element_Type
1738 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1740 begin
1741 if Node = null then
1742 raise Constraint_Error with "key not in map";
1743 end if;
1745 return Node.Element;
1746 end Element;
1748 -------------------------
1749 -- Equivalent_Key_Node --
1750 -------------------------
1752 function Equivalent_Key_Node
1753 (Key : Key_Type;
1754 Node : Node_Access) return Boolean
1756 begin
1757 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1758 end Equivalent_Key_Node;
1760 -------------
1761 -- Exclude --
1762 -------------
1764 procedure Exclude
1765 (Container : in out Set;
1766 Key : Key_Type)
1768 X : Node_Access;
1769 begin
1770 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1771 Free (X);
1772 end Exclude;
1774 ----------
1775 -- Find --
1776 ----------
1778 function Find
1779 (Container : Set;
1780 Key : Key_Type) return Cursor
1782 Node : constant Node_Access :=
1783 Key_Keys.Find (Container.HT, Key);
1785 begin
1786 if Node = null then
1787 return No_Element;
1788 end if;
1790 return Cursor'(Container'Unrestricted_Access, Node);
1791 end Find;
1793 ---------
1794 -- Key --
1795 ---------
1797 function Key (Position : Cursor) return Key_Type is
1798 begin
1799 if Position.Node = null then
1800 raise Constraint_Error with
1801 "Position cursor equals No_Element";
1802 end if;
1804 pragma Assert (Vet (Position), "bad cursor in function Key");
1806 return Key (Position.Node.Element);
1807 end Key;
1809 -------------
1810 -- Replace --
1811 -------------
1813 procedure Replace
1814 (Container : in out Set;
1815 Key : Key_Type;
1816 New_Item : Element_Type)
1818 Node : constant Node_Access :=
1819 Key_Keys.Find (Container.HT, Key);
1821 begin
1822 if Node = null then
1823 raise Constraint_Error with
1824 "attempt to replace key not in set";
1825 end if;
1827 Replace_Element (Container.HT, Node, New_Item);
1828 end Replace;
1830 -----------------------------------
1831 -- Update_Element_Preserving_Key --
1832 -----------------------------------
1834 procedure Update_Element_Preserving_Key
1835 (Container : in out Set;
1836 Position : Cursor;
1837 Process : not null access
1838 procedure (Element : in out Element_Type))
1840 HT : Hash_Table_Type renames Container.HT;
1841 Indx : Hash_Type;
1843 begin
1844 if Position.Node = null then
1845 raise Constraint_Error with
1846 "Position cursor equals No_Element";
1847 end if;
1849 if Position.Container /= Container'Unrestricted_Access then
1850 raise Program_Error with
1851 "Position cursor designates wrong set";
1852 end if;
1854 if HT.Buckets = null
1855 or else HT.Buckets'Length = 0
1856 or else HT.Length = 0
1857 or else Position.Node.Next = Position.Node
1858 then
1859 raise Program_Error with "Position cursor is bad (set is empty)";
1860 end if;
1862 pragma Assert
1863 (Vet (Position),
1864 "bad cursor in Update_Element_Preserving_Key");
1866 Indx := HT_Ops.Index (HT, Position.Node);
1868 declare
1869 E : Element_Type renames Position.Node.Element;
1870 K : constant Key_Type := Key (E);
1872 B : Natural renames HT.Busy;
1873 L : Natural renames HT.Lock;
1875 begin
1876 B := B + 1;
1877 L := L + 1;
1879 begin
1880 Process (E);
1881 exception
1882 when others =>
1883 L := L - 1;
1884 B := B - 1;
1885 raise;
1886 end;
1888 L := L - 1;
1889 B := B - 1;
1891 if Equivalent_Keys (K, Key (E)) then
1892 pragma Assert (Hash (K) = Hash (E));
1893 return;
1894 end if;
1895 end;
1897 if HT.Buckets (Indx) = Position.Node then
1898 HT.Buckets (Indx) := Position.Node.Next;
1900 else
1901 declare
1902 Prev : Node_Access := HT.Buckets (Indx);
1904 begin
1905 while Prev.Next /= Position.Node loop
1906 Prev := Prev.Next;
1908 if Prev = null then
1909 raise Program_Error with
1910 "Position cursor is bad (node not found)";
1911 end if;
1912 end loop;
1914 Prev.Next := Position.Node.Next;
1915 end;
1916 end if;
1918 HT.Length := HT.Length - 1;
1920 declare
1921 X : Node_Access := Position.Node;
1923 begin
1924 Free (X);
1925 end;
1927 raise Program_Error with "key was modified";
1928 end Update_Element_Preserving_Key;
1930 end Generic_Keys;
1932 end Ada.Containers.Hashed_Sets;