2016-06-16 Hristian Kirtchev <kirtchev@adacore.com>
[official-gcc.git] / gcc / ada / a-cfhase.adb
blobcc900f356aaefd77c405431c5f551b17e64f645a
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . F O R M A L _ H A S H E D _ S E T S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2010-2015, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 ------------------------------------------------------------------------------
28 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
29 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
31 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
32 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
34 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
36 with System; use type System.Address;
38 package body Ada.Containers.Formal_Hashed_Sets with
39 SPARK_Mode => Off
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 -- All need comments ???
48 procedure Difference
49 (Left, Right : Set;
50 Target : in out Set);
52 function Equivalent_Keys
53 (Key : Element_Type;
54 Node : Node_Type) return Boolean;
55 pragma Inline (Equivalent_Keys);
57 procedure Free
58 (HT : in out Set;
59 X : Count_Type);
61 generic
62 with procedure Set_Element (Node : in out Node_Type);
63 procedure Generic_Allocate
64 (HT : in out Set;
65 Node : out Count_Type);
67 function Hash_Node (Node : Node_Type) return Hash_Type;
68 pragma Inline (Hash_Node);
70 procedure Insert
71 (Container : in out Set;
72 New_Item : Element_Type;
73 Node : out Count_Type;
74 Inserted : out Boolean);
76 procedure Intersection
77 (Left : Set;
78 Right : Set;
79 Target : in out Set);
81 function Is_In
82 (HT : Set;
83 Key : Node_Type) return Boolean;
84 pragma Inline (Is_In);
86 procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
87 pragma Inline (Set_Element);
89 function Next (Node : Node_Type) return Count_Type;
90 pragma Inline (Next);
92 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
93 pragma Inline (Set_Next);
95 function Vet (Container : Set; Position : Cursor) return Boolean;
97 --------------------------
98 -- Local Instantiations --
99 --------------------------
101 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
102 (HT_Types => HT_Types,
103 Hash_Node => Hash_Node,
104 Next => Next,
105 Set_Next => Set_Next);
107 package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
108 (HT_Types => HT_Types,
109 Next => Next,
110 Set_Next => Set_Next,
111 Key_Type => Element_Type,
112 Hash => Hash,
113 Equivalent_Keys => Equivalent_Keys);
115 procedure Replace_Element is
116 new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
118 ---------
119 -- "=" --
120 ---------
122 function "=" (Left, Right : Set) return Boolean is
123 begin
124 if Length (Left) /= Length (Right) then
125 return False;
126 end if;
128 if Length (Left) = 0 then
129 return True;
130 end if;
132 declare
133 Node : Count_Type;
134 ENode : Count_Type;
136 begin
137 Node := First (Left).Node;
138 while Node /= 0 loop
139 ENode := Find (Container => Right,
140 Item => Left.Nodes (Node).Element).Node;
141 if ENode = 0 or else
142 Right.Nodes (ENode).Element /= Left.Nodes (Node).Element
143 then
144 return False;
145 end if;
147 Node := HT_Ops.Next (Left, Node);
148 end loop;
150 return True;
152 end;
154 end "=";
156 ------------
157 -- Assign --
158 ------------
160 procedure Assign (Target : in out Set; Source : Set) is
161 procedure Insert_Element (Source_Node : Count_Type);
163 procedure Insert_Elements is
164 new HT_Ops.Generic_Iteration (Insert_Element);
166 --------------------
167 -- Insert_Element --
168 --------------------
170 procedure Insert_Element (Source_Node : Count_Type) is
171 N : Node_Type renames Source.Nodes (Source_Node);
172 X : Count_Type;
173 B : Boolean;
175 begin
176 Insert (Target, N.Element, X, B);
177 pragma Assert (B);
178 end Insert_Element;
180 -- Start of processing for Assign
182 begin
183 if Target'Address = Source'Address then
184 return;
185 end if;
187 if Target.Capacity < Length (Source) then
188 raise Storage_Error with "not enough capacity"; -- SE or CE? ???
189 end if;
191 HT_Ops.Clear (Target);
192 Insert_Elements (Source);
193 end Assign;
195 --------------
196 -- Capacity --
197 --------------
199 function Capacity (Container : Set) return Count_Type is
200 begin
201 return Container.Nodes'Length;
202 end Capacity;
204 -----------
205 -- Clear --
206 -----------
208 procedure Clear (Container : in out Set) is
209 begin
210 HT_Ops.Clear (Container);
211 end Clear;
213 --------------
214 -- Contains --
215 --------------
217 function Contains (Container : Set; Item : Element_Type) return Boolean is
218 begin
219 return Find (Container, Item) /= No_Element;
220 end Contains;
222 ----------
223 -- Copy --
224 ----------
226 function Copy
227 (Source : Set;
228 Capacity : Count_Type := 0) return Set
230 C : constant Count_Type :=
231 Count_Type'Max (Capacity, Source.Capacity);
232 H : Hash_Type;
233 N : Count_Type;
234 Target : Set (C, Source.Modulus);
235 Cu : Cursor;
237 begin
238 if 0 < Capacity and then Capacity < Source.Capacity then
239 raise Capacity_Error;
240 end if;
242 Target.Length := Source.Length;
243 Target.Free := Source.Free;
245 H := 1;
246 while H <= Source.Modulus loop
247 Target.Buckets (H) := Source.Buckets (H);
248 H := H + 1;
249 end loop;
251 N := 1;
252 while N <= Source.Capacity loop
253 Target.Nodes (N) := Source.Nodes (N);
254 N := N + 1;
255 end loop;
257 while N <= C loop
258 Cu := (Node => N);
259 Free (Target, Cu.Node);
260 N := N + 1;
261 end loop;
263 return Target;
264 end Copy;
266 ---------------------
267 -- Current_To_Last --
268 ---------------------
270 function Current_To_Last (Container : Set; Current : Cursor) return Set is
271 Curs : Cursor := First (Container);
272 C : Set (Container.Capacity, Container.Modulus) :=
273 Copy (Container, Container.Capacity);
274 Node : Count_Type;
276 begin
277 if Curs = No_Element then
278 Clear (C);
279 return C;
281 elsif Current /= No_Element and not Has_Element (Container, Current) then
282 raise Constraint_Error;
284 else
285 while Curs.Node /= Current.Node loop
286 Node := Curs.Node;
287 Delete (C, Curs);
288 Curs := Next (Container, (Node => Node));
289 end loop;
291 return C;
292 end if;
293 end Current_To_Last;
295 ---------------------
296 -- Default_Modulus --
297 ---------------------
299 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
300 begin
301 return To_Prime (Capacity);
302 end Default_Modulus;
304 ------------
305 -- Delete --
306 ------------
308 procedure Delete
309 (Container : in out Set;
310 Item : Element_Type)
312 X : Count_Type;
314 begin
315 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
317 if X = 0 then
318 raise Constraint_Error with "attempt to delete element not in set";
319 end if;
321 Free (Container, X);
322 end Delete;
324 procedure Delete
325 (Container : in out Set;
326 Position : in out Cursor)
328 begin
329 if not Has_Element (Container, Position) then
330 raise Constraint_Error with "Position cursor has no element";
331 end if;
333 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
335 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
336 Free (Container, Position.Node);
338 Position := No_Element;
339 end Delete;
341 ----------------
342 -- Difference --
343 ----------------
345 procedure Difference
346 (Target : in out Set;
347 Source : Set)
349 Tgt_Node, Src_Node, Src_Last, Src_Length : Count_Type;
351 TN : Nodes_Type renames Target.Nodes;
352 SN : Nodes_Type renames Source.Nodes;
354 begin
355 if Target'Address = Source'Address then
356 Clear (Target);
357 return;
358 end if;
360 Src_Length := Source.Length;
362 if Src_Length = 0 then
363 return;
364 end if;
366 if Src_Length >= Target.Length then
367 Tgt_Node := HT_Ops.First (Target);
368 while Tgt_Node /= 0 loop
369 if Element_Keys.Find (Source, TN (Tgt_Node).Element) /= 0 then
370 declare
371 X : constant Count_Type := Tgt_Node;
372 begin
373 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
374 HT_Ops.Delete_Node_Sans_Free (Target, X);
375 Free (Target, X);
376 end;
378 else
379 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
380 end if;
381 end loop;
383 return;
384 else
385 Src_Node := HT_Ops.First (Source);
386 Src_Last := 0;
387 end if;
389 while Src_Node /= Src_Last loop
390 Tgt_Node := Element_Keys.Find (Target, SN (Src_Node).Element);
392 if Tgt_Node /= 0 then
393 HT_Ops.Delete_Node_Sans_Free (Target, Tgt_Node);
394 Free (Target, Tgt_Node);
395 end if;
397 Src_Node := HT_Ops.Next (Source, Src_Node);
398 end loop;
399 end Difference;
401 procedure Difference
402 (Left, Right : Set;
403 Target : in out Set)
405 procedure Process (L_Node : Count_Type);
407 procedure Iterate is
408 new HT_Ops.Generic_Iteration (Process);
410 -------------
411 -- Process --
412 -------------
414 procedure Process (L_Node : Count_Type) is
415 E : Element_Type renames Left.Nodes (L_Node).Element;
416 X : Count_Type;
417 B : Boolean;
418 begin
419 if Find (Right, E).Node = 0 then
420 Insert (Target, E, X, B);
421 pragma Assert (B);
422 end if;
423 end Process;
425 -- Start of processing for Difference
427 begin
428 Iterate (Left);
429 end Difference;
431 function Difference (Left, Right : Set) return Set is
432 C : Count_Type;
433 H : Hash_Type;
435 begin
436 if Left'Address = Right'Address then
437 return Empty_Set;
438 end if;
440 if Length (Left) = 0 then
441 return Empty_Set;
442 end if;
444 if Length (Right) = 0 then
445 return Left.Copy;
446 end if;
448 C := Length (Left);
449 H := Default_Modulus (C);
451 return S : Set (C, H) do
452 Difference (Left, Right, Target => S);
453 end return;
454 end Difference;
456 -------------
457 -- Element --
458 -------------
460 function Element
461 (Container : Set;
462 Position : Cursor) return Element_Type
464 begin
465 if not Has_Element (Container, Position) then
466 raise Constraint_Error with "Position cursor equals No_Element";
467 end if;
469 pragma Assert (Vet (Container, Position),
470 "bad cursor in function Element");
472 return Container.Nodes (Position.Node).Element;
473 end Element;
475 ---------------------
476 -- Equivalent_Sets --
477 ---------------------
479 function Equivalent_Sets (Left, Right : Set) return Boolean is
481 function Find_Equivalent_Key
482 (R_HT : Hash_Table_Type'Class;
483 L_Node : Node_Type) return Boolean;
484 pragma Inline (Find_Equivalent_Key);
486 function Is_Equivalent is
487 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
489 -------------------------
490 -- Find_Equivalent_Key --
491 -------------------------
493 function Find_Equivalent_Key
494 (R_HT : Hash_Table_Type'Class;
495 L_Node : Node_Type) return Boolean
497 R_Index : constant Hash_Type :=
498 Element_Keys.Index (R_HT, L_Node.Element);
499 R_Node : Count_Type := R_HT.Buckets (R_Index);
500 RN : Nodes_Type renames R_HT.Nodes;
502 begin
503 loop
504 if R_Node = 0 then
505 return False;
506 end if;
508 if Equivalent_Elements
509 (L_Node.Element, RN (R_Node).Element)
510 then
511 return True;
512 end if;
514 R_Node := HT_Ops.Next (R_HT, R_Node);
515 end loop;
516 end Find_Equivalent_Key;
518 -- Start of processing for Equivalent_Sets
520 begin
521 return Is_Equivalent (Left, Right);
522 end Equivalent_Sets;
524 -------------------------
525 -- Equivalent_Elements --
526 -------------------------
528 function Equivalent_Elements
529 (Left : Set;
530 CLeft : Cursor;
531 Right : Set;
532 CRight : Cursor) return Boolean
534 begin
535 if not Has_Element (Left, CLeft) then
536 raise Constraint_Error with
537 "Left cursor of Equivalent_Elements has no element";
538 end if;
540 if not Has_Element (Right, CRight) then
541 raise Constraint_Error with
542 "Right cursor of Equivalent_Elements has no element";
543 end if;
545 pragma Assert (Vet (Left, CLeft),
546 "bad Left cursor in Equivalent_Elements");
547 pragma Assert (Vet (Right, CRight),
548 "bad Right cursor in Equivalent_Elements");
550 declare
551 LN : Node_Type renames Left.Nodes (CLeft.Node);
552 RN : Node_Type renames Right.Nodes (CRight.Node);
553 begin
554 return Equivalent_Elements (LN.Element, RN.Element);
555 end;
556 end Equivalent_Elements;
558 function Equivalent_Elements
559 (Left : Set;
560 CLeft : Cursor;
561 Right : Element_Type) return Boolean
563 begin
564 if not Has_Element (Left, CLeft) then
565 raise Constraint_Error with
566 "Left cursor of Equivalent_Elements has no element";
567 end if;
569 pragma Assert (Vet (Left, CLeft),
570 "Left cursor in Equivalent_Elements is bad");
572 declare
573 LN : Node_Type renames Left.Nodes (CLeft.Node);
574 begin
575 return Equivalent_Elements (LN.Element, Right);
576 end;
577 end Equivalent_Elements;
579 function Equivalent_Elements
580 (Left : Element_Type;
581 Right : Set;
582 CRight : Cursor) return Boolean
584 begin
585 if not Has_Element (Right, CRight) then
586 raise Constraint_Error with
587 "Right cursor of Equivalent_Elements has no element";
588 end if;
590 pragma Assert
591 (Vet (Right, CRight),
592 "Right cursor of Equivalent_Elements is bad");
594 declare
595 RN : Node_Type renames Right.Nodes (CRight.Node);
596 begin
597 return Equivalent_Elements (Left, RN.Element);
598 end;
599 end Equivalent_Elements;
601 ---------------------
602 -- Equivalent_Keys --
603 ---------------------
605 function Equivalent_Keys
606 (Key : Element_Type;
607 Node : Node_Type) return Boolean
609 begin
610 return Equivalent_Elements (Key, Node.Element);
611 end Equivalent_Keys;
613 -------------
614 -- Exclude --
615 -------------
617 procedure Exclude
618 (Container : in out Set;
619 Item : Element_Type)
621 X : Count_Type;
622 begin
623 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
624 Free (Container, X);
625 end Exclude;
627 ----------
628 -- Find --
629 ----------
631 function Find
632 (Container : Set;
633 Item : Element_Type) return Cursor
635 Node : constant Count_Type := Element_Keys.Find (Container, Item);
637 begin
638 if Node = 0 then
639 return No_Element;
640 end if;
642 return (Node => Node);
643 end Find;
645 -----------
646 -- First --
647 -----------
649 function First (Container : Set) return Cursor is
650 Node : constant Count_Type := HT_Ops.First (Container);
652 begin
653 if Node = 0 then
654 return No_Element;
655 end if;
657 return (Node => Node);
658 end First;
660 -----------------------
661 -- First_To_Previous --
662 -----------------------
664 function First_To_Previous
665 (Container : Set;
666 Current : Cursor) return Set
668 Curs : Cursor := Current;
669 C : Set (Container.Capacity, Container.Modulus) :=
670 Copy (Container, Container.Capacity);
671 Node : Count_Type;
673 begin
674 if Curs = No_Element then
675 return C;
677 elsif not Has_Element (Container, Curs) then
678 raise Constraint_Error;
680 else
681 while Curs.Node /= 0 loop
682 Node := Curs.Node;
683 Delete (C, Curs);
684 Curs := Next (Container, (Node => Node));
685 end loop;
687 return C;
688 end if;
689 end First_To_Previous;
691 ----------
692 -- Free --
693 ----------
695 procedure Free
696 (HT : in out Set;
697 X : Count_Type)
699 begin
700 HT.Nodes (X).Has_Element := False;
701 HT_Ops.Free (HT, X);
702 end Free;
704 ----------------------
705 -- Generic_Allocate --
706 ----------------------
708 procedure Generic_Allocate
709 (HT : in out Set;
710 Node : out Count_Type)
712 procedure Allocate is new HT_Ops.Generic_Allocate (Set_Element);
713 begin
714 Allocate (HT, Node);
715 HT.Nodes (Node).Has_Element := True;
716 end Generic_Allocate;
718 -----------------
719 -- Has_Element --
720 -----------------
722 function Has_Element (Container : Set; Position : Cursor) return Boolean is
723 begin
724 if Position.Node = 0
725 or else not Container.Nodes (Position.Node).Has_Element
726 then
727 return False;
728 end if;
730 return True;
731 end Has_Element;
733 ---------------
734 -- Hash_Node --
735 ---------------
737 function Hash_Node (Node : Node_Type) return Hash_Type is
738 begin
739 return Hash (Node.Element);
740 end Hash_Node;
742 -------------
743 -- Include --
744 -------------
746 procedure Include
747 (Container : in out Set;
748 New_Item : Element_Type)
750 Position : Cursor;
751 Inserted : Boolean;
753 begin
754 Insert (Container, New_Item, Position, Inserted);
756 if not Inserted then
757 Container.Nodes (Position.Node).Element := New_Item;
758 end if;
759 end Include;
761 ------------
762 -- Insert --
763 ------------
765 procedure Insert
766 (Container : in out Set;
767 New_Item : Element_Type;
768 Position : out Cursor;
769 Inserted : out Boolean)
771 begin
772 Insert (Container, New_Item, Position.Node, Inserted);
773 end Insert;
775 procedure Insert
776 (Container : in out Set;
777 New_Item : Element_Type)
779 Position : Cursor;
780 Inserted : Boolean;
782 begin
783 Insert (Container, New_Item, Position, Inserted);
785 if not Inserted then
786 raise Constraint_Error with
787 "attempt to insert element already in set";
788 end if;
789 end Insert;
791 procedure Insert
792 (Container : in out Set;
793 New_Item : Element_Type;
794 Node : out Count_Type;
795 Inserted : out Boolean)
797 procedure Allocate_Set_Element (Node : in out Node_Type);
798 pragma Inline (Allocate_Set_Element);
800 function New_Node return Count_Type;
801 pragma Inline (New_Node);
803 procedure Local_Insert is
804 new Element_Keys.Generic_Conditional_Insert (New_Node);
806 procedure Allocate is
807 new Generic_Allocate (Allocate_Set_Element);
809 ---------------------------
810 -- Allocate_Set_Element --
811 ---------------------------
813 procedure Allocate_Set_Element (Node : in out Node_Type) is
814 begin
815 Node.Element := New_Item;
816 end Allocate_Set_Element;
818 --------------
819 -- New_Node --
820 --------------
822 function New_Node return Count_Type is
823 Result : Count_Type;
824 begin
825 Allocate (Container, Result);
826 return Result;
827 end New_Node;
829 -- Start of processing for Insert
831 begin
832 Local_Insert (Container, New_Item, Node, Inserted);
833 end Insert;
835 ------------------
836 -- Intersection --
837 ------------------
839 procedure Intersection
840 (Target : in out Set;
841 Source : Set)
843 Tgt_Node : Count_Type;
844 TN : Nodes_Type renames Target.Nodes;
846 begin
847 if Target'Address = Source'Address then
848 return;
849 end if;
851 if Source.Length = 0 then
852 Clear (Target);
853 return;
854 end if;
856 Tgt_Node := HT_Ops.First (Target);
857 while Tgt_Node /= 0 loop
858 if Find (Source, TN (Tgt_Node).Element).Node /= 0 then
859 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
861 else
862 declare
863 X : constant Count_Type := Tgt_Node;
864 begin
865 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
866 HT_Ops.Delete_Node_Sans_Free (Target, X);
867 Free (Target, X);
868 end;
869 end if;
870 end loop;
871 end Intersection;
873 procedure Intersection
874 (Left : Set;
875 Right : Set;
876 Target : in out Set)
878 procedure Process (L_Node : Count_Type);
880 procedure Iterate is
881 new HT_Ops.Generic_Iteration (Process);
883 -------------
884 -- Process --
885 -------------
887 procedure Process (L_Node : Count_Type) is
888 E : Element_Type renames Left.Nodes (L_Node).Element;
889 X : Count_Type;
890 B : Boolean;
892 begin
893 if Find (Right, E).Node /= 0 then
894 Insert (Target, E, X, B);
895 pragma Assert (B);
896 end if;
897 end Process;
899 -- Start of processing for Intersection
901 begin
902 Iterate (Left);
903 end Intersection;
905 function Intersection (Left, Right : Set) return Set is
906 C : Count_Type;
907 H : Hash_Type;
909 begin
910 if Left'Address = Right'Address then
911 return Left.Copy;
912 end if;
914 C := Count_Type'Min (Length (Left), Length (Right)); -- ???
915 H := Default_Modulus (C);
917 return S : Set (C, H) do
918 if Length (Left) /= 0 and Length (Right) /= 0 then
919 Intersection (Left, Right, Target => S);
920 end if;
921 end return;
922 end Intersection;
924 --------------
925 -- Is_Empty --
926 --------------
928 function Is_Empty (Container : Set) return Boolean is
929 begin
930 return Length (Container) = 0;
931 end Is_Empty;
933 -----------
934 -- Is_In --
935 -----------
937 function Is_In (HT : Set; Key : Node_Type) return Boolean is
938 begin
939 return Element_Keys.Find (HT, Key.Element) /= 0;
940 end Is_In;
942 ---------------
943 -- Is_Subset --
944 ---------------
946 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
947 Subset_Node : Count_Type;
948 Subset_Nodes : Nodes_Type renames Subset.Nodes;
950 begin
951 if Subset'Address = Of_Set'Address then
952 return True;
953 end if;
955 if Length (Subset) > Length (Of_Set) then
956 return False;
957 end if;
959 Subset_Node := First (Subset).Node;
960 while Subset_Node /= 0 loop
961 declare
962 N : Node_Type renames Subset_Nodes (Subset_Node);
963 E : Element_Type renames N.Element;
965 begin
966 if Find (Of_Set, E).Node = 0 then
967 return False;
968 end if;
969 end;
971 Subset_Node := HT_Ops.Next (Subset, Subset_Node);
972 end loop;
974 return True;
975 end Is_Subset;
977 ------------
978 -- Length --
979 ------------
981 function Length (Container : Set) return Count_Type is
982 begin
983 return Container.Length;
984 end Length;
986 ----------
987 -- Move --
988 ----------
990 -- Comments???
992 procedure Move (Target : in out Set; Source : in out Set) is
993 NN : HT_Types.Nodes_Type renames Source.Nodes;
994 X, Y : Count_Type;
996 begin
997 if Target'Address = Source'Address then
998 return;
999 end if;
1001 if Target.Capacity < Length (Source) then
1002 raise Constraint_Error with -- ???
1003 "Source length exceeds Target capacity";
1004 end if;
1006 Clear (Target);
1008 if Source.Length = 0 then
1009 return;
1010 end if;
1012 X := HT_Ops.First (Source);
1013 while X /= 0 loop
1014 Insert (Target, NN (X).Element); -- optimize???
1016 Y := HT_Ops.Next (Source, X);
1018 HT_Ops.Delete_Node_Sans_Free (Source, X);
1019 Free (Source, X);
1021 X := Y;
1022 end loop;
1023 end Move;
1025 ----------
1026 -- Next --
1027 ----------
1029 function Next (Node : Node_Type) return Count_Type is
1030 begin
1031 return Node.Next;
1032 end Next;
1034 function Next (Container : Set; Position : Cursor) return Cursor is
1035 begin
1036 if Position.Node = 0 then
1037 return No_Element;
1038 end if;
1040 if not Has_Element (Container, Position) then
1041 raise Constraint_Error
1042 with "Position has no element";
1043 end if;
1045 pragma Assert (Vet (Container, Position), "bad cursor in Next");
1047 return (Node => HT_Ops.Next (Container, Position.Node));
1048 end Next;
1050 procedure Next (Container : Set; Position : in out Cursor) is
1051 begin
1052 Position := Next (Container, Position);
1053 end Next;
1055 -------------
1056 -- Overlap --
1057 -------------
1059 function Overlap (Left, Right : Set) return Boolean is
1060 Left_Node : Count_Type;
1061 Left_Nodes : Nodes_Type renames Left.Nodes;
1063 begin
1064 if Length (Right) = 0 or Length (Left) = 0 then
1065 return False;
1066 end if;
1068 if Left'Address = Right'Address then
1069 return True;
1070 end if;
1072 Left_Node := First (Left).Node;
1073 while Left_Node /= 0 loop
1074 declare
1075 N : Node_Type renames Left_Nodes (Left_Node);
1076 E : Element_Type renames N.Element;
1077 begin
1078 if Find (Right, E).Node /= 0 then
1079 return True;
1080 end if;
1081 end;
1083 Left_Node := HT_Ops.Next (Left, Left_Node);
1084 end loop;
1086 return False;
1087 end Overlap;
1089 -------------
1090 -- Replace --
1091 -------------
1093 procedure Replace
1094 (Container : in out Set;
1095 New_Item : Element_Type)
1097 Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1099 begin
1100 if Node = 0 then
1101 raise Constraint_Error with
1102 "attempt to replace element not in set";
1103 end if;
1105 Container.Nodes (Node).Element := New_Item;
1106 end Replace;
1108 ---------------------
1109 -- Replace_Element --
1110 ---------------------
1112 procedure Replace_Element
1113 (Container : in out Set;
1114 Position : Cursor;
1115 New_Item : Element_Type)
1117 begin
1118 if not Has_Element (Container, Position) then
1119 raise Constraint_Error with
1120 "Position cursor equals No_Element";
1121 end if;
1123 pragma Assert (Vet (Container, Position),
1124 "bad cursor in Replace_Element");
1126 Replace_Element (Container, Position.Node, New_Item);
1127 end Replace_Element;
1129 ----------------------
1130 -- Reserve_Capacity --
1131 ----------------------
1133 procedure Reserve_Capacity
1134 (Container : in out Set;
1135 Capacity : Count_Type)
1137 begin
1138 if Capacity > Container.Capacity then
1139 raise Constraint_Error with "requested capacity is too large";
1140 end if;
1141 end Reserve_Capacity;
1143 ------------------
1144 -- Set_Element --
1145 ------------------
1147 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1148 begin
1149 Node.Element := Item;
1150 end Set_Element;
1152 --------------
1153 -- Set_Next --
1154 --------------
1156 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1157 begin
1158 Node.Next := Next;
1159 end Set_Next;
1161 ------------------
1162 -- Strict_Equal --
1163 ------------------
1165 function Strict_Equal (Left, Right : Set) return Boolean is
1166 CuL : Cursor := First (Left);
1167 CuR : Cursor := First (Right);
1169 begin
1170 if Length (Left) /= Length (Right) then
1171 return False;
1172 end if;
1174 while CuL.Node /= 0 or CuR.Node /= 0 loop
1175 if CuL.Node /= CuR.Node
1176 or else Left.Nodes (CuL.Node).Element /=
1177 Right.Nodes (CuR.Node).Element
1178 then
1179 return False;
1180 end if;
1182 CuL := Next (Left, CuL);
1183 CuR := Next (Right, CuR);
1184 end loop;
1186 return True;
1187 end Strict_Equal;
1189 --------------------------
1190 -- Symmetric_Difference --
1191 --------------------------
1193 procedure Symmetric_Difference
1194 (Target : in out Set;
1195 Source : Set)
1197 procedure Process (Source_Node : Count_Type);
1198 pragma Inline (Process);
1200 procedure Iterate is new HT_Ops.Generic_Iteration (Process);
1202 -------------
1203 -- Process --
1204 -------------
1206 procedure Process (Source_Node : Count_Type) is
1207 N : Node_Type renames Source.Nodes (Source_Node);
1208 X : Count_Type;
1209 B : Boolean;
1210 begin
1211 if Is_In (Target, N) then
1212 Delete (Target, N.Element);
1213 else
1214 Insert (Target, N.Element, X, B);
1215 pragma Assert (B);
1216 end if;
1217 end Process;
1219 -- Start of processing for Symmetric_Difference
1221 begin
1222 if Target'Address = Source'Address then
1223 Clear (Target);
1224 return;
1225 end if;
1227 if Length (Target) = 0 then
1228 Assign (Target, Source);
1229 return;
1230 end if;
1232 Iterate (Source);
1233 end Symmetric_Difference;
1235 function Symmetric_Difference (Left, Right : Set) return Set is
1236 C : Count_Type;
1237 H : Hash_Type;
1239 begin
1240 if Left'Address = Right'Address then
1241 return Empty_Set;
1242 end if;
1244 if Length (Right) = 0 then
1245 return Left.Copy;
1246 end if;
1248 if Length (Left) = 0 then
1249 return Right.Copy;
1250 end if;
1252 C := Length (Left) + Length (Right);
1253 H := Default_Modulus (C);
1255 return S : Set (C, H) do
1256 Difference (Left, Right, S);
1257 Difference (Right, Left, S);
1258 end return;
1259 end Symmetric_Difference;
1261 ------------
1262 -- To_Set --
1263 ------------
1265 function To_Set (New_Item : Element_Type) return Set is
1266 X : Count_Type;
1267 B : Boolean;
1269 begin
1270 return S : Set (Capacity => 1, Modulus => 1) do
1271 Insert (S, New_Item, X, B);
1272 pragma Assert (B);
1273 end return;
1274 end To_Set;
1276 -----------
1277 -- Union --
1278 -----------
1280 procedure Union
1281 (Target : in out Set;
1282 Source : Set)
1284 procedure Process (Src_Node : Count_Type);
1286 procedure Iterate is
1287 new HT_Ops.Generic_Iteration (Process);
1289 -------------
1290 -- Process --
1291 -------------
1293 procedure Process (Src_Node : Count_Type) is
1294 N : Node_Type renames Source.Nodes (Src_Node);
1295 E : Element_Type renames N.Element;
1297 X : Count_Type;
1298 B : Boolean;
1300 begin
1301 Insert (Target, E, X, B);
1302 end Process;
1304 -- Start of processing for Union
1306 begin
1307 if Target'Address = Source'Address then
1308 return;
1309 end if;
1311 Iterate (Source);
1312 end Union;
1314 function Union (Left, Right : Set) return Set is
1315 C : Count_Type;
1316 H : Hash_Type;
1318 begin
1319 if Left'Address = Right'Address then
1320 return Left.Copy;
1321 end if;
1323 if Length (Right) = 0 then
1324 return Left.Copy;
1325 end if;
1327 if Length (Left) = 0 then
1328 return Right.Copy;
1329 end if;
1331 C := Length (Left) + Length (Right);
1332 H := Default_Modulus (C);
1333 return S : Set (C, H) do
1334 Assign (Target => S, Source => Left);
1335 Union (Target => S, Source => Right);
1336 end return;
1337 end Union;
1339 ---------
1340 -- Vet --
1341 ---------
1343 function Vet (Container : Set; Position : Cursor) return Boolean is
1344 begin
1345 if Position.Node = 0 then
1346 return True;
1347 end if;
1349 declare
1350 S : Set renames Container;
1351 N : Nodes_Type renames S.Nodes;
1352 X : Count_Type;
1354 begin
1355 if S.Length = 0 then
1356 return False;
1357 end if;
1359 if Position.Node > N'Last then
1360 return False;
1361 end if;
1363 if N (Position.Node).Next = Position.Node then
1364 return False;
1365 end if;
1367 X := S.Buckets (Element_Keys.Index (S, N (Position.Node).Element));
1369 for J in 1 .. S.Length loop
1370 if X = Position.Node then
1371 return True;
1372 end if;
1374 if X = 0 then
1375 return False;
1376 end if;
1378 if X = N (X).Next then -- to prevent unnecessary looping
1379 return False;
1380 end if;
1382 X := N (X).Next;
1383 end loop;
1385 return False;
1386 end;
1387 end Vet;
1389 package body Generic_Keys with SPARK_Mode => Off is
1391 -----------------------
1392 -- Local Subprograms --
1393 -----------------------
1395 function Equivalent_Key_Node
1396 (Key : Key_Type;
1397 Node : Node_Type) return Boolean;
1398 pragma Inline (Equivalent_Key_Node);
1400 --------------------------
1401 -- Local Instantiations --
1402 --------------------------
1404 package Key_Keys is
1405 new Hash_Tables.Generic_Bounded_Keys
1406 (HT_Types => HT_Types,
1407 Next => Next,
1408 Set_Next => Set_Next,
1409 Key_Type => Key_Type,
1410 Hash => Hash,
1411 Equivalent_Keys => Equivalent_Key_Node);
1413 --------------
1414 -- Contains --
1415 --------------
1417 function Contains
1418 (Container : Set;
1419 Key : Key_Type) return Boolean
1421 begin
1422 return Find (Container, Key) /= No_Element;
1423 end Contains;
1425 ------------
1426 -- Delete --
1427 ------------
1429 procedure Delete
1430 (Container : in out Set;
1431 Key : Key_Type)
1433 X : Count_Type;
1435 begin
1436 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1438 if X = 0 then
1439 raise Constraint_Error with "attempt to delete key not in set";
1440 end if;
1442 Free (Container, X);
1443 end Delete;
1445 -------------
1446 -- Element --
1447 -------------
1449 function Element
1450 (Container : Set;
1451 Key : Key_Type) return Element_Type
1453 Node : constant Count_Type := Find (Container, Key).Node;
1455 begin
1456 if Node = 0 then
1457 raise Constraint_Error with "key not in map";
1458 end if;
1460 return Container.Nodes (Node).Element;
1461 end Element;
1463 -------------------------
1464 -- Equivalent_Key_Node --
1465 -------------------------
1467 function Equivalent_Key_Node
1468 (Key : Key_Type;
1469 Node : Node_Type) return Boolean
1471 begin
1472 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1473 end Equivalent_Key_Node;
1475 -------------
1476 -- Exclude --
1477 -------------
1479 procedure Exclude
1480 (Container : in out Set;
1481 Key : Key_Type)
1483 X : Count_Type;
1484 begin
1485 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1486 Free (Container, X);
1487 end Exclude;
1489 ----------
1490 -- Find --
1491 ----------
1493 function Find
1494 (Container : Set;
1495 Key : Key_Type) return Cursor
1497 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1498 begin
1499 return (if Node = 0 then No_Element else (Node => Node));
1500 end Find;
1502 ---------
1503 -- Key --
1504 ---------
1506 function Key (Container : Set; Position : Cursor) return Key_Type is
1507 begin
1508 if not Has_Element (Container, Position) then
1509 raise Constraint_Error with
1510 "Position cursor has no element";
1511 end if;
1513 pragma Assert
1514 (Vet (Container, Position), "bad cursor in function Key");
1516 declare
1517 N : Node_Type renames Container.Nodes (Position.Node);
1518 begin
1519 return Key (N.Element);
1520 end;
1521 end Key;
1523 -------------
1524 -- Replace --
1525 -------------
1527 procedure Replace
1528 (Container : in out Set;
1529 Key : Key_Type;
1530 New_Item : Element_Type)
1532 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1534 begin
1535 if Node = 0 then
1536 raise Constraint_Error with
1537 "attempt to replace key not in set";
1538 end if;
1540 Replace_Element (Container, Node, New_Item);
1541 end Replace;
1543 end Generic_Keys;
1545 end Ada.Containers.Formal_Hashed_Sets;