* arm.c (FL_WBUF): Define.
[official-gcc.git] / gcc / ada / a-cohase.adb
blob58d04febfd1f3b9b700b3a39e6a7bc34362f7288
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.HASHED_SETS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004 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, 59 Temple Place - Suite 330, Boston, --
24 -- MA 02111-1307, 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 System; use type System.Address;
46 with Ada.Containers.Prime_Numbers;
48 with Ada.Finalization; use Ada.Finalization;
50 package body Ada.Containers.Hashed_Sets is
52 type Node_Type is
53 limited record
54 Element : Element_Type;
55 Next : Node_Access;
56 end record;
58 function Hash_Node
59 (Node : Node_Access) return Hash_Type;
60 pragma Inline (Hash_Node);
62 function Hash_Node
63 (Node : Node_Access) return Hash_Type is
64 begin
65 return Hash (Node.Element);
66 end Hash_Node;
68 function Next
69 (Node : Node_Access) return Node_Access;
70 pragma Inline (Next);
72 function Next
73 (Node : Node_Access) return Node_Access is
74 begin
75 return Node.Next;
76 end Next;
78 procedure Set_Next
79 (Node : Node_Access;
80 Next : Node_Access);
81 pragma Inline (Set_Next);
83 procedure Set_Next
84 (Node : Node_Access;
85 Next : Node_Access) is
86 begin
87 Node.Next := Next;
88 end Set_Next;
90 function Equivalent_Keys
91 (Key : Element_Type;
92 Node : Node_Access) return Boolean;
93 pragma Inline (Equivalent_Keys);
95 function Equivalent_Keys
96 (Key : Element_Type;
97 Node : Node_Access) return Boolean is
98 begin
99 return Equivalent_Keys (Key, Node.Element);
100 end Equivalent_Keys;
102 function Copy_Node
103 (Source : Node_Access) return Node_Access;
104 pragma Inline (Copy_Node);
106 function Copy_Node
107 (Source : Node_Access) return Node_Access is
109 Target : constant Node_Access :=
110 new Node_Type'(Element => Source.Element,
111 Next => null);
112 begin
113 return Target;
114 end Copy_Node;
117 procedure Free is
118 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
120 package HT_Ops is
121 new Hash_Tables.Generic_Operations
122 (HT_Types => HT_Types,
123 Hash_Table_Type => Set,
124 Null_Node => null,
125 Hash_Node => Hash_Node,
126 Next => Next,
127 Set_Next => Set_Next,
128 Copy_Node => Copy_Node,
129 Free => Free);
131 package Element_Keys is
132 new Hash_Tables.Generic_Keys
133 (HT_Types => HT_Types,
134 HT_Type => Set,
135 Null_Node => null,
136 Next => Next,
137 Set_Next => Set_Next,
138 Key_Type => Element_Type,
139 Hash => Hash,
140 Equivalent_Keys => Equivalent_Keys);
143 procedure Adjust (Container : in out Set) renames HT_Ops.Adjust;
145 procedure Finalize (Container : in out Set) renames HT_Ops.Finalize;
148 function Find_Equal_Key
149 (R_Set : Set;
150 L_Node : Node_Access) return Boolean;
152 function Find_Equal_Key
153 (R_Set : Set;
154 L_Node : Node_Access) return Boolean is
156 R_Index : constant Hash_Type :=
157 Element_Keys.Index (R_Set, L_Node.Element);
159 R_Node : Node_Access := R_Set.Buckets (R_Index);
161 begin
163 loop
165 if R_Node = null then
166 return False;
167 end if;
169 if L_Node.Element = R_Node.Element then
170 -- pragma Assert (Is_Equal_Key (L_Node.Element, R_Node.Element));
171 return True;
172 end if;
174 R_Node := Next (R_Node);
176 end loop;
178 end Find_Equal_Key;
180 function Is_Equal is
181 new HT_Ops.Generic_Equal (Find_Equal_Key);
183 function "=" (Left, Right : Set) return Boolean renames Is_Equal;
186 function Length (Container : Set) return Count_Type is
187 begin
188 return Container.Length;
189 end Length;
192 function Is_Empty (Container : Set) return Boolean is
193 begin
194 return Container.Length = 0;
195 end Is_Empty;
198 procedure Clear (Container : in out Set) renames HT_Ops.Clear;
201 function Element (Position : Cursor) return Element_Type is
202 begin
203 return Position.Node.Element;
204 end Element;
207 procedure Query_Element
208 (Position : in Cursor;
209 Process : not null access procedure (Element : in Element_Type)) is
210 begin
211 Process (Position.Node.Element);
212 end Query_Element;
215 -- TODO:
216 -- procedure Replace_Element (Container : in out Set;
217 -- Position : in Node_Access;
218 -- By : in Element_Type) is
220 -- Node : Node_Access := Position;
222 -- begin
224 -- if Equivalent_Keys (Node.Element, By) then
226 -- begin
227 -- Node.Element := By;
228 -- exception
229 -- when others =>
230 -- HT_Ops.Delete_Node_Sans_Free (Container, Node);
231 -- Free (Node);
232 -- raise;
233 -- end;
235 -- return;
237 -- end if;
239 -- HT_Ops.Delete_Node_Sans_Free (Container, Node);
241 -- begin
242 -- Node.Element := By;
243 -- exception
244 -- when others =>
245 -- Free (Node);
246 -- raise;
247 -- end;
249 -- declare
250 -- function New_Node (Next : Node_Access) return Node_Access;
251 -- pragma Inline (New_Node);
253 -- function New_Node (Next : Node_Access) return Node_Access is
254 -- begin
255 -- Node.Next := Next;
256 -- return Node;
257 -- end New_Node;
259 -- procedure Insert is
260 -- new Element_Keys.Generic_Conditional_Insert (New_Node);
262 -- Result : Node_Access;
263 -- Success : Boolean;
264 -- begin
265 -- Insert
266 -- (HT => Container,
267 -- Key => Node.Element,
268 -- Node => Result,
269 -- Success => Success);
271 -- if not Success then
272 -- Free (Node);
273 -- raise Program_Error;
274 -- end if;
276 -- pragma Assert (Result = Node);
277 -- end;
279 -- end Replace_Element;
282 -- procedure Replace_Element (Container : in out Set;
283 -- Position : in Cursor;
284 -- By : in Element_Type) is
285 -- begin
287 -- if Position.Container = null then
288 -- raise Constraint_Error;
289 -- end if;
291 -- if Position.Container /= Set_Access'(Container'Unchecked_Access) then
292 -- raise Program_Error;
293 -- end if;
295 -- Replace_Element (Container, Position.Node, By);
297 -- end Replace_Element;
300 procedure Move (Target : in out Set;
301 Source : in out Set) renames HT_Ops.Move;
304 procedure Insert (Container : in out Set;
305 New_Item : in Element_Type;
306 Position : out Cursor;
307 Inserted : out Boolean) is
309 function New_Node (Next : Node_Access) return Node_Access;
310 pragma Inline (New_Node);
312 function New_Node (Next : Node_Access) return Node_Access is
313 Node : constant Node_Access := new Node_Type'(New_Item, Next);
314 begin
315 return Node;
316 end New_Node;
318 procedure Insert is
319 new Element_Keys.Generic_Conditional_Insert (New_Node);
321 begin
323 HT_Ops.Ensure_Capacity (Container, Container.Length + 1);
324 Insert (Container, New_Item, Position.Node, Inserted);
325 Position.Container := Container'Unchecked_Access;
327 end Insert;
330 procedure Insert (Container : in out Set;
331 New_Item : in Element_Type) is
333 Position : Cursor;
334 Inserted : Boolean;
336 begin
338 Insert (Container, New_Item, Position, Inserted);
340 if not Inserted then
341 raise Constraint_Error;
342 end if;
344 end Insert;
347 procedure Replace (Container : in out Set;
348 New_Item : in Element_Type) is
350 X : Node_Access := Element_Keys.Find (Container, New_Item);
352 begin
354 if X = null then
355 raise Constraint_Error;
356 end if;
358 X.Element := New_Item;
360 end Replace;
363 procedure Include (Container : in out Set;
364 New_Item : in Element_Type) is
366 Position : Cursor;
367 Inserted : Boolean;
369 begin
371 Insert (Container, New_Item, Position, Inserted);
373 if not Inserted then
374 Position.Node.Element := New_Item;
375 end if;
377 end Include;
380 procedure Delete (Container : in out Set;
381 Item : in Element_Type) is
383 X : Node_Access;
385 begin
387 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
389 if X = null then
390 raise Constraint_Error;
391 end if;
393 Free (X);
395 end Delete;
398 procedure Exclude (Container : in out Set;
399 Item : in Element_Type) is
401 X : Node_Access;
403 begin
405 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
406 Free (X);
408 end Exclude;
411 procedure Delete (Container : in out Set;
412 Position : in out Cursor) is
413 begin
415 if Position = No_Element then
416 return;
417 end if;
419 if Position.Container /= Set_Access'(Container'Unchecked_Access) then
420 raise Program_Error;
421 end if;
423 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
424 Free (Position.Node);
426 Position.Container := null;
428 end Delete;
432 procedure Union (Target : in out Set;
433 Source : in Set) is
435 procedure Process (Src_Node : in Node_Access);
437 procedure Process (Src_Node : in Node_Access) is
439 function New_Node (Next : Node_Access) return Node_Access;
440 pragma Inline (New_Node);
442 function New_Node (Next : Node_Access) return Node_Access is
443 Node : constant Node_Access :=
444 new Node_Type'(Src_Node.Element, Next);
445 begin
446 return Node;
447 end New_Node;
449 procedure Insert is
450 new Element_Keys.Generic_Conditional_Insert (New_Node);
452 Tgt_Node : Node_Access;
453 Success : Boolean;
455 begin
457 Insert (Target, Src_Node.Element, Tgt_Node, Success);
459 end Process;
461 procedure Iterate is
462 new HT_Ops.Generic_Iteration (Process);
464 begin
466 if Target'Address = Source'Address then
467 return;
468 end if;
470 HT_Ops.Ensure_Capacity (Target, Target.Length + Source.Length);
472 Iterate (Source);
474 end Union;
478 function Union (Left, Right : Set) return Set is
480 Buckets : HT_Types.Buckets_Access;
481 Length : Count_Type;
483 begin
485 if Left'Address = Right'Address then
486 return Left;
487 end if;
489 if Right.Length = 0 then
490 return Left;
491 end if;
493 if Left.Length = 0 then
494 return Right;
495 end if;
497 declare
498 Size : constant Hash_Type :=
499 Prime_Numbers.To_Prime (Left.Length + Right.Length);
500 begin
501 Buckets := new Buckets_Type (0 .. Size - 1);
502 end;
504 declare
505 procedure Process (L_Node : Node_Access);
507 procedure Process (L_Node : Node_Access) is
508 I : constant Hash_Type :=
509 Hash (L_Node.Element) mod Buckets'Length;
510 begin
511 Buckets (I) := new Node_Type'(L_Node.Element, Buckets (I));
512 end Process;
514 procedure Iterate is
515 new HT_Ops.Generic_Iteration (Process);
516 begin
517 Iterate (Left);
518 exception
519 when others =>
520 HT_Ops.Free_Hash_Table (Buckets);
521 raise;
522 end;
524 Length := Left.Length;
526 declare
527 procedure Process (Src_Node : Node_Access);
529 procedure Process (Src_Node : Node_Access) is
531 I : constant Hash_Type :=
532 Hash (Src_Node.Element) mod Buckets'Length;
534 Tgt_Node : Node_Access := Buckets (I);
536 begin
538 while Tgt_Node /= null loop
540 if Equivalent_Keys (Src_Node.Element, Tgt_Node.Element) then
541 return;
542 end if;
544 Tgt_Node := Next (Tgt_Node);
546 end loop;
548 Buckets (I) := new Node_Type'(Src_Node.Element, Buckets (I));
549 Length := Length + 1;
551 end Process;
553 procedure Iterate is
554 new HT_Ops.Generic_Iteration (Process);
555 begin
556 Iterate (Right);
557 exception
558 when others =>
559 HT_Ops.Free_Hash_Table (Buckets);
560 raise;
561 end;
563 return (Controlled with Buckets, Length);
565 end Union;
568 function Is_In
569 (HT : Set;
570 Key : Node_Access) return Boolean;
571 pragma Inline (Is_In);
573 function Is_In
574 (HT : Set;
575 Key : Node_Access) return Boolean is
576 begin
577 return Element_Keys.Find (HT, Key.Element) /= null;
578 end Is_In;
581 procedure Intersection (Target : in out Set;
582 Source : in Set) is
584 Tgt_Node : Node_Access;
586 begin
588 if Target'Address = Source'Address then
589 return;
590 end if;
592 if Source.Length = 0 then
593 Clear (Target);
594 return;
595 end if;
597 -- TODO: optimize this to use an explicit
598 -- loop instead of an active iterator
599 -- (similar to how a passive iterator is
600 -- implemented).
602 -- Another possibility is to test which
603 -- set is smaller, and iterate over the
604 -- smaller set.
606 Tgt_Node := HT_Ops.First (Target);
608 while Tgt_Node /= null loop
610 if Is_In (Source, Tgt_Node) then
612 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
614 else
616 declare
617 X : Node_Access := Tgt_Node;
618 begin
619 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
620 HT_Ops.Delete_Node_Sans_Free (Target, X);
621 Free (X);
622 end;
624 end if;
626 end loop;
628 end Intersection;
631 function Intersection (Left, Right : Set) return Set is
633 Buckets : HT_Types.Buckets_Access;
634 Length : Count_Type;
636 begin
638 if Left'Address = Right'Address then
639 return Left;
640 end if;
642 Length := Count_Type'Min (Left.Length, Right.Length);
644 if Length = 0 then
645 return Empty_Set;
646 end if;
648 declare
649 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
650 begin
651 Buckets := new Buckets_Type (0 .. Size - 1);
652 end;
654 Length := 0;
656 declare
657 procedure Process (L_Node : Node_Access);
659 procedure Process (L_Node : Node_Access) is
660 begin
661 if Is_In (Right, L_Node) then
663 declare
664 I : constant Hash_Type :=
665 Hash (L_Node.Element) mod Buckets'Length;
666 begin
667 Buckets (I) := new Node_Type'(L_Node.Element, Buckets (I));
668 end;
670 Length := Length + 1;
672 end if;
673 end Process;
675 procedure Iterate is
676 new HT_Ops.Generic_Iteration (Process);
677 begin
678 Iterate (Left);
679 exception
680 when others =>
681 HT_Ops.Free_Hash_Table (Buckets);
682 raise;
683 end;
685 return (Controlled with Buckets, Length);
687 end Intersection;
690 procedure Difference (Target : in out Set;
691 Source : in Set) is
694 Tgt_Node : Node_Access;
696 begin
698 if Target'Address = Source'Address then
699 Clear (Target);
700 return;
701 end if;
703 if Source.Length = 0 then
704 return;
705 end if;
707 -- TODO: As I noted above, this can be
708 -- written in terms of a loop instead as
709 -- active-iterator style, sort of like a
710 -- passive iterator.
712 Tgt_Node := HT_Ops.First (Target);
714 while Tgt_Node /= null loop
716 if Is_In (Source, Tgt_Node) then
718 declare
719 X : Node_Access := Tgt_Node;
720 begin
721 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
722 HT_Ops.Delete_Node_Sans_Free (Target, X);
723 Free (X);
724 end;
726 else
728 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
730 end if;
732 end loop;
734 end Difference;
738 function Difference (Left, Right : Set) return Set is
740 Buckets : HT_Types.Buckets_Access;
741 Length : Count_Type;
743 begin
745 if Left'Address = Right'Address then
746 return Empty_Set;
747 end if;
749 if Left.Length = 0 then
750 return Empty_Set;
751 end if;
753 if Right.Length = 0 then
754 return Left;
755 end if;
757 declare
758 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
759 begin
760 Buckets := new Buckets_Type (0 .. Size - 1);
761 end;
763 Length := 0;
765 declare
766 procedure Process (L_Node : Node_Access);
768 procedure Process (L_Node : Node_Access) is
769 begin
770 if not Is_In (Right, L_Node) then
772 declare
773 I : constant Hash_Type :=
774 Hash (L_Node.Element) mod Buckets'Length;
775 begin
776 Buckets (I) := new Node_Type'(L_Node.Element, Buckets (I));
777 end;
779 Length := Length + 1;
781 end if;
782 end Process;
784 procedure Iterate is
785 new HT_Ops.Generic_Iteration (Process);
786 begin
787 Iterate (Left);
788 exception
789 when others =>
790 HT_Ops.Free_Hash_Table (Buckets);
791 raise;
792 end;
794 return (Controlled with Buckets, Length);
796 end Difference;
800 procedure Symmetric_Difference (Target : in out Set;
801 Source : in Set) is
802 begin
804 if Target'Address = Source'Address then
805 Clear (Target);
806 return;
807 end if;
809 HT_Ops.Ensure_Capacity (Target, Target.Length + Source.Length);
811 if Target.Length = 0 then
813 declare
814 procedure Process (Src_Node : Node_Access);
816 procedure Process (Src_Node : Node_Access) is
817 E : Element_Type renames Src_Node.Element;
818 B : Buckets_Type renames Target.Buckets.all;
819 I : constant Hash_Type := Hash (E) mod B'Length;
820 N : Count_Type renames Target.Length;
821 begin
822 B (I) := new Node_Type'(E, B (I));
823 N := N + 1;
824 end Process;
826 procedure Iterate is
827 new HT_Ops.Generic_Iteration (Process);
828 begin
829 Iterate (Source);
830 end;
832 else
834 declare
835 procedure Process (Src_Node : Node_Access);
837 procedure Process (Src_Node : Node_Access) is
838 E : Element_Type renames Src_Node.Element;
839 B : Buckets_Type renames Target.Buckets.all;
840 I : constant Hash_Type := Hash (E) mod B'Length;
841 N : Count_Type renames Target.Length;
842 begin
843 if B (I) = null then
845 B (I) := new Node_Type'(E, null);
846 N := N + 1;
848 elsif Equivalent_Keys (E, B (I).Element) then
850 declare
851 X : Node_Access := B (I);
852 begin
853 B (I) := B (I).Next;
854 N := N - 1;
855 Free (X);
856 end;
858 else
860 declare
861 Prev : Node_Access := B (I);
862 Curr : Node_Access := Prev.Next;
863 begin
864 while Curr /= null loop
865 if Equivalent_Keys (E, Curr.Element) then
866 Prev.Next := Curr.Next;
867 N := N - 1;
868 Free (Curr);
869 return;
870 end if;
872 Prev := Curr;
873 Curr := Prev.Next;
874 end loop;
876 B (I) := new Node_Type'(E, B (I));
877 N := N + 1;
878 end;
880 end if;
881 end Process;
883 procedure Iterate is
884 new HT_Ops.Generic_Iteration (Process);
885 begin
886 Iterate (Source);
887 end;
889 end if;
891 end Symmetric_Difference;
894 function Symmetric_Difference (Left, Right : Set) return Set is
896 Buckets : HT_Types.Buckets_Access;
897 Length : Count_Type;
899 begin
901 if Left'Address = Right'Address then
902 return Empty_Set;
903 end if;
905 if Right.Length = 0 then
906 return Left;
907 end if;
909 if Left.Length = 0 then
910 return Right;
911 end if;
913 declare
914 Size : constant Hash_Type :=
915 Prime_Numbers.To_Prime (Left.Length + Right.Length);
916 begin
917 Buckets := new Buckets_Type (0 .. Size - 1);
918 end;
920 Length := 0;
922 declare
923 procedure Process (L_Node : Node_Access);
925 procedure Process (L_Node : Node_Access) is
926 begin
927 if not Is_In (Right, L_Node) then
928 declare
929 E : Element_Type renames L_Node.Element;
930 I : constant Hash_Type := Hash (E) mod Buckets'Length;
931 begin
932 Buckets (I) := new Node_Type'(E, Buckets (I));
933 Length := Length + 1;
934 end;
935 end if;
936 end Process;
938 procedure Iterate is
939 new HT_Ops.Generic_Iteration (Process);
940 begin
941 Iterate (Left);
942 exception
943 when others =>
944 HT_Ops.Free_Hash_Table (Buckets);
945 raise;
946 end;
948 declare
949 procedure Process (R_Node : Node_Access);
951 procedure Process (R_Node : Node_Access) is
952 begin
953 if not Is_In (Left, R_Node) then
954 declare
955 E : Element_Type renames R_Node.Element;
956 I : constant Hash_Type := Hash (E) mod Buckets'Length;
957 begin
958 Buckets (I) := new Node_Type'(E, Buckets (I));
959 Length := Length + 1;
960 end;
961 end if;
962 end Process;
964 procedure Iterate is
965 new HT_Ops.Generic_Iteration (Process);
966 begin
967 Iterate (Right);
968 exception
969 when others =>
970 HT_Ops.Free_Hash_Table (Buckets);
971 raise;
972 end;
974 return (Controlled with Buckets, Length);
976 end Symmetric_Difference;
979 function Is_Subset (Subset : Set;
980 Of_Set : Set) return Boolean is
982 Subset_Node : Node_Access;
984 begin
986 if Subset'Address = Of_Set'Address then
987 return True;
988 end if;
990 if Subset.Length > Of_Set.Length then
991 return False;
992 end if;
994 -- TODO: rewrite this to loop in the
995 -- style of a passive iterator.
997 Subset_Node := HT_Ops.First (Subset);
999 while Subset_Node /= null loop
1000 if not Is_In (Of_Set, Subset_Node) then
1001 return False;
1002 end if;
1004 Subset_Node := HT_Ops.Next (Subset, Subset_Node);
1005 end loop;
1007 return True;
1009 end Is_Subset;
1012 function Overlap (Left, Right : Set) return Boolean is
1014 Left_Node : Node_Access;
1016 begin
1018 if Right.Length = 0 then
1019 return False;
1020 end if;
1022 if Left'Address = Right'Address then
1023 return True;
1024 end if;
1026 Left_Node := HT_Ops.First (Left);
1028 while Left_Node /= null loop
1029 if Is_In (Right, Left_Node) then
1030 return True;
1031 end if;
1033 Left_Node := HT_Ops.Next (Left, Left_Node);
1034 end loop;
1036 return False;
1038 end Overlap;
1041 function Find (Container : Set;
1042 Item : Element_Type) return Cursor is
1044 Node : constant Node_Access := Element_Keys.Find (Container, Item);
1046 begin
1048 if Node = null then
1049 return No_Element;
1050 end if;
1052 return Cursor'(Container'Unchecked_Access, Node);
1054 end Find;
1057 function Contains (Container : Set;
1058 Item : Element_Type) return Boolean is
1059 begin
1060 return Find (Container, Item) /= No_Element;
1061 end Contains;
1065 function First (Container : Set) return Cursor is
1066 Node : constant Node_Access := HT_Ops.First (Container);
1067 begin
1068 if Node = null then
1069 return No_Element;
1070 end if;
1072 return Cursor'(Container'Unchecked_Access, Node);
1073 end First;
1076 -- function First_Element (Container : Set) return Element_Type is
1077 -- Node : constant Node_Access := HT_Ops.First (Container);
1078 -- begin
1079 -- return Node.Element;
1080 -- end First_Element;
1083 function Next (Position : Cursor) return Cursor is
1084 begin
1085 if Position.Container = null
1086 or else Position.Node = null
1087 then
1088 return No_Element;
1089 end if;
1091 declare
1092 S : Set renames Position.Container.all;
1093 Node : constant Node_Access := HT_Ops.Next (S, Position.Node);
1094 begin
1095 if Node = null then
1096 return No_Element;
1097 end if;
1099 return Cursor'(Position.Container, Node);
1100 end;
1101 end Next;
1104 procedure Next (Position : in out Cursor) is
1105 begin
1106 Position := Next (Position);
1107 end Next;
1110 function Has_Element (Position : Cursor) return Boolean is
1111 begin
1112 if Position.Container = null then
1113 return False;
1114 end if;
1116 if Position.Node = null then
1117 return False;
1118 end if;
1120 return True;
1121 end Has_Element;
1124 function Equivalent_Keys (Left, Right : Cursor)
1125 return Boolean is
1126 begin
1127 return Equivalent_Keys (Left.Node.Element, Right.Node.Element);
1128 end Equivalent_Keys;
1131 function Equivalent_Keys (Left : Cursor;
1132 Right : Element_Type)
1133 return Boolean is
1134 begin
1135 return Equivalent_Keys (Left.Node.Element, Right);
1136 end Equivalent_Keys;
1139 function Equivalent_Keys (Left : Element_Type;
1140 Right : Cursor)
1141 return Boolean is
1142 begin
1143 return Equivalent_Keys (Left, Right.Node.Element);
1144 end Equivalent_Keys;
1147 procedure Iterate
1148 (Container : in Set;
1149 Process : not null access procedure (Position : in Cursor)) is
1151 procedure Process_Node (Node : in Node_Access);
1152 pragma Inline (Process_Node);
1154 procedure Process_Node (Node : in Node_Access) is
1155 begin
1156 Process (Cursor'(Container'Unchecked_Access, Node));
1157 end Process_Node;
1159 procedure Iterate is
1160 new HT_Ops.Generic_Iteration (Process_Node);
1161 begin
1162 Iterate (Container);
1163 end Iterate;
1166 function Capacity (Container : Set) return Count_Type
1167 renames HT_Ops.Capacity;
1169 procedure Reserve_Capacity
1170 (Container : in out Set;
1171 Capacity : in Count_Type)
1172 renames HT_Ops.Ensure_Capacity;
1175 procedure Write_Node
1176 (Stream : access Root_Stream_Type'Class;
1177 Node : in Node_Access);
1178 pragma Inline (Write_Node);
1180 procedure Write_Node
1181 (Stream : access Root_Stream_Type'Class;
1182 Node : in Node_Access) is
1183 begin
1184 Element_Type'Write (Stream, Node.Element);
1185 end Write_Node;
1187 procedure Write_Nodes is
1188 new HT_Ops.Generic_Write (Write_Node);
1190 procedure Write
1191 (Stream : access Root_Stream_Type'Class;
1192 Container : in Set) renames Write_Nodes;
1195 function Read_Node (Stream : access Root_Stream_Type'Class)
1196 return Node_Access;
1197 pragma Inline (Read_Node);
1199 function Read_Node (Stream : access Root_Stream_Type'Class)
1200 return Node_Access is
1202 Node : Node_Access := new Node_Type;
1203 begin
1204 Element_Type'Read (Stream, Node.Element);
1205 return Node;
1206 exception
1207 when others =>
1208 Free (Node);
1209 raise;
1210 end Read_Node;
1212 procedure Read_Nodes is
1213 new HT_Ops.Generic_Read (Read_Node);
1215 procedure Read
1216 (Stream : access Root_Stream_Type'Class;
1217 Container : out Set) renames Read_Nodes;
1220 package body Generic_Keys is
1222 function Equivalent_Keys (Left : Cursor;
1223 Right : Key_Type)
1224 return Boolean is
1225 begin
1226 return Equivalent_Keys (Right, Left.Node.Element);
1227 end Equivalent_Keys;
1229 function Equivalent_Keys (Left : Key_Type;
1230 Right : Cursor)
1231 return Boolean is
1232 begin
1233 return Equivalent_Keys (Left, Right.Node.Element);
1234 end Equivalent_Keys;
1236 function Equivalent_Keys
1237 (Key : Key_Type;
1238 Node : Node_Access) return Boolean;
1239 pragma Inline (Equivalent_Keys);
1241 function Equivalent_Keys
1242 (Key : Key_Type;
1243 Node : Node_Access) return Boolean is
1244 begin
1245 return Equivalent_Keys (Key, Node.Element);
1246 end Equivalent_Keys;
1248 package Key_Keys is
1249 new Hash_Tables.Generic_Keys
1250 (HT_Types => HT_Types,
1251 HT_Type => Set,
1252 Null_Node => null,
1253 Next => Next,
1254 Set_Next => Set_Next,
1255 Key_Type => Key_Type,
1256 Hash => Hash,
1257 Equivalent_Keys => Equivalent_Keys);
1260 function Find (Container : Set;
1261 Key : Key_Type)
1262 return Cursor is
1264 Node : constant Node_Access :=
1265 Key_Keys.Find (Container, Key);
1267 begin
1269 if Node = null then
1270 return No_Element;
1271 end if;
1273 return Cursor'(Container'Unchecked_Access, Node);
1275 end Find;
1278 function Contains (Container : Set;
1279 Key : Key_Type) return Boolean is
1280 begin
1281 return Find (Container, Key) /= No_Element;
1282 end Contains;
1285 function Element (Container : Set;
1286 Key : Key_Type)
1287 return Element_Type is
1289 Node : constant Node_Access := Key_Keys.Find (Container, Key);
1290 begin
1291 return Node.Element;
1292 end Element;
1295 function Key (Position : Cursor) return Key_Type is
1296 begin
1297 return Key (Position.Node.Element);
1298 end Key;
1301 -- TODO:
1302 -- procedure Replace (Container : in out Set;
1303 -- Key : in Key_Type;
1304 -- New_Item : in Element_Type) is
1306 -- Node : constant Node_Access :=
1307 -- Key_Keys.Find (Container, Key);
1309 -- begin
1311 -- if Node = null then
1312 -- raise Constraint_Error;
1313 -- end if;
1315 -- Replace_Element (Container, Node, New_Item);
1317 -- end Replace;
1320 procedure Delete (Container : in out Set;
1321 Key : in Key_Type) is
1323 X : Node_Access;
1325 begin
1327 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1329 if X = null then
1330 raise Constraint_Error;
1331 end if;
1333 Free (X);
1335 end Delete;
1338 procedure Exclude (Container : in out Set;
1339 Key : in Key_Type) is
1341 X : Node_Access;
1343 begin
1345 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1346 Free (X);
1348 end Exclude;
1351 procedure Checked_Update_Element
1352 (Container : in out Set;
1353 Position : in Cursor;
1354 Process : not null access
1355 procedure (Element : in out Element_Type)) is
1357 begin
1359 if Position.Container = null then
1360 raise Constraint_Error;
1361 end if;
1363 if Position.Container /= Set_Access'(Container'Unchecked_Access) then
1364 raise Program_Error;
1365 end if;
1367 declare
1368 Old_Key : Key_Type renames Key (Position.Node.Element);
1369 begin
1370 Process (Position.Node.Element);
1372 if Equivalent_Keys (Old_Key, Position.Node.Element) then
1373 return;
1374 end if;
1375 end;
1377 declare
1378 function New_Node (Next : Node_Access) return Node_Access;
1379 pragma Inline (New_Node);
1381 function New_Node (Next : Node_Access) return Node_Access is
1382 begin
1383 Position.Node.Next := Next;
1384 return Position.Node;
1385 end New_Node;
1387 procedure Insert is
1388 new Key_Keys.Generic_Conditional_Insert (New_Node);
1390 Result : Node_Access;
1391 Success : Boolean;
1392 begin
1393 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
1395 Insert
1396 (HT => Container,
1397 Key => Key (Position.Node.Element),
1398 Node => Result,
1399 Success => Success);
1401 if not Success then
1402 declare
1403 X : Node_Access := Position.Node;
1404 begin
1405 Free (X);
1406 end;
1408 raise Program_Error;
1409 end if;
1411 pragma Assert (Result = Position.Node);
1412 end;
1414 end Checked_Update_Element;
1416 end Generic_Keys;
1418 end Ada.Containers.Hashed_Sets;