OSDN Git Service

2011-12-02 Thomas Quinot <quinot@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / a-cfhase.adb
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-2011, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17 --                                                                          --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception,   --
20 -- version 3.1, as published by the Free Software Foundation.               --
21 --                                                                          --
22 -- You should have received a copy of the GNU General Public License and    --
23 -- a copy of the GCC Runtime Library Exception along with this program;     --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25 -- <http://www.gnu.org/licenses/>.                                          --
26 ------------------------------------------------------------------------------
27
28 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
29 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
30
31 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
32 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
33
34 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
35
36 with System; use type System.Address;
37
38 package body Ada.Containers.Formal_Hashed_Sets is
39
40    -----------------------
41    -- Local Subprograms --
42    -----------------------
43
44    --  All need comments ???
45
46    procedure Difference
47      (Left, Right : Set;
48       Target      : in out Set);
49
50    function Equivalent_Keys
51      (Key  : Element_Type;
52       Node : Node_Type) return Boolean;
53    pragma Inline (Equivalent_Keys);
54
55    procedure Free
56      (HT : in out Set;
57       X  : Count_Type);
58
59    generic
60       with procedure Set_Element (Node : in out Node_Type);
61    procedure Generic_Allocate
62      (HT   : in out Set;
63       Node : out Count_Type);
64
65    function Hash_Node (Node : Node_Type) return Hash_Type;
66    pragma Inline (Hash_Node);
67
68    procedure Insert
69      (Container       : in out Set;
70       New_Item : Element_Type;
71       Node     : out Count_Type;
72       Inserted : out Boolean);
73
74    procedure Intersection
75      (Left   : Set;
76       Right  : Set;
77       Target : in out Set);
78
79    function Is_In
80      (HT  : Set;
81       Key : Node_Type) return Boolean;
82    pragma Inline (Is_In);
83
84    procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
85    pragma Inline (Set_Element);
86
87    function Next (Node : Node_Type) return Count_Type;
88    pragma Inline (Next);
89
90    procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
91    pragma Inline (Set_Next);
92
93    function Vet (Container : Set; Position : Cursor) return Boolean;
94
95    --------------------------
96    -- Local Instantiations --
97    --------------------------
98
99    package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
100      (HT_Types  => HT_Types,
101       Hash_Node => Hash_Node,
102       Next      => Next,
103       Set_Next  => Set_Next);
104
105    package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
106      (HT_Types        => HT_Types,
107       Next            => Next,
108       Set_Next        => Set_Next,
109       Key_Type        => Element_Type,
110       Hash            => Hash,
111       Equivalent_Keys => Equivalent_Keys);
112
113    procedure Replace_Element is
114      new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
115
116    ---------
117    -- "=" --
118    ---------
119
120    function "=" (Left, Right : Set) return Boolean is
121    begin
122       if Length (Left) /= Length (Right) then
123          return False;
124       end if;
125
126       if Length (Left) = 0 then
127          return True;
128       end if;
129
130       declare
131          Node  : Count_Type;
132          ENode : Count_Type;
133
134       begin
135          Node  := First (Left).Node;
136          while Node /= 0 loop
137             ENode := Find (Container => Right,
138                            Item      => Left.Nodes (Node).Element).Node;
139             if ENode = 0 or else
140               Right.Nodes (ENode).Element /= Left.Nodes (Node).Element
141             then
142                return False;
143             end if;
144
145             Node := HT_Ops.Next (Left, Node);
146          end loop;
147
148          return True;
149
150       end;
151
152    end "=";
153
154    ------------
155    -- Assign --
156    ------------
157
158    procedure Assign (Target : in out Set; Source : Set) is
159       procedure Insert_Element (Source_Node : Count_Type);
160
161       procedure Insert_Elements is
162         new HT_Ops.Generic_Iteration (Insert_Element);
163
164       --------------------
165       -- Insert_Element --
166       --------------------
167
168       procedure Insert_Element (Source_Node : Count_Type) is
169          N : Node_Type renames Source.Nodes (Source_Node);
170          X : Count_Type;
171          B : Boolean;
172
173       begin
174          Insert (Target, N.Element, X, B);
175          pragma Assert (B);
176       end Insert_Element;
177
178    --  Start of processing for Assign
179
180    begin
181       if Target'Address = Source'Address then
182          return;
183       end if;
184
185       if Target.Capacity < Length (Source) then
186          raise Storage_Error with "not enough capacity";  -- SE or CE? ???
187       end if;
188
189       HT_Ops.Clear (Target);
190       Insert_Elements (Source);
191    end Assign;
192
193    --------------
194    -- Capacity --
195    --------------
196
197    function Capacity (Container : Set) return Count_Type is
198    begin
199       return Container.Nodes'Length;
200    end Capacity;
201
202    -----------
203    -- Clear --
204    -----------
205
206    procedure Clear (Container : in out Set) is
207    begin
208       HT_Ops.Clear (Container);
209    end Clear;
210
211    --------------
212    -- Contains --
213    --------------
214
215    function Contains (Container : Set; Item : Element_Type) return Boolean is
216    begin
217       return Find (Container, Item) /= No_Element;
218    end Contains;
219
220    ----------
221    -- Copy --
222    ----------
223
224    function Copy
225      (Source   : Set;
226       Capacity : Count_Type := 0) return Set
227    is
228       C      : constant Count_Type :=
229                  Count_Type'Max (Capacity, Source.Capacity);
230       H      : Hash_Type;
231       N      : Count_Type;
232       Target : Set (C, Source.Modulus);
233       Cu     : Cursor;
234
235    begin
236       Target.Length := Source.Length;
237       Target.Free := Source.Free;
238
239       H := 1;
240       while H <= Source.Modulus loop
241          Target.Buckets (H) := Source.Buckets (H);
242          H := H + 1;
243       end loop;
244
245       N := 1;
246       while N <= Source.Capacity loop
247          Target.Nodes (N) := Source.Nodes (N);
248          N := N + 1;
249       end loop;
250
251       while N <= C loop
252          Cu := (Node => N);
253          Free (Target, Cu.Node);
254          N := N + 1;
255       end loop;
256
257       return Target;
258    end Copy;
259
260    ---------------------
261    -- Default_Modulus --
262    ---------------------
263
264    function Default_Modulus (Capacity : Count_Type) return Hash_Type is
265    begin
266       return To_Prime (Capacity);
267    end Default_Modulus;
268
269    ------------
270    -- Delete --
271    ------------
272
273    procedure Delete
274      (Container : in out Set;
275       Item      : Element_Type)
276    is
277       X : Count_Type;
278
279    begin
280       Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
281
282       if X = 0 then
283          raise Constraint_Error with "attempt to delete element not in set";
284       end if;
285
286       Free (Container, X);
287    end Delete;
288
289    procedure Delete
290      (Container : in out Set;
291       Position  : in out Cursor)
292    is
293    begin
294       if not Has_Element (Container, Position) then
295          raise Constraint_Error with "Position cursor has no element";
296       end if;
297
298       if Container.Busy > 0 then
299          raise Program_Error with
300            "attempt to tamper with elements (set is busy)";
301       end if;
302
303       pragma Assert (Vet (Container, Position), "bad cursor in Delete");
304
305       HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
306       Free (Container, Position.Node);
307
308       Position := No_Element;
309    end Delete;
310
311    ----------------
312    -- Difference --
313    ----------------
314
315    procedure Difference
316      (Target : in out Set;
317       Source : Set)
318    is
319       Tgt_Node, Src_Node, Src_Last, Src_Length : Count_Type;
320
321       TN : Nodes_Type renames Target.Nodes;
322       SN : Nodes_Type renames Source.Nodes;
323
324    begin
325       if Target'Address = Source'Address then
326          Clear (Target);
327          return;
328       end if;
329
330       Src_Length := Source.Length;
331
332       if Src_Length = 0 then
333          return;
334       end if;
335
336       if Target.Busy > 0 then
337          raise Program_Error with
338            "attempt to tamper with elements (set is busy)";
339       end if;
340
341       if Src_Length >= Target.Length then
342          Tgt_Node := HT_Ops.First (Target);
343          while Tgt_Node /= 0 loop
344             if Element_Keys.Find (Source, TN (Tgt_Node).Element) /= 0 then
345                declare
346                   X : constant Count_Type := Tgt_Node;
347                begin
348                   Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
349                   HT_Ops.Delete_Node_Sans_Free (Target, X);
350                   Free (Target, X);
351                end;
352
353             else
354                Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
355             end if;
356          end loop;
357
358          return;
359       else
360          Src_Node := HT_Ops.First (Source);
361          Src_Last := 0;
362       end if;
363
364       while Src_Node /= Src_Last loop
365          Tgt_Node := Element_Keys.Find (Target, SN (Src_Node).Element);
366
367          if Tgt_Node /= 0 then
368             HT_Ops.Delete_Node_Sans_Free (Target, Tgt_Node);
369             Free (Target, Tgt_Node);
370          end if;
371
372          Src_Node := HT_Ops.Next (Source, Src_Node);
373       end loop;
374    end Difference;
375
376    procedure Difference
377      (Left, Right : Set;
378       Target      : in out Set)
379    is
380       procedure Process (L_Node : Count_Type);
381
382       procedure Iterate is
383         new HT_Ops.Generic_Iteration (Process);
384
385       -------------
386       -- Process --
387       -------------
388
389       procedure Process (L_Node : Count_Type) is
390          E : Element_Type renames Left.Nodes (L_Node).Element;
391          X : Count_Type;
392          B : Boolean;
393       begin
394          if Find (Right, E).Node = 0 then
395             Insert (Target, E, X, B);
396             pragma Assert (B);
397          end if;
398       end Process;
399
400    --  Start of processing for Difference
401
402    begin
403       Iterate (Left);
404    end Difference;
405
406    function Difference (Left, Right : Set) return Set is
407       C : Count_Type;
408       H : Hash_Type;
409
410    begin
411       if Left'Address = Right'Address then
412          return Empty_Set;
413       end if;
414
415       if Length (Left) = 0 then
416          return Empty_Set;
417       end if;
418
419       if Length (Right) = 0 then
420          return Left.Copy;
421       end if;
422
423       C := Length (Left);
424       H := Default_Modulus (C);
425
426       return S : Set (C, H) do
427          Difference (Left, Right, Target => S);
428       end return;
429    end Difference;
430
431    -------------
432    -- Element --
433    -------------
434
435    function Element
436      (Container : Set;
437       Position  : Cursor) return Element_Type
438    is
439    begin
440       if not Has_Element (Container, Position) then
441          raise Constraint_Error with "Position cursor equals No_Element";
442       end if;
443
444       pragma Assert (Vet (Container, Position),
445                      "bad cursor in function Element");
446
447       return Container.Nodes (Position.Node).Element;
448    end Element;
449
450    ---------------------
451    -- Equivalent_Sets --
452    ---------------------
453
454    function Equivalent_Sets (Left, Right : Set) return Boolean is
455
456       function Find_Equivalent_Key
457         (R_HT   : Hash_Table_Type'Class;
458          L_Node : Node_Type) return Boolean;
459       pragma Inline (Find_Equivalent_Key);
460
461       function Is_Equivalent is
462         new HT_Ops.Generic_Equal (Find_Equivalent_Key);
463
464       -------------------------
465       -- Find_Equivalent_Key --
466       -------------------------
467
468       function Find_Equivalent_Key
469         (R_HT   : Hash_Table_Type'Class;
470          L_Node : Node_Type) return Boolean
471       is
472          R_Index : constant Hash_Type :=
473                      Element_Keys.Index (R_HT, L_Node.Element);
474          R_Node  : Count_Type := R_HT.Buckets (R_Index);
475          RN      : Nodes_Type renames R_HT.Nodes;
476
477       begin
478          loop
479             if R_Node = 0 then
480                return False;
481             end if;
482
483             if Equivalent_Elements (L_Node.Element,
484                                     RN (R_Node).Element) then
485                return True;
486             end if;
487
488             R_Node := HT_Ops.Next (R_HT, R_Node);
489          end loop;
490       end Find_Equivalent_Key;
491
492    --  Start of processing of Equivalent_Sets
493
494    begin
495       return Is_Equivalent (Left, Right);
496    end Equivalent_Sets;
497
498    -------------------------
499    -- Equivalent_Elements --
500    -------------------------
501
502    function Equivalent_Elements
503      (Left  : Set;
504       CLeft : Cursor;
505       Right  : Set;
506       CRight : Cursor) return Boolean
507    is
508    begin
509       if not Has_Element (Left, CLeft) then
510          raise Constraint_Error with
511            "Left cursor of Equivalent_Elements has no element";
512       end if;
513
514       if not Has_Element (Right, CRight) then
515          raise Constraint_Error with
516            "Right cursor of Equivalent_Elements has no element";
517       end if;
518
519       pragma Assert (Vet (Left, CLeft),
520                      "bad Left cursor in Equivalent_Elements");
521       pragma Assert (Vet (Right, CRight),
522                      "bad Right cursor in Equivalent_Elements");
523
524       declare
525          LN : Node_Type renames Left.Nodes (CLeft.Node);
526          RN : Node_Type renames Right.Nodes (CRight.Node);
527       begin
528          return Equivalent_Elements (LN.Element, RN.Element);
529       end;
530    end Equivalent_Elements;
531
532    function Equivalent_Elements
533      (Left  : Set;
534       CLeft : Cursor;
535       Right : Element_Type) return Boolean
536    is
537    begin
538       if not Has_Element (Left, CLeft) then
539          raise Constraint_Error with
540            "Left cursor of Equivalent_Elements has no element";
541       end if;
542
543       pragma Assert (Vet (Left, CLeft),
544                      "Left cursor in Equivalent_Elements is bad");
545
546       declare
547          LN : Node_Type renames Left.Nodes (CLeft.Node);
548       begin
549          return Equivalent_Elements (LN.Element, Right);
550       end;
551    end Equivalent_Elements;
552
553    function Equivalent_Elements
554      (Left   : Element_Type;
555       Right  : Set;
556       CRight : Cursor) return Boolean
557    is
558    begin
559       if not Has_Element (Right, CRight) then
560          raise Constraint_Error with
561            "Right cursor of Equivalent_Elements has no element";
562       end if;
563
564       pragma Assert
565         (Vet (Right, CRight),
566          "Right cursor of Equivalent_Elements is bad");
567
568       declare
569          RN : Node_Type renames Right.Nodes (CRight.Node);
570       begin
571          return Equivalent_Elements (Left, RN.Element);
572       end;
573    end Equivalent_Elements;
574
575    --  What does the following comment signify???
576    --  NOT MODIFIED
577
578    ---------------------
579    -- Equivalent_Keys --
580    ---------------------
581
582    function Equivalent_Keys
583      (Key  : Element_Type;
584       Node : Node_Type) return Boolean
585    is
586    begin
587       return Equivalent_Elements (Key, Node.Element);
588    end Equivalent_Keys;
589
590    -------------
591    -- Exclude --
592    -------------
593
594    procedure Exclude
595      (Container : in out Set;
596       Item      : Element_Type)
597    is
598       X : Count_Type;
599    begin
600       Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
601       Free (Container, X);
602    end Exclude;
603
604    ----------
605    -- Find --
606    ----------
607
608    function Find
609      (Container : Set;
610       Item      : Element_Type) return Cursor
611    is
612       Node : constant Count_Type := Element_Keys.Find (Container, Item);
613
614    begin
615       if Node = 0 then
616          return No_Element;
617       end if;
618
619       return (Node => Node);
620    end Find;
621
622    -----------
623    -- First --
624    -----------
625
626    function First (Container : Set) return Cursor is
627       Node : constant Count_Type := HT_Ops.First (Container);
628
629    begin
630       if Node = 0 then
631          return No_Element;
632       end if;
633
634       return (Node => Node);
635    end First;
636
637    ----------
638    -- Free --
639    ----------
640
641    procedure Free
642      (HT : in out Set;
643       X  : Count_Type)
644    is
645    begin
646       HT.Nodes (X).Has_Element := False;
647       HT_Ops.Free (HT, X);
648    end Free;
649
650    ----------------------
651    -- Generic_Allocate --
652    ----------------------
653
654    procedure Generic_Allocate
655      (HT   : in out Set;
656       Node : out Count_Type)
657    is
658       procedure Allocate is new HT_Ops.Generic_Allocate (Set_Element);
659    begin
660       Allocate (HT, Node);
661       HT.Nodes (Node).Has_Element := True;
662    end Generic_Allocate;
663
664    -----------------
665    -- Has_Element --
666    -----------------
667
668    function Has_Element (Container : Set; Position : Cursor) return Boolean is
669    begin
670       if Position.Node = 0
671         or else not Container.Nodes (Position.Node).Has_Element
672       then
673          return False;
674       end if;
675
676       return True;
677    end Has_Element;
678
679    ---------------
680    -- Hash_Node --
681    ---------------
682
683    function Hash_Node (Node : Node_Type) return Hash_Type is
684    begin
685       return Hash (Node.Element);
686    end Hash_Node;
687
688    -------------
689    -- Include --
690    -------------
691
692    procedure Include
693      (Container : in out Set;
694       New_Item  : Element_Type)
695    is
696       Position : Cursor;
697       Inserted : Boolean;
698
699    begin
700       Insert (Container, New_Item, Position, Inserted);
701
702       if not Inserted then
703          if Container.Lock > 0 then
704             raise Program_Error with
705               "attempt to tamper with cursors (set is locked)";
706          end if;
707
708          Container.Nodes (Position.Node).Element := New_Item;
709       end if;
710    end Include;
711
712    ------------
713    -- Insert --
714    ------------
715
716    procedure Insert
717      (Container : in out Set;
718       New_Item  : Element_Type;
719       Position  : out Cursor;
720       Inserted  : out Boolean)
721    is
722    begin
723       Insert (Container, New_Item, Position.Node, Inserted);
724    end Insert;
725
726    procedure Insert
727      (Container : in out Set;
728       New_Item  : Element_Type)
729    is
730       Position : Cursor;
731       Inserted : Boolean;
732
733    begin
734       Insert (Container, New_Item, Position, Inserted);
735
736       if not Inserted then
737          raise Constraint_Error with
738            "attempt to insert element already in set";
739       end if;
740    end Insert;
741
742    procedure Insert
743      (Container : in out Set;
744       New_Item  : Element_Type;
745       Node      : out Count_Type;
746       Inserted  : out Boolean)
747    is
748       procedure Allocate_Set_Element (Node : in out Node_Type);
749       pragma Inline (Allocate_Set_Element);
750
751       function New_Node return Count_Type;
752       pragma Inline (New_Node);
753
754       procedure Local_Insert is
755         new Element_Keys.Generic_Conditional_Insert (New_Node);
756
757       procedure Allocate is
758         new Generic_Allocate (Allocate_Set_Element);
759
760       ---------------------------
761       --  Allocate_Set_Element --
762       ---------------------------
763
764       procedure Allocate_Set_Element (Node : in out Node_Type) is
765       begin
766          Node.Element := New_Item;
767       end Allocate_Set_Element;
768
769       --------------
770       -- New_Node --
771       --------------
772
773       function New_Node return Count_Type is
774          Result : Count_Type;
775       begin
776          Allocate (Container, Result);
777          return Result;
778       end New_Node;
779
780    --  Start of processing for Insert
781
782    begin
783       Local_Insert (Container, New_Item, Node, Inserted);
784    end Insert;
785
786    ------------------
787    -- Intersection --
788    ------------------
789
790    procedure Intersection
791      (Target : in out Set;
792       Source : Set)
793    is
794       Tgt_Node : Count_Type;
795       TN       : Nodes_Type renames Target.Nodes;
796
797    begin
798       if Target'Address = Source'Address then
799          return;
800       end if;
801
802       if Source.Length = 0 then
803          Clear (Target);
804          return;
805       end if;
806
807       if Target.Busy > 0 then
808          raise Program_Error with
809            "attempt to tamper with elements (set is busy)";
810       end if;
811
812       Tgt_Node := HT_Ops.First (Target);
813       while Tgt_Node /= 0 loop
814          if Find (Source, TN (Tgt_Node).Element).Node /= 0 then
815             Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
816
817          else
818             declare
819                X : constant Count_Type := Tgt_Node;
820             begin
821                Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
822                HT_Ops.Delete_Node_Sans_Free (Target, X);
823                Free (Target, X);
824             end;
825          end if;
826       end loop;
827    end Intersection;
828
829    procedure Intersection
830      (Left   : Set;
831       Right  : Set;
832       Target : in out Set)
833    is
834       procedure Process (L_Node : Count_Type);
835
836       procedure Iterate is
837         new HT_Ops.Generic_Iteration (Process);
838
839       -------------
840       -- Process --
841       -------------
842
843       procedure Process (L_Node : Count_Type) is
844          E : Element_Type renames Left.Nodes (L_Node).Element;
845          X : Count_Type;
846          B : Boolean;
847
848       begin
849          if Find (Right, E).Node /= 0 then
850             Insert (Target, E, X, B);
851             pragma Assert (B);
852          end if;
853       end Process;
854
855    --  Start of processing for Intersection
856
857    begin
858       Iterate (Left);
859    end Intersection;
860
861    function Intersection (Left, Right : Set) return Set is
862       C : Count_Type;
863       H : Hash_Type;
864
865    begin
866       if Left'Address = Right'Address then
867          return Left.Copy;
868       end if;
869
870       C := Count_Type'Min (Length (Left), Length (Right));  -- ???
871       H := Default_Modulus (C);
872
873       return S : Set (C, H) do
874          if Length (Left) /= 0 and Length (Right) /= 0 then
875                Intersection (Left, Right, Target => S);
876          end if;
877       end return;
878    end Intersection;
879
880    --------------
881    -- Is_Empty --
882    --------------
883
884    function Is_Empty (Container : Set) return Boolean is
885    begin
886       return Length (Container) = 0;
887    end Is_Empty;
888
889    -----------
890    -- Is_In --
891    -----------
892
893    function Is_In (HT : Set; Key : Node_Type) return Boolean is
894    begin
895       return Element_Keys.Find (HT, Key.Element) /= 0;
896    end Is_In;
897
898    ---------------
899    -- Is_Subset --
900    ---------------
901
902    function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
903       Subset_Node  : Count_Type;
904       Subset_Nodes : Nodes_Type renames Subset.Nodes;
905
906    begin
907       if Subset'Address = Of_Set'Address then
908          return True;
909       end if;
910
911       if Length (Subset) > Length (Of_Set) then
912          return False;
913       end if;
914
915       Subset_Node := First (Subset).Node;
916       while Subset_Node /= 0 loop
917          declare
918             N : Node_Type renames Subset_Nodes (Subset_Node);
919             E : Element_Type renames N.Element;
920
921          begin
922             if Find (Of_Set, E).Node = 0 then
923                return False;
924             end if;
925          end;
926
927          Subset_Node := HT_Ops.Next (Subset, Subset_Node);
928       end loop;
929
930       return True;
931    end Is_Subset;
932
933    -------------
934    -- Iterate --
935    -------------
936
937    procedure Iterate
938      (Container : Set;
939       Process   :
940       not null access procedure (Container : Set; Position : Cursor))
941    is
942       procedure Process_Node (Node : Count_Type);
943       pragma Inline (Process_Node);
944
945       procedure Iterate is
946         new HT_Ops.Generic_Iteration (Process_Node);
947
948       ------------------
949       -- Process_Node --
950       ------------------
951
952       procedure Process_Node (Node : Count_Type) is
953       begin
954          Process (Container, (Node => Node));
955       end Process_Node;
956
957       B : Natural renames Container'Unrestricted_Access.Busy;
958
959    --  Start of processing for Iterate
960
961    begin
962       B := B + 1;
963
964       begin
965          Iterate (Container);
966       exception
967          when others =>
968             B := B - 1;
969             raise;
970       end;
971
972       B := B - 1;
973    end Iterate;
974
975    ----------
976    -- Left --
977    ----------
978
979    function Left (Container : Set; Position : Cursor) return Set is
980       Curs : Cursor := Position;
981       C    : Set (Container.Capacity, Container.Modulus) :=
982                Copy (Container, Container.Capacity);
983       Node : Count_Type;
984
985    begin
986       if Curs = No_Element then
987          return C;
988       end if;
989
990       if not Has_Element (Container, Curs) then
991          raise Constraint_Error;
992       end if;
993
994       while Curs.Node /= 0 loop
995          Node := Curs.Node;
996          Delete (C, Curs);
997          Curs := Next (Container, (Node => Node));
998       end loop;
999
1000       return C;
1001    end Left;
1002
1003    ------------
1004    -- Length --
1005    ------------
1006
1007    function Length (Container : Set) return Count_Type is
1008    begin
1009       return Container.Length;
1010    end Length;
1011
1012    ----------
1013    -- Move --
1014    ----------
1015
1016    --  Comments???
1017
1018    procedure Move (Target : in out Set; Source : in out Set) is
1019       NN   : HT_Types.Nodes_Type renames Source.Nodes;
1020       X, Y : Count_Type;
1021
1022    begin
1023       if Target'Address = Source'Address then
1024          return;
1025       end if;
1026
1027       if Target.Capacity < Length (Source) then
1028          raise Constraint_Error with  -- ???
1029            "Source length exceeds Target capacity";
1030       end if;
1031
1032       if Source.Busy > 0 then
1033          raise Program_Error with
1034            "attempt to tamper with cursors of Source (list is busy)";
1035       end if;
1036
1037       Clear (Target);
1038
1039       if Source.Length = 0 then
1040          return;
1041       end if;
1042
1043       X := HT_Ops.First (Source);
1044       while X /= 0 loop
1045          Insert (Target, NN (X).Element);  -- optimize???
1046
1047          Y := HT_Ops.Next (Source, X);
1048
1049          HT_Ops.Delete_Node_Sans_Free (Source, X);
1050          Free (Source, X);
1051
1052          X := Y;
1053       end loop;
1054    end Move;
1055
1056    ----------
1057    -- Next --
1058    ----------
1059
1060    function Next (Node : Node_Type) return Count_Type is
1061    begin
1062       return Node.Next;
1063    end Next;
1064
1065    function Next (Container : Set; Position : Cursor) return Cursor is
1066    begin
1067       if Position.Node = 0 then
1068          return No_Element;
1069       end if;
1070
1071       if not Has_Element (Container, Position) then
1072          raise Constraint_Error
1073            with "Position has no element";
1074       end if;
1075
1076       pragma Assert (Vet (Container, Position), "bad cursor in Next");
1077
1078       return (Node => HT_Ops.Next (Container, Position.Node));
1079    end Next;
1080
1081    procedure Next (Container : Set; Position : in out Cursor) is
1082    begin
1083       Position := Next (Container, Position);
1084    end Next;
1085
1086    -------------
1087    -- Overlap --
1088    -------------
1089
1090    function Overlap (Left, Right : Set) return Boolean is
1091       Left_Node  : Count_Type;
1092       Left_Nodes : Nodes_Type renames Left.Nodes;
1093
1094    begin
1095       if Length (Right) = 0 or Length (Left) = 0 then
1096          return False;
1097       end if;
1098
1099       if Left'Address = Right'Address then
1100          return True;
1101       end if;
1102
1103       Left_Node := First (Left).Node;
1104       while Left_Node /= 0 loop
1105          declare
1106             N : Node_Type renames Left_Nodes (Left_Node);
1107             E : Element_Type renames N.Element;
1108          begin
1109             if Find (Right, E).Node /= 0 then
1110                return True;
1111             end if;
1112          end;
1113
1114          Left_Node := HT_Ops.Next (Left, Left_Node);
1115       end loop;
1116
1117       return False;
1118    end Overlap;
1119
1120    -------------------
1121    -- Query_Element --
1122    -------------------
1123
1124    procedure Query_Element
1125      (Container : in out Set;
1126       Position  : Cursor;
1127       Process   : not null access procedure (Element : Element_Type))
1128    is
1129    begin
1130       if not Has_Element (Container, Position) then
1131          raise Constraint_Error with
1132            "Position cursor of Query_Element has no element";
1133       end if;
1134
1135       pragma Assert (Vet (Container, Position), "bad cursor in Query_Element");
1136
1137       declare
1138          B : Natural renames Container.Busy;
1139          L : Natural renames Container.Lock;
1140
1141       begin
1142          B := B + 1;
1143          L := L + 1;
1144
1145          begin
1146             Process (Container.Nodes (Position.Node).Element);
1147          exception
1148             when others =>
1149                L := L - 1;
1150                B := B - 1;
1151                raise;
1152          end;
1153
1154          L := L - 1;
1155          B := B - 1;
1156       end;
1157    end Query_Element;
1158
1159    ----------
1160    -- Read --
1161    ----------
1162
1163    procedure Read
1164      (Stream    : not null access Root_Stream_Type'Class;
1165       Container : out Set)
1166    is
1167       function Read_Node (Stream : not null access Root_Stream_Type'Class)
1168                           return Count_Type;
1169
1170       procedure Read_Nodes is
1171         new HT_Ops.Generic_Read (Read_Node);
1172
1173       ---------------
1174       -- Read_Node --
1175       ---------------
1176
1177       function Read_Node (Stream : not null access Root_Stream_Type'Class)
1178                           return Count_Type
1179       is
1180          procedure Read_Element (Node : in out Node_Type);
1181          pragma Inline (Read_Element);
1182
1183          procedure Allocate is new Generic_Allocate (Read_Element);
1184
1185          ------------------
1186          -- Read_Element --
1187          ------------------
1188
1189          procedure Read_Element (Node : in out Node_Type) is
1190          begin
1191             Element_Type'Read (Stream, Node.Element);
1192          end Read_Element;
1193
1194          Node : Count_Type;
1195
1196       --  Start of processing for Read_Node
1197
1198       begin
1199          Allocate (Container, Node);
1200          return Node;
1201       end Read_Node;
1202
1203    --  Start of processing for Read
1204
1205    begin
1206       Read_Nodes (Stream, Container);
1207    end Read;
1208
1209    procedure Read
1210      (Stream : not null access Root_Stream_Type'Class;
1211       Item   : out Cursor)
1212    is
1213    begin
1214       raise Program_Error with "attempt to stream set cursor";
1215    end Read;
1216
1217    -------------
1218    -- Replace --
1219    -------------
1220
1221    procedure Replace
1222      (Container : in out Set;
1223       New_Item  : Element_Type)
1224    is
1225       Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1226
1227    begin
1228       if Node = 0 then
1229          raise Constraint_Error with
1230            "attempt to replace element not in set";
1231       end if;
1232
1233       if Container.Lock > 0 then
1234          raise Program_Error with
1235            "attempt to tamper with cursors (set is locked)";
1236       end if;
1237
1238       Container.Nodes (Node).Element := New_Item;
1239    end Replace;
1240
1241    ---------------------
1242    -- Replace_Element --
1243    ---------------------
1244
1245    procedure Replace_Element
1246      (Container : in out Set;
1247       Position  : Cursor;
1248       New_Item  : Element_Type)
1249    is
1250    begin
1251       if not Has_Element (Container, Position) then
1252          raise Constraint_Error with
1253            "Position cursor equals No_Element";
1254       end if;
1255
1256       pragma Assert (Vet (Container, Position),
1257                      "bad cursor in Replace_Element");
1258
1259       Replace_Element (Container, Position.Node, New_Item);
1260    end Replace_Element;
1261
1262    ----------------------
1263    -- Reserve_Capacity --
1264    ----------------------
1265
1266    procedure Reserve_Capacity
1267      (Container : in out Set;
1268       Capacity  : Count_Type)
1269    is
1270    begin
1271       if Capacity > Container.Capacity then
1272          raise Constraint_Error with "requested capacity is too large";
1273       end if;
1274    end Reserve_Capacity;
1275
1276    -----------
1277    -- Right --
1278    -----------
1279
1280    function Right (Container : Set; Position : Cursor) return Set is
1281       Curs : Cursor := First (Container);
1282       C    : Set (Container.Capacity, Container.Modulus) :=
1283                Copy (Container, Container.Capacity);
1284       Node : Count_Type;
1285
1286    begin
1287       if Curs = No_Element then
1288          Clear (C);
1289          return C;
1290       end if;
1291
1292       if Position /= No_Element and not Has_Element (Container, Position) then
1293          raise Constraint_Error;
1294       end if;
1295
1296       while Curs.Node /= Position.Node loop
1297          Node := Curs.Node;
1298          Delete (C, Curs);
1299          Curs := Next (Container, (Node => Node));
1300       end loop;
1301
1302       return C;
1303    end Right;
1304
1305    ------------------
1306    --  Set_Element --
1307    ------------------
1308
1309    procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1310    begin
1311       Node.Element := Item;
1312    end Set_Element;
1313
1314    --------------
1315    -- Set_Next --
1316    --------------
1317
1318    procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1319    begin
1320       Node.Next := Next;
1321    end Set_Next;
1322
1323    ------------------
1324    -- Strict_Equal --
1325    ------------------
1326
1327    function Strict_Equal (Left, Right : Set) return Boolean is
1328       CuL : Cursor := First (Left);
1329       CuR : Cursor := First (Right);
1330
1331    begin
1332       if Length (Left) /= Length (Right) then
1333          return False;
1334       end if;
1335
1336       while CuL.Node /= 0 or CuR.Node /= 0 loop
1337          if CuL.Node /= CuR.Node
1338            or else Left.Nodes (CuL.Node).Element /=
1339                    Right.Nodes (CuR.Node).Element
1340          then
1341             return False;
1342          end if;
1343
1344          CuL := Next (Left, CuL);
1345          CuR := Next (Right, CuR);
1346       end loop;
1347
1348       return True;
1349    end Strict_Equal;
1350
1351    --------------------------
1352    -- Symmetric_Difference --
1353    --------------------------
1354
1355    procedure Symmetric_Difference
1356      (Target : in out Set;
1357       Source : Set)
1358    is
1359       procedure Process (Source_Node : Count_Type);
1360       pragma Inline (Process);
1361
1362       procedure Iterate is new HT_Ops.Generic_Iteration (Process);
1363
1364       -------------
1365       -- Process --
1366       -------------
1367
1368       procedure Process (Source_Node : Count_Type) is
1369          N : Node_Type renames Source.Nodes (Source_Node);
1370          X : Count_Type;
1371          B : Boolean;
1372       begin
1373          if Is_In (Target, N) then
1374             Delete (Target, N.Element);
1375          else
1376             Insert (Target, N.Element, X, B);
1377             pragma Assert (B);
1378          end if;
1379       end Process;
1380
1381    --  Start of processing for Symmetric_Difference
1382
1383    begin
1384       if Target'Address = Source'Address then
1385          Clear (Target);
1386          return;
1387       end if;
1388
1389       if Length (Target) = 0 then
1390          Assign (Target, Source);
1391          return;
1392       end if;
1393
1394       if Target.Busy > 0 then
1395          raise Program_Error with
1396            "attempt to tamper with elements (set is busy)";
1397       end if;
1398
1399       Iterate (Source);
1400    end Symmetric_Difference;
1401
1402    function Symmetric_Difference (Left, Right : Set) return Set is
1403       C : Count_Type;
1404       H : Hash_Type;
1405
1406    begin
1407       if Left'Address = Right'Address then
1408          return Empty_Set;
1409       end if;
1410
1411       if Length (Right) = 0 then
1412          return Left.Copy;
1413       end if;
1414
1415       if Length (Left) = 0 then
1416          return Right.Copy;
1417       end if;
1418
1419       C := Length (Left) + Length (Right);
1420       H := Default_Modulus (C);
1421
1422       return S : Set (C, H) do
1423          Difference (Left, Right, S);
1424          Difference (Right, Left, S);
1425       end return;
1426    end Symmetric_Difference;
1427
1428    ------------
1429    -- To_Set --
1430    ------------
1431
1432    function To_Set (New_Item : Element_Type) return Set is
1433       X : Count_Type;
1434       B : Boolean;
1435
1436    begin
1437       return S : Set (Capacity => 1, Modulus => 1) do
1438          Insert (S, New_Item, X, B);
1439          pragma Assert (B);
1440       end return;
1441    end To_Set;
1442
1443    -----------
1444    -- Union --
1445    -----------
1446
1447    procedure Union
1448      (Target : in out Set;
1449       Source : Set)
1450    is
1451       procedure Process (Src_Node : Count_Type);
1452
1453       procedure Iterate is
1454         new HT_Ops.Generic_Iteration (Process);
1455
1456       -------------
1457       -- Process --
1458       -------------
1459
1460       procedure Process (Src_Node : Count_Type) is
1461          N : Node_Type renames Source.Nodes (Src_Node);
1462          E : Element_Type renames N.Element;
1463
1464          X : Count_Type;
1465          B : Boolean;
1466
1467       begin
1468          Insert (Target, E, X, B);
1469       end Process;
1470
1471       --  Start of processing for Union
1472
1473    begin
1474
1475       if Target'Address = Source'Address then
1476          return;
1477       end if;
1478
1479       if Target.Busy > 0 then
1480          raise Program_Error with
1481            "attempt to tamper with elements (set is busy)";
1482       end if;
1483       Iterate (Source);
1484    end Union;
1485
1486    function Union (Left, Right : Set) return Set is
1487       C : Count_Type;
1488       H : Hash_Type;
1489
1490    begin
1491       if Left'Address = Right'Address then
1492          return Left.Copy;
1493       end if;
1494
1495       if Length (Right) = 0 then
1496          return Left.Copy;
1497       end if;
1498
1499       if Length (Left) = 0 then
1500          return Right.Copy;
1501       end if;
1502
1503       C := Length (Left) + Length (Right);
1504       H := Default_Modulus (C);
1505       return S : Set (C, H) do
1506          Assign (Target => S, Source => Left);
1507          Union (Target => S, Source => Right);
1508       end return;
1509    end Union;
1510
1511    ---------
1512    -- Vet --
1513    ---------
1514
1515    function Vet (Container : Set; Position : Cursor) return Boolean is
1516    begin
1517       if Position.Node = 0 then
1518          return True;
1519       end if;
1520
1521       declare
1522          S : Set renames Container;
1523          N : Nodes_Type renames S.Nodes;
1524          X : Count_Type;
1525
1526       begin
1527          if S.Length = 0 then
1528             return False;
1529          end if;
1530
1531          if Position.Node > N'Last then
1532             return False;
1533          end if;
1534
1535          if N (Position.Node).Next = Position.Node then
1536             return False;
1537          end if;
1538
1539          X := S.Buckets (Element_Keys.Index (S, N (Position.Node).Element));
1540
1541          for J in 1 .. S.Length loop
1542             if X = Position.Node then
1543                return True;
1544             end if;
1545
1546             if X = 0 then
1547                return False;
1548             end if;
1549
1550             if X = N (X).Next then  --  to prevent unnecessary looping
1551                return False;
1552             end if;
1553
1554             X := N (X).Next;
1555          end loop;
1556
1557          return False;
1558       end;
1559    end Vet;
1560
1561    -----------
1562    -- Write --
1563    -----------
1564
1565    procedure Write
1566      (Stream    : not null access Root_Stream_Type'Class;
1567       Container : Set)
1568    is
1569       procedure Write_Node
1570         (Stream : not null access Root_Stream_Type'Class;
1571          Node   : Node_Type);
1572       pragma Inline (Write_Node);
1573
1574       procedure Write_Nodes is
1575         new HT_Ops.Generic_Write (Write_Node);
1576
1577       ----------------
1578       -- Write_Node --
1579       ----------------
1580
1581       procedure Write_Node
1582         (Stream : not null access Root_Stream_Type'Class;
1583          Node   : Node_Type)
1584       is
1585       begin
1586          Element_Type'Write (Stream, Node.Element);
1587       end Write_Node;
1588
1589       --  Start of processing for Write
1590
1591    begin
1592       Write_Nodes (Stream, Container);
1593    end Write;
1594
1595    procedure Write
1596      (Stream : not null access Root_Stream_Type'Class;
1597       Item   : Cursor)
1598    is
1599    begin
1600       raise Program_Error with "attempt to stream set cursor";
1601    end Write;
1602    package body Generic_Keys is
1603
1604       -----------------------
1605       -- Local Subprograms --
1606       -----------------------
1607
1608       function Equivalent_Key_Node
1609         (Key  : Key_Type;
1610          Node : Node_Type) return Boolean;
1611       pragma Inline (Equivalent_Key_Node);
1612
1613       --------------------------
1614       -- Local Instantiations --
1615       --------------------------
1616
1617       package Key_Keys is
1618         new Hash_Tables.Generic_Bounded_Keys
1619           (HT_Types        => HT_Types,
1620            Next            => Next,
1621            Set_Next        => Set_Next,
1622            Key_Type        => Key_Type,
1623            Hash            => Hash,
1624            Equivalent_Keys => Equivalent_Key_Node);
1625
1626       --------------
1627       -- Contains --
1628       --------------
1629
1630       function Contains
1631         (Container : Set;
1632          Key       : Key_Type) return Boolean
1633       is
1634       begin
1635          return Find (Container, Key) /= No_Element;
1636       end Contains;
1637
1638       ------------
1639       -- Delete --
1640       ------------
1641
1642       procedure Delete
1643         (Container : in out Set;
1644          Key       : Key_Type)
1645       is
1646          X : Count_Type;
1647
1648       begin
1649
1650          Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1651
1652          if X = 0 then
1653             raise Constraint_Error with "attempt to delete key not in set";
1654          end if;
1655
1656          Free (Container, X);
1657       end Delete;
1658
1659       -------------
1660       -- Element --
1661       -------------
1662
1663       function Element
1664         (Container : Set;
1665          Key       : Key_Type) return Element_Type
1666       is
1667          Node : constant Count_Type := Find (Container, Key).Node;
1668
1669       begin
1670          if Node = 0 then
1671             raise Constraint_Error with "key not in map";
1672          end if;
1673
1674          return Container.Nodes (Node).Element;
1675       end Element;
1676
1677       -------------------------
1678       -- Equivalent_Key_Node --
1679       -------------------------
1680
1681       function Equivalent_Key_Node
1682         (Key  : Key_Type;
1683          Node : Node_Type) return Boolean
1684       is
1685       begin
1686          return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1687       end Equivalent_Key_Node;
1688
1689       -------------
1690       -- Exclude --
1691       -------------
1692
1693       procedure Exclude
1694         (Container : in out Set;
1695          Key       : Key_Type)
1696       is
1697          X : Count_Type;
1698       begin
1699          Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1700          Free (Container, X);
1701       end Exclude;
1702
1703       ----------
1704       -- Find --
1705       ----------
1706
1707       function Find
1708         (Container : Set;
1709          Key       : Key_Type) return Cursor
1710       is
1711          Node : constant Count_Type := Key_Keys.Find (Container, Key);
1712       begin
1713          return (if Node = 0 then No_Element else (Node => Node));
1714       end Find;
1715
1716       ---------
1717       -- Key --
1718       ---------
1719
1720       function Key (Container : Set; Position : Cursor) return Key_Type is
1721       begin
1722          if not Has_Element (Container, Position) then
1723             raise Constraint_Error with
1724               "Position cursor has no element";
1725          end if;
1726
1727          pragma Assert
1728            (Vet (Container, Position), "bad cursor in function Key");
1729
1730          declare
1731             N  : Node_Type renames Container.Nodes (Position.Node);
1732          begin
1733             return Key (N.Element);
1734          end;
1735       end Key;
1736
1737       -------------
1738       -- Replace --
1739       -------------
1740
1741       procedure Replace
1742         (Container : in out Set;
1743          Key       : Key_Type;
1744          New_Item  : Element_Type)
1745       is
1746          Node : constant Count_Type := Key_Keys.Find (Container, Key);
1747
1748       begin
1749          if Node = 0 then
1750             raise Constraint_Error with
1751               "attempt to replace key not in set";
1752          end if;
1753
1754          Replace_Element (Container, Node, New_Item);
1755       end Replace;
1756
1757       -----------------------------------
1758       -- Update_Element_Preserving_Key --
1759       -----------------------------------
1760
1761       procedure Update_Element_Preserving_Key
1762         (Container : in out Set;
1763          Position  : Cursor;
1764          Process   : not null access
1765                        procedure (Element : in out Element_Type))
1766       is
1767          Indx : Hash_Type;
1768          N    : Nodes_Type renames Container.Nodes;
1769
1770       begin
1771
1772          if Position.Node = 0 then
1773             raise Constraint_Error with
1774               "Position cursor equals No_Element";
1775          end if;
1776
1777          pragma Assert
1778            (Vet (Container, Position),
1779             "bad cursor in Update_Element_Preserving_Key");
1780
1781       --  Record bucket now, in case key is changed
1782
1783          Indx := HT_Ops.Index (Container.Buckets, N (Position.Node));
1784
1785          declare
1786             E : Element_Type renames N (Position.Node).Element;
1787             K : constant Key_Type := Key (E);
1788             B : Natural renames Container.Busy;
1789             L : Natural renames Container.Lock;
1790
1791          begin
1792             B := B + 1;
1793             L := L + 1;
1794
1795             begin
1796                Process (E);
1797             exception
1798                when others =>
1799                   L := L - 1;
1800                   B := B - 1;
1801                   raise;
1802             end;
1803
1804             L := L - 1;
1805             B := B - 1;
1806
1807             if Equivalent_Keys (K, Key (E)) then
1808                pragma Assert (Hash (K) = Hash (E));
1809                return;
1810             end if;
1811          end;
1812
1813          --  Key was modified, so remove this node from set
1814
1815          if Container.Buckets (Indx) = Position.Node then
1816             Container.Buckets (Indx) := N (Position.Node).Next;
1817
1818          else
1819             declare
1820                Prev : Count_Type := Container.Buckets (Indx);
1821
1822             begin
1823                while N (Prev).Next /= Position.Node loop
1824                   Prev := N (Prev).Next;
1825
1826                   if Prev = 0 then
1827                      raise Program_Error with
1828                        "Position cursor is bad (node not found)";
1829                   end if;
1830                end loop;
1831
1832                N (Prev).Next := N (Position.Node).Next;
1833             end;
1834          end if;
1835
1836          Container.Length := Container.Length - 1;
1837          Free (Container, Position.Node);
1838
1839          raise Program_Error with "key was modified";
1840       end Update_Element_Preserving_Key;
1841
1842    end Generic_Keys;
1843
1844 end Ada.Containers.Formal_Hashed_Sets;