* config/sh/sh.c (sh_gimplify_va_arg_expr): Don't call
[official-gcc.git] / gcc / ada / a-cbhase.adb
blobe477690d997716109cf0e93d50a57d1cd3920cc9
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ H A S H E D _ S E T S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2010, 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 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
31 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
33 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
34 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
36 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
38 with System; use type System.Address;
40 package body Ada.Containers.Bounded_Hashed_Sets is
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 function Equivalent_Keys
47 (Key : Element_Type;
48 Node : Node_Type) return Boolean;
49 pragma Inline (Equivalent_Keys);
51 function Hash_Node (Node : Node_Type) return Hash_Type;
52 pragma Inline (Hash_Node);
54 procedure Insert
55 (Container : in out Set;
56 New_Item : Element_Type;
57 Node : out Count_Type;
58 Inserted : out Boolean);
60 function Is_In
61 (HT : Set;
62 Key : Node_Type) return Boolean;
63 pragma Inline (Is_In);
65 procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
66 pragma Inline (Set_Element);
68 function Next (Node : Node_Type) return Count_Type;
69 pragma Inline (Next);
71 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
72 pragma Inline (Set_Next);
74 function Vet (Position : Cursor) return Boolean;
76 --------------------------
77 -- Local Instantiations --
78 --------------------------
80 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
81 (HT_Types => HT_Types,
82 Hash_Node => Hash_Node,
83 Next => Next,
84 Set_Next => Set_Next);
86 package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
87 (HT_Types => HT_Types,
88 Next => Next,
89 Set_Next => Set_Next,
90 Key_Type => Element_Type,
91 Hash => Hash,
92 Equivalent_Keys => Equivalent_Keys);
94 procedure Replace_Element is
95 new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
97 ---------
98 -- "=" --
99 ---------
101 function "=" (Left, Right : Set) return Boolean is
102 function Find_Equal_Key
103 (R_HT : Hash_Table_Type'Class;
104 L_Node : Node_Type) return Boolean;
105 pragma Inline (Find_Equal_Key);
107 function Is_Equal is
108 new HT_Ops.Generic_Equal (Find_Equal_Key);
110 --------------------
111 -- Find_Equal_Key --
112 --------------------
114 function Find_Equal_Key
115 (R_HT : Hash_Table_Type'Class;
116 L_Node : Node_Type) return Boolean
118 R_Index : constant Hash_Type :=
119 Element_Keys.Index (R_HT, L_Node.Element);
121 R_Node : Count_Type := R_HT.Buckets (R_Index);
123 begin
124 loop
125 if R_Node = 0 then
126 return False;
127 end if;
129 if L_Node.Element = R_HT.Nodes (R_Node).Element then
130 return True;
131 end if;
133 R_Node := Next (R_HT.Nodes (R_Node));
134 end loop;
135 end Find_Equal_Key;
137 -- Start of processing for "="
139 begin
140 return Is_Equal (Left, Right);
141 end "=";
143 ------------
144 -- Assign --
145 ------------
147 procedure Assign (Target : in out Set; Source : Set) is
148 procedure Insert_Element (Source_Node : Count_Type);
150 procedure Insert_Elements is
151 new HT_Ops.Generic_Iteration (Insert_Element);
153 --------------------
154 -- Insert_Element --
155 --------------------
157 procedure Insert_Element (Source_Node : Count_Type) is
158 N : Node_Type renames Source.Nodes (Source_Node);
159 X : Count_Type;
160 B : Boolean;
162 begin
163 Insert (Target, N.Element, X, B);
164 pragma Assert (B);
165 end Insert_Element;
167 -- Start of processing for Assign
169 begin
170 if Target'Address = Source'Address then
171 return;
172 end if;
174 if Target.Capacity < Source.Length then
175 raise Capacity_Error
176 with "Target capacity is less than Source length";
177 end if;
179 HT_Ops.Clear (Target);
180 Insert_Elements (Source);
181 end Assign;
183 --------------
184 -- Capacity --
185 --------------
187 function Capacity (Container : Set) return Count_Type is
188 begin
189 return Container.Capacity;
190 end Capacity;
192 -----------
193 -- Clear --
194 -----------
196 procedure Clear (Container : in out Set) is
197 begin
198 HT_Ops.Clear (Container);
199 end Clear;
201 --------------
202 -- Contains --
203 --------------
205 function Contains (Container : Set; Item : Element_Type) return Boolean is
206 begin
207 return Find (Container, Item) /= No_Element;
208 end Contains;
210 ----------
211 -- Copy --
212 ----------
214 function Copy
215 (Source : Set;
216 Capacity : Count_Type := 0;
217 Modulus : Hash_Type := 0) return Set
219 C : Count_Type;
220 M : Hash_Type;
222 begin
223 if Capacity = 0 then
224 C := Source.Length;
226 elsif Capacity >= Source.Length then
227 C := Capacity;
229 else
230 raise Capacity_Error with "Capacity value too small";
231 end if;
233 if Modulus = 0 then
234 M := Default_Modulus (C);
235 else
236 M := Modulus;
237 end if;
239 return Target : Set (Capacity => C, Modulus => M) do
240 Assign (Target => Target, Source => Source);
241 end return;
242 end Copy;
244 ---------------------
245 -- Default_Modulus --
246 ---------------------
248 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
249 begin
250 return To_Prime (Capacity);
251 end Default_Modulus;
253 ------------
254 -- Delete --
255 ------------
257 procedure Delete
258 (Container : in out Set;
259 Item : Element_Type)
261 X : Count_Type;
263 begin
264 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
266 if X = 0 then
267 raise Constraint_Error with "attempt to delete element not in set";
268 end if;
270 HT_Ops.Free (Container, X);
271 end Delete;
273 procedure Delete
274 (Container : in out Set;
275 Position : in out Cursor)
277 begin
278 if Position.Node = 0 then
279 raise Constraint_Error with "Position cursor equals No_Element";
280 end if;
282 if Position.Container /= Container'Unrestricted_Access then
283 raise Program_Error with "Position cursor designates wrong set";
284 end if;
286 if Container.Busy > 0 then
287 raise Program_Error with
288 "attempt to tamper with cursors (set is busy)";
289 end if;
291 pragma Assert (Vet (Position), "bad cursor in Delete");
293 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
294 HT_Ops.Free (Container, Position.Node);
296 Position := No_Element;
297 end Delete;
299 ----------------
300 -- Difference --
301 ----------------
303 procedure Difference
304 (Target : in out Set;
305 Source : Set)
307 Tgt_Node, Src_Node : Count_Type;
309 TN : Nodes_Type renames Target.Nodes;
310 SN : Nodes_Type renames Source.Nodes;
312 begin
313 if Target'Address = Source'Address then
314 HT_Ops.Clear (Target);
315 return;
316 end if;
318 if Source.Length = 0 then
319 return;
320 end if;
322 if Target.Busy > 0 then
323 raise Program_Error with
324 "attempt to tamper with cursors (set is busy)";
325 end if;
327 if Source.Length < Target.Length then
328 Src_Node := HT_Ops.First (Source);
329 while Src_Node /= 0 loop
330 Tgt_Node := Element_Keys.Find (Target, SN (Src_Node).Element);
332 if Tgt_Node /= 0 then
333 HT_Ops.Delete_Node_Sans_Free (Target, Tgt_Node);
334 HT_Ops.Free (Target, Tgt_Node);
335 end if;
337 Src_Node := HT_Ops.Next (Source, Src_Node);
338 end loop;
340 else
341 Tgt_Node := HT_Ops.First (Target);
342 while Tgt_Node /= 0 loop
343 if Is_In (Source, TN (Tgt_Node)) then
344 declare
345 X : constant Count_Type := Tgt_Node;
346 begin
347 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
348 HT_Ops.Delete_Node_Sans_Free (Target, X);
349 HT_Ops.Free (Target, X);
350 end;
352 else
353 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
354 end if;
355 end loop;
356 end if;
357 end Difference;
359 function Difference (Left, Right : Set) return Set is
360 begin
361 if Left'Address = Right'Address then
362 return Empty_Set;
363 end if;
365 if Left.Length = 0 then
366 return Empty_Set;
367 end if;
369 if Right.Length = 0 then
370 return Left;
371 end if;
373 return Result : Set (Left.Length, To_Prime (Left.Length)) do
374 Iterate_Left : declare
375 procedure Process (L_Node : Count_Type);
377 procedure Iterate is
378 new HT_Ops.Generic_Iteration (Process);
380 -------------
381 -- Process --
382 -------------
384 procedure Process (L_Node : Count_Type) is
385 N : Node_Type renames Left.Nodes (L_Node);
386 X : Count_Type;
387 B : Boolean;
389 begin
390 if not Is_In (Right, N) then
391 Insert (Result, N.Element, X, B); -- optimize this ???
392 pragma Assert (B);
393 pragma Assert (X > 0);
394 end if;
395 end Process;
397 -- Start of processing for Iterate_Left
399 begin
400 Iterate (Left);
401 end Iterate_Left;
402 end return;
403 end Difference;
405 -------------
406 -- Element --
407 -------------
409 function Element (Position : Cursor) return Element_Type is
410 begin
411 if Position.Node = 0 then
412 raise Constraint_Error with "Position cursor equals No_Element";
413 end if;
415 pragma Assert (Vet (Position), "bad cursor in function Element");
417 declare
418 S : Set renames Position.Container.all;
419 N : Node_Type renames S.Nodes (Position.Node);
421 begin
422 return N.Element;
423 end;
424 end Element;
426 ---------------------
427 -- Equivalent_Sets --
428 ---------------------
430 function Equivalent_Sets (Left, Right : Set) return Boolean is
431 function Find_Equivalent_Key
432 (R_HT : Hash_Table_Type'Class;
433 L_Node : Node_Type) return Boolean;
434 pragma Inline (Find_Equivalent_Key);
436 function Is_Equivalent is
437 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
439 -------------------------
440 -- Find_Equivalent_Key --
441 -------------------------
443 function Find_Equivalent_Key
444 (R_HT : Hash_Table_Type'Class;
445 L_Node : Node_Type) return Boolean
447 R_Index : constant Hash_Type :=
448 Element_Keys.Index (R_HT, L_Node.Element);
450 R_Node : Count_Type := R_HT.Buckets (R_Index);
452 RN : Nodes_Type renames R_HT.Nodes;
454 begin
455 loop
456 if R_Node = 0 then
457 return False;
458 end if;
460 if Equivalent_Elements (L_Node.Element, RN (R_Node).Element) then
461 return True;
462 end if;
464 R_Node := HT_Ops.Next (R_HT, R_Node);
465 end loop;
466 end Find_Equivalent_Key;
468 -- Start of processing for Equivalent_Sets
470 begin
471 return Is_Equivalent (Left, Right);
472 end Equivalent_Sets;
474 -------------------------
475 -- Equivalent_Elements --
476 -------------------------
478 function Equivalent_Elements (Left, Right : Cursor)
479 return Boolean is
480 begin
481 if Left.Node = 0 then
482 raise Constraint_Error with
483 "Left cursor of Equivalent_Elements equals No_Element";
484 end if;
486 if Right.Node = 0 then
487 raise Constraint_Error with
488 "Right cursor of Equivalent_Elements equals No_Element";
489 end if;
491 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
492 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
494 declare
495 LN : Node_Type renames Left.Container.Nodes (Left.Node);
496 RN : Node_Type renames Right.Container.Nodes (Right.Node);
498 begin
499 return Equivalent_Elements (LN.Element, RN.Element);
500 end;
501 end Equivalent_Elements;
503 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
504 return Boolean is
505 begin
506 if Left.Node = 0 then
507 raise Constraint_Error with
508 "Left cursor of Equivalent_Elements equals No_Element";
509 end if;
511 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad");
513 declare
514 LN : Node_Type renames Left.Container.Nodes (Left.Node);
515 begin
516 return Equivalent_Elements (LN.Element, Right);
517 end;
518 end Equivalent_Elements;
520 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
521 return Boolean is
522 begin
523 if Right.Node = 0 then
524 raise Constraint_Error with
525 "Right cursor of Equivalent_Elements equals No_Element";
526 end if;
528 pragma Assert
529 (Vet (Right),
530 "Right cursor of Equivalent_Elements is bad");
532 declare
533 RN : Node_Type renames Right.Container.Nodes (Right.Node);
534 begin
535 return Equivalent_Elements (Left, RN.Element);
536 end;
537 end Equivalent_Elements;
539 ---------------------
540 -- Equivalent_Keys --
541 ---------------------
543 function Equivalent_Keys (Key : Element_Type; Node : Node_Type)
544 return Boolean is
545 begin
546 return Equivalent_Elements (Key, Node.Element);
547 end Equivalent_Keys;
549 -------------
550 -- Exclude --
551 -------------
553 procedure Exclude
554 (Container : in out Set;
555 Item : Element_Type)
557 X : Count_Type;
558 begin
559 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
560 HT_Ops.Free (Container, X);
561 end Exclude;
563 ----------
564 -- Find --
565 ----------
567 function Find
568 (Container : Set;
569 Item : Element_Type) return Cursor
571 Node : constant Count_Type := Element_Keys.Find (Container, Item);
573 begin
574 if Node = 0 then
575 return No_Element;
576 end if;
578 return Cursor'(Container'Unrestricted_Access, Node);
579 end Find;
581 -----------
582 -- First --
583 -----------
585 function First (Container : Set) return Cursor is
586 Node : constant Count_Type := HT_Ops.First (Container);
588 begin
589 if Node = 0 then
590 return No_Element;
591 end if;
593 return Cursor'(Container'Unrestricted_Access, Node);
594 end First;
596 -----------------
597 -- Has_Element --
598 -----------------
600 function Has_Element (Position : Cursor) return Boolean is
601 begin
602 pragma Assert (Vet (Position), "bad cursor in Has_Element");
603 return Position.Node /= 0;
604 end Has_Element;
606 ---------------
607 -- Hash_Node --
608 ---------------
610 function Hash_Node (Node : Node_Type) return Hash_Type is
611 begin
612 return Hash (Node.Element);
613 end Hash_Node;
615 -------------
616 -- Include --
617 -------------
619 procedure Include
620 (Container : in out Set;
621 New_Item : Element_Type)
623 Position : Cursor;
624 Inserted : Boolean;
626 begin
627 Insert (Container, New_Item, Position, Inserted);
629 if not Inserted then
630 if Container.Lock > 0 then
631 raise Program_Error with
632 "attempt to tamper with elements (set is locked)";
633 end if;
635 Container.Nodes (Position.Node).Element := New_Item;
636 end if;
637 end Include;
639 ------------
640 -- Insert --
641 ------------
643 procedure Insert
644 (Container : in out Set;
645 New_Item : Element_Type;
646 Position : out Cursor;
647 Inserted : out Boolean)
649 begin
650 Insert (Container, New_Item, Position.Node, Inserted);
651 Position.Container := Container'Unchecked_Access;
652 end Insert;
654 procedure Insert
655 (Container : in out Set;
656 New_Item : Element_Type)
658 Position : Cursor;
659 pragma Unreferenced (Position);
661 Inserted : Boolean;
663 begin
664 Insert (Container, New_Item, Position, Inserted);
666 if not Inserted then
667 raise Constraint_Error with
668 "attempt to insert element already in set";
669 end if;
670 end Insert;
672 procedure Insert
673 (Container : in out Set;
674 New_Item : Element_Type;
675 Node : out Count_Type;
676 Inserted : out Boolean)
678 procedure Allocate_Set_Element (Node : in out Node_Type);
679 pragma Inline (Allocate_Set_Element);
681 function New_Node return Count_Type;
682 pragma Inline (New_Node);
684 procedure Local_Insert is
685 new Element_Keys.Generic_Conditional_Insert (New_Node);
687 procedure Allocate is
688 new HT_Ops.Generic_Allocate (Allocate_Set_Element);
690 ---------------------------
691 -- Allocate_Set_Element --
692 ---------------------------
694 procedure Allocate_Set_Element (Node : in out Node_Type) is
695 begin
696 Node.Element := New_Item;
697 end Allocate_Set_Element;
699 --------------
700 -- New_Node --
701 --------------
703 function New_Node return Count_Type is
704 Result : Count_Type;
705 begin
706 Allocate (Container, Result);
707 return Result;
708 end New_Node;
710 -- Start of processing for Insert
712 begin
713 -- ???
714 -- if HT_Ops.Capacity (HT) = 0 then
715 -- HT_Ops.Reserve_Capacity (HT, 1);
716 -- end if;
718 Local_Insert (Container, New_Item, Node, Inserted);
720 -- ???
721 -- if Inserted
722 -- and then HT.Length > HT_Ops.Capacity (HT)
723 -- then
724 -- HT_Ops.Reserve_Capacity (HT, HT.Length);
725 -- end if;
726 end Insert;
728 ------------------
729 -- Intersection --
730 ------------------
732 procedure Intersection
733 (Target : in out Set;
734 Source : Set)
736 Tgt_Node : Count_Type;
737 TN : Nodes_Type renames Target.Nodes;
739 begin
740 if Target'Address = Source'Address then
741 return;
742 end if;
744 if Source.Length = 0 then
745 HT_Ops.Clear (Target);
746 return;
747 end if;
749 if Target.Busy > 0 then
750 raise Program_Error with
751 "attempt to tamper with cursors (set is busy)";
752 end if;
754 Tgt_Node := HT_Ops.First (Target);
755 while Tgt_Node /= 0 loop
756 if Is_In (Source, TN (Tgt_Node)) then
757 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
759 else
760 declare
761 X : constant Count_Type := Tgt_Node;
762 begin
763 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
764 HT_Ops.Delete_Node_Sans_Free (Target, X);
765 HT_Ops.Free (Target, X);
766 end;
767 end if;
768 end loop;
769 end Intersection;
771 function Intersection (Left, Right : Set) return Set is
772 C : Count_Type;
774 begin
775 if Left'Address = Right'Address then
776 return Left;
777 end if;
779 C := Count_Type'Min (Left.Length, Right.Length);
781 if C = 0 then
782 return Empty_Set;
783 end if;
785 return Result : Set (C, To_Prime (C)) do
786 Iterate_Left : declare
787 procedure Process (L_Node : Count_Type);
789 procedure Iterate is
790 new HT_Ops.Generic_Iteration (Process);
792 -------------
793 -- Process --
794 -------------
796 procedure Process (L_Node : Count_Type) is
797 N : Node_Type renames Left.Nodes (L_Node);
798 X : Count_Type;
799 B : Boolean;
801 begin
802 if Is_In (Right, N) then
803 Insert (Result, N.Element, X, B); -- optimize ???
804 pragma Assert (B);
805 pragma Assert (X > 0);
806 end if;
807 end Process;
809 -- Start of processing for Iterate_Left
811 begin
812 Iterate (Left);
813 end Iterate_Left;
814 end return;
815 end Intersection;
817 --------------
818 -- Is_Empty --
819 --------------
821 function Is_Empty (Container : Set) return Boolean is
822 begin
823 return Container.Length = 0;
824 end Is_Empty;
826 -----------
827 -- Is_In --
828 -----------
830 function Is_In (HT : Set; Key : Node_Type) return Boolean is
831 begin
832 return Element_Keys.Find (HT, Key.Element) /= 0;
833 end Is_In;
835 ---------------
836 -- Is_Subset --
837 ---------------
839 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
840 Subset_Node : Count_Type;
841 SN : Nodes_Type renames Subset.Nodes;
843 begin
844 if Subset'Address = Of_Set'Address then
845 return True;
846 end if;
848 if Subset.Length > Of_Set.Length then
849 return False;
850 end if;
852 Subset_Node := HT_Ops.First (Subset);
853 while Subset_Node /= 0 loop
854 if not Is_In (Of_Set, SN (Subset_Node)) then
855 return False;
856 end if;
857 Subset_Node := HT_Ops.Next (Subset, Subset_Node);
858 end loop;
860 return True;
861 end Is_Subset;
863 -------------
864 -- Iterate --
865 -------------
867 procedure Iterate
868 (Container : Set;
869 Process : not null access procedure (Position : Cursor))
871 procedure Process_Node (Node : Count_Type);
872 pragma Inline (Process_Node);
874 procedure Iterate is
875 new HT_Ops.Generic_Iteration (Process_Node);
877 ------------------
878 -- Process_Node --
879 ------------------
881 procedure Process_Node (Node : Count_Type) is
882 begin
883 Process (Cursor'(Container'Unrestricted_Access, Node));
884 end Process_Node;
886 B : Natural renames Container'Unrestricted_Access.Busy;
888 -- Start of processing for Iterate
890 begin
891 B := B + 1;
893 begin
894 Iterate (Container);
895 exception
896 when others =>
897 B := B - 1;
898 raise;
899 end;
901 B := B - 1;
902 end Iterate;
904 ------------
905 -- Length --
906 ------------
908 function Length (Container : Set) return Count_Type is
909 begin
910 return Container.Length;
911 end Length;
913 ----------
914 -- Move --
915 ----------
917 procedure Move (Target : in out Set; Source : in out Set) is
918 begin
919 if Target'Address = Source'Address then
920 return;
921 end if;
923 if Source.Busy > 0 then
924 raise Program_Error with
925 "attempt to tamper with cursors (container is busy)";
926 end if;
928 Assign (Target => Target, Source => Source);
929 end Move;
931 ----------
932 -- Next --
933 ----------
935 function Next (Node : Node_Type) return Count_Type is
936 begin
937 return Node.Next;
938 end Next;
940 function Next (Position : Cursor) return Cursor is
941 begin
942 if Position.Node = 0 then
943 return No_Element;
944 end if;
946 pragma Assert (Vet (Position), "bad cursor in Next");
948 declare
949 HT : Set renames Position.Container.all;
950 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
952 begin
953 if Node = 0 then
954 return No_Element;
955 end if;
957 return Cursor'(Position.Container, Node);
958 end;
959 end Next;
961 procedure Next (Position : in out Cursor) is
962 begin
963 Position := Next (Position);
964 end Next;
966 -------------
967 -- Overlap --
968 -------------
970 function Overlap (Left, Right : Set) return Boolean is
971 Left_Node : Count_Type;
973 begin
974 if Right.Length = 0 then
975 return False;
976 end if;
978 if Left'Address = Right'Address then
979 return True;
980 end if;
982 Left_Node := HT_Ops.First (Left);
983 while Left_Node /= 0 loop
984 if Is_In (Right, Left.Nodes (Left_Node)) then
985 return True;
986 end if;
987 Left_Node := HT_Ops.Next (Left, Left_Node);
988 end loop;
990 return False;
991 end Overlap;
993 -------------------
994 -- Query_Element --
995 -------------------
997 procedure Query_Element
998 (Position : Cursor;
999 Process : not null access procedure (Element : Element_Type))
1001 begin
1002 if Position.Node = 0 then
1003 raise Constraint_Error with
1004 "Position cursor of Query_Element equals No_Element";
1005 end if;
1007 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1009 declare
1010 S : Set renames Position.Container.all;
1011 B : Natural renames S.Busy;
1012 L : Natural renames S.Lock;
1014 begin
1015 B := B + 1;
1016 L := L + 1;
1018 begin
1019 Process (S.Nodes (Position.Node).Element);
1020 exception
1021 when others =>
1022 L := L - 1;
1023 B := B - 1;
1024 raise;
1025 end;
1027 L := L - 1;
1028 B := B - 1;
1029 end;
1030 end Query_Element;
1032 ----------
1033 -- Read --
1034 ----------
1036 procedure Read
1037 (Stream : not null access Root_Stream_Type'Class;
1038 Container : out Set)
1040 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1041 return Count_Type;
1043 procedure Read_Nodes is
1044 new HT_Ops.Generic_Read (Read_Node);
1046 ---------------
1047 -- Read_Node --
1048 ---------------
1050 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1051 return Count_Type
1053 procedure Read_Element (Node : in out Node_Type);
1054 pragma Inline (Read_Element);
1056 procedure Allocate is
1057 new HT_Ops.Generic_Allocate (Read_Element);
1059 procedure Read_Element (Node : in out Node_Type) is
1060 begin
1061 Element_Type'Read (Stream, Node.Element);
1062 end Read_Element;
1064 Node : Count_Type;
1066 -- Start of processing for Read_Node
1068 begin
1069 Allocate (Container, Node);
1070 return Node;
1071 end Read_Node;
1073 -- Start of processing for Read
1075 begin
1076 Read_Nodes (Stream, Container);
1077 end Read;
1079 procedure Read
1080 (Stream : not null access Root_Stream_Type'Class;
1081 Item : out Cursor)
1083 begin
1084 raise Program_Error with "attempt to stream set cursor";
1085 end Read;
1087 -------------
1088 -- Replace --
1089 -------------
1091 procedure Replace
1092 (Container : in out Set;
1093 New_Item : Element_Type)
1095 Node : constant Count_Type :=
1096 Element_Keys.Find (Container, New_Item);
1098 begin
1099 if Node = 0 then
1100 raise Constraint_Error with
1101 "attempt to replace element not in set";
1102 end if;
1104 if Container.Lock > 0 then
1105 raise Program_Error with
1106 "attempt to tamper with elements (set is locked)";
1107 end if;
1109 Container.Nodes (Node).Element := New_Item;
1110 end Replace;
1112 procedure Replace_Element
1113 (Container : in out Set;
1114 Position : Cursor;
1115 New_Item : Element_Type)
1117 begin
1118 if Position.Node = 0 then
1119 raise Constraint_Error with
1120 "Position cursor equals No_Element";
1121 end if;
1123 if Position.Container /= Container'Unrestricted_Access then
1124 raise Program_Error with
1125 "Position cursor designates wrong set";
1126 end if;
1128 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1130 Replace_Element (Container, Position.Node, New_Item);
1131 end Replace_Element;
1133 ----------------------
1134 -- Reserve_Capacity --
1135 ----------------------
1137 procedure Reserve_Capacity
1138 (Container : in out Set;
1139 Capacity : Count_Type)
1141 begin
1142 if Capacity > Container.Capacity then
1143 raise Capacity_Error with "requested capacity is too large";
1144 end if;
1145 end Reserve_Capacity;
1147 ------------------
1148 -- Set_Element --
1149 ------------------
1151 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1152 begin
1153 Node.Element := Item;
1154 end Set_Element;
1156 --------------
1157 -- Set_Next --
1158 --------------
1160 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1161 begin
1162 Node.Next := Next;
1163 end Set_Next;
1165 --------------------------
1166 -- Symmetric_Difference --
1167 --------------------------
1169 procedure Symmetric_Difference
1170 (Target : in out Set;
1171 Source : Set)
1173 procedure Process (Source_Node : Count_Type);
1174 pragma Inline (Process);
1176 procedure Iterate is
1177 new HT_Ops.Generic_Iteration (Process);
1179 -------------
1180 -- Process --
1181 -------------
1183 procedure Process (Source_Node : Count_Type) is
1184 N : Node_Type renames Source.Nodes (Source_Node);
1185 X : Count_Type;
1186 B : Boolean;
1188 begin
1189 if Is_In (Target, N) then
1190 Delete (Target, N.Element);
1191 else
1192 Insert (Target, N.Element, X, B);
1193 pragma Assert (B);
1194 end if;
1195 end Process;
1197 -- Start of processing for Symmetric_Difference
1199 begin
1200 if Target'Address = Source'Address then
1201 HT_Ops.Clear (Target);
1202 return;
1203 end if;
1205 if Target.Length = 0 then
1206 Assign (Target => Target, Source => Source);
1207 return;
1208 end if;
1210 if Target.Busy > 0 then
1211 raise Program_Error with
1212 "attempt to tamper with cursors (set is busy)";
1213 end if;
1215 Iterate (Source);
1216 end Symmetric_Difference;
1218 function Symmetric_Difference (Left, Right : Set) return Set is
1219 C : Count_Type;
1221 begin
1222 if Left'Address = Right'Address then
1223 return Empty_Set;
1224 end if;
1226 if Right.Length = 0 then
1227 return Left;
1228 end if;
1230 if Left.Length = 0 then
1231 return Right;
1232 end if;
1234 C := Left.Length + Right.Length;
1236 return Result : Set (C, To_Prime (C)) do
1237 Iterate_Left : declare
1238 procedure Process (L_Node : Count_Type);
1240 procedure Iterate is
1241 new HT_Ops.Generic_Iteration (Process);
1243 -------------
1244 -- Process --
1245 -------------
1247 procedure Process (L_Node : Count_Type) is
1248 N : Node_Type renames Left.Nodes (L_Node);
1249 X : Count_Type;
1250 B : Boolean;
1252 begin
1253 if not Is_In (Right, N) then
1254 Insert (Result, N.Element, X, B);
1255 pragma Assert (B);
1256 end if;
1257 end Process;
1259 -- Start of processing for Iterate_Left
1261 begin
1262 Iterate (Left);
1263 end Iterate_Left;
1265 Iterate_Right : declare
1266 procedure Process (R_Node : Count_Type);
1268 procedure Iterate is
1269 new HT_Ops.Generic_Iteration (Process);
1271 -------------
1272 -- Process --
1273 -------------
1275 procedure Process (R_Node : Count_Type) is
1276 N : Node_Type renames Left.Nodes (R_Node);
1277 X : Count_Type;
1278 B : Boolean;
1280 begin
1281 if not Is_In (Left, N) then
1282 Insert (Result, N.Element, X, B);
1283 pragma Assert (B);
1284 end if;
1285 end Process;
1287 -- Start of processing for Iterate_Right
1289 begin
1290 Iterate (Right);
1291 end Iterate_Right;
1292 end return;
1293 end Symmetric_Difference;
1295 ------------
1296 -- To_Set --
1297 ------------
1299 function To_Set (New_Item : Element_Type) return Set is
1300 X : Count_Type;
1301 B : Boolean;
1303 begin
1304 return Result : Set (1, 1) do
1305 Insert (Result, New_Item, X, B);
1306 pragma Assert (B);
1307 end return;
1308 end To_Set;
1310 -----------
1311 -- Union --
1312 -----------
1314 procedure Union
1315 (Target : in out Set;
1316 Source : Set)
1318 procedure Process (Src_Node : Count_Type);
1320 procedure Iterate is
1321 new HT_Ops.Generic_Iteration (Process);
1323 -------------
1324 -- Process --
1325 -------------
1327 procedure Process (Src_Node : Count_Type) is
1328 N : Node_Type renames Source.Nodes (Src_Node);
1329 X : Count_Type;
1330 B : Boolean;
1332 begin
1333 Insert (Target, N.Element, X, B);
1334 end Process;
1336 -- Start of processing for Union
1338 begin
1339 if Target'Address = Source'Address then
1340 return;
1341 end if;
1343 if Target.Busy > 0 then
1344 raise Program_Error with
1345 "attempt to tamper with cursors (set is busy)";
1346 end if;
1348 -- ???
1349 -- declare
1350 -- N : constant Count_Type := Target.Length + Source.Length;
1351 -- begin
1352 -- if N > HT_Ops.Capacity (Target.HT) then
1353 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1354 -- end if;
1355 -- end;
1357 Iterate (Source);
1358 end Union;
1360 function Union (Left, Right : Set) return Set is
1361 C : Count_Type;
1363 begin
1364 if Left'Address = Right'Address then
1365 return Left;
1366 end if;
1368 if Right.Length = 0 then
1369 return Left;
1370 end if;
1372 if Left.Length = 0 then
1373 return Right;
1374 end if;
1376 C := Left.Length + Right.Length;
1378 return Result : Set (C, To_Prime (C)) do
1379 Assign (Target => Result, Source => Left);
1380 Union (Target => Result, Source => Right);
1381 end return;
1382 end Union;
1384 ---------
1385 -- Vet --
1386 ---------
1388 function Vet (Position : Cursor) return Boolean is
1389 begin
1390 if Position.Node = 0 then
1391 return Position.Container = null;
1392 end if;
1394 if Position.Container = null then
1395 return False;
1396 end if;
1398 declare
1399 S : Set renames Position.Container.all;
1400 N : Nodes_Type renames S.Nodes;
1401 X : Count_Type;
1403 begin
1404 if S.Length = 0 then
1405 return False;
1406 end if;
1408 if Position.Node > N'Last then
1409 return False;
1410 end if;
1412 if N (Position.Node).Next = Position.Node then
1413 return False;
1414 end if;
1416 X := S.Buckets (Element_Keys.Index (S, N (Position.Node).Element));
1418 for J in 1 .. S.Length loop
1419 if X = Position.Node then
1420 return True;
1421 end if;
1423 if X = 0 then
1424 return False;
1425 end if;
1427 if X = N (X).Next then -- to prevent unnecessary looping
1428 return False;
1429 end if;
1431 X := N (X).Next;
1432 end loop;
1434 return False;
1435 end;
1436 end Vet;
1438 -----------
1439 -- Write --
1440 -----------
1442 procedure Write
1443 (Stream : not null access Root_Stream_Type'Class;
1444 Container : Set)
1446 procedure Write_Node
1447 (Stream : not null access Root_Stream_Type'Class;
1448 Node : Node_Type);
1449 pragma Inline (Write_Node);
1451 procedure Write_Nodes is
1452 new HT_Ops.Generic_Write (Write_Node);
1454 ----------------
1455 -- Write_Node --
1456 ----------------
1458 procedure Write_Node
1459 (Stream : not null access Root_Stream_Type'Class;
1460 Node : Node_Type)
1462 begin
1463 Element_Type'Write (Stream, Node.Element);
1464 end Write_Node;
1466 -- Start of processing for Write
1468 begin
1469 Write_Nodes (Stream, Container);
1470 end Write;
1472 procedure Write
1473 (Stream : not null access Root_Stream_Type'Class;
1474 Item : Cursor)
1476 begin
1477 raise Program_Error with "attempt to stream set cursor";
1478 end Write;
1480 package body Generic_Keys is
1482 -----------------------
1483 -- Local Subprograms --
1484 -----------------------
1486 function Equivalent_Key_Node
1487 (Key : Key_Type;
1488 Node : Node_Type) return Boolean;
1489 pragma Inline (Equivalent_Key_Node);
1491 --------------------------
1492 -- Local Instantiations --
1493 --------------------------
1495 package Key_Keys is
1496 new Hash_Tables.Generic_Bounded_Keys
1497 (HT_Types => HT_Types,
1498 Next => Next,
1499 Set_Next => Set_Next,
1500 Key_Type => Key_Type,
1501 Hash => Hash,
1502 Equivalent_Keys => Equivalent_Key_Node);
1504 --------------
1505 -- Contains --
1506 --------------
1508 function Contains
1509 (Container : Set;
1510 Key : Key_Type) return Boolean
1512 begin
1513 return Find (Container, Key) /= No_Element;
1514 end Contains;
1516 ------------
1517 -- Delete --
1518 ------------
1520 procedure Delete
1521 (Container : in out Set;
1522 Key : Key_Type)
1524 X : Count_Type;
1526 begin
1527 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1529 if X = 0 then
1530 raise Constraint_Error with "attempt to delete key not in set";
1531 end if;
1533 HT_Ops.Free (Container, X);
1534 end Delete;
1536 -------------
1537 -- Element --
1538 -------------
1540 function Element
1541 (Container : Set;
1542 Key : Key_Type) return Element_Type
1544 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1546 begin
1547 if Node = 0 then
1548 raise Constraint_Error with "key not in map";
1549 end if;
1551 return Container.Nodes (Node).Element;
1552 end Element;
1554 -------------------------
1555 -- Equivalent_Key_Node --
1556 -------------------------
1558 function Equivalent_Key_Node
1559 (Key : Key_Type;
1560 Node : Node_Type) return Boolean
1562 begin
1563 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1564 end Equivalent_Key_Node;
1566 -------------
1567 -- Exclude --
1568 -------------
1570 procedure Exclude
1571 (Container : in out Set;
1572 Key : Key_Type)
1574 X : Count_Type;
1575 begin
1576 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1577 HT_Ops.Free (Container, X);
1578 end Exclude;
1580 ----------
1581 -- Find --
1582 ----------
1584 function Find
1585 (Container : Set;
1586 Key : Key_Type) return Cursor
1588 Node : constant Count_Type :=
1589 Key_Keys.Find (Container, Key);
1591 begin
1592 if Node = 0 then
1593 return No_Element;
1594 end if;
1596 return Cursor'(Container'Unrestricted_Access, Node);
1597 end Find;
1599 ---------
1600 -- Key --
1601 ---------
1603 function Key (Position : Cursor) return Key_Type is
1604 begin
1605 if Position.Node = 0 then
1606 raise Constraint_Error with
1607 "Position cursor equals No_Element";
1608 end if;
1610 pragma Assert (Vet (Position), "bad cursor in function Key");
1612 return Key (Position.Container.Nodes (Position.Node).Element);
1613 end Key;
1615 -------------
1616 -- Replace --
1617 -------------
1619 procedure Replace
1620 (Container : in out Set;
1621 Key : Key_Type;
1622 New_Item : Element_Type)
1624 Node : constant Count_Type :=
1625 Key_Keys.Find (Container, Key);
1627 begin
1628 if Node = 0 then
1629 raise Constraint_Error with
1630 "attempt to replace key not in set";
1631 end if;
1633 Replace_Element (Container, Node, New_Item);
1634 end Replace;
1636 -----------------------------------
1637 -- Update_Element_Preserving_Key --
1638 -----------------------------------
1640 procedure Update_Element_Preserving_Key
1641 (Container : in out Set;
1642 Position : Cursor;
1643 Process : not null access
1644 procedure (Element : in out Element_Type))
1646 Indx : Hash_Type;
1647 N : Nodes_Type renames Container.Nodes;
1649 begin
1650 if Position.Node = 0 then
1651 raise Constraint_Error with
1652 "Position cursor equals No_Element";
1653 end if;
1655 if Position.Container /= Container'Unrestricted_Access then
1656 raise Program_Error with
1657 "Position cursor designates wrong set";
1658 end if;
1660 -- ???
1661 -- if HT.Buckets = null
1662 -- or else HT.Buckets'Length = 0
1663 -- or else HT.Length = 0
1664 -- or else Position.Node.Next = Position.Node
1665 -- then
1666 -- raise Program_Error with
1667 -- "Position cursor is bad (set is empty)";
1668 -- end if;
1670 pragma Assert
1671 (Vet (Position),
1672 "bad cursor in Update_Element_Preserving_Key");
1674 -- Record bucket now, in case key is changed.
1675 Indx := HT_Ops.Index (Container.Buckets, N (Position.Node));
1677 declare
1678 E : Element_Type renames N (Position.Node).Element;
1679 K : constant Key_Type := Key (E);
1681 B : Natural renames Container.Busy;
1682 L : Natural renames Container.Lock;
1684 begin
1685 B := B + 1;
1686 L := L + 1;
1688 begin
1689 Process (E);
1690 exception
1691 when others =>
1692 L := L - 1;
1693 B := B - 1;
1694 raise;
1695 end;
1697 L := L - 1;
1698 B := B - 1;
1700 if Equivalent_Keys (K, Key (E)) then
1701 pragma Assert (Hash (K) = Hash (E));
1702 return;
1703 end if;
1704 end;
1706 -- Key was modified, so remove this node from set.
1708 if Container.Buckets (Indx) = Position.Node then
1709 Container.Buckets (Indx) := N (Position.Node).Next;
1711 else
1712 declare
1713 Prev : Count_Type := Container.Buckets (Indx);
1715 begin
1716 while N (Prev).Next /= Position.Node loop
1717 Prev := N (Prev).Next;
1719 if Prev = 0 then
1720 raise Program_Error with
1721 "Position cursor is bad (node not found)";
1722 end if;
1723 end loop;
1725 N (Prev).Next := N (Position.Node).Next;
1726 end;
1727 end if;
1729 Container.Length := Container.Length - 1;
1730 HT_Ops.Free (Container, Position.Node);
1732 raise Program_Error with "key was modified";
1733 end Update_Element_Preserving_Key;
1735 end Generic_Keys;
1737 end Ada.Containers.Bounded_Hashed_Sets;