* libgfortran.h (support_fpu_underflow_control,
[official-gcc.git] / gcc / ada / a-cbhase.adb
blob640fb8e6136de6fcdf6af1be55d5b842a7cb0053
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-2013, 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 (HT : Set; Key : Node_Type) return Boolean;
61 pragma Inline (Is_In);
63 procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
64 pragma Inline (Set_Element);
66 function Next (Node : Node_Type) return Count_Type;
67 pragma Inline (Next);
69 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
70 pragma Inline (Set_Next);
72 function Vet (Position : Cursor) return Boolean;
74 --------------------------
75 -- Local Instantiations --
76 --------------------------
78 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
79 (HT_Types => HT_Types,
80 Hash_Node => Hash_Node,
81 Next => Next,
82 Set_Next => Set_Next);
84 package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
85 (HT_Types => HT_Types,
86 Next => Next,
87 Set_Next => Set_Next,
88 Key_Type => Element_Type,
89 Hash => Hash,
90 Equivalent_Keys => Equivalent_Keys);
92 procedure Replace_Element is
93 new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
95 ---------
96 -- "=" --
97 ---------
99 function "=" (Left, Right : Set) return Boolean is
100 function Find_Equal_Key
101 (R_HT : Hash_Table_Type'Class;
102 L_Node : Node_Type) return Boolean;
103 pragma Inline (Find_Equal_Key);
105 function Is_Equal is
106 new HT_Ops.Generic_Equal (Find_Equal_Key);
108 --------------------
109 -- Find_Equal_Key --
110 --------------------
112 function Find_Equal_Key
113 (R_HT : Hash_Table_Type'Class;
114 L_Node : Node_Type) return Boolean
116 R_Index : constant Hash_Type :=
117 Element_Keys.Index (R_HT, L_Node.Element);
119 R_Node : Count_Type := R_HT.Buckets (R_Index);
121 begin
122 loop
123 if R_Node = 0 then
124 return False;
125 end if;
127 if L_Node.Element = R_HT.Nodes (R_Node).Element then
128 return True;
129 end if;
131 R_Node := Next (R_HT.Nodes (R_Node));
132 end loop;
133 end Find_Equal_Key;
135 -- Start of processing for "="
137 begin
138 return Is_Equal (Left, Right);
139 end "=";
141 ------------
142 -- Assign --
143 ------------
145 procedure Assign (Target : in out Set; Source : Set) is
146 procedure Insert_Element (Source_Node : Count_Type);
148 procedure Insert_Elements is
149 new HT_Ops.Generic_Iteration (Insert_Element);
151 --------------------
152 -- Insert_Element --
153 --------------------
155 procedure Insert_Element (Source_Node : Count_Type) is
156 N : Node_Type renames Source.Nodes (Source_Node);
157 X : Count_Type;
158 B : Boolean;
159 begin
160 Insert (Target, N.Element, X, B);
161 pragma Assert (B);
162 end Insert_Element;
164 -- Start of processing for Assign
166 begin
167 if Target'Address = Source'Address then
168 return;
169 end if;
171 if Target.Capacity < Source.Length then
172 raise Capacity_Error
173 with "Target capacity is less than Source length";
174 end if;
176 HT_Ops.Clear (Target);
177 Insert_Elements (Source);
178 end Assign;
180 --------------
181 -- Capacity --
182 --------------
184 function Capacity (Container : Set) return Count_Type is
185 begin
186 return Container.Capacity;
187 end Capacity;
189 -----------
190 -- Clear --
191 -----------
193 procedure Clear (Container : in out Set) is
194 begin
195 HT_Ops.Clear (Container);
196 end Clear;
198 ------------------------
199 -- Constant_Reference --
200 ------------------------
202 function Constant_Reference
203 (Container : aliased Set;
204 Position : Cursor) return Constant_Reference_Type
206 begin
207 if Position.Container = null then
208 raise Constraint_Error with "Position cursor has no element";
209 end if;
211 if Position.Container /= Container'Unrestricted_Access then
212 raise Program_Error with
213 "Position cursor designates wrong container";
214 end if;
216 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
218 declare
219 N : Node_Type renames Container.Nodes (Position.Node);
220 begin
221 return (Element => N.Element'Access);
222 end;
223 end Constant_Reference;
225 --------------
226 -- Contains --
227 --------------
229 function Contains (Container : Set; Item : Element_Type) return Boolean is
230 begin
231 return Find (Container, Item) /= No_Element;
232 end Contains;
234 ----------
235 -- Copy --
236 ----------
238 function Copy
239 (Source : Set;
240 Capacity : Count_Type := 0;
241 Modulus : Hash_Type := 0) return Set
243 C : Count_Type;
244 M : Hash_Type;
246 begin
247 if Capacity = 0 then
248 C := Source.Length;
249 elsif Capacity >= Source.Length then
250 C := Capacity;
251 else
252 raise Capacity_Error with "Capacity value too small";
253 end if;
255 if Modulus = 0 then
256 M := Default_Modulus (C);
257 else
258 M := Modulus;
259 end if;
261 return Target : Set (Capacity => C, Modulus => M) do
262 Assign (Target => Target, Source => Source);
263 end return;
264 end Copy;
266 ---------------------
267 -- Default_Modulus --
268 ---------------------
270 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
271 begin
272 return To_Prime (Capacity);
273 end Default_Modulus;
275 ------------
276 -- Delete --
277 ------------
279 procedure Delete
280 (Container : in out Set;
281 Item : Element_Type)
283 X : Count_Type;
285 begin
286 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
288 if X = 0 then
289 raise Constraint_Error with "attempt to delete element not in set";
290 end if;
292 HT_Ops.Free (Container, X);
293 end Delete;
295 procedure Delete
296 (Container : in out Set;
297 Position : in out Cursor)
299 begin
300 if Position.Node = 0 then
301 raise Constraint_Error with "Position cursor equals No_Element";
302 end if;
304 if Position.Container /= Container'Unrestricted_Access then
305 raise Program_Error with "Position cursor designates wrong set";
306 end if;
308 if Container.Busy > 0 then
309 raise Program_Error with
310 "attempt to tamper with cursors (set is busy)";
311 end if;
313 pragma Assert (Vet (Position), "bad cursor in Delete");
315 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
316 HT_Ops.Free (Container, Position.Node);
318 Position := No_Element;
319 end Delete;
321 ----------------
322 -- Difference --
323 ----------------
325 procedure Difference
326 (Target : in out Set;
327 Source : Set)
329 Tgt_Node, Src_Node : Count_Type;
331 Src : Set renames Source'Unrestricted_Access.all;
333 TN : Nodes_Type renames Target.Nodes;
334 SN : Nodes_Type renames Source.Nodes;
336 begin
337 if Target'Address = Source'Address then
338 HT_Ops.Clear (Target);
339 return;
340 end if;
342 if Source.Length = 0 then
343 return;
344 end if;
346 if Target.Busy > 0 then
347 raise Program_Error with
348 "attempt to tamper with cursors (set is busy)";
349 end if;
351 if Source.Length < Target.Length then
352 Src_Node := HT_Ops.First (Source);
353 while Src_Node /= 0 loop
354 Tgt_Node := Element_Keys.Find (Target, SN (Src_Node).Element);
356 if Tgt_Node /= 0 then
357 HT_Ops.Delete_Node_Sans_Free (Target, Tgt_Node);
358 HT_Ops.Free (Target, Tgt_Node);
359 end if;
361 Src_Node := HT_Ops.Next (Src, Src_Node);
362 end loop;
364 else
365 Tgt_Node := HT_Ops.First (Target);
366 while Tgt_Node /= 0 loop
367 if Is_In (Source, TN (Tgt_Node)) then
368 declare
369 X : constant Count_Type := Tgt_Node;
370 begin
371 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
372 HT_Ops.Delete_Node_Sans_Free (Target, X);
373 HT_Ops.Free (Target, X);
374 end;
376 else
377 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
378 end if;
379 end loop;
380 end if;
381 end Difference;
383 function Difference (Left, Right : Set) return Set is
384 begin
385 if Left'Address = Right'Address then
386 return Empty_Set;
387 end if;
389 if Left.Length = 0 then
390 return Empty_Set;
391 end if;
393 if Right.Length = 0 then
394 return Left;
395 end if;
397 return Result : Set (Left.Length, To_Prime (Left.Length)) do
398 Iterate_Left : declare
399 procedure Process (L_Node : Count_Type);
401 procedure Iterate is
402 new HT_Ops.Generic_Iteration (Process);
404 -------------
405 -- Process --
406 -------------
408 procedure Process (L_Node : Count_Type) is
409 N : Node_Type renames Left.Nodes (L_Node);
410 X : Count_Type;
411 B : Boolean;
412 begin
413 if not Is_In (Right, N) then
414 Insert (Result, N.Element, X, B); -- optimize this ???
415 pragma Assert (B);
416 pragma Assert (X > 0);
417 end if;
418 end Process;
420 -- Start of processing for Iterate_Left
422 begin
423 Iterate (Left);
424 end Iterate_Left;
425 end return;
426 end Difference;
428 -------------
429 -- Element --
430 -------------
432 function Element (Position : Cursor) return Element_Type is
433 begin
434 if Position.Node = 0 then
435 raise Constraint_Error with "Position cursor equals No_Element";
436 end if;
438 pragma Assert (Vet (Position), "bad cursor in function Element");
440 declare
441 S : Set renames Position.Container.all;
442 N : Node_Type renames S.Nodes (Position.Node);
443 begin
444 return N.Element;
445 end;
446 end Element;
448 ---------------------
449 -- Equivalent_Sets --
450 ---------------------
452 function Equivalent_Sets (Left, Right : Set) return Boolean is
453 function Find_Equivalent_Key
454 (R_HT : Hash_Table_Type'Class;
455 L_Node : Node_Type) return Boolean;
456 pragma Inline (Find_Equivalent_Key);
458 function Is_Equivalent is
459 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
461 -------------------------
462 -- Find_Equivalent_Key --
463 -------------------------
465 function Find_Equivalent_Key
466 (R_HT : Hash_Table_Type'Class;
467 L_Node : Node_Type) return Boolean
469 R_Index : constant Hash_Type :=
470 Element_Keys.Index (R_HT, L_Node.Element);
472 R_Node : Count_Type := R_HT.Buckets (R_Index);
474 RN : Nodes_Type renames R_HT.Nodes;
476 begin
477 loop
478 if R_Node = 0 then
479 return False;
480 end if;
482 if Equivalent_Elements (L_Node.Element, RN (R_Node).Element) then
483 return True;
484 end if;
486 R_Node := Next (R_HT.Nodes (R_Node));
487 end loop;
488 end Find_Equivalent_Key;
490 -- Start of processing for Equivalent_Sets
492 begin
493 return Is_Equivalent (Left, Right);
494 end Equivalent_Sets;
496 -------------------------
497 -- Equivalent_Elements --
498 -------------------------
500 function Equivalent_Elements (Left, Right : Cursor)
501 return Boolean is
503 begin
504 if Left.Node = 0 then
505 raise Constraint_Error with
506 "Left cursor of Equivalent_Elements equals No_Element";
507 end if;
509 if Right.Node = 0 then
510 raise Constraint_Error with
511 "Right cursor of Equivalent_Elements equals No_Element";
512 end if;
514 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
515 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
517 -- AI05-0022 requires that a container implementation detect element
518 -- tampering by a generic actual subprogram. However, the following case
519 -- falls outside the scope of that AI. Randy Brukardt explained on the
520 -- ARG list on 2013/02/07 that:
522 -- (Begin Quote):
523 -- But for an operation like "<" [the ordered set analog of
524 -- Equivalent_Elements], there is no need to "dereference" a cursor
525 -- after the call to the generic formal parameter function, so nothing
526 -- bad could happen if tampering is undetected. And the operation can
527 -- safely return a result without a problem even if an element is
528 -- deleted from the container.
529 -- (End Quote).
531 declare
532 LN : Node_Type renames Left.Container.Nodes (Left.Node);
533 RN : Node_Type renames Right.Container.Nodes (Right.Node);
534 begin
535 return Equivalent_Elements (LN.Element, RN.Element);
536 end;
537 end Equivalent_Elements;
539 function Equivalent_Elements
540 (Left : Cursor;
541 Right : Element_Type) return Boolean
543 begin
544 if Left.Node = 0 then
545 raise Constraint_Error with
546 "Left cursor of Equivalent_Elements equals No_Element";
547 end if;
549 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad");
551 declare
552 LN : Node_Type renames Left.Container.Nodes (Left.Node);
553 begin
554 return Equivalent_Elements (LN.Element, Right);
555 end;
556 end Equivalent_Elements;
558 function Equivalent_Elements
559 (Left : Element_Type;
560 Right : Cursor) return Boolean
562 begin
563 if Right.Node = 0 then
564 raise Constraint_Error with
565 "Right cursor of Equivalent_Elements equals No_Element";
566 end if;
568 pragma Assert
569 (Vet (Right),
570 "Right cursor of Equivalent_Elements is bad");
572 declare
573 RN : Node_Type renames Right.Container.Nodes (Right.Node);
574 begin
575 return Equivalent_Elements (Left, RN.Element);
576 end;
577 end Equivalent_Elements;
579 ---------------------
580 -- Equivalent_Keys --
581 ---------------------
583 function Equivalent_Keys
584 (Key : Element_Type;
585 Node : Node_Type) return Boolean
587 begin
588 return Equivalent_Elements (Key, Node.Element);
589 end Equivalent_Keys;
591 -------------
592 -- Exclude --
593 -------------
595 procedure Exclude
596 (Container : in out Set;
597 Item : Element_Type)
599 X : Count_Type;
600 begin
601 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
602 HT_Ops.Free (Container, X);
603 end Exclude;
605 --------------
606 -- Finalize --
607 --------------
609 procedure Finalize (Object : in out Iterator) is
610 begin
611 if Object.Container /= null then
612 declare
613 B : Natural renames Object.Container.all.Busy;
614 begin
615 B := B - 1;
616 end;
617 end if;
618 end Finalize;
620 ----------
621 -- Find --
622 ----------
624 function Find
625 (Container : Set;
626 Item : Element_Type) return Cursor
628 Node : constant Count_Type :=
629 Element_Keys.Find (Container'Unrestricted_Access.all, Item);
630 begin
631 return (if Node = 0 then No_Element
632 else Cursor'(Container'Unrestricted_Access, Node));
633 end Find;
635 -----------
636 -- First --
637 -----------
639 function First (Container : Set) return Cursor is
640 Node : constant Count_Type := HT_Ops.First (Container);
641 begin
642 return (if Node = 0 then No_Element
643 else Cursor'(Container'Unrestricted_Access, Node));
644 end First;
646 overriding function First (Object : Iterator) return Cursor is
647 begin
648 return Object.Container.First;
649 end First;
651 -----------------
652 -- Has_Element --
653 -----------------
655 function Has_Element (Position : Cursor) return Boolean is
656 begin
657 pragma Assert (Vet (Position), "bad cursor in Has_Element");
658 return Position.Node /= 0;
659 end Has_Element;
661 ---------------
662 -- Hash_Node --
663 ---------------
665 function Hash_Node (Node : Node_Type) return Hash_Type is
666 begin
667 return Hash (Node.Element);
668 end Hash_Node;
670 -------------
671 -- Include --
672 -------------
674 procedure Include
675 (Container : in out Set;
676 New_Item : Element_Type)
678 Position : Cursor;
679 Inserted : Boolean;
681 begin
682 Insert (Container, New_Item, Position, Inserted);
684 if not Inserted then
685 if Container.Lock > 0 then
686 raise Program_Error with
687 "attempt to tamper with elements (set is locked)";
688 end if;
690 Container.Nodes (Position.Node).Element := New_Item;
691 end if;
692 end Include;
694 ------------
695 -- Insert --
696 ------------
698 procedure Insert
699 (Container : in out Set;
700 New_Item : Element_Type;
701 Position : out Cursor;
702 Inserted : out Boolean)
704 begin
705 Insert (Container, New_Item, Position.Node, Inserted);
706 Position.Container := Container'Unchecked_Access;
707 end Insert;
709 procedure Insert
710 (Container : in out Set;
711 New_Item : Element_Type)
713 Position : Cursor;
714 pragma Unreferenced (Position);
716 Inserted : Boolean;
718 begin
719 Insert (Container, New_Item, Position, Inserted);
721 if not Inserted then
722 raise Constraint_Error with
723 "attempt to insert element already in set";
724 end if;
725 end Insert;
727 procedure Insert
728 (Container : in out Set;
729 New_Item : Element_Type;
730 Node : out Count_Type;
731 Inserted : out Boolean)
733 procedure Allocate_Set_Element (Node : in out Node_Type);
734 pragma Inline (Allocate_Set_Element);
736 function New_Node return Count_Type;
737 pragma Inline (New_Node);
739 procedure Local_Insert is
740 new Element_Keys.Generic_Conditional_Insert (New_Node);
742 procedure Allocate is
743 new HT_Ops.Generic_Allocate (Allocate_Set_Element);
745 ---------------------------
746 -- Allocate_Set_Element --
747 ---------------------------
749 procedure Allocate_Set_Element (Node : in out Node_Type) is
750 begin
751 Node.Element := New_Item;
752 end Allocate_Set_Element;
754 --------------
755 -- New_Node --
756 --------------
758 function New_Node return Count_Type is
759 Result : Count_Type;
760 begin
761 Allocate (Container, Result);
762 return Result;
763 end New_Node;
765 -- Start of processing for Insert
767 begin
768 -- The buckets array length is specified by the user as a discriminant
769 -- of the container type, so it is possible for the buckets array to
770 -- have a length of zero. We must check for this case specifically, in
771 -- order to prevent divide-by-zero errors later, when we compute the
772 -- buckets array index value for an element, given its hash value.
774 if Container.Buckets'Length = 0 then
775 raise Capacity_Error with "No capacity for insertion";
776 end if;
778 Local_Insert (Container, New_Item, Node, Inserted);
779 end Insert;
781 ------------------
782 -- Intersection --
783 ------------------
785 procedure Intersection
786 (Target : in out Set;
787 Source : Set)
789 Tgt_Node : Count_Type;
790 TN : Nodes_Type renames Target.Nodes;
792 begin
793 if Target'Address = Source'Address then
794 return;
795 end if;
797 if Source.Length = 0 then
798 HT_Ops.Clear (Target);
799 return;
800 end if;
802 if Target.Busy > 0 then
803 raise Program_Error with
804 "attempt to tamper with cursors (set is busy)";
805 end if;
807 Tgt_Node := HT_Ops.First (Target);
808 while Tgt_Node /= 0 loop
809 if Is_In (Source, TN (Tgt_Node)) then
810 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
812 else
813 declare
814 X : constant Count_Type := Tgt_Node;
815 begin
816 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
817 HT_Ops.Delete_Node_Sans_Free (Target, X);
818 HT_Ops.Free (Target, X);
819 end;
820 end if;
821 end loop;
822 end Intersection;
824 function Intersection (Left, Right : Set) return Set is
825 C : Count_Type;
827 begin
828 if Left'Address = Right'Address then
829 return Left;
830 end if;
832 C := Count_Type'Min (Left.Length, Right.Length);
834 if C = 0 then
835 return Empty_Set;
836 end if;
838 return Result : Set (C, To_Prime (C)) do
839 Iterate_Left : declare
840 procedure Process (L_Node : Count_Type);
842 procedure Iterate is
843 new HT_Ops.Generic_Iteration (Process);
845 -------------
846 -- Process --
847 -------------
849 procedure Process (L_Node : Count_Type) is
850 N : Node_Type renames Left.Nodes (L_Node);
851 X : Count_Type;
852 B : Boolean;
854 begin
855 if Is_In (Right, N) then
856 Insert (Result, N.Element, X, B); -- optimize ???
857 pragma Assert (B);
858 pragma Assert (X > 0);
859 end if;
860 end Process;
862 -- Start of processing for Iterate_Left
864 begin
865 Iterate (Left);
866 end Iterate_Left;
867 end return;
868 end Intersection;
870 --------------
871 -- Is_Empty --
872 --------------
874 function Is_Empty (Container : Set) return Boolean is
875 begin
876 return Container.Length = 0;
877 end Is_Empty;
879 -----------
880 -- Is_In --
881 -----------
883 function Is_In (HT : Set; Key : Node_Type) return Boolean is
884 begin
885 return Element_Keys.Find (HT'Unrestricted_Access.all, Key.Element) /= 0;
886 end Is_In;
888 ---------------
889 -- Is_Subset --
890 ---------------
892 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
893 Subset_Node : Count_Type;
894 SN : Nodes_Type renames Subset.Nodes;
896 begin
897 if Subset'Address = Of_Set'Address then
898 return True;
899 end if;
901 if Subset.Length > Of_Set.Length then
902 return False;
903 end if;
905 Subset_Node := HT_Ops.First (Subset);
906 while Subset_Node /= 0 loop
907 if not Is_In (Of_Set, SN (Subset_Node)) then
908 return False;
909 end if;
910 Subset_Node := HT_Ops.Next
911 (Subset'Unrestricted_Access.all, Subset_Node);
912 end loop;
914 return True;
915 end Is_Subset;
917 -------------
918 -- Iterate --
919 -------------
921 procedure Iterate
922 (Container : Set;
923 Process : not null access procedure (Position : Cursor))
925 procedure Process_Node (Node : Count_Type);
926 pragma Inline (Process_Node);
928 procedure Iterate is
929 new HT_Ops.Generic_Iteration (Process_Node);
931 ------------------
932 -- Process_Node --
933 ------------------
935 procedure Process_Node (Node : Count_Type) is
936 begin
937 Process (Cursor'(Container'Unrestricted_Access, Node));
938 end Process_Node;
940 B : Natural renames Container'Unrestricted_Access.all.Busy;
942 -- Start of processing for Iterate
944 begin
945 B := B + 1;
947 begin
948 Iterate (Container);
949 exception
950 when others =>
951 B := B - 1;
952 raise;
953 end;
955 B := B - 1;
956 end Iterate;
958 function Iterate (Container : Set)
959 return Set_Iterator_Interfaces.Forward_Iterator'Class
961 B : Natural renames Container'Unrestricted_Access.all.Busy;
962 begin
963 B := B + 1;
964 return It : constant Iterator :=
965 Iterator'(Limited_Controlled with
966 Container => Container'Unrestricted_Access);
967 end Iterate;
969 ------------
970 -- Length --
971 ------------
973 function Length (Container : Set) return Count_Type is
974 begin
975 return Container.Length;
976 end Length;
978 ----------
979 -- Move --
980 ----------
982 procedure Move (Target : in out Set; Source : in out Set) is
983 begin
984 if Target'Address = Source'Address then
985 return;
986 end if;
988 if Source.Busy > 0 then
989 raise Program_Error with
990 "attempt to tamper with cursors (container is busy)";
991 end if;
993 Target.Assign (Source);
994 Source.Clear;
995 end Move;
997 ----------
998 -- Next --
999 ----------
1001 function Next (Node : Node_Type) return Count_Type is
1002 begin
1003 return Node.Next;
1004 end Next;
1006 function Next (Position : Cursor) return Cursor is
1007 begin
1008 if Position.Node = 0 then
1009 return No_Element;
1010 end if;
1012 pragma Assert (Vet (Position), "bad cursor in Next");
1014 declare
1015 HT : Set renames Position.Container.all;
1016 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
1018 begin
1019 if Node = 0 then
1020 return No_Element;
1021 end if;
1023 return Cursor'(Position.Container, Node);
1024 end;
1025 end Next;
1027 procedure Next (Position : in out Cursor) is
1028 begin
1029 Position := Next (Position);
1030 end Next;
1032 function Next
1033 (Object : Iterator;
1034 Position : Cursor) return Cursor
1036 begin
1037 if Position.Container = null then
1038 return No_Element;
1039 end if;
1041 if Position.Container /= Object.Container then
1042 raise Program_Error with
1043 "Position cursor of Next designates wrong set";
1044 end if;
1046 return Next (Position);
1047 end Next;
1049 -------------
1050 -- Overlap --
1051 -------------
1053 function Overlap (Left, Right : Set) return Boolean is
1054 Left_Node : Count_Type;
1056 begin
1057 if Right.Length = 0 then
1058 return False;
1059 end if;
1061 if Left'Address = Right'Address then
1062 return True;
1063 end if;
1065 Left_Node := HT_Ops.First (Left);
1066 while Left_Node /= 0 loop
1067 if Is_In (Right, Left.Nodes (Left_Node)) then
1068 return True;
1069 end if;
1070 Left_Node := HT_Ops.Next (Left'Unrestricted_Access.all, Left_Node);
1071 end loop;
1073 return False;
1074 end Overlap;
1076 -------------------
1077 -- Query_Element --
1078 -------------------
1080 procedure Query_Element
1081 (Position : Cursor;
1082 Process : not null access procedure (Element : Element_Type))
1084 begin
1085 if Position.Node = 0 then
1086 raise Constraint_Error with
1087 "Position cursor of Query_Element equals No_Element";
1088 end if;
1090 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1092 declare
1093 S : Set renames Position.Container.all;
1094 B : Natural renames S.Busy;
1095 L : Natural renames S.Lock;
1097 begin
1098 B := B + 1;
1099 L := L + 1;
1101 begin
1102 Process (S.Nodes (Position.Node).Element);
1103 exception
1104 when others =>
1105 L := L - 1;
1106 B := B - 1;
1107 raise;
1108 end;
1110 L := L - 1;
1111 B := B - 1;
1112 end;
1113 end Query_Element;
1115 ----------
1116 -- Read --
1117 ----------
1119 procedure Read
1120 (Stream : not null access Root_Stream_Type'Class;
1121 Container : out Set)
1123 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1124 return Count_Type;
1126 procedure Read_Nodes is
1127 new HT_Ops.Generic_Read (Read_Node);
1129 ---------------
1130 -- Read_Node --
1131 ---------------
1133 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1134 return Count_Type
1136 procedure Read_Element (Node : in out Node_Type);
1137 pragma Inline (Read_Element);
1139 procedure Allocate is
1140 new HT_Ops.Generic_Allocate (Read_Element);
1142 procedure Read_Element (Node : in out Node_Type) is
1143 begin
1144 Element_Type'Read (Stream, Node.Element);
1145 end Read_Element;
1147 Node : Count_Type;
1149 -- Start of processing for Read_Node
1151 begin
1152 Allocate (Container, Node);
1153 return Node;
1154 end Read_Node;
1156 -- Start of processing for Read
1158 begin
1159 Read_Nodes (Stream, Container);
1160 end Read;
1162 procedure Read
1163 (Stream : not null access Root_Stream_Type'Class;
1164 Item : out Cursor)
1166 begin
1167 raise Program_Error with "attempt to stream set cursor";
1168 end Read;
1170 procedure Read
1171 (Stream : not null access Root_Stream_Type'Class;
1172 Item : out Constant_Reference_Type)
1174 begin
1175 raise Program_Error with "attempt to stream reference";
1176 end Read;
1178 -------------
1179 -- Replace --
1180 -------------
1182 procedure Replace
1183 (Container : in out Set;
1184 New_Item : Element_Type)
1186 Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1188 begin
1189 if Node = 0 then
1190 raise Constraint_Error with
1191 "attempt to replace element not in set";
1192 end if;
1194 if Container.Lock > 0 then
1195 raise Program_Error with
1196 "attempt to tamper with elements (set is locked)";
1197 end if;
1199 Container.Nodes (Node).Element := New_Item;
1200 end Replace;
1202 procedure Replace_Element
1203 (Container : in out Set;
1204 Position : Cursor;
1205 New_Item : Element_Type)
1207 begin
1208 if Position.Node = 0 then
1209 raise Constraint_Error with
1210 "Position cursor equals No_Element";
1211 end if;
1213 if Position.Container /= Container'Unrestricted_Access then
1214 raise Program_Error with
1215 "Position cursor designates wrong set";
1216 end if;
1218 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1220 Replace_Element (Container, Position.Node, New_Item);
1221 end Replace_Element;
1223 ----------------------
1224 -- Reserve_Capacity --
1225 ----------------------
1227 procedure Reserve_Capacity
1228 (Container : in out Set;
1229 Capacity : Count_Type)
1231 begin
1232 if Capacity > Container.Capacity then
1233 raise Capacity_Error with "requested capacity is too large";
1234 end if;
1235 end Reserve_Capacity;
1237 ------------------
1238 -- Set_Element --
1239 ------------------
1241 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1242 begin
1243 Node.Element := Item;
1244 end Set_Element;
1246 --------------
1247 -- Set_Next --
1248 --------------
1250 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1251 begin
1252 Node.Next := Next;
1253 end Set_Next;
1255 --------------------------
1256 -- Symmetric_Difference --
1257 --------------------------
1259 procedure Symmetric_Difference
1260 (Target : in out Set;
1261 Source : Set)
1263 procedure Process (Source_Node : Count_Type);
1264 pragma Inline (Process);
1266 procedure Iterate is
1267 new HT_Ops.Generic_Iteration (Process);
1269 -------------
1270 -- Process --
1271 -------------
1273 procedure Process (Source_Node : Count_Type) is
1274 N : Node_Type renames Source.Nodes (Source_Node);
1275 X : Count_Type;
1276 B : Boolean;
1278 begin
1279 if Is_In (Target, N) then
1280 Delete (Target, N.Element);
1281 else
1282 Insert (Target, N.Element, X, B);
1283 pragma Assert (B);
1284 end if;
1285 end Process;
1287 -- Start of processing for Symmetric_Difference
1289 begin
1290 if Target'Address = Source'Address then
1291 HT_Ops.Clear (Target);
1292 return;
1293 end if;
1295 if Target.Length = 0 then
1296 Assign (Target => Target, Source => Source);
1297 return;
1298 end if;
1300 if Target.Busy > 0 then
1301 raise Program_Error with
1302 "attempt to tamper with cursors (set is busy)";
1303 end if;
1305 Iterate (Source);
1306 end Symmetric_Difference;
1308 function Symmetric_Difference (Left, Right : Set) return Set is
1309 C : Count_Type;
1311 begin
1312 if Left'Address = Right'Address then
1313 return Empty_Set;
1314 end if;
1316 if Right.Length = 0 then
1317 return Left;
1318 end if;
1320 if Left.Length = 0 then
1321 return Right;
1322 end if;
1324 C := Left.Length + Right.Length;
1326 return Result : Set (C, To_Prime (C)) do
1327 Iterate_Left : declare
1328 procedure Process (L_Node : Count_Type);
1330 procedure Iterate is
1331 new HT_Ops.Generic_Iteration (Process);
1333 -------------
1334 -- Process --
1335 -------------
1337 procedure Process (L_Node : Count_Type) is
1338 N : Node_Type renames Left.Nodes (L_Node);
1339 X : Count_Type;
1340 B : Boolean;
1341 begin
1342 if not Is_In (Right, N) then
1343 Insert (Result, N.Element, X, B);
1344 pragma Assert (B);
1345 end if;
1346 end Process;
1348 -- Start of processing for Iterate_Left
1350 begin
1351 Iterate (Left);
1352 end Iterate_Left;
1354 Iterate_Right : declare
1355 procedure Process (R_Node : Count_Type);
1357 procedure Iterate is
1358 new HT_Ops.Generic_Iteration (Process);
1360 -------------
1361 -- Process --
1362 -------------
1364 procedure Process (R_Node : Count_Type) is
1365 N : Node_Type renames Right.Nodes (R_Node);
1366 X : Count_Type;
1367 B : Boolean;
1368 begin
1369 if not Is_In (Left, N) then
1370 Insert (Result, N.Element, X, B);
1371 pragma Assert (B);
1372 end if;
1373 end Process;
1375 -- Start of processing for Iterate_Right
1377 begin
1378 Iterate (Right);
1379 end Iterate_Right;
1380 end return;
1381 end Symmetric_Difference;
1383 ------------
1384 -- To_Set --
1385 ------------
1387 function To_Set (New_Item : Element_Type) return Set is
1388 X : Count_Type;
1389 B : Boolean;
1390 begin
1391 return Result : Set (1, 1) do
1392 Insert (Result, New_Item, X, B);
1393 pragma Assert (B);
1394 end return;
1395 end To_Set;
1397 -----------
1398 -- Union --
1399 -----------
1401 procedure Union
1402 (Target : in out Set;
1403 Source : Set)
1405 procedure Process (Src_Node : Count_Type);
1407 procedure Iterate is
1408 new HT_Ops.Generic_Iteration (Process);
1410 -------------
1411 -- Process --
1412 -------------
1414 procedure Process (Src_Node : Count_Type) is
1415 N : Node_Type renames Source.Nodes (Src_Node);
1416 X : Count_Type;
1417 B : Boolean;
1418 begin
1419 Insert (Target, N.Element, X, B);
1420 end Process;
1422 -- Start of processing for Union
1424 begin
1425 if Target'Address = Source'Address then
1426 return;
1427 end if;
1429 if Target.Busy > 0 then
1430 raise Program_Error with
1431 "attempt to tamper with cursors (set is busy)";
1432 end if;
1434 -- ??? why is this code commented out ???
1435 -- declare
1436 -- N : constant Count_Type := Target.Length + Source.Length;
1437 -- begin
1438 -- if N > HT_Ops.Capacity (Target.HT) then
1439 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1440 -- end if;
1441 -- end;
1443 Iterate (Source);
1444 end Union;
1446 function Union (Left, Right : Set) return Set is
1447 C : Count_Type;
1449 begin
1450 if Left'Address = Right'Address then
1451 return Left;
1452 end if;
1454 if Right.Length = 0 then
1455 return Left;
1456 end if;
1458 if Left.Length = 0 then
1459 return Right;
1460 end if;
1462 C := Left.Length + Right.Length;
1464 return Result : Set (C, To_Prime (C)) do
1465 Assign (Target => Result, Source => Left);
1466 Union (Target => Result, Source => Right);
1467 end return;
1468 end Union;
1470 ---------
1471 -- Vet --
1472 ---------
1474 function Vet (Position : Cursor) return Boolean is
1475 begin
1476 if Position.Node = 0 then
1477 return Position.Container = null;
1478 end if;
1480 if Position.Container = null then
1481 return False;
1482 end if;
1484 declare
1485 S : Set renames Position.Container.all;
1486 N : Nodes_Type renames S.Nodes;
1487 X : Count_Type;
1489 begin
1490 if S.Length = 0 then
1491 return False;
1492 end if;
1494 if Position.Node > N'Last then
1495 return False;
1496 end if;
1498 if N (Position.Node).Next = Position.Node then
1499 return False;
1500 end if;
1502 X := S.Buckets (Element_Keys.Checked_Index
1503 (S, N (Position.Node).Element));
1505 for J in 1 .. S.Length loop
1506 if X = Position.Node then
1507 return True;
1508 end if;
1510 if X = 0 then
1511 return False;
1512 end if;
1514 if X = N (X).Next then -- to prevent unnecessary looping
1515 return False;
1516 end if;
1518 X := N (X).Next;
1519 end loop;
1521 return False;
1522 end;
1523 end Vet;
1525 -----------
1526 -- Write --
1527 -----------
1529 procedure Write
1530 (Stream : not null access Root_Stream_Type'Class;
1531 Container : Set)
1533 procedure Write_Node
1534 (Stream : not null access Root_Stream_Type'Class;
1535 Node : Node_Type);
1536 pragma Inline (Write_Node);
1538 procedure Write_Nodes is
1539 new HT_Ops.Generic_Write (Write_Node);
1541 ----------------
1542 -- Write_Node --
1543 ----------------
1545 procedure Write_Node
1546 (Stream : not null access Root_Stream_Type'Class;
1547 Node : Node_Type)
1549 begin
1550 Element_Type'Write (Stream, Node.Element);
1551 end Write_Node;
1553 -- Start of processing for Write
1555 begin
1556 Write_Nodes (Stream, Container);
1557 end Write;
1559 procedure Write
1560 (Stream : not null access Root_Stream_Type'Class;
1561 Item : Cursor)
1563 begin
1564 raise Program_Error with "attempt to stream set cursor";
1565 end Write;
1567 procedure Write
1568 (Stream : not null access Root_Stream_Type'Class;
1569 Item : Constant_Reference_Type)
1571 begin
1572 raise Program_Error with "attempt to stream reference";
1573 end Write;
1575 package body Generic_Keys is
1577 -----------------------
1578 -- Local Subprograms --
1579 -----------------------
1581 function Equivalent_Key_Node
1582 (Key : Key_Type;
1583 Node : Node_Type) return Boolean;
1584 pragma Inline (Equivalent_Key_Node);
1586 --------------------------
1587 -- Local Instantiations --
1588 --------------------------
1590 package Key_Keys is
1591 new Hash_Tables.Generic_Bounded_Keys
1592 (HT_Types => HT_Types,
1593 Next => Next,
1594 Set_Next => Set_Next,
1595 Key_Type => Key_Type,
1596 Hash => Hash,
1597 Equivalent_Keys => Equivalent_Key_Node);
1599 ------------------------
1600 -- Constant_Reference --
1601 ------------------------
1603 function Constant_Reference
1604 (Container : aliased Set;
1605 Key : Key_Type) return Constant_Reference_Type
1607 Node : constant Count_Type :=
1608 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1610 begin
1611 if Node = 0 then
1612 raise Constraint_Error with "key not in set";
1613 end if;
1615 declare
1616 N : Node_Type renames Container.Nodes (Node);
1617 begin
1618 return (Element => N.Element'Access);
1619 end;
1620 end Constant_Reference;
1622 --------------
1623 -- Contains --
1624 --------------
1626 function Contains
1627 (Container : Set;
1628 Key : Key_Type) return Boolean
1630 begin
1631 return Find (Container, Key) /= No_Element;
1632 end Contains;
1634 ------------
1635 -- Delete --
1636 ------------
1638 procedure Delete
1639 (Container : in out Set;
1640 Key : Key_Type)
1642 X : Count_Type;
1644 begin
1645 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1647 if X = 0 then
1648 raise Constraint_Error with "attempt to delete key not in set";
1649 end if;
1651 HT_Ops.Free (Container, X);
1652 end Delete;
1654 -------------
1655 -- Element --
1656 -------------
1658 function Element
1659 (Container : Set;
1660 Key : Key_Type) return Element_Type
1662 Node : constant Count_Type :=
1663 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1665 begin
1666 if Node = 0 then
1667 raise Constraint_Error with "key not in set";
1668 end if;
1670 return Container.Nodes (Node).Element;
1671 end Element;
1673 -------------------------
1674 -- Equivalent_Key_Node --
1675 -------------------------
1677 function Equivalent_Key_Node
1678 (Key : Key_Type;
1679 Node : Node_Type) return Boolean
1681 begin
1682 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1683 end Equivalent_Key_Node;
1685 -------------
1686 -- Exclude --
1687 -------------
1689 procedure Exclude
1690 (Container : in out Set;
1691 Key : Key_Type)
1693 X : Count_Type;
1694 begin
1695 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1696 HT_Ops.Free (Container, X);
1697 end Exclude;
1699 ----------
1700 -- Find --
1701 ----------
1703 function Find
1704 (Container : Set;
1705 Key : Key_Type) return Cursor
1707 Node : constant Count_Type :=
1708 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1709 begin
1710 return (if Node = 0 then No_Element
1711 else Cursor'(Container'Unrestricted_Access, Node));
1712 end Find;
1714 ---------
1715 -- Key --
1716 ---------
1718 function Key (Position : Cursor) return Key_Type is
1719 begin
1720 if Position.Node = 0 then
1721 raise Constraint_Error with
1722 "Position cursor equals No_Element";
1723 end if;
1725 pragma Assert (Vet (Position), "bad cursor in function Key");
1726 return Key (Position.Container.Nodes (Position.Node).Element);
1727 end Key;
1729 ----------
1730 -- Read --
1731 ----------
1733 procedure Read
1734 (Stream : not null access Root_Stream_Type'Class;
1735 Item : out Reference_Type)
1737 begin
1738 raise Program_Error with "attempt to stream reference";
1739 end Read;
1741 ------------------------------
1742 -- Reference_Preserving_Key --
1743 ------------------------------
1745 function Reference_Preserving_Key
1746 (Container : aliased in out Set;
1747 Position : Cursor) return Reference_Type
1749 begin
1750 if Position.Container = null then
1751 raise Constraint_Error with "Position cursor has no element";
1752 end if;
1754 if Position.Container /= Container'Unrestricted_Access then
1755 raise Program_Error with
1756 "Position cursor designates wrong container";
1757 end if;
1759 pragma Assert
1760 (Vet (Position),
1761 "bad cursor in function Reference_Preserving_Key");
1763 -- Some form of finalization will be required in order to actually
1764 -- check that the key-part of the element designated by Position has
1765 -- not changed. ???
1767 declare
1768 N : Node_Type renames Container.Nodes (Position.Node);
1769 begin
1770 return (Element => N.Element'Access);
1771 end;
1772 end Reference_Preserving_Key;
1774 function Reference_Preserving_Key
1775 (Container : aliased in out Set;
1776 Key : Key_Type) return Reference_Type
1778 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1780 begin
1781 if Node = 0 then
1782 raise Constraint_Error with "key not in set";
1783 end if;
1785 declare
1786 N : Node_Type renames Container.Nodes (Node);
1787 begin
1788 return (Element => N.Element'Access);
1789 end;
1790 end Reference_Preserving_Key;
1792 -------------
1793 -- Replace --
1794 -------------
1796 procedure Replace
1797 (Container : in out Set;
1798 Key : Key_Type;
1799 New_Item : Element_Type)
1801 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1803 begin
1804 if Node = 0 then
1805 raise Constraint_Error with
1806 "attempt to replace key not in set";
1807 end if;
1809 Replace_Element (Container, Node, New_Item);
1810 end Replace;
1812 -----------------------------------
1813 -- Update_Element_Preserving_Key --
1814 -----------------------------------
1816 procedure Update_Element_Preserving_Key
1817 (Container : in out Set;
1818 Position : Cursor;
1819 Process : not null access
1820 procedure (Element : in out Element_Type))
1822 Indx : Hash_Type;
1823 N : Nodes_Type renames Container.Nodes;
1825 begin
1826 if Position.Node = 0 then
1827 raise Constraint_Error with
1828 "Position cursor equals No_Element";
1829 end if;
1831 if Position.Container /= Container'Unrestricted_Access then
1832 raise Program_Error with
1833 "Position cursor designates wrong set";
1834 end if;
1836 -- ??? why is this code commented out ???
1837 -- if HT.Buckets = null
1838 -- or else HT.Buckets'Length = 0
1839 -- or else HT.Length = 0
1840 -- or else Position.Node.Next = Position.Node
1841 -- then
1842 -- raise Program_Error with
1843 -- "Position cursor is bad (set is empty)";
1844 -- end if;
1846 pragma Assert
1847 (Vet (Position),
1848 "bad cursor in Update_Element_Preserving_Key");
1850 -- Per AI05-0022, the container implementation is required to detect
1851 -- element tampering by a generic actual subprogram.
1853 declare
1854 E : Element_Type renames N (Position.Node).Element;
1855 K : constant Key_Type := Key (E);
1857 B : Natural renames Container.Busy;
1858 L : Natural renames Container.Lock;
1860 Eq : Boolean;
1862 begin
1863 B := B + 1;
1864 L := L + 1;
1866 begin
1867 -- Record bucket now, in case key is changed
1868 Indx := HT_Ops.Index (Container.Buckets, N (Position.Node));
1870 Process (E);
1872 Eq := Equivalent_Keys (K, Key (E));
1873 exception
1874 when others =>
1875 L := L - 1;
1876 B := B - 1;
1877 raise;
1878 end;
1880 L := L - 1;
1881 B := B - 1;
1883 if Eq then
1884 return;
1885 end if;
1886 end;
1888 -- Key was modified, so remove this node from set.
1890 if Container.Buckets (Indx) = Position.Node then
1891 Container.Buckets (Indx) := N (Position.Node).Next;
1893 else
1894 declare
1895 Prev : Count_Type := Container.Buckets (Indx);
1897 begin
1898 while N (Prev).Next /= Position.Node loop
1899 Prev := N (Prev).Next;
1901 if Prev = 0 then
1902 raise Program_Error with
1903 "Position cursor is bad (node not found)";
1904 end if;
1905 end loop;
1907 N (Prev).Next := N (Position.Node).Next;
1908 end;
1909 end if;
1911 Container.Length := Container.Length - 1;
1912 HT_Ops.Free (Container, Position.Node);
1914 raise Program_Error with "key was modified";
1915 end Update_Element_Preserving_Key;
1917 -----------
1918 -- Write --
1919 -----------
1921 procedure Write
1922 (Stream : not null access Root_Stream_Type'Class;
1923 Item : Reference_Type)
1925 begin
1926 raise Program_Error with "attempt to stream reference";
1927 end Write;
1929 end Generic_Keys;
1931 end Ada.Containers.Bounded_Hashed_Sets;