Daily bump.
[official-gcc.git] / gcc / ada / a-cihase.adb
blob235f6e36806d2ce2b5bb65b934ee46bc23599e3a
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . --
6 -- I N D E F I N I T E _ H A S H E D _ S E T S --
7 -- --
8 -- B o d y --
9 -- --
10 -- Copyright (C) 2004-2007, Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
21 -- Boston, MA 02110-1301, USA. --
22 -- --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
29 -- --
30 -- This unit has originally being developed by Matthew J Heaney. --
31 ------------------------------------------------------------------------------
33 with Ada.Unchecked_Deallocation;
35 with Ada.Containers.Hash_Tables.Generic_Operations;
36 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
38 with Ada.Containers.Hash_Tables.Generic_Keys;
39 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
41 with Ada.Containers.Prime_Numbers;
43 with System; use type System.Address;
45 package body Ada.Containers.Indefinite_Hashed_Sets is
47 -----------------------
48 -- Local Subprograms --
49 -----------------------
51 procedure Assign (Node : Node_Access; Item : Element_Type);
52 pragma Inline (Assign);
54 function Copy_Node (Source : Node_Access) return Node_Access;
55 pragma Inline (Copy_Node);
57 function Equivalent_Keys
58 (Key : Element_Type;
59 Node : Node_Access) return Boolean;
60 pragma Inline (Equivalent_Keys);
62 function Find_Equal_Key
63 (R_HT : Hash_Table_Type;
64 L_Node : Node_Access) return Boolean;
66 function Find_Equivalent_Key
67 (R_HT : Hash_Table_Type;
68 L_Node : Node_Access) return Boolean;
70 procedure Free (X : in out Node_Access);
72 function Hash_Node (Node : Node_Access) return Hash_Type;
73 pragma Inline (Hash_Node);
75 procedure Insert
76 (HT : in out Hash_Table_Type;
77 New_Item : Element_Type;
78 Node : out Node_Access;
79 Inserted : out Boolean);
81 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean;
82 pragma Inline (Is_In);
84 function Next (Node : Node_Access) return Node_Access;
85 pragma Inline (Next);
87 function Read_Node (Stream : not null access Root_Stream_Type'Class)
88 return Node_Access;
89 pragma Inline (Read_Node);
91 procedure Set_Next (Node : Node_Access; Next : Node_Access);
92 pragma Inline (Set_Next);
94 function Vet (Position : Cursor) return Boolean;
96 procedure Write_Node
97 (Stream : not null access Root_Stream_Type'Class;
98 Node : Node_Access);
99 pragma Inline (Write_Node);
101 --------------------------
102 -- Local Instantiations --
103 --------------------------
105 procedure Free_Element is
106 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
108 package HT_Ops is
109 new Hash_Tables.Generic_Operations
110 (HT_Types => HT_Types,
111 Hash_Node => Hash_Node,
112 Next => Next,
113 Set_Next => Set_Next,
114 Copy_Node => Copy_Node,
115 Free => Free);
117 package Element_Keys is
118 new Hash_Tables.Generic_Keys
119 (HT_Types => HT_Types,
120 Next => Next,
121 Set_Next => Set_Next,
122 Key_Type => Element_Type,
123 Hash => Hash,
124 Equivalent_Keys => Equivalent_Keys);
126 function Is_Equal is
127 new HT_Ops.Generic_Equal (Find_Equal_Key);
129 function Is_Equivalent is
130 new HT_Ops.Generic_Equal (Find_Equivalent_Key);
132 procedure Read_Nodes is
133 new HT_Ops.Generic_Read (Read_Node);
135 procedure Replace_Element is
136 new Element_Keys.Generic_Replace_Element (Hash_Node, Assign);
138 procedure Write_Nodes is
139 new HT_Ops.Generic_Write (Write_Node);
141 ---------
142 -- "=" --
143 ---------
145 function "=" (Left, Right : Set) return Boolean is
146 begin
147 return Is_Equal (Left.HT, Right.HT);
148 end "=";
150 ------------
151 -- Adjust --
152 ------------
154 procedure Adjust (Container : in out Set) is
155 begin
156 HT_Ops.Adjust (Container.HT);
157 end Adjust;
159 ------------
160 -- Assign --
161 ------------
163 procedure Assign (Node : Node_Access; Item : Element_Type) is
164 X : Element_Access := Node.Element;
165 begin
166 Node.Element := new Element_Type'(Item);
167 Free_Element (X);
168 end Assign;
170 --------------
171 -- Capacity --
172 --------------
174 function Capacity (Container : Set) return Count_Type is
175 begin
176 return HT_Ops.Capacity (Container.HT);
177 end Capacity;
179 -----------
180 -- Clear --
181 -----------
183 procedure Clear (Container : in out Set) is
184 begin
185 HT_Ops.Clear (Container.HT);
186 end Clear;
188 --------------
189 -- Contains --
190 --------------
192 function Contains (Container : Set; Item : Element_Type) return Boolean is
193 begin
194 return Find (Container, Item) /= No_Element;
195 end Contains;
197 ---------------
198 -- Copy_Node --
199 ---------------
201 function Copy_Node (Source : Node_Access) return Node_Access is
202 E : Element_Access := new Element_Type'(Source.Element.all);
203 begin
204 return new Node_Type'(Element => E, Next => null);
205 exception
206 when others =>
207 Free_Element (E);
208 raise;
209 end Copy_Node;
211 ------------
212 -- Delete --
213 ------------
215 procedure Delete
216 (Container : in out Set;
217 Item : Element_Type)
219 X : Node_Access;
221 begin
222 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
224 if X = null then
225 raise Constraint_Error with "attempt to delete element not in set";
226 end if;
228 Free (X);
229 end Delete;
231 procedure Delete
232 (Container : in out Set;
233 Position : in out Cursor)
235 begin
236 if Position.Node = null then
237 raise Constraint_Error with "Position cursor equals No_Element";
238 end if;
240 if Position.Node.Element = null then
241 raise Program_Error with "Position cursor is bad";
242 end if;
244 if Position.Container /= Container'Unrestricted_Access then
245 raise Program_Error with "Position cursor designates wrong set";
246 end if;
248 if Container.HT.Busy > 0 then
249 raise Program_Error with
250 "attempt to tamper with elements (set is busy)";
251 end if;
253 pragma Assert (Vet (Position), "Position cursor is bad");
255 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
257 Free (Position.Node);
258 Position.Container := null;
259 end Delete;
261 ----------------
262 -- Difference --
263 ----------------
265 procedure Difference
266 (Target : in out Set;
267 Source : Set)
269 Tgt_Node : Node_Access;
271 begin
272 if Target'Address = Source'Address then
273 Clear (Target);
274 return;
275 end if;
277 if Source.HT.Length = 0 then
278 return;
279 end if;
281 if Target.HT.Busy > 0 then
282 raise Program_Error with
283 "attempt to tamper with elements (set is busy)";
284 end if;
286 if Source.HT.Length < Target.HT.Length then
287 declare
288 Src_Node : Node_Access;
290 begin
291 Src_Node := HT_Ops.First (Source.HT);
292 while Src_Node /= null loop
293 Tgt_Node := Element_Keys.Find (Target.HT, Src_Node.Element.all);
295 if Tgt_Node /= null then
296 HT_Ops.Delete_Node_Sans_Free (Target.HT, Tgt_Node);
297 Free (Tgt_Node);
298 end if;
300 Src_Node := HT_Ops.Next (Source.HT, Src_Node);
301 end loop;
302 end;
304 else
305 Tgt_Node := HT_Ops.First (Target.HT);
306 while Tgt_Node /= null loop
307 if Is_In (Source.HT, Tgt_Node) then
308 declare
309 X : Node_Access := Tgt_Node;
310 begin
311 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
312 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
313 Free (X);
314 end;
316 else
317 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
318 end if;
319 end loop;
320 end if;
321 end Difference;
323 function Difference (Left, Right : Set) return Set is
324 Buckets : HT_Types.Buckets_Access;
325 Length : Count_Type;
327 begin
328 if Left'Address = Right'Address then
329 return Empty_Set;
330 end if;
332 if Left.Length = 0 then
333 return Empty_Set;
334 end if;
336 if Right.Length = 0 then
337 return Left;
338 end if;
340 declare
341 Size : constant Hash_Type := Prime_Numbers.To_Prime (Left.Length);
342 begin
343 Buckets := HT_Ops.New_Buckets (Length => Size);
344 end;
346 Length := 0;
348 Iterate_Left : declare
349 procedure Process (L_Node : Node_Access);
351 procedure Iterate is
352 new HT_Ops.Generic_Iteration (Process);
354 -------------
355 -- Process --
356 -------------
358 procedure Process (L_Node : Node_Access) is
359 begin
360 if not Is_In (Right.HT, L_Node) then
361 declare
362 Src : Element_Type renames L_Node.Element.all;
363 Indx : constant Hash_Type := Hash (Src) mod Buckets'Length;
364 Bucket : Node_Access renames Buckets (Indx);
365 Tgt : Element_Access := new Element_Type'(Src);
366 begin
367 Bucket := new Node_Type'(Tgt, Bucket);
368 exception
369 when others =>
370 Free_Element (Tgt);
371 raise;
372 end;
374 Length := Length + 1;
375 end if;
376 end Process;
378 -- Start of processing for Iterate_Left
380 begin
381 Iterate (Left.HT);
382 exception
383 when others =>
384 HT_Ops.Free_Hash_Table (Buckets);
385 raise;
386 end Iterate_Left;
388 return (Controlled with HT => (Buckets, Length, 0, 0));
389 end Difference;
391 -------------
392 -- Element --
393 -------------
395 function Element (Position : Cursor) return Element_Type is
396 begin
397 if Position.Node = null then
398 raise Constraint_Error with "Position cursor of equals No_Element";
399 end if;
401 if Position.Node.Element = null then -- handle dangling reference
402 raise Program_Error with "Position cursor is bad";
403 end if;
405 pragma Assert (Vet (Position), "bad cursor in function Element");
407 return Position.Node.Element.all;
408 end Element;
410 ---------------------
411 -- Equivalent_Sets --
412 ---------------------
414 function Equivalent_Sets (Left, Right : Set) return Boolean is
415 begin
416 return Is_Equivalent (Left.HT, Right.HT);
417 end Equivalent_Sets;
419 -------------------------
420 -- Equivalent_Elements --
421 -------------------------
423 function Equivalent_Elements (Left, Right : Cursor)
424 return Boolean is
425 begin
426 if Left.Node = null then
427 raise Constraint_Error with
428 "Left cursor of Equivalent_Elements equals No_Element";
429 end if;
431 if Right.Node = null then
432 raise Constraint_Error with
433 "Right cursor of Equivalent_Elements equals No_Element";
434 end if;
436 if Left.Node.Element = null then
437 raise Program_Error with
438 "Left cursor of Equivalent_Elements is bad";
439 end if;
441 if Right.Node.Element = null then
442 raise Program_Error with
443 "Right cursor of Equivalent_Elements is bad";
444 end if;
446 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
447 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
449 return Equivalent_Elements
450 (Left.Node.Element.all,
451 Right.Node.Element.all);
452 end Equivalent_Elements;
454 function Equivalent_Elements (Left : Cursor; Right : Element_Type)
455 return Boolean is
456 begin
457 if Left.Node = null then
458 raise Constraint_Error with
459 "Left cursor of Equivalent_Elements equals No_Element";
460 end if;
462 if Left.Node.Element = null then
463 raise Program_Error with
464 "Left cursor of Equivalent_Elements is bad";
465 end if;
467 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Elements");
469 return Equivalent_Elements (Left.Node.Element.all, Right);
470 end Equivalent_Elements;
472 function Equivalent_Elements (Left : Element_Type; Right : Cursor)
473 return Boolean is
474 begin
475 if Right.Node = null then
476 raise Constraint_Error with
477 "Right cursor of Equivalent_Elements equals No_Element";
478 end if;
480 if Right.Node.Element = null then
481 raise Program_Error with
482 "Right cursor of Equivalent_Elements is bad";
483 end if;
485 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Elements");
487 return Equivalent_Elements (Left, Right.Node.Element.all);
488 end Equivalent_Elements;
490 ---------------------
491 -- Equivalent_Keys --
492 ---------------------
494 function Equivalent_Keys (Key : Element_Type; Node : Node_Access)
495 return Boolean is
496 begin
497 return Equivalent_Elements (Key, Node.Element.all);
498 end Equivalent_Keys;
500 -------------
501 -- Exclude --
502 -------------
504 procedure Exclude
505 (Container : in out Set;
506 Item : Element_Type)
508 X : Node_Access;
509 begin
510 Element_Keys.Delete_Key_Sans_Free (Container.HT, Item, X);
511 Free (X);
512 end Exclude;
514 --------------
515 -- Finalize --
516 --------------
518 procedure Finalize (Container : in out Set) is
519 begin
520 HT_Ops.Finalize (Container.HT);
521 end Finalize;
523 ----------
524 -- Find --
525 ----------
527 function Find
528 (Container : Set;
529 Item : Element_Type) return Cursor
531 Node : constant Node_Access := Element_Keys.Find (Container.HT, Item);
533 begin
534 if Node = null then
535 return No_Element;
536 end if;
538 return Cursor'(Container'Unrestricted_Access, Node);
539 end Find;
541 --------------------
542 -- Find_Equal_Key --
543 --------------------
545 function Find_Equal_Key
546 (R_HT : Hash_Table_Type;
547 L_Node : Node_Access) return Boolean
549 R_Index : constant Hash_Type :=
550 Element_Keys.Index (R_HT, L_Node.Element.all);
552 R_Node : Node_Access := R_HT.Buckets (R_Index);
554 begin
555 loop
556 if R_Node = null then
557 return False;
558 end if;
560 if L_Node.Element.all = R_Node.Element.all then
561 return True;
562 end if;
564 R_Node := Next (R_Node);
565 end loop;
566 end Find_Equal_Key;
568 -------------------------
569 -- Find_Equivalent_Key --
570 -------------------------
572 function Find_Equivalent_Key
573 (R_HT : Hash_Table_Type;
574 L_Node : Node_Access) return Boolean
576 R_Index : constant Hash_Type :=
577 Element_Keys.Index (R_HT, L_Node.Element.all);
579 R_Node : Node_Access := R_HT.Buckets (R_Index);
581 begin
582 loop
583 if R_Node = null then
584 return False;
585 end if;
587 if Equivalent_Elements (L_Node.Element.all, R_Node.Element.all) then
588 return True;
589 end if;
591 R_Node := Next (R_Node);
592 end loop;
593 end Find_Equivalent_Key;
595 -----------
596 -- First --
597 -----------
599 function First (Container : Set) return Cursor is
600 Node : constant Node_Access := HT_Ops.First (Container.HT);
602 begin
603 if Node = null then
604 return No_Element;
605 end if;
607 return Cursor'(Container'Unrestricted_Access, Node);
608 end First;
610 ----------
611 -- Free --
612 ----------
614 procedure Free (X : in out Node_Access) is
615 procedure Deallocate is
616 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
618 begin
619 if X = null then
620 return;
621 end if;
623 X.Next := X; -- detect mischief (in Vet)
625 begin
626 Free_Element (X.Element);
627 exception
628 when others =>
629 X.Element := null;
630 Deallocate (X);
631 raise;
632 end;
634 Deallocate (X);
635 end Free;
637 -----------------
638 -- Has_Element --
639 -----------------
641 function Has_Element (Position : Cursor) return Boolean is
642 begin
643 pragma Assert (Vet (Position), "bad cursor in Has_Element");
644 return Position.Node /= null;
645 end Has_Element;
647 ---------------
648 -- Hash_Node --
649 ---------------
651 function Hash_Node (Node : Node_Access) return Hash_Type is
652 begin
653 return Hash (Node.Element.all);
654 end Hash_Node;
656 -------------
657 -- Include --
658 -------------
660 procedure Include
661 (Container : in out Set;
662 New_Item : Element_Type)
664 Position : Cursor;
665 Inserted : Boolean;
667 X : Element_Access;
669 begin
670 Insert (Container, New_Item, Position, Inserted);
672 if not Inserted then
673 if Container.HT.Lock > 0 then
674 raise Program_Error with
675 "attempt to tamper with cursors (set is locked)";
676 end if;
678 X := Position.Node.Element;
680 Position.Node.Element := new Element_Type'(New_Item);
682 Free_Element (X);
683 end if;
684 end Include;
686 ------------
687 -- Insert --
688 ------------
690 procedure Insert
691 (Container : in out Set;
692 New_Item : Element_Type;
693 Position : out Cursor;
694 Inserted : out Boolean)
696 begin
697 Insert (Container.HT, New_Item, Position.Node, Inserted);
698 Position.Container := Container'Unchecked_Access;
699 end Insert;
701 procedure Insert
702 (Container : in out Set;
703 New_Item : Element_Type)
705 Position : Cursor;
706 pragma Unreferenced (Position);
708 Inserted : Boolean;
710 begin
711 Insert (Container, New_Item, Position, Inserted);
713 if not Inserted then
714 raise Constraint_Error with
715 "attempt to insert element already in set";
716 end if;
717 end Insert;
719 procedure Insert
720 (HT : in out Hash_Table_Type;
721 New_Item : Element_Type;
722 Node : out Node_Access;
723 Inserted : out Boolean)
725 function New_Node (Next : Node_Access) return Node_Access;
726 pragma Inline (New_Node);
728 procedure Local_Insert is
729 new Element_Keys.Generic_Conditional_Insert (New_Node);
731 --------------
732 -- New_Node --
733 --------------
735 function New_Node (Next : Node_Access) return Node_Access is
736 Element : Element_Access := new Element_Type'(New_Item);
738 begin
739 return new Node_Type'(Element, Next);
740 exception
741 when others =>
742 Free_Element (Element);
743 raise;
744 end New_Node;
746 -- Start of processing for Insert
748 begin
749 if HT_Ops.Capacity (HT) = 0 then
750 HT_Ops.Reserve_Capacity (HT, 1);
751 end if;
753 Local_Insert (HT, New_Item, Node, Inserted);
755 if Inserted
756 and then HT.Length > HT_Ops.Capacity (HT)
757 then
758 HT_Ops.Reserve_Capacity (HT, HT.Length);
759 end if;
760 end Insert;
762 ------------------
763 -- Intersection --
764 ------------------
766 procedure Intersection
767 (Target : in out Set;
768 Source : Set)
770 Tgt_Node : Node_Access;
772 begin
773 if Target'Address = Source'Address then
774 return;
775 end if;
777 if Source.Length = 0 then
778 Clear (Target);
779 return;
780 end if;
782 if Target.HT.Busy > 0 then
783 raise Program_Error with
784 "attempt to tamper with elements (set is busy)";
785 end if;
787 Tgt_Node := HT_Ops.First (Target.HT);
788 while Tgt_Node /= null loop
789 if Is_In (Source.HT, Tgt_Node) then
790 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
792 else
793 declare
794 X : Node_Access := Tgt_Node;
795 begin
796 Tgt_Node := HT_Ops.Next (Target.HT, Tgt_Node);
797 HT_Ops.Delete_Node_Sans_Free (Target.HT, X);
798 Free (X);
799 end;
800 end if;
801 end loop;
802 end Intersection;
804 function Intersection (Left, Right : Set) return Set is
805 Buckets : HT_Types.Buckets_Access;
806 Length : Count_Type;
808 begin
809 if Left'Address = Right'Address then
810 return Left;
811 end if;
813 Length := Count_Type'Min (Left.Length, Right.Length);
815 if Length = 0 then
816 return Empty_Set;
817 end if;
819 declare
820 Size : constant Hash_Type := Prime_Numbers.To_Prime (Length);
821 begin
822 Buckets := HT_Ops.New_Buckets (Length => Size);
823 end;
825 Length := 0;
827 Iterate_Left : declare
828 procedure Process (L_Node : Node_Access);
830 procedure Iterate is
831 new HT_Ops.Generic_Iteration (Process);
833 -------------
834 -- Process --
835 -------------
837 procedure Process (L_Node : Node_Access) is
838 begin
839 if Is_In (Right.HT, L_Node) then
840 declare
841 Src : Element_Type renames L_Node.Element.all;
843 Indx : constant Hash_Type := Hash (Src) mod Buckets'Length;
845 Bucket : Node_Access renames Buckets (Indx);
847 Tgt : Element_Access := new Element_Type'(Src);
849 begin
850 Bucket := new Node_Type'(Tgt, Bucket);
851 exception
852 when others =>
853 Free_Element (Tgt);
854 raise;
855 end;
857 Length := Length + 1;
858 end if;
859 end Process;
861 -- Start of processing for Iterate_Left
863 begin
864 Iterate (Left.HT);
865 exception
866 when others =>
867 HT_Ops.Free_Hash_Table (Buckets);
868 raise;
869 end Iterate_Left;
871 return (Controlled with HT => (Buckets, Length, 0, 0));
872 end Intersection;
874 --------------
875 -- Is_Empty --
876 --------------
878 function Is_Empty (Container : Set) return Boolean is
879 begin
880 return Container.HT.Length = 0;
881 end Is_Empty;
883 -----------
884 -- Is_In --
885 -----------
887 function Is_In (HT : Hash_Table_Type; Key : Node_Access) return Boolean is
888 begin
889 return Element_Keys.Find (HT, Key.Element.all) /= null;
890 end Is_In;
892 ---------------
893 -- Is_Subset --
894 ---------------
896 function Is_Subset
897 (Subset : Set;
898 Of_Set : Set) return Boolean
900 Subset_Node : Node_Access;
902 begin
903 if Subset'Address = Of_Set'Address then
904 return True;
905 end if;
907 if Subset.Length > Of_Set.Length then
908 return False;
909 end if;
911 Subset_Node := HT_Ops.First (Subset.HT);
912 while Subset_Node /= null loop
913 if not Is_In (Of_Set.HT, Subset_Node) then
914 return False;
915 end if;
917 Subset_Node := HT_Ops.Next (Subset.HT, Subset_Node);
918 end loop;
920 return True;
921 end Is_Subset;
923 -------------
924 -- Iterate --
925 -------------
927 procedure Iterate
928 (Container : Set;
929 Process : not null access procedure (Position : Cursor))
931 procedure Process_Node (Node : Node_Access);
932 pragma Inline (Process_Node);
934 procedure Iterate is
935 new HT_Ops.Generic_Iteration (Process_Node);
937 ------------------
938 -- Process_Node --
939 ------------------
941 procedure Process_Node (Node : Node_Access) is
942 begin
943 Process (Cursor'(Container'Unrestricted_Access, Node));
944 end Process_Node;
946 B : Natural renames Container'Unrestricted_Access.HT.Busy;
948 -- Start of processing for Iterate
950 begin
951 B := B + 1;
953 begin
954 Iterate (Container.HT);
955 exception
956 when others =>
957 B := B - 1;
958 raise;
959 end;
961 B := B - 1;
962 end Iterate;
964 ------------
965 -- Length --
966 ------------
968 function Length (Container : Set) return Count_Type is
969 begin
970 return Container.HT.Length;
971 end Length;
973 ----------
974 -- Move --
975 ----------
977 procedure Move (Target : in out Set; Source : in out Set) is
978 begin
979 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
980 end Move;
982 ----------
983 -- Next --
984 ----------
986 function Next (Node : Node_Access) return Node_Access is
987 begin
988 return Node.Next;
989 end Next;
991 function Next (Position : Cursor) return Cursor is
992 begin
993 if Position.Node = null then
994 return No_Element;
995 end if;
997 if Position.Node.Element = null then
998 raise Program_Error with "bad cursor in Next";
999 end if;
1001 pragma Assert (Vet (Position), "bad cursor in Next");
1003 declare
1004 HT : Hash_Table_Type renames Position.Container.HT;
1005 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
1007 begin
1008 if Node = null then
1009 return No_Element;
1010 end if;
1012 return Cursor'(Position.Container, Node);
1013 end;
1014 end Next;
1016 procedure Next (Position : in out Cursor) is
1017 begin
1018 Position := Next (Position);
1019 end Next;
1021 -------------
1022 -- Overlap --
1023 -------------
1025 function Overlap (Left, Right : Set) return Boolean is
1026 Left_Node : Node_Access;
1028 begin
1029 if Right.Length = 0 then
1030 return False;
1031 end if;
1033 if Left'Address = Right'Address then
1034 return True;
1035 end if;
1037 Left_Node := HT_Ops.First (Left.HT);
1038 while Left_Node /= null loop
1039 if Is_In (Right.HT, Left_Node) then
1040 return True;
1041 end if;
1043 Left_Node := HT_Ops.Next (Left.HT, Left_Node);
1044 end loop;
1046 return False;
1047 end Overlap;
1049 -------------------
1050 -- Query_Element --
1051 -------------------
1053 procedure Query_Element
1054 (Position : Cursor;
1055 Process : not null access procedure (Element : Element_Type))
1057 begin
1058 if Position.Node = null then
1059 raise Constraint_Error with
1060 "Position cursor of Query_Element equals No_Element";
1061 end if;
1063 if Position.Node.Element = null then
1064 raise Program_Error with "bad cursor in Query_Element";
1065 end if;
1067 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1069 declare
1070 HT : Hash_Table_Type renames
1071 Position.Container'Unrestricted_Access.all.HT;
1073 B : Natural renames HT.Busy;
1074 L : Natural renames HT.Lock;
1076 begin
1077 B := B + 1;
1078 L := L + 1;
1080 begin
1081 Process (Position.Node.Element.all);
1082 exception
1083 when others =>
1084 L := L - 1;
1085 B := B - 1;
1086 raise;
1087 end;
1089 L := L - 1;
1090 B := B - 1;
1091 end;
1092 end Query_Element;
1094 ----------
1095 -- Read --
1096 ----------
1098 procedure Read
1099 (Stream : not null access Root_Stream_Type'Class;
1100 Container : out Set)
1102 begin
1103 Read_Nodes (Stream, Container.HT);
1104 end Read;
1106 procedure Read
1107 (Stream : not null access Root_Stream_Type'Class;
1108 Item : out Cursor)
1110 begin
1111 raise Program_Error with "attempt to stream set cursor";
1112 end Read;
1114 ---------------
1115 -- Read_Node --
1116 ---------------
1118 function Read_Node
1119 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1121 X : Element_Access := new Element_Type'(Element_Type'Input (Stream));
1123 begin
1124 return new Node_Type'(X, null);
1125 exception
1126 when others =>
1127 Free_Element (X);
1128 raise;
1129 end Read_Node;
1131 -------------
1132 -- Replace --
1133 -------------
1135 procedure Replace
1136 (Container : in out Set;
1137 New_Item : Element_Type)
1139 Node : constant Node_Access :=
1140 Element_Keys.Find (Container.HT, New_Item);
1142 X : Element_Access;
1143 pragma Warnings (Off, X);
1145 begin
1146 if Node = null then
1147 raise Constraint_Error with
1148 "attempt to replace element not in set";
1149 end if;
1151 if Container.HT.Lock > 0 then
1152 raise Program_Error with
1153 "attempt to tamper with cursors (set is locked)";
1154 end if;
1156 X := Node.Element;
1158 Node.Element := new Element_Type'(New_Item);
1160 Free_Element (X);
1161 end Replace;
1163 ---------------------
1164 -- Replace_Element --
1165 ---------------------
1167 procedure Replace_Element
1168 (Container : in out Set;
1169 Position : Cursor;
1170 New_Item : Element_Type)
1172 begin
1173 if Position.Node = null then
1174 raise Constraint_Error with "Position cursor equals No_Element";
1175 end if;
1177 if Position.Node.Element = null then
1178 raise Program_Error with "bad cursor in Replace_Element";
1179 end if;
1181 if Position.Container /= Container'Unrestricted_Access then
1182 raise Program_Error with
1183 "Position cursor designates wrong set";
1184 end if;
1186 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1188 Replace_Element (Container.HT, Position.Node, New_Item);
1189 end Replace_Element;
1191 ----------------------
1192 -- Reserve_Capacity --
1193 ----------------------
1195 procedure Reserve_Capacity
1196 (Container : in out Set;
1197 Capacity : Count_Type)
1199 begin
1200 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1201 end Reserve_Capacity;
1203 --------------
1204 -- Set_Next --
1205 --------------
1207 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1208 begin
1209 Node.Next := Next;
1210 end Set_Next;
1212 --------------------------
1213 -- Symmetric_Difference --
1214 --------------------------
1216 procedure Symmetric_Difference
1217 (Target : in out Set;
1218 Source : Set)
1220 begin
1221 if Target'Address = Source'Address then
1222 Clear (Target);
1223 return;
1224 end if;
1226 if Target.HT.Busy > 0 then
1227 raise Program_Error with
1228 "attempt to tamper with elements (set is busy)";
1229 end if;
1231 declare
1232 N : constant Count_Type := Target.Length + Source.Length;
1233 begin
1234 if N > HT_Ops.Capacity (Target.HT) then
1235 HT_Ops.Reserve_Capacity (Target.HT, N);
1236 end if;
1237 end;
1239 if Target.Length = 0 then
1240 Iterate_Source_When_Empty_Target : declare
1241 procedure Process (Src_Node : Node_Access);
1243 procedure Iterate is
1244 new HT_Ops.Generic_Iteration (Process);
1246 -------------
1247 -- Process --
1248 -------------
1250 procedure Process (Src_Node : Node_Access) is
1251 E : Element_Type renames Src_Node.Element.all;
1252 B : Buckets_Type renames Target.HT.Buckets.all;
1253 J : constant Hash_Type := Hash (E) mod B'Length;
1254 N : Count_Type renames Target.HT.Length;
1256 begin
1257 declare
1258 X : Element_Access := new Element_Type'(E);
1259 begin
1260 B (J) := new Node_Type'(X, B (J));
1261 exception
1262 when others =>
1263 Free_Element (X);
1264 raise;
1265 end;
1267 N := N + 1;
1268 end Process;
1270 -- Start of processing for Iterate_Source_When_Empty_Target
1272 begin
1273 Iterate (Source.HT);
1274 end Iterate_Source_When_Empty_Target;
1276 else
1277 Iterate_Source : declare
1278 procedure Process (Src_Node : Node_Access);
1280 procedure Iterate is
1281 new HT_Ops.Generic_Iteration (Process);
1283 -------------
1284 -- Process --
1285 -------------
1287 procedure Process (Src_Node : Node_Access) is
1288 E : Element_Type renames Src_Node.Element.all;
1289 B : Buckets_Type renames Target.HT.Buckets.all;
1290 J : constant Hash_Type := Hash (E) mod B'Length;
1291 N : Count_Type renames Target.HT.Length;
1293 begin
1294 if B (J) = null then
1295 declare
1296 X : Element_Access := new Element_Type'(E);
1297 begin
1298 B (J) := new Node_Type'(X, null);
1299 exception
1300 when others =>
1301 Free_Element (X);
1302 raise;
1303 end;
1305 N := N + 1;
1307 elsif Equivalent_Elements (E, B (J).Element.all) then
1308 declare
1309 X : Node_Access := B (J);
1310 begin
1311 B (J) := B (J).Next;
1312 N := N - 1;
1313 Free (X);
1314 end;
1316 else
1317 declare
1318 Prev : Node_Access := B (J);
1319 Curr : Node_Access := Prev.Next;
1321 begin
1322 while Curr /= null loop
1323 if Equivalent_Elements (E, Curr.Element.all) then
1324 Prev.Next := Curr.Next;
1325 N := N - 1;
1326 Free (Curr);
1327 return;
1328 end if;
1330 Prev := Curr;
1331 Curr := Prev.Next;
1332 end loop;
1334 declare
1335 X : Element_Access := new Element_Type'(E);
1336 begin
1337 B (J) := new Node_Type'(X, B (J));
1338 exception
1339 when others =>
1340 Free_Element (X);
1341 raise;
1342 end;
1344 N := N + 1;
1345 end;
1346 end if;
1347 end Process;
1349 -- Start of processing for Iterate_Source
1351 begin
1352 Iterate (Source.HT);
1353 end Iterate_Source;
1354 end if;
1355 end Symmetric_Difference;
1357 function Symmetric_Difference (Left, Right : Set) return Set is
1358 Buckets : HT_Types.Buckets_Access;
1359 Length : Count_Type;
1361 begin
1362 if Left'Address = Right'Address then
1363 return Empty_Set;
1364 end if;
1366 if Right.Length = 0 then
1367 return Left;
1368 end if;
1370 if Left.Length = 0 then
1371 return Right;
1372 end if;
1374 declare
1375 Size : constant Hash_Type :=
1376 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1377 begin
1378 Buckets := HT_Ops.New_Buckets (Length => Size);
1379 end;
1381 Length := 0;
1383 Iterate_Left : declare
1384 procedure Process (L_Node : Node_Access);
1386 procedure Iterate is
1387 new HT_Ops.Generic_Iteration (Process);
1389 -------------
1390 -- Process --
1391 -------------
1393 procedure Process (L_Node : Node_Access) is
1394 begin
1395 if not Is_In (Right.HT, L_Node) then
1396 declare
1397 E : Element_Type renames L_Node.Element.all;
1398 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1400 begin
1401 declare
1402 X : Element_Access := new Element_Type'(E);
1403 begin
1404 Buckets (J) := new Node_Type'(X, Buckets (J));
1405 exception
1406 when others =>
1407 Free_Element (X);
1408 raise;
1409 end;
1411 Length := Length + 1;
1412 end;
1413 end if;
1414 end Process;
1416 -- Start of processing for Iterate_Left
1418 begin
1419 Iterate (Left.HT);
1420 exception
1421 when others =>
1422 HT_Ops.Free_Hash_Table (Buckets);
1423 raise;
1424 end Iterate_Left;
1426 Iterate_Right : declare
1427 procedure Process (R_Node : Node_Access);
1429 procedure Iterate is
1430 new HT_Ops.Generic_Iteration (Process);
1432 -------------
1433 -- Process --
1434 -------------
1436 procedure Process (R_Node : Node_Access) is
1437 begin
1438 if not Is_In (Left.HT, R_Node) then
1439 declare
1440 E : Element_Type renames R_Node.Element.all;
1441 J : constant Hash_Type := Hash (E) mod Buckets'Length;
1443 begin
1444 declare
1445 X : Element_Access := new Element_Type'(E);
1446 begin
1447 Buckets (J) := new Node_Type'(X, Buckets (J));
1448 exception
1449 when others =>
1450 Free_Element (X);
1451 raise;
1452 end;
1454 Length := Length + 1;
1455 end;
1456 end if;
1457 end Process;
1459 -- Start of processing for Iterate_Right
1461 begin
1462 Iterate (Right.HT);
1463 exception
1464 when others =>
1465 HT_Ops.Free_Hash_Table (Buckets);
1466 raise;
1467 end Iterate_Right;
1469 return (Controlled with HT => (Buckets, Length, 0, 0));
1470 end Symmetric_Difference;
1472 ------------
1473 -- To_Set --
1474 ------------
1476 function To_Set (New_Item : Element_Type) return Set is
1477 HT : Hash_Table_Type;
1479 Node : Node_Access;
1480 Inserted : Boolean;
1481 pragma Unreferenced (Node, Inserted);
1483 begin
1484 Insert (HT, New_Item, Node, Inserted);
1485 return Set'(Controlled with HT);
1486 end To_Set;
1488 -----------
1489 -- Union --
1490 -----------
1492 procedure Union
1493 (Target : in out Set;
1494 Source : Set)
1496 procedure Process (Src_Node : Node_Access);
1498 procedure Iterate is
1499 new HT_Ops.Generic_Iteration (Process);
1501 -------------
1502 -- Process --
1503 -------------
1505 procedure Process (Src_Node : Node_Access) is
1506 Src : Element_Type renames Src_Node.Element.all;
1508 function New_Node (Next : Node_Access) return Node_Access;
1509 pragma Inline (New_Node);
1511 procedure Insert is
1512 new Element_Keys.Generic_Conditional_Insert (New_Node);
1514 --------------
1515 -- New_Node --
1516 --------------
1518 function New_Node (Next : Node_Access) return Node_Access is
1519 Tgt : Element_Access := new Element_Type'(Src);
1521 begin
1522 return new Node_Type'(Tgt, Next);
1523 exception
1524 when others =>
1525 Free_Element (Tgt);
1526 raise;
1527 end New_Node;
1529 Tgt_Node : Node_Access;
1530 Success : Boolean;
1531 pragma Unreferenced (Tgt_Node, Success);
1533 -- Start of processing for Process
1535 begin
1536 Insert (Target.HT, Src, Tgt_Node, Success);
1537 end Process;
1539 -- Start of processing for Union
1541 begin
1542 if Target'Address = Source'Address then
1543 return;
1544 end if;
1546 if Target.HT.Busy > 0 then
1547 raise Program_Error with
1548 "attempt to tamper with elements (set is busy)";
1549 end if;
1551 declare
1552 N : constant Count_Type := Target.Length + Source.Length;
1553 begin
1554 if N > HT_Ops.Capacity (Target.HT) then
1555 HT_Ops.Reserve_Capacity (Target.HT, N);
1556 end if;
1557 end;
1559 Iterate (Source.HT);
1560 end Union;
1562 function Union (Left, Right : Set) return Set is
1563 Buckets : HT_Types.Buckets_Access;
1564 Length : Count_Type;
1566 begin
1567 if Left'Address = Right'Address then
1568 return Left;
1569 end if;
1571 if Right.Length = 0 then
1572 return Left;
1573 end if;
1575 if Left.Length = 0 then
1576 return Right;
1577 end if;
1579 declare
1580 Size : constant Hash_Type :=
1581 Prime_Numbers.To_Prime (Left.Length + Right.Length);
1582 begin
1583 Buckets := HT_Ops.New_Buckets (Length => Size);
1584 end;
1586 Iterate_Left : declare
1587 procedure Process (L_Node : Node_Access);
1589 procedure Iterate is
1590 new HT_Ops.Generic_Iteration (Process);
1592 -------------
1593 -- Process --
1594 -------------
1596 procedure Process (L_Node : Node_Access) is
1597 Src : Element_Type renames L_Node.Element.all;
1599 J : constant Hash_Type := Hash (Src) mod Buckets'Length;
1601 Bucket : Node_Access renames Buckets (J);
1603 Tgt : Element_Access := new Element_Type'(Src);
1605 begin
1606 Bucket := new Node_Type'(Tgt, Bucket);
1607 exception
1608 when others =>
1609 Free_Element (Tgt);
1610 raise;
1611 end Process;
1613 -- Start of processing for Process
1615 begin
1616 Iterate (Left.HT);
1617 exception
1618 when others =>
1619 HT_Ops.Free_Hash_Table (Buckets);
1620 raise;
1621 end Iterate_Left;
1623 Length := Left.Length;
1625 Iterate_Right : declare
1626 procedure Process (Src_Node : Node_Access);
1628 procedure Iterate is
1629 new HT_Ops.Generic_Iteration (Process);
1631 -------------
1632 -- Process --
1633 -------------
1635 procedure Process (Src_Node : Node_Access) is
1636 Src : Element_Type renames Src_Node.Element.all;
1637 Idx : constant Hash_Type := Hash (Src) mod Buckets'Length;
1639 Tgt_Node : Node_Access := Buckets (Idx);
1641 begin
1642 while Tgt_Node /= null loop
1643 if Equivalent_Elements (Src, Tgt_Node.Element.all) then
1644 return;
1645 end if;
1646 Tgt_Node := Next (Tgt_Node);
1647 end loop;
1649 declare
1650 Tgt : Element_Access := new Element_Type'(Src);
1651 begin
1652 Buckets (Idx) := new Node_Type'(Tgt, Buckets (Idx));
1653 exception
1654 when others =>
1655 Free_Element (Tgt);
1656 raise;
1657 end;
1659 Length := Length + 1;
1660 end Process;
1662 -- Start of processing for Iterate_Right
1664 begin
1665 Iterate (Right.HT);
1666 exception
1667 when others =>
1668 HT_Ops.Free_Hash_Table (Buckets);
1669 raise;
1670 end Iterate_Right;
1672 return (Controlled with HT => (Buckets, Length, 0, 0));
1673 end Union;
1675 ---------
1676 -- Vet --
1677 ---------
1679 function Vet (Position : Cursor) return Boolean is
1680 begin
1681 if Position.Node = null then
1682 return Position.Container = null;
1683 end if;
1685 if Position.Container = null then
1686 return False;
1687 end if;
1689 if Position.Node.Next = Position.Node then
1690 return False;
1691 end if;
1693 if Position.Node.Element = null then
1694 return False;
1695 end if;
1697 declare
1698 HT : Hash_Table_Type renames Position.Container.HT;
1699 X : Node_Access;
1701 begin
1702 if HT.Length = 0 then
1703 return False;
1704 end if;
1706 if HT.Buckets = null
1707 or else HT.Buckets'Length = 0
1708 then
1709 return False;
1710 end if;
1712 X := HT.Buckets (Element_Keys.Index (HT, Position.Node.Element.all));
1714 for J in 1 .. HT.Length loop
1715 if X = Position.Node then
1716 return True;
1717 end if;
1719 if X = null then
1720 return False;
1721 end if;
1723 if X = X.Next then -- to prevent unnecessary looping
1724 return False;
1725 end if;
1727 X := X.Next;
1728 end loop;
1730 return False;
1731 end;
1732 end Vet;
1734 -----------
1735 -- Write --
1736 -----------
1738 procedure Write
1739 (Stream : not null access Root_Stream_Type'Class;
1740 Container : Set)
1742 begin
1743 Write_Nodes (Stream, Container.HT);
1744 end Write;
1746 procedure Write
1747 (Stream : not null access Root_Stream_Type'Class;
1748 Item : Cursor)
1750 begin
1751 raise Program_Error with "attempt to stream set cursor";
1752 end Write;
1754 ----------------
1755 -- Write_Node --
1756 ----------------
1758 procedure Write_Node
1759 (Stream : not null access Root_Stream_Type'Class;
1760 Node : Node_Access)
1762 begin
1763 Element_Type'Output (Stream, Node.Element.all);
1764 end Write_Node;
1766 package body Generic_Keys is
1768 -----------------------
1769 -- Local Subprograms --
1770 -----------------------
1772 function Equivalent_Key_Node
1773 (Key : Key_Type;
1774 Node : Node_Access) return Boolean;
1775 pragma Inline (Equivalent_Key_Node);
1777 --------------------------
1778 -- Local Instantiations --
1779 --------------------------
1781 package Key_Keys is
1782 new Hash_Tables.Generic_Keys
1783 (HT_Types => HT_Types,
1784 Next => Next,
1785 Set_Next => Set_Next,
1786 Key_Type => Key_Type,
1787 Hash => Hash,
1788 Equivalent_Keys => Equivalent_Key_Node);
1790 --------------
1791 -- Contains --
1792 --------------
1794 function Contains
1795 (Container : Set;
1796 Key : Key_Type) return Boolean
1798 begin
1799 return Find (Container, Key) /= No_Element;
1800 end Contains;
1802 ------------
1803 -- Delete --
1804 ------------
1806 procedure Delete
1807 (Container : in out Set;
1808 Key : Key_Type)
1810 X : Node_Access;
1812 begin
1813 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1815 if X = null then
1816 raise Constraint_Error with "key not in map";
1817 end if;
1819 Free (X);
1820 end Delete;
1822 -------------
1823 -- Element --
1824 -------------
1826 function Element
1827 (Container : Set;
1828 Key : Key_Type) return Element_Type
1830 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1832 begin
1833 if Node = null then
1834 raise Constraint_Error with "key not in map";
1835 end if;
1837 return Node.Element.all;
1838 end Element;
1840 -------------------------
1841 -- Equivalent_Key_Node --
1842 -------------------------
1844 function Equivalent_Key_Node
1845 (Key : Key_Type;
1846 Node : Node_Access) return Boolean is
1847 begin
1848 return Equivalent_Keys (Key, Generic_Keys.Key (Node.Element.all));
1849 end Equivalent_Key_Node;
1851 -------------
1852 -- Exclude --
1853 -------------
1855 procedure Exclude
1856 (Container : in out Set;
1857 Key : Key_Type)
1859 X : Node_Access;
1860 begin
1861 Key_Keys.Delete_Key_Sans_Free (Container.HT, Key, X);
1862 Free (X);
1863 end Exclude;
1865 ----------
1866 -- Find --
1867 ----------
1869 function Find
1870 (Container : Set;
1871 Key : Key_Type) return Cursor
1873 Node : constant Node_Access := Key_Keys.Find (Container.HT, Key);
1875 begin
1876 if Node = null then
1877 return No_Element;
1878 end if;
1880 return Cursor'(Container'Unrestricted_Access, Node);
1881 end Find;
1883 ---------
1884 -- Key --
1885 ---------
1887 function Key (Position : Cursor) return Key_Type is
1888 begin
1889 if Position.Node = null then
1890 raise Constraint_Error with
1891 "Position cursor equals No_Element";
1892 end if;
1894 if Position.Node.Element = null then
1895 raise Program_Error with "Position cursor is bad";
1896 end if;
1898 pragma Assert (Vet (Position), "bad cursor in function Key");
1900 return Key (Position.Node.Element.all);
1901 end Key;
1903 -------------
1904 -- Replace --
1905 -------------
1907 procedure Replace
1908 (Container : in out Set;
1909 Key : Key_Type;
1910 New_Item : Element_Type)
1912 Node : constant Node_Access :=
1913 Key_Keys.Find (Container.HT, Key);
1915 begin
1916 if Node = null then
1917 raise Constraint_Error with
1918 "attempt to replace key not in set";
1919 end if;
1921 Replace_Element (Container.HT, Node, New_Item);
1922 end Replace;
1924 procedure Update_Element_Preserving_Key
1925 (Container : in out Set;
1926 Position : Cursor;
1927 Process : not null access
1928 procedure (Element : in out Element_Type))
1930 HT : Hash_Table_Type renames Container.HT;
1931 Indx : Hash_Type;
1933 begin
1934 if Position.Node = null then
1935 raise Constraint_Error with
1936 "Position cursor equals No_Element";
1937 end if;
1939 if Position.Node.Element = null
1940 or else Position.Node.Next = Position.Node
1941 then
1942 raise Program_Error with "Position cursor is bad";
1943 end if;
1945 if Position.Container /= Container'Unrestricted_Access then
1946 raise Program_Error with
1947 "Position cursor designates wrong set";
1948 end if;
1950 if HT.Buckets = null
1951 or else HT.Buckets'Length = 0
1952 or else HT.Length = 0
1953 then
1954 raise Program_Error with "Position cursor is bad (set is empty)";
1955 end if;
1957 pragma Assert
1958 (Vet (Position),
1959 "bad cursor in Update_Element_Preserving_Key");
1961 Indx := HT_Ops.Index (HT, Position.Node);
1963 declare
1964 E : Element_Type renames Position.Node.Element.all;
1965 K : constant Key_Type := Key (E);
1967 B : Natural renames HT.Busy;
1968 L : Natural renames HT.Lock;
1970 begin
1971 B := B + 1;
1972 L := L + 1;
1974 begin
1975 Process (E);
1976 exception
1977 when others =>
1978 L := L - 1;
1979 B := B - 1;
1980 raise;
1981 end;
1983 L := L - 1;
1984 B := B - 1;
1986 if Equivalent_Keys (K, Key (E)) then
1987 pragma Assert (Hash (K) = Hash (E));
1988 return;
1989 end if;
1990 end;
1992 if HT.Buckets (Indx) = Position.Node then
1993 HT.Buckets (Indx) := Position.Node.Next;
1995 else
1996 declare
1997 Prev : Node_Access := HT.Buckets (Indx);
1999 begin
2000 while Prev.Next /= Position.Node loop
2001 Prev := Prev.Next;
2003 if Prev = null then
2004 raise Program_Error with
2005 "Position cursor is bad (node not found)";
2006 end if;
2007 end loop;
2009 Prev.Next := Position.Node.Next;
2010 end;
2011 end if;
2013 HT.Length := HT.Length - 1;
2015 declare
2016 X : Node_Access := Position.Node;
2018 begin
2019 Free (X);
2020 end;
2022 raise Program_Error with "key was modified";
2023 end Update_Element_Preserving_Key;
2025 end Generic_Keys;
2027 end Ada.Containers.Indefinite_Hashed_Sets;