PR c++/33620
[official-gcc.git] / gcc / ada / a-cihama.adb
blob45dfe984d51114d2142fedc220e33d368b9ba3a6
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 _ M A P 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.Containers.Hash_Tables.Generic_Operations;
34 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
36 with Ada.Containers.Hash_Tables.Generic_Keys;
37 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
39 with Ada.Unchecked_Deallocation;
41 package body Ada.Containers.Indefinite_Hashed_Maps is
43 procedure Free_Key is
44 new Ada.Unchecked_Deallocation (Key_Type, Key_Access);
46 procedure Free_Element is
47 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
49 -----------------------
50 -- Local Subprograms --
51 -----------------------
53 function Copy_Node (Node : Node_Access) return Node_Access;
54 pragma Inline (Copy_Node);
56 function Equivalent_Key_Node
57 (Key : Key_Type;
58 Node : Node_Access) return Boolean;
59 pragma Inline (Equivalent_Key_Node);
61 function Find_Equal_Key
62 (R_HT : Hash_Table_Type;
63 L_Node : Node_Access) return Boolean;
65 procedure Free (X : in out Node_Access);
66 -- pragma Inline (Free);
68 function Hash_Node (Node : Node_Access) return Hash_Type;
69 pragma Inline (Hash_Node);
71 function Next (Node : Node_Access) return Node_Access;
72 pragma Inline (Next);
74 function Read_Node
75 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
77 procedure Set_Next (Node : Node_Access; Next : Node_Access);
78 pragma Inline (Set_Next);
80 function Vet (Position : Cursor) return Boolean;
82 procedure Write_Node
83 (Stream : not null access Root_Stream_Type'Class;
84 Node : Node_Access);
86 --------------------------
87 -- Local Instantiations --
88 --------------------------
90 package HT_Ops is
91 new Ada.Containers.Hash_Tables.Generic_Operations
92 (HT_Types => HT_Types,
93 Hash_Node => Hash_Node,
94 Next => Next,
95 Set_Next => Set_Next,
96 Copy_Node => Copy_Node,
97 Free => Free);
99 package Key_Ops is
100 new Hash_Tables.Generic_Keys
101 (HT_Types => HT_Types,
102 Next => Next,
103 Set_Next => Set_Next,
104 Key_Type => Key_Type,
105 Hash => Hash,
106 Equivalent_Keys => Equivalent_Key_Node);
108 ---------
109 -- "=" --
110 ---------
112 function Is_Equal is new HT_Ops.Generic_Equal (Find_Equal_Key);
114 function "=" (Left, Right : Map) return Boolean is
115 begin
116 return Is_Equal (Left.HT, Right.HT);
117 end "=";
119 ------------
120 -- Adjust --
121 ------------
123 procedure Adjust (Container : in out Map) is
124 begin
125 HT_Ops.Adjust (Container.HT);
126 end Adjust;
128 --------------
129 -- Capacity --
130 --------------
132 function Capacity (Container : Map) return Count_Type is
133 begin
134 return HT_Ops.Capacity (Container.HT);
135 end Capacity;
137 -----------
138 -- Clear --
139 -----------
141 procedure Clear (Container : in out Map) is
142 begin
143 HT_Ops.Clear (Container.HT);
144 end Clear;
146 --------------
147 -- Contains --
148 --------------
150 function Contains (Container : Map; Key : Key_Type) return Boolean is
151 begin
152 return Find (Container, Key) /= No_Element;
153 end Contains;
155 ---------------
156 -- Copy_Node --
157 ---------------
159 function Copy_Node (Node : Node_Access) return Node_Access is
160 K : Key_Access := new Key_Type'(Node.Key.all);
161 E : Element_Access;
163 begin
164 E := new Element_Type'(Node.Element.all);
165 return new Node_Type'(K, E, null);
167 exception
168 when others =>
169 Free_Key (K);
170 Free_Element (E);
171 raise;
172 end Copy_Node;
174 ------------
175 -- Delete --
176 ------------
178 procedure Delete (Container : in out Map; Key : Key_Type) is
179 X : Node_Access;
181 begin
182 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
184 if X = null then
185 raise Constraint_Error with "attempt to delete key not in map";
186 end if;
188 Free (X);
189 end Delete;
191 procedure Delete (Container : in out Map; Position : in out Cursor) is
192 begin
193 if Position.Node = null then
194 raise Constraint_Error with
195 "Position cursor of Delete equals No_Element";
196 end if;
198 if Position.Container /= Container'Unrestricted_Access then
199 raise Program_Error with
200 "Position cursor of Delete designates wrong map";
201 end if;
203 if Container.HT.Busy > 0 then
204 raise Program_Error with
205 "Delete attempted to tamper with elements (map is busy)";
206 end if;
208 pragma Assert (Vet (Position), "bad cursor in Delete");
210 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
212 Free (Position.Node);
213 Position.Container := null;
214 end Delete;
216 -------------
217 -- Element --
218 -------------
220 function Element (Container : Map; Key : Key_Type) return Element_Type is
221 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
223 begin
224 if Node = null then
225 raise Constraint_Error with
226 "no element available because key not in map";
227 end if;
229 return Node.Element.all;
230 end Element;
232 function Element (Position : Cursor) return Element_Type is
233 begin
234 if Position.Node = null then
235 raise Constraint_Error with
236 "Position cursor of function Element equals No_Element";
237 end if;
239 if Position.Node.Element = null then
240 raise Program_Error with
241 "Position cursor of function Element is bad";
242 end if;
244 pragma Assert (Vet (Position), "bad cursor in function Element");
246 return Position.Node.Element.all;
247 end Element;
249 -------------------------
250 -- Equivalent_Key_Node --
251 -------------------------
253 function Equivalent_Key_Node
254 (Key : Key_Type;
255 Node : Node_Access) return Boolean
257 begin
258 return Equivalent_Keys (Key, Node.Key.all);
259 end Equivalent_Key_Node;
261 ---------------------
262 -- Equivalent_Keys --
263 ---------------------
265 function Equivalent_Keys (Left, Right : Cursor) return Boolean is
266 begin
267 if Left.Node = null then
268 raise Constraint_Error with
269 "Left cursor of Equivalent_Keys equals No_Element";
270 end if;
272 if Right.Node = null then
273 raise Constraint_Error with
274 "Right cursor of Equivalent_Keys equals No_Element";
275 end if;
277 if Left.Node.Key = null then
278 raise Program_Error with
279 "Left cursor of Equivalent_Keys is bad";
280 end if;
282 if Right.Node.Key = null then
283 raise Program_Error with
284 "Right cursor of Equivalent_Keys is bad";
285 end if;
287 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
288 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
290 return Equivalent_Keys (Left.Node.Key.all, Right.Node.Key.all);
291 end Equivalent_Keys;
293 function Equivalent_Keys
294 (Left : Cursor;
295 Right : Key_Type) return Boolean
297 begin
298 if Left.Node = null then
299 raise Constraint_Error with
300 "Left cursor of Equivalent_Keys equals No_Element";
301 end if;
303 if Left.Node.Key = null then
304 raise Program_Error with
305 "Left cursor of Equivalent_Keys is bad";
306 end if;
308 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
310 return Equivalent_Keys (Left.Node.Key.all, Right);
311 end Equivalent_Keys;
313 function Equivalent_Keys
314 (Left : Key_Type;
315 Right : Cursor) return Boolean
317 begin
318 if Right.Node = null then
319 raise Constraint_Error with
320 "Right cursor of Equivalent_Keys equals No_Element";
321 end if;
323 if Right.Node.Key = null then
324 raise Program_Error with
325 "Right cursor of Equivalent_Keys is bad";
326 end if;
328 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
330 return Equivalent_Keys (Left, Right.Node.Key.all);
331 end Equivalent_Keys;
333 -------------
334 -- Exclude --
335 -------------
337 procedure Exclude (Container : in out Map; Key : Key_Type) is
338 X : Node_Access;
339 begin
340 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
341 Free (X);
342 end Exclude;
344 --------------
345 -- Finalize --
346 --------------
348 procedure Finalize (Container : in out Map) is
349 begin
350 HT_Ops.Finalize (Container.HT);
351 end Finalize;
353 ----------
354 -- Find --
355 ----------
357 function Find (Container : Map; Key : Key_Type) return Cursor is
358 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
360 begin
361 if Node = null then
362 return No_Element;
363 end if;
365 return Cursor'(Container'Unchecked_Access, Node);
366 end Find;
368 --------------------
369 -- Find_Equal_Key --
370 --------------------
372 function Find_Equal_Key
373 (R_HT : Hash_Table_Type;
374 L_Node : Node_Access) return Boolean
376 R_Index : constant Hash_Type := Key_Ops.Index (R_HT, L_Node.Key.all);
377 R_Node : Node_Access := R_HT.Buckets (R_Index);
379 begin
380 while R_Node /= null loop
381 if Equivalent_Keys (L_Node.Key.all, R_Node.Key.all) then
382 return L_Node.Element.all = R_Node.Element.all;
383 end if;
385 R_Node := R_Node.Next;
386 end loop;
388 return False;
389 end Find_Equal_Key;
391 -----------
392 -- First --
393 -----------
395 function First (Container : Map) return Cursor is
396 Node : constant Node_Access := HT_Ops.First (Container.HT);
398 begin
399 if Node = null then
400 return No_Element;
401 end if;
403 return Cursor'(Container'Unchecked_Access, Node);
404 end First;
406 ----------
407 -- Free --
408 ----------
410 procedure Free (X : in out Node_Access) is
411 procedure Deallocate is
412 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
413 begin
414 if X = null then
415 return;
416 end if;
418 X.Next := X; -- detect mischief (in Vet)
420 begin
421 Free_Key (X.Key);
422 exception
423 when others =>
424 X.Key := null;
426 begin
427 Free_Element (X.Element);
428 exception
429 when others =>
430 X.Element := null;
431 end;
433 Deallocate (X);
434 raise;
435 end;
437 begin
438 Free_Element (X.Element);
439 exception
440 when others =>
441 X.Element := null;
443 Deallocate (X);
444 raise;
445 end;
447 Deallocate (X);
448 end Free;
450 -----------------
451 -- Has_Element --
452 -----------------
454 function Has_Element (Position : Cursor) return Boolean is
455 begin
456 pragma Assert (Vet (Position), "bad cursor in Has_Element");
457 return Position.Node /= null;
458 end Has_Element;
460 ---------------
461 -- Hash_Node --
462 ---------------
464 function Hash_Node (Node : Node_Access) return Hash_Type is
465 begin
466 return Hash (Node.Key.all);
467 end Hash_Node;
469 -------------
470 -- Include --
471 -------------
473 procedure Include
474 (Container : in out Map;
475 Key : Key_Type;
476 New_Item : Element_Type)
478 Position : Cursor;
479 Inserted : Boolean;
481 K : Key_Access;
482 E : Element_Access;
484 begin
485 Insert (Container, Key, New_Item, Position, Inserted);
487 if not Inserted then
488 if Container.HT.Lock > 0 then
489 raise Program_Error with
490 "Include attempted to tamper with cursors (map is locked)";
491 end if;
493 K := Position.Node.Key;
494 E := Position.Node.Element;
496 Position.Node.Key := new Key_Type'(Key);
498 begin
499 Position.Node.Element := new Element_Type'(New_Item);
500 exception
501 when others =>
502 Free_Key (K);
503 raise;
504 end;
506 Free_Key (K);
507 Free_Element (E);
508 end if;
509 end Include;
511 ------------
512 -- Insert --
513 ------------
515 procedure Insert
516 (Container : in out Map;
517 Key : Key_Type;
518 New_Item : Element_Type;
519 Position : out Cursor;
520 Inserted : out Boolean)
522 function New_Node (Next : Node_Access) return Node_Access;
524 procedure Local_Insert is
525 new Key_Ops.Generic_Conditional_Insert (New_Node);
527 --------------
528 -- New_Node --
529 --------------
531 function New_Node (Next : Node_Access) return Node_Access is
532 K : Key_Access := new Key_Type'(Key);
533 E : Element_Access;
535 begin
536 E := new Element_Type'(New_Item);
537 return new Node_Type'(K, E, Next);
538 exception
539 when others =>
540 Free_Key (K);
541 Free_Element (E);
542 raise;
543 end New_Node;
545 HT : Hash_Table_Type renames Container.HT;
547 -- Start of processing for Insert
549 begin
550 if HT_Ops.Capacity (HT) = 0 then
551 HT_Ops.Reserve_Capacity (HT, 1);
552 end if;
554 Local_Insert (HT, Key, Position.Node, Inserted);
556 if Inserted
557 and then HT.Length > HT_Ops.Capacity (HT)
558 then
559 HT_Ops.Reserve_Capacity (HT, HT.Length);
560 end if;
562 Position.Container := Container'Unchecked_Access;
563 end Insert;
565 procedure Insert
566 (Container : in out Map;
567 Key : Key_Type;
568 New_Item : Element_Type)
570 Position : Cursor;
571 pragma Unreferenced (Position);
573 Inserted : Boolean;
575 begin
576 Insert (Container, Key, New_Item, Position, Inserted);
578 if not Inserted then
579 raise Constraint_Error with
580 "attempt to insert key already in map";
581 end if;
582 end Insert;
584 --------------
585 -- Is_Empty --
586 --------------
588 function Is_Empty (Container : Map) return Boolean is
589 begin
590 return Container.HT.Length = 0;
591 end Is_Empty;
593 -------------
594 -- Iterate --
595 -------------
597 procedure Iterate
598 (Container : Map;
599 Process : not null access procedure (Position : Cursor))
601 procedure Process_Node (Node : Node_Access);
602 pragma Inline (Process_Node);
604 procedure Local_Iterate is
605 new HT_Ops.Generic_Iteration (Process_Node);
607 ------------------
608 -- Process_Node --
609 ------------------
611 procedure Process_Node (Node : Node_Access) is
612 begin
613 Process (Cursor'(Container'Unchecked_Access, Node));
614 end Process_Node;
616 B : Natural renames Container'Unrestricted_Access.HT.Busy;
618 -- Start of processing Iterate
620 begin
621 B := B + 1;
623 begin
624 Local_Iterate (Container.HT);
625 exception
626 when others =>
627 B := B - 1;
628 raise;
629 end;
631 B := B - 1;
632 end Iterate;
634 ---------
635 -- Key --
636 ---------
638 function Key (Position : Cursor) return Key_Type is
639 begin
640 if Position.Node = null then
641 raise Constraint_Error with
642 "Position cursor of function Key equals No_Element";
643 end if;
645 if Position.Node.Key = null then
646 raise Program_Error with
647 "Position cursor of function Key is bad";
648 end if;
650 pragma Assert (Vet (Position), "bad cursor in function Key");
652 return Position.Node.Key.all;
653 end Key;
655 ------------
656 -- Length --
657 ------------
659 function Length (Container : Map) return Count_Type is
660 begin
661 return Container.HT.Length;
662 end Length;
664 ----------
665 -- Move --
666 ----------
668 procedure Move
669 (Target : in out Map;
670 Source : in out Map)
672 begin
673 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
674 end Move;
676 ----------
677 -- Next --
678 ----------
680 function Next (Node : Node_Access) return Node_Access is
681 begin
682 return Node.Next;
683 end Next;
685 procedure Next (Position : in out Cursor) is
686 begin
687 Position := Next (Position);
688 end Next;
690 function Next (Position : Cursor) return Cursor is
691 begin
692 if Position.Node = null then
693 return No_Element;
694 end if;
696 if Position.Node.Key = null
697 or else Position.Node.Element = null
698 then
699 raise Program_Error with "Position cursor of Next is bad";
700 end if;
702 pragma Assert (Vet (Position), "Position cursor of Next is bad");
704 declare
705 HT : Hash_Table_Type renames Position.Container.HT;
706 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
708 begin
709 if Node = null then
710 return No_Element;
711 end if;
713 return Cursor'(Position.Container, Node);
714 end;
715 end Next;
717 -------------------
718 -- Query_Element --
719 -------------------
721 procedure Query_Element
722 (Position : Cursor;
723 Process : not null access procedure (Key : Key_Type;
724 Element : Element_Type))
726 begin
727 if Position.Node = null then
728 raise Constraint_Error with
729 "Position cursor of Query_Element equals No_Element";
730 end if;
732 if Position.Node.Key = null
733 or else Position.Node.Element = null
734 then
735 raise Program_Error with
736 "Position cursor of Query_Element is bad";
737 end if;
739 pragma Assert (Vet (Position), "bad cursor in Query_Element");
741 declare
742 M : Map renames Position.Container.all;
743 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
745 B : Natural renames HT.Busy;
746 L : Natural renames HT.Lock;
748 begin
749 B := B + 1;
750 L := L + 1;
752 declare
753 K : Key_Type renames Position.Node.Key.all;
754 E : Element_Type renames Position.Node.Element.all;
756 begin
757 Process (K, E);
758 exception
759 when others =>
760 L := L - 1;
761 B := B - 1;
762 raise;
763 end;
765 L := L - 1;
766 B := B - 1;
767 end;
768 end Query_Element;
770 ----------
771 -- Read --
772 ----------
774 procedure Read_Nodes is new HT_Ops.Generic_Read (Read_Node);
776 procedure Read
777 (Stream : not null access Root_Stream_Type'Class;
778 Container : out Map)
780 begin
781 Read_Nodes (Stream, Container.HT);
782 end Read;
784 procedure Read
785 (Stream : not null access Root_Stream_Type'Class;
786 Item : out Cursor)
788 begin
789 raise Program_Error with "attempt to stream map cursor";
790 end Read;
792 ---------------
793 -- Read_Node --
794 ---------------
796 function Read_Node
797 (Stream : not null access Root_Stream_Type'Class) return Node_Access
799 Node : Node_Access := new Node_Type;
801 begin
802 begin
803 Node.Key := new Key_Type'(Key_Type'Input (Stream));
804 exception
805 when others =>
806 Free (Node);
807 raise;
808 end;
810 begin
811 Node.Element := new Element_Type'(Element_Type'Input (Stream));
812 exception
813 when others =>
814 Free_Key (Node.Key);
815 Free (Node);
816 raise;
817 end;
819 return Node;
820 end Read_Node;
822 -------------
823 -- Replace --
824 -------------
826 procedure Replace
827 (Container : in out Map;
828 Key : Key_Type;
829 New_Item : Element_Type)
831 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
833 K : Key_Access;
834 E : Element_Access;
836 begin
837 if Node = null then
838 raise Constraint_Error with
839 "attempt to replace key not in map";
840 end if;
842 if Container.HT.Lock > 0 then
843 raise Program_Error with
844 "Replace attempted to tamper with cursors (map is locked)";
845 end if;
847 K := Node.Key;
848 E := Node.Element;
850 Node.Key := new Key_Type'(Key);
852 begin
853 Node.Element := new Element_Type'(New_Item);
854 exception
855 when others =>
856 Free_Key (K);
857 raise;
858 end;
860 Free_Key (K);
861 Free_Element (E);
862 end Replace;
864 ---------------------
865 -- Replace_Element --
866 ---------------------
868 procedure Replace_Element
869 (Container : in out Map;
870 Position : Cursor;
871 New_Item : Element_Type)
873 begin
874 if Position.Node = null then
875 raise Constraint_Error with
876 "Position cursor of Replace_Element equals No_Element";
877 end if;
879 if Position.Node.Key = null
880 or else Position.Node.Element = null
881 then
882 raise Program_Error with
883 "Position cursor of Replace_Element is bad";
884 end if;
886 if Position.Container /= Container'Unrestricted_Access then
887 raise Program_Error with
888 "Position cursor of Replace_Element designates wrong map";
889 end if;
891 if Position.Container.HT.Lock > 0 then
892 raise Program_Error with
893 "Replace_Element attempted to tamper with cursors (map is locked)";
894 end if;
896 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
898 declare
899 X : Element_Access := Position.Node.Element;
901 begin
902 Position.Node.Element := new Element_Type'(New_Item);
903 Free_Element (X);
904 end;
905 end Replace_Element;
907 ----------------------
908 -- Reserve_Capacity --
909 ----------------------
911 procedure Reserve_Capacity
912 (Container : in out Map;
913 Capacity : Count_Type)
915 begin
916 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
917 end Reserve_Capacity;
919 --------------
920 -- Set_Next --
921 --------------
923 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
924 begin
925 Node.Next := Next;
926 end Set_Next;
928 --------------------
929 -- Update_Element --
930 --------------------
932 procedure Update_Element
933 (Container : in out Map;
934 Position : Cursor;
935 Process : not null access procedure (Key : Key_Type;
936 Element : in out Element_Type))
938 begin
939 if Position.Node = null then
940 raise Constraint_Error with
941 "Position cursor of Update_Element equals No_Element";
942 end if;
944 if Position.Node.Key = null
945 or else Position.Node.Element = null
946 then
947 raise Program_Error with
948 "Position cursor of Update_Element is bad";
949 end if;
951 if Position.Container /= Container'Unrestricted_Access then
952 raise Program_Error with
953 "Position cursor of Update_Element designates wrong map";
954 end if;
956 pragma Assert (Vet (Position), "bad cursor in Update_Element");
958 declare
959 HT : Hash_Table_Type renames Container.HT;
961 B : Natural renames HT.Busy;
962 L : Natural renames HT.Lock;
964 begin
965 B := B + 1;
966 L := L + 1;
968 declare
969 K : Key_Type renames Position.Node.Key.all;
971 E : Element_Type renames Position.Node.Element.all;
972 pragma Unreferenced (E);
974 begin
975 Process (K, E);
977 exception
978 when others =>
979 L := L - 1;
980 B := B - 1;
981 raise;
982 end;
984 L := L - 1;
985 B := B - 1;
986 end;
987 end Update_Element;
989 ---------
990 -- Vet --
991 ---------
993 function Vet (Position : Cursor) return Boolean is
994 begin
995 if Position.Node = null then
996 return Position.Container = null;
997 end if;
999 if Position.Container = null then
1000 return False;
1001 end if;
1003 if Position.Node.Next = Position.Node then
1004 return False;
1005 end if;
1007 if Position.Node.Key = null then
1008 return False;
1009 end if;
1011 if Position.Node.Element = null then
1012 return False;
1013 end if;
1015 declare
1016 HT : Hash_Table_Type renames Position.Container.HT;
1017 X : Node_Access;
1019 begin
1020 if HT.Length = 0 then
1021 return False;
1022 end if;
1024 if HT.Buckets = null
1025 or else HT.Buckets'Length = 0
1026 then
1027 return False;
1028 end if;
1030 X := HT.Buckets (Key_Ops.Index (HT, Position.Node.Key.all));
1032 for J in 1 .. HT.Length loop
1033 if X = Position.Node then
1034 return True;
1035 end if;
1037 if X = null then
1038 return False;
1039 end if;
1041 if X = X.Next then -- to prevent endless loop
1042 return False;
1043 end if;
1045 X := X.Next;
1046 end loop;
1048 return False;
1049 end;
1050 end Vet;
1052 -----------
1053 -- Write --
1054 -----------
1056 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
1058 procedure Write
1059 (Stream : not null access Root_Stream_Type'Class;
1060 Container : Map)
1062 begin
1063 Write_Nodes (Stream, Container.HT);
1064 end Write;
1066 procedure Write
1067 (Stream : not null access Root_Stream_Type'Class;
1068 Item : Cursor)
1070 begin
1071 raise Program_Error with "attempt to stream map cursor";
1072 end Write;
1074 ----------------
1075 -- Write_Node --
1076 ----------------
1078 procedure Write_Node
1079 (Stream : not null access Root_Stream_Type'Class;
1080 Node : Node_Access)
1082 begin
1083 Key_Type'Output (Stream, Node.Key.all);
1084 Element_Type'Output (Stream, Node.Element.all);
1085 end Write_Node;
1087 end Ada.Containers.Indefinite_Hashed_Maps;