* config/darwin.c (darwin_assemble_visibility): Treat
[official-gcc.git] / gcc / ada / a-cihama.adb
blob2d889cdfb1bc42d0b025d1150d5c55c24b3a881d
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.INDEFINITE_HASHED_MAPS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2012, 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_Operations;
31 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
33 with Ada.Containers.Hash_Tables.Generic_Keys;
34 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
36 with Ada.Unchecked_Deallocation;
38 with System; use type System.Address;
40 package body Ada.Containers.Indefinite_Hashed_Maps is
42 procedure Free_Key is
43 new Ada.Unchecked_Deallocation (Key_Type, Key_Access);
45 procedure Free_Element is
46 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
48 type Iterator is new Limited_Controlled and
49 Map_Iterator_Interfaces.Forward_Iterator with
50 record
51 Container : Map_Access;
52 end record;
54 overriding procedure Finalize (Object : in out Iterator);
56 overriding function First (Object : Iterator) return Cursor;
58 overriding function Next
59 (Object : Iterator;
60 Position : Cursor) return Cursor;
62 -----------------------
63 -- Local Subprograms --
64 -----------------------
66 function Copy_Node (Node : Node_Access) return Node_Access;
67 pragma Inline (Copy_Node);
69 function Equivalent_Key_Node
70 (Key : Key_Type;
71 Node : Node_Access) return Boolean;
72 pragma Inline (Equivalent_Key_Node);
74 function Find_Equal_Key
75 (R_HT : Hash_Table_Type;
76 L_Node : Node_Access) return Boolean;
78 procedure Free (X : in out Node_Access);
79 -- pragma Inline (Free);
81 function Hash_Node (Node : Node_Access) return Hash_Type;
82 pragma Inline (Hash_Node);
84 function Next (Node : Node_Access) return Node_Access;
85 pragma Inline (Next);
87 function Read_Node
88 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
90 procedure Set_Next (Node : Node_Access; Next : Node_Access);
91 pragma Inline (Set_Next);
93 function Vet (Position : Cursor) return Boolean;
95 procedure Write_Node
96 (Stream : not null access Root_Stream_Type'Class;
97 Node : Node_Access);
99 --------------------------
100 -- Local Instantiations --
101 --------------------------
103 package HT_Ops is new Ada.Containers.Hash_Tables.Generic_Operations
104 (HT_Types => HT_Types,
105 Hash_Node => Hash_Node,
106 Next => Next,
107 Set_Next => Set_Next,
108 Copy_Node => Copy_Node,
109 Free => Free);
111 package Key_Ops is new Hash_Tables.Generic_Keys
112 (HT_Types => HT_Types,
113 Next => Next,
114 Set_Next => Set_Next,
115 Key_Type => Key_Type,
116 Hash => Hash,
117 Equivalent_Keys => Equivalent_Key_Node);
119 ---------
120 -- "=" --
121 ---------
123 function Is_Equal is new HT_Ops.Generic_Equal (Find_Equal_Key);
125 overriding function "=" (Left, Right : Map) return Boolean is
126 begin
127 return Is_Equal (Left.HT, Right.HT);
128 end "=";
130 ------------
131 -- Adjust --
132 ------------
134 procedure Adjust (Container : in out Map) is
135 begin
136 HT_Ops.Adjust (Container.HT);
137 end Adjust;
139 procedure Adjust (Control : in out Reference_Control_Type) is
140 begin
141 if Control.Container /= null then
142 declare
143 M : Map renames Control.Container.all;
144 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
145 B : Natural renames HT.Busy;
146 L : Natural renames HT.Lock;
147 begin
148 B := B + 1;
149 L := L + 1;
150 end;
151 end if;
152 end Adjust;
154 ------------
155 -- Assign --
156 ------------
158 procedure Assign (Target : in out Map; Source : Map) is
159 procedure Insert_Item (Node : Node_Access);
160 pragma Inline (Insert_Item);
162 procedure Insert_Items is new HT_Ops.Generic_Iteration (Insert_Item);
164 -----------------
165 -- Insert_Item --
166 -----------------
168 procedure Insert_Item (Node : Node_Access) is
169 begin
170 Target.Insert (Key => Node.Key.all, New_Item => Node.Element.all);
171 end Insert_Item;
173 -- Start of processing for Assign
175 begin
176 if Target'Address = Source'Address then
177 return;
178 end if;
180 Target.Clear;
182 if Target.Capacity < Source.Length then
183 Target.Reserve_Capacity (Source.Length);
184 end if;
186 Insert_Items (Target.HT);
187 end Assign;
189 --------------
190 -- Capacity --
191 --------------
193 function Capacity (Container : Map) return Count_Type is
194 begin
195 return HT_Ops.Capacity (Container.HT);
196 end Capacity;
198 -----------
199 -- Clear --
200 -----------
202 procedure Clear (Container : in out Map) is
203 begin
204 HT_Ops.Clear (Container.HT);
205 end Clear;
207 ------------------------
208 -- Constant_Reference --
209 ------------------------
211 function Constant_Reference
212 (Container : aliased Map;
213 Position : Cursor) return Constant_Reference_Type
215 begin
216 if Position.Container = null then
217 raise Constraint_Error with
218 "Position cursor has no element";
219 end if;
221 if Position.Container /= Container'Unrestricted_Access then
222 raise Program_Error with
223 "Position cursor designates wrong map";
224 end if;
226 if Position.Node.Element = null then
227 raise Program_Error with
228 "Position cursor has no element";
229 end if;
231 pragma Assert
232 (Vet (Position),
233 "Position cursor in Constant_Reference is bad");
235 declare
236 M : Map renames Position.Container.all;
237 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
238 B : Natural renames HT.Busy;
239 L : Natural renames HT.Lock;
240 begin
241 return R : constant Constant_Reference_Type :=
242 (Element => Position.Node.Element.all'Access,
243 Control => (Controlled with Container'Unrestricted_Access))
245 B := B + 1;
246 L := L + 1;
247 end return;
248 end;
249 end Constant_Reference;
251 function Constant_Reference
252 (Container : aliased Map;
253 Key : Key_Type) return Constant_Reference_Type
255 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
257 begin
258 if Node = null then
259 raise Constraint_Error with "key not in map";
260 end if;
262 if Node.Element = null then
263 raise Program_Error with "key has no element";
264 end if;
266 declare
267 M : Map renames Container'Unrestricted_Access.all;
268 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
269 B : Natural renames HT.Busy;
270 L : Natural renames HT.Lock;
271 begin
272 return R : constant Constant_Reference_Type :=
273 (Element => Node.Element.all'Access,
274 Control => (Controlled with Container'Unrestricted_Access))
276 B := B + 1;
277 L := L + 1;
278 end return;
279 end;
280 end Constant_Reference;
282 --------------
283 -- Contains --
284 --------------
286 function Contains (Container : Map; Key : Key_Type) return Boolean is
287 begin
288 return Find (Container, Key) /= No_Element;
289 end Contains;
291 ----------
292 -- Copy --
293 ----------
295 function Copy
296 (Source : Map;
297 Capacity : Count_Type := 0) return Map
299 C : Count_Type;
301 begin
302 if Capacity = 0 then
303 C := Source.Length;
305 elsif Capacity >= Source.Length then
306 C := Capacity;
308 else
309 raise Capacity_Error
310 with "Requested capacity is less than Source length";
311 end if;
313 return Target : Map do
314 Target.Reserve_Capacity (C);
315 Target.Assign (Source);
316 end return;
317 end Copy;
319 ---------------
320 -- Copy_Node --
321 ---------------
323 function Copy_Node (Node : Node_Access) return Node_Access is
324 K : Key_Access := new Key_Type'(Node.Key.all);
325 E : Element_Access;
327 begin
328 E := new Element_Type'(Node.Element.all);
329 return new Node_Type'(K, E, null);
331 exception
332 when others =>
333 Free_Key (K);
334 Free_Element (E);
335 raise;
336 end Copy_Node;
338 ------------
339 -- Delete --
340 ------------
342 procedure Delete (Container : in out Map; Key : Key_Type) is
343 X : Node_Access;
345 begin
346 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
348 if X = null then
349 raise Constraint_Error with "attempt to delete key not in map";
350 end if;
352 Free (X);
353 end Delete;
355 procedure Delete (Container : in out Map; Position : in out Cursor) is
356 begin
357 if Position.Node = null then
358 raise Constraint_Error with
359 "Position cursor of Delete equals No_Element";
360 end if;
362 if Position.Container /= Container'Unrestricted_Access then
363 raise Program_Error with
364 "Position cursor of Delete designates wrong map";
365 end if;
367 if Container.HT.Busy > 0 then
368 raise Program_Error with
369 "Delete attempted to tamper with cursors (map is busy)";
370 end if;
372 pragma Assert (Vet (Position), "bad cursor in Delete");
374 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
376 Free (Position.Node);
377 Position.Container := null;
378 end Delete;
380 -------------
381 -- Element --
382 -------------
384 function Element (Container : Map; Key : Key_Type) return Element_Type is
385 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
387 begin
388 if Node = null then
389 raise Constraint_Error with
390 "no element available because key not in map";
391 end if;
393 return Node.Element.all;
394 end Element;
396 function Element (Position : Cursor) return Element_Type is
397 begin
398 if Position.Node = null then
399 raise Constraint_Error with
400 "Position cursor of function Element equals No_Element";
401 end if;
403 if Position.Node.Element = null then
404 raise Program_Error with
405 "Position cursor of function Element is bad";
406 end if;
408 pragma Assert (Vet (Position), "bad cursor in function Element");
410 return Position.Node.Element.all;
411 end Element;
413 -------------------------
414 -- Equivalent_Key_Node --
415 -------------------------
417 function Equivalent_Key_Node
418 (Key : Key_Type;
419 Node : Node_Access) return Boolean
421 begin
422 return Equivalent_Keys (Key, Node.Key.all);
423 end Equivalent_Key_Node;
425 ---------------------
426 -- Equivalent_Keys --
427 ---------------------
429 function Equivalent_Keys (Left, Right : Cursor) return Boolean is
430 begin
431 if Left.Node = null then
432 raise Constraint_Error with
433 "Left cursor of Equivalent_Keys equals No_Element";
434 end if;
436 if Right.Node = null then
437 raise Constraint_Error with
438 "Right cursor of Equivalent_Keys equals No_Element";
439 end if;
441 if Left.Node.Key = null then
442 raise Program_Error with
443 "Left cursor of Equivalent_Keys is bad";
444 end if;
446 if Right.Node.Key = null then
447 raise Program_Error with
448 "Right cursor of Equivalent_Keys is bad";
449 end if;
451 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
452 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
454 return Equivalent_Keys (Left.Node.Key.all, Right.Node.Key.all);
455 end Equivalent_Keys;
457 function Equivalent_Keys
458 (Left : Cursor;
459 Right : Key_Type) return Boolean
461 begin
462 if Left.Node = null then
463 raise Constraint_Error with
464 "Left cursor of Equivalent_Keys equals No_Element";
465 end if;
467 if Left.Node.Key = null then
468 raise Program_Error with
469 "Left cursor of Equivalent_Keys is bad";
470 end if;
472 pragma Assert (Vet (Left), "bad Left cursor in Equivalent_Keys");
474 return Equivalent_Keys (Left.Node.Key.all, Right);
475 end Equivalent_Keys;
477 function Equivalent_Keys
478 (Left : Key_Type;
479 Right : Cursor) return Boolean
481 begin
482 if Right.Node = null then
483 raise Constraint_Error with
484 "Right cursor of Equivalent_Keys equals No_Element";
485 end if;
487 if Right.Node.Key = null then
488 raise Program_Error with
489 "Right cursor of Equivalent_Keys is bad";
490 end if;
492 pragma Assert (Vet (Right), "bad Right cursor in Equivalent_Keys");
494 return Equivalent_Keys (Left, Right.Node.Key.all);
495 end Equivalent_Keys;
497 -------------
498 -- Exclude --
499 -------------
501 procedure Exclude (Container : in out Map; Key : Key_Type) is
502 X : Node_Access;
503 begin
504 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
505 Free (X);
506 end Exclude;
508 --------------
509 -- Finalize --
510 --------------
512 procedure Finalize (Container : in out Map) is
513 begin
514 HT_Ops.Finalize (Container.HT);
515 end Finalize;
517 procedure Finalize (Object : in out Iterator) is
518 begin
519 if Object.Container /= null then
520 declare
521 B : Natural renames Object.Container.all.HT.Busy;
522 begin
523 B := B - 1;
524 end;
525 end if;
526 end Finalize;
528 procedure Finalize (Control : in out Reference_Control_Type) is
529 begin
530 if Control.Container /= null then
531 declare
532 M : Map renames Control.Container.all;
533 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
534 B : Natural renames HT.Busy;
535 L : Natural renames HT.Lock;
536 begin
537 B := B - 1;
538 L := L - 1;
539 end;
541 Control.Container := null;
542 end if;
543 end Finalize;
545 ----------
546 -- Find --
547 ----------
549 function Find (Container : Map; Key : Key_Type) return Cursor is
550 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
552 begin
553 if Node = null then
554 return No_Element;
555 end if;
557 return Cursor'(Container'Unrestricted_Access, Node);
558 end Find;
560 --------------------
561 -- Find_Equal_Key --
562 --------------------
564 function Find_Equal_Key
565 (R_HT : Hash_Table_Type;
566 L_Node : Node_Access) return Boolean
568 R_Index : constant Hash_Type := Key_Ops.Index (R_HT, L_Node.Key.all);
569 R_Node : Node_Access := R_HT.Buckets (R_Index);
571 begin
572 while R_Node /= null loop
573 if Equivalent_Keys (L_Node.Key.all, R_Node.Key.all) then
574 return L_Node.Element.all = R_Node.Element.all;
575 end if;
577 R_Node := R_Node.Next;
578 end loop;
580 return False;
581 end Find_Equal_Key;
583 -----------
584 -- First --
585 -----------
587 function First (Container : Map) return Cursor is
588 Node : constant Node_Access := HT_Ops.First (Container.HT);
589 begin
590 if Node = null then
591 return No_Element;
592 else
593 return Cursor'(Container'Unrestricted_Access, Node);
594 end if;
595 end First;
597 function First (Object : Iterator) return Cursor is
598 begin
599 return Object.Container.First;
600 end First;
602 ----------
603 -- Free --
604 ----------
606 procedure Free (X : in out Node_Access) is
607 procedure Deallocate is
608 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
610 begin
611 if X = null then
612 return;
613 end if;
615 X.Next := X; -- detect mischief (in Vet)
617 begin
618 Free_Key (X.Key);
619 exception
620 when others =>
621 X.Key := null;
623 begin
624 Free_Element (X.Element);
625 exception
626 when others =>
627 X.Element := null;
628 end;
630 Deallocate (X);
631 raise;
632 end;
634 begin
635 Free_Element (X.Element);
636 exception
637 when others =>
638 X.Element := null;
640 Deallocate (X);
641 raise;
642 end;
644 Deallocate (X);
645 end Free;
647 -----------------
648 -- Has_Element --
649 -----------------
651 function Has_Element (Position : Cursor) return Boolean is
652 begin
653 pragma Assert (Vet (Position), "bad cursor in Has_Element");
654 return Position.Node /= null;
655 end Has_Element;
657 ---------------
658 -- Hash_Node --
659 ---------------
661 function Hash_Node (Node : Node_Access) return Hash_Type is
662 begin
663 return Hash (Node.Key.all);
664 end Hash_Node;
666 -------------
667 -- Include --
668 -------------
670 procedure Include
671 (Container : in out Map;
672 Key : Key_Type;
673 New_Item : Element_Type)
675 Position : Cursor;
676 Inserted : Boolean;
678 K : Key_Access;
679 E : Element_Access;
681 begin
682 Insert (Container, Key, New_Item, Position, Inserted);
684 if not Inserted then
685 if Container.HT.Lock > 0 then
686 raise Program_Error with
687 "Include attempted to tamper with elements (map is locked)";
688 end if;
690 K := Position.Node.Key;
691 E := Position.Node.Element;
693 Position.Node.Key := new Key_Type'(Key);
695 declare
696 -- The element allocator may need an accessibility check in the
697 -- case the actual type is class-wide or has access discriminants
698 -- (see RM 4.8(10.1) and AI12-0035).
700 pragma Unsuppress (Accessibility_Check);
702 begin
703 Position.Node.Element := new Element_Type'(New_Item);
705 exception
706 when others =>
707 Free_Key (K);
708 raise;
709 end;
711 Free_Key (K);
712 Free_Element (E);
713 end if;
714 end Include;
716 ------------
717 -- Insert --
718 ------------
720 procedure Insert
721 (Container : in out Map;
722 Key : Key_Type;
723 New_Item : Element_Type;
724 Position : out Cursor;
725 Inserted : out Boolean)
727 function New_Node (Next : Node_Access) return Node_Access;
729 procedure Local_Insert is
730 new Key_Ops.Generic_Conditional_Insert (New_Node);
732 --------------
733 -- New_Node --
734 --------------
736 function New_Node (Next : Node_Access) return Node_Access is
737 K : Key_Access := new Key_Type'(Key);
738 E : Element_Access;
740 -- The element allocator may need an accessibility check in the case
741 -- the actual type is class-wide or has access discriminants (see
742 -- RM 4.8(10.1) and AI12-0035).
744 pragma Unsuppress (Accessibility_Check);
746 begin
747 E := new Element_Type'(New_Item);
748 return new Node_Type'(K, E, Next);
750 exception
751 when others =>
752 Free_Key (K);
753 Free_Element (E);
754 raise;
755 end New_Node;
757 HT : Hash_Table_Type renames Container.HT;
759 -- Start of processing for Insert
761 begin
762 if HT_Ops.Capacity (HT) = 0 then
763 HT_Ops.Reserve_Capacity (HT, 1);
764 end if;
766 Local_Insert (HT, Key, Position.Node, Inserted);
768 if Inserted
769 and then HT.Length > HT_Ops.Capacity (HT)
770 then
771 HT_Ops.Reserve_Capacity (HT, HT.Length);
772 end if;
774 Position.Container := Container'Unchecked_Access;
775 end Insert;
777 procedure Insert
778 (Container : in out Map;
779 Key : Key_Type;
780 New_Item : Element_Type)
782 Position : Cursor;
783 pragma Unreferenced (Position);
785 Inserted : Boolean;
787 begin
788 Insert (Container, Key, New_Item, Position, Inserted);
790 if not Inserted then
791 raise Constraint_Error with
792 "attempt to insert key already in map";
793 end if;
794 end Insert;
796 --------------
797 -- Is_Empty --
798 --------------
800 function Is_Empty (Container : Map) return Boolean is
801 begin
802 return Container.HT.Length = 0;
803 end Is_Empty;
805 -------------
806 -- Iterate --
807 -------------
809 procedure Iterate
810 (Container : Map;
811 Process : not null access procedure (Position : Cursor))
813 procedure Process_Node (Node : Node_Access);
814 pragma Inline (Process_Node);
816 procedure Local_Iterate is
817 new HT_Ops.Generic_Iteration (Process_Node);
819 ------------------
820 -- Process_Node --
821 ------------------
823 procedure Process_Node (Node : Node_Access) is
824 begin
825 Process (Cursor'(Container'Unrestricted_Access, Node));
826 end Process_Node;
828 B : Natural renames Container'Unrestricted_Access.all.HT.Busy;
830 -- Start of processing Iterate
832 begin
833 B := B + 1;
835 begin
836 Local_Iterate (Container.HT);
837 exception
838 when others =>
839 B := B - 1;
840 raise;
841 end;
843 B := B - 1;
844 end Iterate;
846 function Iterate
847 (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class
849 B : Natural renames Container'Unrestricted_Access.all.HT.Busy;
850 begin
851 return It : constant Iterator :=
852 (Limited_Controlled with Container => Container'Unrestricted_Access)
854 B := B + 1;
855 end return;
856 end Iterate;
858 ---------
859 -- Key --
860 ---------
862 function Key (Position : Cursor) return Key_Type is
863 begin
864 if Position.Node = null then
865 raise Constraint_Error with
866 "Position cursor of function Key equals No_Element";
867 end if;
869 if Position.Node.Key = null then
870 raise Program_Error with
871 "Position cursor of function Key is bad";
872 end if;
874 pragma Assert (Vet (Position), "bad cursor in function Key");
876 return Position.Node.Key.all;
877 end Key;
879 ------------
880 -- Length --
881 ------------
883 function Length (Container : Map) return Count_Type is
884 begin
885 return Container.HT.Length;
886 end Length;
888 ----------
889 -- Move --
890 ----------
892 procedure Move
893 (Target : in out Map;
894 Source : in out Map)
896 begin
897 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
898 end Move;
900 ----------
901 -- Next --
902 ----------
904 function Next (Node : Node_Access) return Node_Access is
905 begin
906 return Node.Next;
907 end Next;
909 procedure Next (Position : in out Cursor) is
910 begin
911 Position := Next (Position);
912 end Next;
914 function Next (Position : Cursor) return Cursor is
915 begin
916 if Position.Node = null then
917 return No_Element;
918 end if;
920 if Position.Node.Key = null
921 or else Position.Node.Element = null
922 then
923 raise Program_Error with "Position cursor of Next is bad";
924 end if;
926 pragma Assert (Vet (Position), "Position cursor of Next is bad");
928 declare
929 HT : Hash_Table_Type renames Position.Container.HT;
930 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
931 begin
932 if Node = null then
933 return No_Element;
934 else
935 return Cursor'(Position.Container, Node);
936 end if;
937 end;
938 end Next;
940 function Next (Object : Iterator; Position : Cursor) return Cursor is
941 begin
942 if Position.Container = null then
943 return No_Element;
944 end if;
946 if Position.Container /= Object.Container then
947 raise Program_Error with
948 "Position cursor of Next designates wrong map";
949 end if;
951 return Next (Position);
952 end Next;
954 -------------------
955 -- Query_Element --
956 -------------------
958 procedure Query_Element
959 (Position : Cursor;
960 Process : not null access procedure (Key : Key_Type;
961 Element : Element_Type))
963 begin
964 if Position.Node = null then
965 raise Constraint_Error with
966 "Position cursor of Query_Element equals No_Element";
967 end if;
969 if Position.Node.Key = null
970 or else Position.Node.Element = null
971 then
972 raise Program_Error with
973 "Position cursor of Query_Element is bad";
974 end if;
976 pragma Assert (Vet (Position), "bad cursor in Query_Element");
978 declare
979 M : Map renames Position.Container.all;
980 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
982 B : Natural renames HT.Busy;
983 L : Natural renames HT.Lock;
985 begin
986 B := B + 1;
987 L := L + 1;
989 declare
990 K : Key_Type renames Position.Node.Key.all;
991 E : Element_Type renames Position.Node.Element.all;
993 begin
994 Process (K, E);
995 exception
996 when others =>
997 L := L - 1;
998 B := B - 1;
999 raise;
1000 end;
1002 L := L - 1;
1003 B := B - 1;
1004 end;
1005 end Query_Element;
1007 ----------
1008 -- Read --
1009 ----------
1011 procedure Read_Nodes is new HT_Ops.Generic_Read (Read_Node);
1013 procedure Read
1014 (Stream : not null access Root_Stream_Type'Class;
1015 Container : out Map)
1017 begin
1018 Read_Nodes (Stream, Container.HT);
1019 end Read;
1021 procedure Read
1022 (Stream : not null access Root_Stream_Type'Class;
1023 Item : out Cursor)
1025 begin
1026 raise Program_Error with "attempt to stream map cursor";
1027 end Read;
1029 procedure Read
1030 (Stream : not null access Root_Stream_Type'Class;
1031 Item : out Reference_Type)
1033 begin
1034 raise Program_Error with "attempt to stream reference";
1035 end Read;
1037 procedure Read
1038 (Stream : not null access Root_Stream_Type'Class;
1039 Item : out Constant_Reference_Type)
1041 begin
1042 raise Program_Error with "attempt to stream reference";
1043 end Read;
1045 ---------------
1046 -- Read_Node --
1047 ---------------
1049 function Read_Node
1050 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1052 Node : Node_Access := new Node_Type;
1054 begin
1055 begin
1056 Node.Key := new Key_Type'(Key_Type'Input (Stream));
1057 exception
1058 when others =>
1059 Free (Node);
1060 raise;
1061 end;
1063 begin
1064 Node.Element := new Element_Type'(Element_Type'Input (Stream));
1065 exception
1066 when others =>
1067 Free_Key (Node.Key);
1068 Free (Node);
1069 raise;
1070 end;
1072 return Node;
1073 end Read_Node;
1075 ---------------
1076 -- Reference --
1077 ---------------
1079 function Reference
1080 (Container : aliased in out Map;
1081 Position : Cursor) return Reference_Type
1083 begin
1084 if Position.Container = null then
1085 raise Constraint_Error with
1086 "Position cursor has no element";
1087 end if;
1089 if Position.Container /= Container'Unrestricted_Access then
1090 raise Program_Error with
1091 "Position cursor designates wrong map";
1092 end if;
1094 if Position.Node.Element = null then
1095 raise Program_Error with
1096 "Position cursor has no element";
1097 end if;
1099 pragma Assert
1100 (Vet (Position),
1101 "Position cursor in function Reference is bad");
1103 declare
1104 M : Map renames Position.Container.all;
1105 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
1106 B : Natural renames HT.Busy;
1107 L : Natural renames HT.Lock;
1108 begin
1109 return R : constant Reference_Type :=
1110 (Element => Position.Node.Element.all'Access,
1111 Control => (Controlled with Position.Container))
1113 B := B + 1;
1114 L := L + 1;
1115 end return;
1116 end;
1117 end Reference;
1119 function Reference
1120 (Container : aliased in out Map;
1121 Key : Key_Type) return Reference_Type
1123 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
1125 begin
1126 if Node = null then
1127 raise Constraint_Error with "key not in map";
1128 end if;
1130 if Node.Element = null then
1131 raise Program_Error with "key has no element";
1132 end if;
1134 declare
1135 M : Map renames Container'Unrestricted_Access.all;
1136 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
1137 B : Natural renames HT.Busy;
1138 L : Natural renames HT.Lock;
1139 begin
1140 return R : constant Reference_Type :=
1141 (Element => Node.Element.all'Access,
1142 Control => (Controlled with Container'Unrestricted_Access))
1144 B := B + 1;
1145 L := L + 1;
1146 end return;
1147 end;
1148 end Reference;
1150 -------------
1151 -- Replace --
1152 -------------
1154 procedure Replace
1155 (Container : in out Map;
1156 Key : Key_Type;
1157 New_Item : Element_Type)
1159 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
1161 K : Key_Access;
1162 E : Element_Access;
1164 begin
1165 if Node = null then
1166 raise Constraint_Error with
1167 "attempt to replace key not in map";
1168 end if;
1170 if Container.HT.Lock > 0 then
1171 raise Program_Error with
1172 "Replace attempted to tamper with elements (map is locked)";
1173 end if;
1175 K := Node.Key;
1176 E := Node.Element;
1178 Node.Key := new Key_Type'(Key);
1180 declare
1181 -- The element allocator may need an accessibility check in the case
1182 -- the actual type is class-wide or has access discriminants (see
1183 -- RM 4.8(10.1) and AI12-0035).
1185 pragma Unsuppress (Accessibility_Check);
1187 begin
1188 Node.Element := new Element_Type'(New_Item);
1190 exception
1191 when others =>
1192 Free_Key (K);
1193 raise;
1194 end;
1196 Free_Key (K);
1197 Free_Element (E);
1198 end Replace;
1200 ---------------------
1201 -- Replace_Element --
1202 ---------------------
1204 procedure Replace_Element
1205 (Container : in out Map;
1206 Position : Cursor;
1207 New_Item : Element_Type)
1209 begin
1210 if Position.Node = null then
1211 raise Constraint_Error with
1212 "Position cursor of Replace_Element equals No_Element";
1213 end if;
1215 if Position.Node.Key = null
1216 or else Position.Node.Element = null
1217 then
1218 raise Program_Error with
1219 "Position cursor of Replace_Element is bad";
1220 end if;
1222 if Position.Container /= Container'Unrestricted_Access then
1223 raise Program_Error with
1224 "Position cursor of Replace_Element designates wrong map";
1225 end if;
1227 if Position.Container.HT.Lock > 0 then
1228 raise Program_Error with
1229 "Replace_Element attempted to tamper with elements (map is locked)";
1230 end if;
1232 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1234 declare
1235 X : Element_Access := Position.Node.Element;
1237 -- The element allocator may need an accessibility check in the case
1238 -- the actual type is class-wide or has access discriminants (see
1239 -- RM 4.8(10.1) and AI12-0035).
1241 pragma Unsuppress (Accessibility_Check);
1243 begin
1244 Position.Node.Element := new Element_Type'(New_Item);
1245 Free_Element (X);
1246 end;
1247 end Replace_Element;
1249 ----------------------
1250 -- Reserve_Capacity --
1251 ----------------------
1253 procedure Reserve_Capacity
1254 (Container : in out Map;
1255 Capacity : Count_Type)
1257 begin
1258 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1259 end Reserve_Capacity;
1261 --------------
1262 -- Set_Next --
1263 --------------
1265 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1266 begin
1267 Node.Next := Next;
1268 end Set_Next;
1270 --------------------
1271 -- Update_Element --
1272 --------------------
1274 procedure Update_Element
1275 (Container : in out Map;
1276 Position : Cursor;
1277 Process : not null access procedure (Key : Key_Type;
1278 Element : in out Element_Type))
1280 begin
1281 if Position.Node = null then
1282 raise Constraint_Error with
1283 "Position cursor of Update_Element equals No_Element";
1284 end if;
1286 if Position.Node.Key = null
1287 or else Position.Node.Element = null
1288 then
1289 raise Program_Error with
1290 "Position cursor of Update_Element is bad";
1291 end if;
1293 if Position.Container /= Container'Unrestricted_Access then
1294 raise Program_Error with
1295 "Position cursor of Update_Element designates wrong map";
1296 end if;
1298 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1300 declare
1301 HT : Hash_Table_Type renames Container.HT;
1303 B : Natural renames HT.Busy;
1304 L : Natural renames HT.Lock;
1306 begin
1307 B := B + 1;
1308 L := L + 1;
1310 declare
1311 K : Key_Type renames Position.Node.Key.all;
1312 E : Element_Type renames Position.Node.Element.all;
1314 begin
1315 Process (K, E);
1317 exception
1318 when others =>
1319 L := L - 1;
1320 B := B - 1;
1321 raise;
1322 end;
1324 L := L - 1;
1325 B := B - 1;
1326 end;
1327 end Update_Element;
1329 ---------
1330 -- Vet --
1331 ---------
1333 function Vet (Position : Cursor) return Boolean is
1334 begin
1335 if Position.Node = null then
1336 return Position.Container = null;
1337 end if;
1339 if Position.Container = null then
1340 return False;
1341 end if;
1343 if Position.Node.Next = Position.Node then
1344 return False;
1345 end if;
1347 if Position.Node.Key = null then
1348 return False;
1349 end if;
1351 if Position.Node.Element = null then
1352 return False;
1353 end if;
1355 declare
1356 HT : Hash_Table_Type renames Position.Container.HT;
1357 X : Node_Access;
1359 begin
1360 if HT.Length = 0 then
1361 return False;
1362 end if;
1364 if HT.Buckets = null
1365 or else HT.Buckets'Length = 0
1366 then
1367 return False;
1368 end if;
1370 X := HT.Buckets (Key_Ops.Index (HT, Position.Node.Key.all));
1372 for J in 1 .. HT.Length loop
1373 if X = Position.Node then
1374 return True;
1375 end if;
1377 if X = null then
1378 return False;
1379 end if;
1381 if X = X.Next then -- to prevent unnecessary looping
1382 return False;
1383 end if;
1385 X := X.Next;
1386 end loop;
1388 return False;
1389 end;
1390 end Vet;
1392 -----------
1393 -- Write --
1394 -----------
1396 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
1398 procedure Write
1399 (Stream : not null access Root_Stream_Type'Class;
1400 Container : Map)
1402 begin
1403 Write_Nodes (Stream, Container.HT);
1404 end Write;
1406 procedure Write
1407 (Stream : not null access Root_Stream_Type'Class;
1408 Item : Cursor)
1410 begin
1411 raise Program_Error with "attempt to stream map cursor";
1412 end Write;
1414 procedure Write
1415 (Stream : not null access Root_Stream_Type'Class;
1416 Item : Reference_Type)
1418 begin
1419 raise Program_Error with "attempt to stream reference";
1420 end Write;
1422 procedure Write
1423 (Stream : not null access Root_Stream_Type'Class;
1424 Item : Constant_Reference_Type)
1426 begin
1427 raise Program_Error with "attempt to stream reference";
1428 end Write;
1430 ----------------
1431 -- Write_Node --
1432 ----------------
1434 procedure Write_Node
1435 (Stream : not null access Root_Stream_Type'Class;
1436 Node : Node_Access)
1438 begin
1439 Key_Type'Output (Stream, Node.Key.all);
1440 Element_Type'Output (Stream, Node.Element.all);
1441 end Write_Node;
1443 end Ada.Containers.Indefinite_Hashed_Maps;