Small ChangeLog tweak.
[official-gcc.git] / gcc / ada / a-cbhase.adb
blob59b0bdb99de30230ca0b4f9cf6923f70486fe666
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-2015, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
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.Helpers; use Ada.Containers.Helpers;
38 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
40 with System; use type System.Address;
42 package body Ada.Containers.Bounded_Hashed_Sets is
44 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
45 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
46 -- See comment in Ada.Containers.Helpers
48 -----------------------
49 -- Local Subprograms --
50 -----------------------
52 function Equivalent_Keys
53 (Key : Element_Type;
54 Node : Node_Type) return Boolean;
55 pragma Inline (Equivalent_Keys);
57 function Hash_Node (Node : Node_Type) return Hash_Type;
58 pragma Inline (Hash_Node);
60 procedure Insert
61 (Container : in out Set;
62 New_Item : Element_Type;
63 Node : out Count_Type;
64 Inserted : out Boolean);
66 function Is_In (HT : Set; Key : Node_Type) return Boolean;
67 pragma Inline (Is_In);
69 procedure Set_Element (Node : in out Node_Type; Item : Element_Type);
70 pragma Inline (Set_Element);
72 function Next (Node : Node_Type) return Count_Type;
73 pragma Inline (Next);
75 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
76 pragma Inline (Set_Next);
78 function Vet (Position : Cursor) return Boolean;
80 --------------------------
81 -- Local Instantiations --
82 --------------------------
84 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
85 (HT_Types => HT_Types,
86 Hash_Node => Hash_Node,
87 Next => Next,
88 Set_Next => Set_Next);
90 package Element_Keys is new Hash_Tables.Generic_Bounded_Keys
91 (HT_Types => HT_Types,
92 Next => Next,
93 Set_Next => Set_Next,
94 Key_Type => Element_Type,
95 Hash => Hash,
96 Equivalent_Keys => Equivalent_Keys);
98 procedure Replace_Element is
99 new Element_Keys.Generic_Replace_Element (Hash_Node, Set_Element);
101 ---------
102 -- "=" --
103 ---------
105 function "=" (Left, Right : Set) return Boolean is
106 function Find_Equal_Key
107 (R_HT : Hash_Table_Type'Class;
108 L_Node : Node_Type) return Boolean;
109 pragma Inline (Find_Equal_Key);
111 function Is_Equal is
112 new HT_Ops.Generic_Equal (Find_Equal_Key);
114 --------------------
115 -- Find_Equal_Key --
116 --------------------
118 function Find_Equal_Key
119 (R_HT : Hash_Table_Type'Class;
120 L_Node : Node_Type) return Boolean
122 R_Index : constant Hash_Type :=
123 Element_Keys.Index (R_HT, L_Node.Element);
125 R_Node : Count_Type := R_HT.Buckets (R_Index);
127 begin
128 loop
129 if R_Node = 0 then
130 return False;
131 end if;
133 if L_Node.Element = R_HT.Nodes (R_Node).Element then
134 return True;
135 end if;
137 R_Node := Next (R_HT.Nodes (R_Node));
138 end loop;
139 end Find_Equal_Key;
141 -- Start of processing for "="
143 begin
144 return Is_Equal (Left, Right);
145 end "=";
147 ------------
148 -- Assign --
149 ------------
151 procedure Assign (Target : in out Set; Source : Set) is
152 procedure Insert_Element (Source_Node : Count_Type);
154 procedure Insert_Elements is
155 new HT_Ops.Generic_Iteration (Insert_Element);
157 --------------------
158 -- Insert_Element --
159 --------------------
161 procedure Insert_Element (Source_Node : Count_Type) is
162 N : Node_Type renames Source.Nodes (Source_Node);
163 X : Count_Type;
164 B : Boolean;
165 begin
166 Insert (Target, N.Element, X, B);
167 pragma Assert (B);
168 end Insert_Element;
170 -- Start of processing for Assign
172 begin
173 if Target'Address = Source'Address then
174 return;
175 end if;
177 if Checks and then Target.Capacity < Source.Length then
178 raise Capacity_Error
179 with "Target capacity is less than Source length";
180 end if;
182 HT_Ops.Clear (Target);
183 Insert_Elements (Source);
184 end Assign;
186 --------------
187 -- Capacity --
188 --------------
190 function Capacity (Container : Set) return Count_Type is
191 begin
192 return Container.Capacity;
193 end Capacity;
195 -----------
196 -- Clear --
197 -----------
199 procedure Clear (Container : in out Set) is
200 begin
201 HT_Ops.Clear (Container);
202 end Clear;
204 ------------------------
205 -- Constant_Reference --
206 ------------------------
208 function Constant_Reference
209 (Container : aliased Set;
210 Position : Cursor) return Constant_Reference_Type
212 begin
213 if Checks and then Position.Container = null then
214 raise Constraint_Error with "Position cursor has no element";
215 end if;
217 if Checks and then Position.Container /= Container'Unrestricted_Access
218 then
219 raise Program_Error with
220 "Position cursor designates wrong container";
221 end if;
223 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
225 declare
226 N : Node_Type renames Container.Nodes (Position.Node);
227 TC : constant Tamper_Counts_Access :=
228 Container.TC'Unrestricted_Access;
229 begin
230 return R : constant Constant_Reference_Type :=
231 (Element => N.Element'Access,
232 Control => (Controlled with TC))
234 Lock (TC.all);
235 end return;
236 end;
237 end Constant_Reference;
239 --------------
240 -- Contains --
241 --------------
243 function Contains (Container : Set; Item : Element_Type) return Boolean is
244 begin
245 return Find (Container, Item) /= No_Element;
246 end Contains;
248 ----------
249 -- Copy --
250 ----------
252 function Copy
253 (Source : Set;
254 Capacity : Count_Type := 0;
255 Modulus : Hash_Type := 0) return Set
257 C : Count_Type;
258 M : Hash_Type;
260 begin
261 if Capacity = 0 then
262 C := Source.Length;
263 elsif Capacity >= Source.Length then
264 C := Capacity;
265 elsif Checks then
266 raise Capacity_Error with "Capacity value too small";
267 end if;
269 if Modulus = 0 then
270 M := Default_Modulus (C);
271 else
272 M := Modulus;
273 end if;
275 return Target : Set (Capacity => C, Modulus => M) do
276 Assign (Target => Target, Source => Source);
277 end return;
278 end Copy;
280 ---------------------
281 -- Default_Modulus --
282 ---------------------
284 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
285 begin
286 return To_Prime (Capacity);
287 end Default_Modulus;
289 ------------
290 -- Delete --
291 ------------
293 procedure Delete
294 (Container : in out Set;
295 Item : Element_Type)
297 X : Count_Type;
299 begin
300 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
302 if Checks and then X = 0 then
303 raise Constraint_Error with "attempt to delete element not in set";
304 end if;
306 HT_Ops.Free (Container, X);
307 end Delete;
309 procedure Delete
310 (Container : in out Set;
311 Position : in out Cursor)
313 begin
314 if Checks and then Position.Node = 0 then
315 raise Constraint_Error with "Position cursor equals No_Element";
316 end if;
318 if Checks and then Position.Container /= Container'Unrestricted_Access
319 then
320 raise Program_Error with "Position cursor designates wrong set";
321 end if;
323 TC_Check (Container.TC);
325 pragma Assert (Vet (Position), "bad cursor in Delete");
327 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
328 HT_Ops.Free (Container, Position.Node);
330 Position := No_Element;
331 end Delete;
333 ----------------
334 -- Difference --
335 ----------------
337 procedure Difference
338 (Target : in out Set;
339 Source : Set)
341 Tgt_Node, Src_Node : Count_Type;
343 Src : Set renames Source'Unrestricted_Access.all;
345 TN : Nodes_Type renames Target.Nodes;
346 SN : Nodes_Type renames Source.Nodes;
348 begin
349 if Target'Address = Source'Address then
350 HT_Ops.Clear (Target);
351 return;
352 end if;
354 if Source.Length = 0 then
355 return;
356 end if;
358 TC_Check (Target.TC);
360 if Source.Length < Target.Length then
361 Src_Node := HT_Ops.First (Source);
362 while Src_Node /= 0 loop
363 Tgt_Node := Element_Keys.Find (Target, SN (Src_Node).Element);
365 if Tgt_Node /= 0 then
366 HT_Ops.Delete_Node_Sans_Free (Target, Tgt_Node);
367 HT_Ops.Free (Target, Tgt_Node);
368 end if;
370 Src_Node := HT_Ops.Next (Src, Src_Node);
371 end loop;
373 else
374 Tgt_Node := HT_Ops.First (Target);
375 while Tgt_Node /= 0 loop
376 if Is_In (Source, TN (Tgt_Node)) then
377 declare
378 X : constant Count_Type := Tgt_Node;
379 begin
380 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
381 HT_Ops.Delete_Node_Sans_Free (Target, X);
382 HT_Ops.Free (Target, X);
383 end;
385 else
386 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
387 end if;
388 end loop;
389 end if;
390 end Difference;
392 function Difference (Left, Right : Set) return Set is
393 begin
394 if Left'Address = Right'Address then
395 return Empty_Set;
396 end if;
398 if Left.Length = 0 then
399 return Empty_Set;
400 end if;
402 if Right.Length = 0 then
403 return Left;
404 end if;
406 return Result : Set (Left.Length, To_Prime (Left.Length)) do
407 Iterate_Left : declare
408 procedure Process (L_Node : Count_Type);
410 procedure Iterate is
411 new HT_Ops.Generic_Iteration (Process);
413 -------------
414 -- Process --
415 -------------
417 procedure Process (L_Node : Count_Type) is
418 N : Node_Type renames Left.Nodes (L_Node);
419 X : Count_Type;
420 B : Boolean;
421 begin
422 if not Is_In (Right, N) then
423 Insert (Result, N.Element, X, B); -- optimize this ???
424 pragma Assert (B);
425 pragma Assert (X > 0);
426 end if;
427 end Process;
429 -- Start of processing for Iterate_Left
431 begin
432 Iterate (Left);
433 end Iterate_Left;
434 end return;
435 end Difference;
437 -------------
438 -- Element --
439 -------------
441 function Element (Position : Cursor) return Element_Type is
442 begin
443 if Checks and then Position.Node = 0 then
444 raise Constraint_Error with "Position cursor equals No_Element";
445 end if;
447 pragma Assert (Vet (Position), "bad cursor in function Element");
449 declare
450 S : Set renames Position.Container.all;
451 N : Node_Type renames S.Nodes (Position.Node);
452 begin
453 return N.Element;
454 end;
455 end Element;
457 ---------------------
458 -- Equivalent_Sets --
459 ---------------------
461 function Equivalent_Sets (Left, Right : Set) return Boolean is
462 function Find_Equivalent_Key
463 (R_HT : Hash_Table_Type'Class;
464 L_Node : Node_Type) return Boolean;
465 pragma Inline (Find_Equivalent_Key);
467 function Is_Equivalent is
468 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
470 -------------------------
471 -- Find_Equivalent_Key --
472 -------------------------
474 function Find_Equivalent_Key
475 (R_HT : Hash_Table_Type'Class;
476 L_Node : Node_Type) return Boolean
478 R_Index : constant Hash_Type :=
479 Element_Keys.Index (R_HT, L_Node.Element);
481 R_Node : Count_Type := R_HT.Buckets (R_Index);
483 RN : Nodes_Type renames R_HT.Nodes;
485 begin
486 loop
487 if R_Node = 0 then
488 return False;
489 end if;
491 if Equivalent_Elements (L_Node.Element, RN (R_Node).Element) then
492 return True;
493 end if;
495 R_Node := Next (R_HT.Nodes (R_Node));
496 end loop;
497 end Find_Equivalent_Key;
499 -- Start of processing for Equivalent_Sets
501 begin
502 return Is_Equivalent (Left, Right);
503 end Equivalent_Sets;
505 -------------------------
506 -- Equivalent_Elements --
507 -------------------------
509 function Equivalent_Elements (Left, Right : Cursor)
510 return Boolean is
512 begin
513 if Checks and then Left.Node = 0 then
514 raise Constraint_Error with
515 "Left cursor of Equivalent_Elements equals No_Element";
516 end if;
518 if Checks and then Right.Node = 0 then
519 raise Constraint_Error with
520 "Right cursor of Equivalent_Elements equals No_Element";
521 end if;
523 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
524 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
526 -- AI05-0022 requires that a container implementation detect element
527 -- tampering by a generic actual subprogram. However, the following case
528 -- falls outside the scope of that AI. Randy Brukardt explained on the
529 -- ARG list on 2013/02/07 that:
531 -- (Begin Quote):
532 -- But for an operation like "<" [the ordered set analog of
533 -- Equivalent_Elements], there is no need to "dereference" a cursor
534 -- after the call to the generic formal parameter function, so nothing
535 -- bad could happen if tampering is undetected. And the operation can
536 -- safely return a result without a problem even if an element is
537 -- deleted from the container.
538 -- (End Quote).
540 declare
541 LN : Node_Type renames Left.Container.Nodes (Left.Node);
542 RN : Node_Type renames Right.Container.Nodes (Right.Node);
543 begin
544 return Equivalent_Elements (LN.Element, RN.Element);
545 end;
546 end Equivalent_Elements;
548 function Equivalent_Elements
549 (Left : Cursor;
550 Right : Element_Type) return Boolean
552 begin
553 if Checks and then Left.Node = 0 then
554 raise Constraint_Error with
555 "Left cursor of Equivalent_Elements equals No_Element";
556 end if;
558 pragma Assert (Vet (Left), "Left cursor in Equivalent_Elements is bad");
560 declare
561 LN : Node_Type renames Left.Container.Nodes (Left.Node);
562 begin
563 return Equivalent_Elements (LN.Element, Right);
564 end;
565 end Equivalent_Elements;
567 function Equivalent_Elements
568 (Left : Element_Type;
569 Right : Cursor) return Boolean
571 begin
572 if Checks and then Right.Node = 0 then
573 raise Constraint_Error with
574 "Right cursor of Equivalent_Elements equals No_Element";
575 end if;
577 pragma Assert
578 (Vet (Right),
579 "Right cursor of Equivalent_Elements is bad");
581 declare
582 RN : Node_Type renames Right.Container.Nodes (Right.Node);
583 begin
584 return Equivalent_Elements (Left, RN.Element);
585 end;
586 end Equivalent_Elements;
588 ---------------------
589 -- Equivalent_Keys --
590 ---------------------
592 function Equivalent_Keys
593 (Key : Element_Type;
594 Node : Node_Type) return Boolean
596 begin
597 return Equivalent_Elements (Key, Node.Element);
598 end Equivalent_Keys;
600 -------------
601 -- Exclude --
602 -------------
604 procedure Exclude
605 (Container : in out Set;
606 Item : Element_Type)
608 X : Count_Type;
609 begin
610 Element_Keys.Delete_Key_Sans_Free (Container, Item, X);
611 HT_Ops.Free (Container, X);
612 end Exclude;
614 --------------
615 -- Finalize --
616 --------------
618 procedure Finalize (Object : in out Iterator) is
619 begin
620 if Object.Container /= null then
621 Unbusy (Object.Container.TC);
622 end if;
623 end Finalize;
625 ----------
626 -- Find --
627 ----------
629 function Find
630 (Container : Set;
631 Item : Element_Type) return Cursor
633 Node : constant Count_Type :=
634 Element_Keys.Find (Container'Unrestricted_Access.all, Item);
635 begin
636 return (if Node = 0 then No_Element
637 else Cursor'(Container'Unrestricted_Access, Node));
638 end Find;
640 -----------
641 -- First --
642 -----------
644 function First (Container : Set) return Cursor is
645 Node : constant Count_Type := HT_Ops.First (Container);
646 begin
647 return (if Node = 0 then No_Element
648 else Cursor'(Container'Unrestricted_Access, Node));
649 end First;
651 overriding function First (Object : Iterator) return Cursor is
652 begin
653 return Object.Container.First;
654 end First;
656 ------------------------
657 -- Get_Element_Access --
658 ------------------------
660 function Get_Element_Access
661 (Position : Cursor) return not null Element_Access is
662 begin
663 return Position.Container.Nodes (Position.Node).Element'Access;
664 end Get_Element_Access;
666 -----------------
667 -- Has_Element --
668 -----------------
670 function Has_Element (Position : Cursor) return Boolean is
671 begin
672 pragma Assert (Vet (Position), "bad cursor in Has_Element");
673 return Position.Node /= 0;
674 end Has_Element;
676 ---------------
677 -- Hash_Node --
678 ---------------
680 function Hash_Node (Node : Node_Type) return Hash_Type is
681 begin
682 return Hash (Node.Element);
683 end Hash_Node;
685 -------------
686 -- Include --
687 -------------
689 procedure Include
690 (Container : in out Set;
691 New_Item : Element_Type)
693 Position : Cursor;
694 Inserted : Boolean;
696 begin
697 Insert (Container, New_Item, Position, Inserted);
699 if not Inserted then
700 TE_Check (Container.TC);
702 Container.Nodes (Position.Node).Element := New_Item;
703 end if;
704 end Include;
706 ------------
707 -- Insert --
708 ------------
710 procedure Insert
711 (Container : in out Set;
712 New_Item : Element_Type;
713 Position : out Cursor;
714 Inserted : out Boolean)
716 begin
717 Insert (Container, New_Item, Position.Node, Inserted);
718 Position.Container := Container'Unchecked_Access;
719 end Insert;
721 procedure Insert
722 (Container : in out Set;
723 New_Item : Element_Type)
725 Position : Cursor;
726 pragma Unreferenced (Position);
728 Inserted : Boolean;
730 begin
731 Insert (Container, New_Item, Position, Inserted);
733 if Checks and then not Inserted then
734 raise Constraint_Error with
735 "attempt to insert element already in set";
736 end if;
737 end Insert;
739 procedure Insert
740 (Container : in out Set;
741 New_Item : Element_Type;
742 Node : out Count_Type;
743 Inserted : out Boolean)
745 procedure Allocate_Set_Element (Node : in out Node_Type);
746 pragma Inline (Allocate_Set_Element);
748 function New_Node return Count_Type;
749 pragma Inline (New_Node);
751 procedure Local_Insert is
752 new Element_Keys.Generic_Conditional_Insert (New_Node);
754 procedure Allocate is
755 new HT_Ops.Generic_Allocate (Allocate_Set_Element);
757 ---------------------------
758 -- Allocate_Set_Element --
759 ---------------------------
761 procedure Allocate_Set_Element (Node : in out Node_Type) is
762 begin
763 Node.Element := New_Item;
764 end Allocate_Set_Element;
766 --------------
767 -- New_Node --
768 --------------
770 function New_Node return Count_Type is
771 Result : Count_Type;
772 begin
773 Allocate (Container, Result);
774 return Result;
775 end New_Node;
777 -- Start of processing for Insert
779 begin
780 -- The buckets array length is specified by the user as a discriminant
781 -- of the container type, so it is possible for the buckets array to
782 -- have a length of zero. We must check for this case specifically, in
783 -- order to prevent divide-by-zero errors later, when we compute the
784 -- buckets array index value for an element, given its hash value.
786 if Checks and then Container.Buckets'Length = 0 then
787 raise Capacity_Error with "No capacity for insertion";
788 end if;
790 Local_Insert (Container, New_Item, Node, Inserted);
791 end Insert;
793 ------------------
794 -- Intersection --
795 ------------------
797 procedure Intersection
798 (Target : in out Set;
799 Source : Set)
801 Tgt_Node : Count_Type;
802 TN : Nodes_Type renames Target.Nodes;
804 begin
805 if Target'Address = Source'Address then
806 return;
807 end if;
809 if Source.Length = 0 then
810 HT_Ops.Clear (Target);
811 return;
812 end if;
814 TC_Check (Target.TC);
816 Tgt_Node := HT_Ops.First (Target);
817 while Tgt_Node /= 0 loop
818 if Is_In (Source, TN (Tgt_Node)) then
819 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
821 else
822 declare
823 X : constant Count_Type := Tgt_Node;
824 begin
825 Tgt_Node := HT_Ops.Next (Target, Tgt_Node);
826 HT_Ops.Delete_Node_Sans_Free (Target, X);
827 HT_Ops.Free (Target, X);
828 end;
829 end if;
830 end loop;
831 end Intersection;
833 function Intersection (Left, Right : Set) return Set is
834 C : Count_Type;
836 begin
837 if Left'Address = Right'Address then
838 return Left;
839 end if;
841 C := Count_Type'Min (Left.Length, Right.Length);
843 if C = 0 then
844 return Empty_Set;
845 end if;
847 return Result : Set (C, To_Prime (C)) do
848 Iterate_Left : declare
849 procedure Process (L_Node : Count_Type);
851 procedure Iterate is
852 new HT_Ops.Generic_Iteration (Process);
854 -------------
855 -- Process --
856 -------------
858 procedure Process (L_Node : Count_Type) is
859 N : Node_Type renames Left.Nodes (L_Node);
860 X : Count_Type;
861 B : Boolean;
863 begin
864 if Is_In (Right, N) then
865 Insert (Result, N.Element, X, B); -- optimize ???
866 pragma Assert (B);
867 pragma Assert (X > 0);
868 end if;
869 end Process;
871 -- Start of processing for Iterate_Left
873 begin
874 Iterate (Left);
875 end Iterate_Left;
876 end return;
877 end Intersection;
879 --------------
880 -- Is_Empty --
881 --------------
883 function Is_Empty (Container : Set) return Boolean is
884 begin
885 return Container.Length = 0;
886 end Is_Empty;
888 -----------
889 -- Is_In --
890 -----------
892 function Is_In (HT : Set; Key : Node_Type) return Boolean is
893 begin
894 return Element_Keys.Find (HT'Unrestricted_Access.all, Key.Element) /= 0;
895 end Is_In;
897 ---------------
898 -- Is_Subset --
899 ---------------
901 function Is_Subset (Subset : Set; Of_Set : Set) return Boolean is
902 Subset_Node : Count_Type;
903 SN : Nodes_Type renames Subset.Nodes;
905 begin
906 if Subset'Address = Of_Set'Address then
907 return True;
908 end if;
910 if Subset.Length > Of_Set.Length then
911 return False;
912 end if;
914 Subset_Node := HT_Ops.First (Subset);
915 while Subset_Node /= 0 loop
916 if not Is_In (Of_Set, SN (Subset_Node)) then
917 return False;
918 end if;
919 Subset_Node := HT_Ops.Next
920 (Subset'Unrestricted_Access.all, Subset_Node);
921 end loop;
923 return True;
924 end Is_Subset;
926 -------------
927 -- Iterate --
928 -------------
930 procedure Iterate
931 (Container : Set;
932 Process : not null access procedure (Position : Cursor))
934 procedure Process_Node (Node : Count_Type);
935 pragma Inline (Process_Node);
937 procedure Iterate is
938 new HT_Ops.Generic_Iteration (Process_Node);
940 ------------------
941 -- Process_Node --
942 ------------------
944 procedure Process_Node (Node : Count_Type) is
945 begin
946 Process (Cursor'(Container'Unrestricted_Access, Node));
947 end Process_Node;
949 Busy : With_Busy (Container.TC'Unrestricted_Access);
951 -- Start of processing for Iterate
953 begin
954 Iterate (Container);
955 end Iterate;
957 function Iterate (Container : Set)
958 return Set_Iterator_Interfaces.Forward_Iterator'Class
960 begin
961 Busy (Container.TC'Unrestricted_Access.all);
962 return It : constant Iterator :=
963 Iterator'(Limited_Controlled with
964 Container => Container'Unrestricted_Access);
965 end Iterate;
967 ------------
968 -- Length --
969 ------------
971 function Length (Container : Set) return Count_Type is
972 begin
973 return Container.Length;
974 end Length;
976 ----------
977 -- Move --
978 ----------
980 procedure Move (Target : in out Set; Source : in out Set) is
981 begin
982 if Target'Address = Source'Address then
983 return;
984 end if;
986 TC_Check (Source.TC);
988 Target.Assign (Source);
989 Source.Clear;
990 end Move;
992 ----------
993 -- Next --
994 ----------
996 function Next (Node : Node_Type) return Count_Type is
997 begin
998 return Node.Next;
999 end Next;
1001 function Next (Position : Cursor) return Cursor is
1002 begin
1003 if Position.Node = 0 then
1004 return No_Element;
1005 end if;
1007 pragma Assert (Vet (Position), "bad cursor in Next");
1009 declare
1010 HT : Set renames Position.Container.all;
1011 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
1013 begin
1014 if Node = 0 then
1015 return No_Element;
1016 end if;
1018 return Cursor'(Position.Container, Node);
1019 end;
1020 end Next;
1022 procedure Next (Position : in out Cursor) is
1023 begin
1024 Position := Next (Position);
1025 end Next;
1027 function Next
1028 (Object : Iterator;
1029 Position : Cursor) return Cursor
1031 begin
1032 if Position.Container = null then
1033 return No_Element;
1034 end if;
1036 if Checks and then Position.Container /= Object.Container then
1037 raise Program_Error with
1038 "Position cursor of Next designates wrong set";
1039 end if;
1041 return Next (Position);
1042 end Next;
1044 -------------
1045 -- Overlap --
1046 -------------
1048 function Overlap (Left, Right : Set) return Boolean is
1049 Left_Node : Count_Type;
1051 begin
1052 if Right.Length = 0 then
1053 return False;
1054 end if;
1056 if Left'Address = Right'Address then
1057 return True;
1058 end if;
1060 Left_Node := HT_Ops.First (Left);
1061 while Left_Node /= 0 loop
1062 if Is_In (Right, Left.Nodes (Left_Node)) then
1063 return True;
1064 end if;
1065 Left_Node := HT_Ops.Next (Left'Unrestricted_Access.all, Left_Node);
1066 end loop;
1068 return False;
1069 end Overlap;
1071 ----------------------
1072 -- Pseudo_Reference --
1073 ----------------------
1075 function Pseudo_Reference
1076 (Container : aliased Set'Class) return Reference_Control_Type
1078 TC : constant Tamper_Counts_Access :=
1079 Container.TC'Unrestricted_Access;
1080 begin
1081 return R : constant Reference_Control_Type := (Controlled with TC) do
1082 Lock (TC.all);
1083 end return;
1084 end Pseudo_Reference;
1086 -------------------
1087 -- Query_Element --
1088 -------------------
1090 procedure Query_Element
1091 (Position : Cursor;
1092 Process : not null access procedure (Element : Element_Type))
1094 begin
1095 if Checks and then Position.Node = 0 then
1096 raise Constraint_Error with
1097 "Position cursor of Query_Element equals No_Element";
1098 end if;
1100 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1102 declare
1103 S : Set renames Position.Container.all;
1104 Lock : With_Lock (S.TC'Unrestricted_Access);
1105 begin
1106 Process (S.Nodes (Position.Node).Element);
1107 end;
1108 end Query_Element;
1110 ----------
1111 -- Read --
1112 ----------
1114 procedure Read
1115 (Stream : not null access Root_Stream_Type'Class;
1116 Container : out Set)
1118 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1119 return Count_Type;
1121 procedure Read_Nodes is
1122 new HT_Ops.Generic_Read (Read_Node);
1124 ---------------
1125 -- Read_Node --
1126 ---------------
1128 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1129 return Count_Type
1131 procedure Read_Element (Node : in out Node_Type);
1132 pragma Inline (Read_Element);
1134 procedure Allocate is
1135 new HT_Ops.Generic_Allocate (Read_Element);
1137 procedure Read_Element (Node : in out Node_Type) is
1138 begin
1139 Element_Type'Read (Stream, Node.Element);
1140 end Read_Element;
1142 Node : Count_Type;
1144 -- Start of processing for Read_Node
1146 begin
1147 Allocate (Container, Node);
1148 return Node;
1149 end Read_Node;
1151 -- Start of processing for Read
1153 begin
1154 Read_Nodes (Stream, Container);
1155 end Read;
1157 procedure Read
1158 (Stream : not null access Root_Stream_Type'Class;
1159 Item : out Cursor)
1161 begin
1162 raise Program_Error with "attempt to stream set cursor";
1163 end Read;
1165 procedure Read
1166 (Stream : not null access Root_Stream_Type'Class;
1167 Item : out Constant_Reference_Type)
1169 begin
1170 raise Program_Error with "attempt to stream reference";
1171 end Read;
1173 -------------
1174 -- Replace --
1175 -------------
1177 procedure Replace
1178 (Container : in out Set;
1179 New_Item : Element_Type)
1181 Node : constant Count_Type := Element_Keys.Find (Container, New_Item);
1183 begin
1184 if Checks and then Node = 0 then
1185 raise Constraint_Error with
1186 "attempt to replace element not in set";
1187 end if;
1189 TE_Check (Container.TC);
1191 Container.Nodes (Node).Element := New_Item;
1192 end Replace;
1194 procedure Replace_Element
1195 (Container : in out Set;
1196 Position : Cursor;
1197 New_Item : Element_Type)
1199 begin
1200 if Checks and then Position.Node = 0 then
1201 raise Constraint_Error with
1202 "Position cursor equals No_Element";
1203 end if;
1205 if Checks and then Position.Container /= Container'Unrestricted_Access
1206 then
1207 raise Program_Error with
1208 "Position cursor designates wrong set";
1209 end if;
1211 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1213 Replace_Element (Container, Position.Node, New_Item);
1214 end Replace_Element;
1216 ----------------------
1217 -- Reserve_Capacity --
1218 ----------------------
1220 procedure Reserve_Capacity
1221 (Container : in out Set;
1222 Capacity : Count_Type)
1224 begin
1225 if Checks and then Capacity > Container.Capacity then
1226 raise Capacity_Error with "requested capacity is too large";
1227 end if;
1228 end Reserve_Capacity;
1230 ------------------
1231 -- Set_Element --
1232 ------------------
1234 procedure Set_Element (Node : in out Node_Type; Item : Element_Type) is
1235 begin
1236 Node.Element := Item;
1237 end Set_Element;
1239 --------------
1240 -- Set_Next --
1241 --------------
1243 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1244 begin
1245 Node.Next := Next;
1246 end Set_Next;
1248 --------------------------
1249 -- Symmetric_Difference --
1250 --------------------------
1252 procedure Symmetric_Difference
1253 (Target : in out Set;
1254 Source : Set)
1256 procedure Process (Source_Node : Count_Type);
1257 pragma Inline (Process);
1259 procedure Iterate is
1260 new HT_Ops.Generic_Iteration (Process);
1262 -------------
1263 -- Process --
1264 -------------
1266 procedure Process (Source_Node : Count_Type) is
1267 N : Node_Type renames Source.Nodes (Source_Node);
1268 X : Count_Type;
1269 B : Boolean;
1271 begin
1272 if Is_In (Target, N) then
1273 Delete (Target, N.Element);
1274 else
1275 Insert (Target, N.Element, X, B);
1276 pragma Assert (B);
1277 end if;
1278 end Process;
1280 -- Start of processing for Symmetric_Difference
1282 begin
1283 if Target'Address = Source'Address then
1284 HT_Ops.Clear (Target);
1285 return;
1286 end if;
1288 if Target.Length = 0 then
1289 Assign (Target => Target, Source => Source);
1290 return;
1291 end if;
1293 TC_Check (Target.TC);
1295 Iterate (Source);
1296 end Symmetric_Difference;
1298 function Symmetric_Difference (Left, Right : Set) return Set is
1299 C : Count_Type;
1301 begin
1302 if Left'Address = Right'Address then
1303 return Empty_Set;
1304 end if;
1306 if Right.Length = 0 then
1307 return Left;
1308 end if;
1310 if Left.Length = 0 then
1311 return Right;
1312 end if;
1314 C := Left.Length + Right.Length;
1316 return Result : Set (C, To_Prime (C)) do
1317 Iterate_Left : declare
1318 procedure Process (L_Node : Count_Type);
1320 procedure Iterate is
1321 new HT_Ops.Generic_Iteration (Process);
1323 -------------
1324 -- Process --
1325 -------------
1327 procedure Process (L_Node : Count_Type) is
1328 N : Node_Type renames Left.Nodes (L_Node);
1329 X : Count_Type;
1330 B : Boolean;
1331 begin
1332 if not Is_In (Right, N) then
1333 Insert (Result, N.Element, X, B);
1334 pragma Assert (B);
1335 end if;
1336 end Process;
1338 -- Start of processing for Iterate_Left
1340 begin
1341 Iterate (Left);
1342 end Iterate_Left;
1344 Iterate_Right : declare
1345 procedure Process (R_Node : Count_Type);
1347 procedure Iterate is
1348 new HT_Ops.Generic_Iteration (Process);
1350 -------------
1351 -- Process --
1352 -------------
1354 procedure Process (R_Node : Count_Type) is
1355 N : Node_Type renames Right.Nodes (R_Node);
1356 X : Count_Type;
1357 B : Boolean;
1358 begin
1359 if not Is_In (Left, N) then
1360 Insert (Result, N.Element, X, B);
1361 pragma Assert (B);
1362 end if;
1363 end Process;
1365 -- Start of processing for Iterate_Right
1367 begin
1368 Iterate (Right);
1369 end Iterate_Right;
1370 end return;
1371 end Symmetric_Difference;
1373 ------------
1374 -- To_Set --
1375 ------------
1377 function To_Set (New_Item : Element_Type) return Set is
1378 X : Count_Type;
1379 B : Boolean;
1380 begin
1381 return Result : Set (1, 1) do
1382 Insert (Result, New_Item, X, B);
1383 pragma Assert (B);
1384 end return;
1385 end To_Set;
1387 -----------
1388 -- Union --
1389 -----------
1391 procedure Union
1392 (Target : in out Set;
1393 Source : Set)
1395 procedure Process (Src_Node : Count_Type);
1397 procedure Iterate is
1398 new HT_Ops.Generic_Iteration (Process);
1400 -------------
1401 -- Process --
1402 -------------
1404 procedure Process (Src_Node : Count_Type) is
1405 N : Node_Type renames Source.Nodes (Src_Node);
1406 X : Count_Type;
1407 B : Boolean;
1408 begin
1409 Insert (Target, N.Element, X, B);
1410 end Process;
1412 -- Start of processing for Union
1414 begin
1415 if Target'Address = Source'Address then
1416 return;
1417 end if;
1419 TC_Check (Target.TC);
1421 -- ??? why is this code commented out ???
1422 -- declare
1423 -- N : constant Count_Type := Target.Length + Source.Length;
1424 -- begin
1425 -- if N > HT_Ops.Capacity (Target.HT) then
1426 -- HT_Ops.Reserve_Capacity (Target.HT, N);
1427 -- end if;
1428 -- end;
1430 Iterate (Source);
1431 end Union;
1433 function Union (Left, Right : Set) return Set is
1434 C : Count_Type;
1436 begin
1437 if Left'Address = Right'Address then
1438 return Left;
1439 end if;
1441 if Right.Length = 0 then
1442 return Left;
1443 end if;
1445 if Left.Length = 0 then
1446 return Right;
1447 end if;
1449 C := Left.Length + Right.Length;
1451 return Result : Set (C, To_Prime (C)) do
1452 Assign (Target => Result, Source => Left);
1453 Union (Target => Result, Source => Right);
1454 end return;
1455 end Union;
1457 ---------
1458 -- Vet --
1459 ---------
1461 function Vet (Position : Cursor) return Boolean is
1462 begin
1463 if Position.Node = 0 then
1464 return Position.Container = null;
1465 end if;
1467 if Position.Container = null then
1468 return False;
1469 end if;
1471 declare
1472 S : Set renames Position.Container.all;
1473 N : Nodes_Type renames S.Nodes;
1474 X : Count_Type;
1476 begin
1477 if S.Length = 0 then
1478 return False;
1479 end if;
1481 if Position.Node > N'Last then
1482 return False;
1483 end if;
1485 if N (Position.Node).Next = Position.Node then
1486 return False;
1487 end if;
1489 X := S.Buckets (Element_Keys.Checked_Index
1490 (S, N (Position.Node).Element));
1492 for J in 1 .. S.Length loop
1493 if X = Position.Node then
1494 return True;
1495 end if;
1497 if X = 0 then
1498 return False;
1499 end if;
1501 if X = N (X).Next then -- to prevent unnecessary looping
1502 return False;
1503 end if;
1505 X := N (X).Next;
1506 end loop;
1508 return False;
1509 end;
1510 end Vet;
1512 -----------
1513 -- Write --
1514 -----------
1516 procedure Write
1517 (Stream : not null access Root_Stream_Type'Class;
1518 Container : Set)
1520 procedure Write_Node
1521 (Stream : not null access Root_Stream_Type'Class;
1522 Node : Node_Type);
1523 pragma Inline (Write_Node);
1525 procedure Write_Nodes is
1526 new HT_Ops.Generic_Write (Write_Node);
1528 ----------------
1529 -- Write_Node --
1530 ----------------
1532 procedure Write_Node
1533 (Stream : not null access Root_Stream_Type'Class;
1534 Node : Node_Type)
1536 begin
1537 Element_Type'Write (Stream, Node.Element);
1538 end Write_Node;
1540 -- Start of processing for Write
1542 begin
1543 Write_Nodes (Stream, Container);
1544 end Write;
1546 procedure Write
1547 (Stream : not null access Root_Stream_Type'Class;
1548 Item : Cursor)
1550 begin
1551 raise Program_Error with "attempt to stream set cursor";
1552 end Write;
1554 procedure Write
1555 (Stream : not null access Root_Stream_Type'Class;
1556 Item : Constant_Reference_Type)
1558 begin
1559 raise Program_Error with "attempt to stream reference";
1560 end Write;
1562 package body Generic_Keys is
1564 -----------------------
1565 -- Local Subprograms --
1566 -----------------------
1568 function Equivalent_Key_Node
1569 (Key : Key_Type;
1570 Node : Node_Type) return Boolean;
1571 pragma Inline (Equivalent_Key_Node);
1573 --------------------------
1574 -- Local Instantiations --
1575 --------------------------
1577 package Key_Keys is
1578 new Hash_Tables.Generic_Bounded_Keys
1579 (HT_Types => HT_Types,
1580 Next => Next,
1581 Set_Next => Set_Next,
1582 Key_Type => Key_Type,
1583 Hash => Hash,
1584 Equivalent_Keys => Equivalent_Key_Node);
1586 ------------------------
1587 -- Constant_Reference --
1588 ------------------------
1590 function Constant_Reference
1591 (Container : aliased Set;
1592 Key : Key_Type) return Constant_Reference_Type
1594 Node : constant Count_Type :=
1595 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1597 begin
1598 if Checks and then Node = 0 then
1599 raise Constraint_Error with "key not in set";
1600 end if;
1602 declare
1603 N : Node_Type renames Container.Nodes (Node);
1604 TC : constant Tamper_Counts_Access :=
1605 Container.TC'Unrestricted_Access;
1606 begin
1607 return R : constant Constant_Reference_Type :=
1608 (Element => N.Element'Access,
1609 Control => (Controlled with TC))
1611 Lock (TC.all);
1612 end return;
1613 end;
1614 end Constant_Reference;
1616 --------------
1617 -- Contains --
1618 --------------
1620 function Contains
1621 (Container : Set;
1622 Key : Key_Type) return Boolean
1624 begin
1625 return Find (Container, Key) /= No_Element;
1626 end Contains;
1628 ------------
1629 -- Delete --
1630 ------------
1632 procedure Delete
1633 (Container : in out Set;
1634 Key : Key_Type)
1636 X : Count_Type;
1638 begin
1639 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1641 if Checks and then X = 0 then
1642 raise Constraint_Error with "attempt to delete key not in set";
1643 end if;
1645 HT_Ops.Free (Container, X);
1646 end Delete;
1648 -------------
1649 -- Element --
1650 -------------
1652 function Element
1653 (Container : Set;
1654 Key : Key_Type) return Element_Type
1656 Node : constant Count_Type :=
1657 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1659 begin
1660 if Checks and then Node = 0 then
1661 raise Constraint_Error with "key not in set";
1662 end if;
1664 return Container.Nodes (Node).Element;
1665 end Element;
1667 -------------------------
1668 -- Equivalent_Key_Node --
1669 -------------------------
1671 function Equivalent_Key_Node
1672 (Key : Key_Type;
1673 Node : Node_Type) return Boolean
1675 begin
1676 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element));
1677 end Equivalent_Key_Node;
1679 -------------
1680 -- Exclude --
1681 -------------
1683 procedure Exclude
1684 (Container : in out Set;
1685 Key : Key_Type)
1687 X : Count_Type;
1688 begin
1689 Key_Keys.Delete_Key_Sans_Free (Container, Key, X);
1690 HT_Ops.Free (Container, X);
1691 end Exclude;
1693 --------------
1694 -- Finalize --
1695 --------------
1697 procedure Finalize (Control : in out Reference_Control_Type) is
1698 begin
1699 if Control.Container /= null then
1700 Impl.Reference_Control_Type (Control).Finalize;
1702 if Checks and then
1703 Hash (Key (Element (Control.Old_Pos))) /= Control.Old_Hash
1704 then
1705 HT_Ops.Delete_Node_At_Index
1706 (Control.Container.all, Control.Index, Control.Old_Pos.Node);
1707 raise Program_Error with "key not preserved in reference";
1708 end if;
1710 Control.Container := null;
1711 end if;
1712 end Finalize;
1714 ----------
1715 -- Find --
1716 ----------
1718 function Find
1719 (Container : Set;
1720 Key : Key_Type) return Cursor
1722 Node : constant Count_Type :=
1723 Key_Keys.Find (Container'Unrestricted_Access.all, Key);
1724 begin
1725 return (if Node = 0 then No_Element
1726 else Cursor'(Container'Unrestricted_Access, Node));
1727 end Find;
1729 ---------
1730 -- Key --
1731 ---------
1733 function Key (Position : Cursor) return Key_Type is
1734 begin
1735 if Checks and then Position.Node = 0 then
1736 raise Constraint_Error with
1737 "Position cursor equals No_Element";
1738 end if;
1740 pragma Assert (Vet (Position), "bad cursor in function Key");
1741 return Key (Position.Container.Nodes (Position.Node).Element);
1742 end Key;
1744 ----------
1745 -- Read --
1746 ----------
1748 procedure Read
1749 (Stream : not null access Root_Stream_Type'Class;
1750 Item : out Reference_Type)
1752 begin
1753 raise Program_Error with "attempt to stream reference";
1754 end Read;
1756 ------------------------------
1757 -- Reference_Preserving_Key --
1758 ------------------------------
1760 function Reference_Preserving_Key
1761 (Container : aliased in out Set;
1762 Position : Cursor) return Reference_Type
1764 begin
1765 if Checks and then Position.Container = null then
1766 raise Constraint_Error with "Position cursor has no element";
1767 end if;
1769 if Checks and then Position.Container /= Container'Unrestricted_Access
1770 then
1771 raise Program_Error with
1772 "Position cursor designates wrong container";
1773 end if;
1775 pragma Assert
1776 (Vet (Position),
1777 "bad cursor in function Reference_Preserving_Key");
1779 declare
1780 N : Node_Type renames Container.Nodes (Position.Node);
1781 begin
1782 return R : constant Reference_Type :=
1783 (Element => N.Element'Unrestricted_Access,
1784 Control =>
1785 (Controlled with
1786 Container.TC'Unrestricted_Access,
1787 Container'Unrestricted_Access,
1788 Index => Key_Keys.Index (Container, Key (Position)),
1789 Old_Pos => Position,
1790 Old_Hash => Hash (Key (Position))))
1792 Lock (Container.TC);
1793 end return;
1794 end;
1795 end Reference_Preserving_Key;
1797 function Reference_Preserving_Key
1798 (Container : aliased in out Set;
1799 Key : Key_Type) return Reference_Type
1801 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1803 begin
1804 if Checks and then Node = 0 then
1805 raise Constraint_Error with "key not in set";
1806 end if;
1808 declare
1809 P : constant Cursor := Find (Container, Key);
1810 begin
1811 return R : constant Reference_Type :=
1812 (Element => Container.Nodes (Node).Element'Unrestricted_Access,
1813 Control =>
1814 (Controlled with
1815 Container.TC'Unrestricted_Access,
1816 Container'Unrestricted_Access,
1817 Index => Key_Keys.Index (Container, Key),
1818 Old_Pos => P,
1819 Old_Hash => Hash (Key)))
1821 Lock (Container.TC);
1822 end return;
1823 end;
1824 end Reference_Preserving_Key;
1826 -------------
1827 -- Replace --
1828 -------------
1830 procedure Replace
1831 (Container : in out Set;
1832 Key : Key_Type;
1833 New_Item : Element_Type)
1835 Node : constant Count_Type := Key_Keys.Find (Container, Key);
1837 begin
1838 if Checks and then Node = 0 then
1839 raise Constraint_Error with
1840 "attempt to replace key not in set";
1841 end if;
1843 Replace_Element (Container, Node, New_Item);
1844 end Replace;
1846 -----------------------------------
1847 -- Update_Element_Preserving_Key --
1848 -----------------------------------
1850 procedure Update_Element_Preserving_Key
1851 (Container : in out Set;
1852 Position : Cursor;
1853 Process : not null access
1854 procedure (Element : in out Element_Type))
1856 Indx : Hash_Type;
1857 N : Nodes_Type renames Container.Nodes;
1859 begin
1860 if Checks and then Position.Node = 0 then
1861 raise Constraint_Error with
1862 "Position cursor equals No_Element";
1863 end if;
1865 if Checks and then Position.Container /= Container'Unrestricted_Access
1866 then
1867 raise Program_Error with
1868 "Position cursor designates wrong set";
1869 end if;
1871 -- ??? why is this code commented out ???
1872 -- if HT.Buckets = null
1873 -- or else HT.Buckets'Length = 0
1874 -- or else HT.Length = 0
1875 -- or else Position.Node.Next = Position.Node
1876 -- then
1877 -- raise Program_Error with
1878 -- "Position cursor is bad (set is empty)";
1879 -- end if;
1881 pragma Assert
1882 (Vet (Position),
1883 "bad cursor in Update_Element_Preserving_Key");
1885 -- Per AI05-0022, the container implementation is required to detect
1886 -- element tampering by a generic actual subprogram.
1888 declare
1889 E : Element_Type renames N (Position.Node).Element;
1890 K : constant Key_Type := Key (E);
1891 Lock : With_Lock (Container.TC'Unrestricted_Access);
1892 begin
1893 -- Record bucket now, in case key is changed
1894 Indx := HT_Ops.Index (Container.Buckets, N (Position.Node));
1896 Process (E);
1898 if Equivalent_Keys (K, Key (E)) then
1899 return;
1900 end if;
1901 end;
1903 -- Key was modified, so remove this node from set.
1905 if Container.Buckets (Indx) = Position.Node then
1906 Container.Buckets (Indx) := N (Position.Node).Next;
1908 else
1909 declare
1910 Prev : Count_Type := Container.Buckets (Indx);
1912 begin
1913 while N (Prev).Next /= Position.Node loop
1914 Prev := N (Prev).Next;
1916 if Checks and then Prev = 0 then
1917 raise Program_Error with
1918 "Position cursor is bad (node not found)";
1919 end if;
1920 end loop;
1922 N (Prev).Next := N (Position.Node).Next;
1923 end;
1924 end if;
1926 Container.Length := Container.Length - 1;
1927 HT_Ops.Free (Container, Position.Node);
1929 raise Program_Error with "key was modified";
1930 end Update_Element_Preserving_Key;
1932 -----------
1933 -- Write --
1934 -----------
1936 procedure Write
1937 (Stream : not null access Root_Stream_Type'Class;
1938 Item : Reference_Type)
1940 begin
1941 raise Program_Error with "attempt to stream reference";
1942 end Write;
1944 end Generic_Keys;
1946 end Ada.Containers.Bounded_Hashed_Sets;