2014-02-20 Richard Biener <rguenther@suse.de>
[official-gcc.git] / gcc / ada / a-cohama.adb
blob541e95a14e6db8741259614410c32fb357841a98
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . H A S H E D _ M A P S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2013, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Unchecked_Deallocation;
32 with Ada.Containers.Hash_Tables.Generic_Operations;
33 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Operations);
35 with Ada.Containers.Hash_Tables.Generic_Keys;
36 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Keys);
38 with System; use type System.Address;
40 package body Ada.Containers.Hashed_Maps is
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 function Copy_Node
47 (Source : Node_Access) return Node_Access;
48 pragma Inline (Copy_Node);
50 function Equivalent_Key_Node
51 (Key : Key_Type;
52 Node : Node_Access) return Boolean;
53 pragma Inline (Equivalent_Key_Node);
55 procedure Free (X : in out Node_Access);
57 function Find_Equal_Key
58 (R_HT : Hash_Table_Type;
59 L_Node : Node_Access) return Boolean;
61 function Hash_Node (Node : Node_Access) return Hash_Type;
62 pragma Inline (Hash_Node);
64 function Next (Node : Node_Access) return Node_Access;
65 pragma Inline (Next);
67 function Read_Node
68 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
69 pragma Inline (Read_Node);
71 procedure Set_Next (Node : Node_Access; Next : Node_Access);
72 pragma Inline (Set_Next);
74 function Vet (Position : Cursor) return Boolean;
76 procedure Write_Node
77 (Stream : not null access Root_Stream_Type'Class;
78 Node : Node_Access);
79 pragma Inline (Write_Node);
81 --------------------------
82 -- Local Instantiations --
83 --------------------------
85 package HT_Ops is new Hash_Tables.Generic_Operations
86 (HT_Types => HT_Types,
87 Hash_Node => Hash_Node,
88 Next => Next,
89 Set_Next => Set_Next,
90 Copy_Node => Copy_Node,
91 Free => Free);
93 package Key_Ops is new Hash_Tables.Generic_Keys
94 (HT_Types => HT_Types,
95 Next => Next,
96 Set_Next => Set_Next,
97 Key_Type => Key_Type,
98 Hash => Hash,
99 Equivalent_Keys => Equivalent_Key_Node);
101 function Is_Equal is new HT_Ops.Generic_Equal (Find_Equal_Key);
103 procedure Read_Nodes is new HT_Ops.Generic_Read (Read_Node);
104 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
106 ---------
107 -- "=" --
108 ---------
110 function "=" (Left, Right : Map) return Boolean is
111 begin
112 return Is_Equal (Left.HT, Right.HT);
113 end "=";
115 ------------
116 -- Adjust --
117 ------------
119 procedure Adjust (Container : in out Map) is
120 begin
121 HT_Ops.Adjust (Container.HT);
122 end Adjust;
124 procedure Adjust (Control : in out Reference_Control_Type) is
125 begin
126 if Control.Container /= null then
127 declare
128 HT : Hash_Table_Type renames Control.Container.all.HT;
129 B : Natural renames HT.Busy;
130 L : Natural renames HT.Lock;
131 begin
132 B := B + 1;
133 L := L + 1;
134 end;
135 end if;
136 end Adjust;
138 ------------
139 -- Assign --
140 ------------
142 procedure Assign (Target : in out Map; Source : Map) is
143 procedure Insert_Item (Node : Node_Access);
144 pragma Inline (Insert_Item);
146 procedure Insert_Items is new HT_Ops.Generic_Iteration (Insert_Item);
148 -----------------
149 -- Insert_Item --
150 -----------------
152 procedure Insert_Item (Node : Node_Access) is
153 begin
154 Target.Insert (Key => Node.Key, New_Item => Node.Element);
155 end Insert_Item;
157 -- Start of processing for Assign
159 begin
160 if Target'Address = Source'Address then
161 return;
162 end if;
164 Target.Clear;
166 if Target.Capacity < Source.Length then
167 Target.Reserve_Capacity (Source.Length);
168 end if;
170 Insert_Items (Source.HT);
171 end Assign;
173 --------------
174 -- Capacity --
175 --------------
177 function Capacity (Container : Map) return Count_Type is
178 begin
179 return HT_Ops.Capacity (Container.HT);
180 end Capacity;
182 -----------
183 -- Clear --
184 -----------
186 procedure Clear (Container : in out Map) is
187 begin
188 HT_Ops.Clear (Container.HT);
189 end Clear;
191 ------------------------
192 -- Constant_Reference --
193 ------------------------
195 function Constant_Reference
196 (Container : aliased Map;
197 Position : Cursor) return Constant_Reference_Type
199 begin
200 if Position.Container = null then
201 raise Constraint_Error with
202 "Position cursor has no element";
203 end if;
205 if Position.Container /= Container'Unrestricted_Access then
206 raise Program_Error with
207 "Position cursor designates wrong map";
208 end if;
210 pragma Assert
211 (Vet (Position),
212 "Position cursor in Constant_Reference is bad");
214 declare
215 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
216 B : Natural renames HT.Busy;
217 L : Natural renames HT.Lock;
218 begin
219 return R : constant Constant_Reference_Type :=
220 (Element => Position.Node.Element'Access,
221 Control => (Controlled with Position.Container))
223 B := B + 1;
224 L := L + 1;
225 end return;
226 end;
227 end Constant_Reference;
229 function Constant_Reference
230 (Container : aliased Map;
231 Key : Key_Type) return Constant_Reference_Type
233 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
234 Node : constant Node_Access := Key_Ops.Find (HT, Key);
236 begin
237 if Node = null then
238 raise Constraint_Error with "key not in map";
239 end if;
241 declare
242 B : Natural renames HT.Busy;
243 L : Natural renames HT.Lock;
244 begin
245 return R : constant Constant_Reference_Type :=
246 (Element => Node.Element'Access,
247 Control => (Controlled with Container'Unrestricted_Access))
249 B := B + 1;
250 L := L + 1;
251 end return;
252 end;
253 end Constant_Reference;
255 --------------
256 -- Contains --
257 --------------
259 function Contains (Container : Map; Key : Key_Type) return Boolean is
260 begin
261 return Find (Container, Key) /= No_Element;
262 end Contains;
264 ----------
265 -- Copy --
266 ----------
268 function Copy
269 (Source : Map;
270 Capacity : Count_Type := 0) return Map
272 C : Count_Type;
274 begin
275 if Capacity = 0 then
276 C := Source.Length;
278 elsif Capacity >= Source.Length then
279 C := Capacity;
281 else
282 raise Capacity_Error
283 with "Requested capacity is less than Source length";
284 end if;
286 return Target : Map do
287 Target.Reserve_Capacity (C);
288 Target.Assign (Source);
289 end return;
290 end Copy;
292 ---------------
293 -- Copy_Node --
294 ---------------
296 function Copy_Node
297 (Source : Node_Access) return Node_Access
299 Target : constant Node_Access :=
300 new Node_Type'(Key => Source.Key,
301 Element => Source.Element,
302 Next => null);
303 begin
304 return Target;
305 end Copy_Node;
307 ------------
308 -- Delete --
309 ------------
311 procedure Delete (Container : in out Map; Key : Key_Type) is
312 X : Node_Access;
314 begin
315 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
317 if X = null then
318 raise Constraint_Error with "attempt to delete key not in map";
319 end if;
321 Free (X);
322 end Delete;
324 procedure Delete (Container : in out Map; Position : in out Cursor) is
325 begin
326 if Position.Node = null then
327 raise Constraint_Error with
328 "Position cursor of Delete equals No_Element";
329 end if;
331 if Position.Container /= Container'Unrestricted_Access then
332 raise Program_Error with
333 "Position cursor of Delete designates wrong map";
334 end if;
336 if Container.HT.Busy > 0 then
337 raise Program_Error with
338 "Delete attempted to tamper with cursors (map is busy)";
339 end if;
341 pragma Assert (Vet (Position), "bad cursor in Delete");
343 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
345 Free (Position.Node);
346 Position.Container := null;
347 end Delete;
349 -------------
350 -- Element --
351 -------------
353 function Element (Container : Map; Key : Key_Type) return Element_Type is
354 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
355 Node : constant Node_Access := Key_Ops.Find (HT, Key);
357 begin
358 if Node = null then
359 raise Constraint_Error with
360 "no element available because key not in map";
361 end if;
363 return Node.Element;
364 end Element;
366 function Element (Position : Cursor) return Element_Type is
367 begin
368 if Position.Node = null then
369 raise Constraint_Error with
370 "Position cursor of function Element equals No_Element";
371 end if;
373 pragma Assert (Vet (Position), "bad cursor in function Element");
375 return Position.Node.Element;
376 end Element;
378 -------------------------
379 -- Equivalent_Key_Node --
380 -------------------------
382 function Equivalent_Key_Node
383 (Key : Key_Type;
384 Node : Node_Access) return Boolean is
385 begin
386 return Equivalent_Keys (Key, Node.Key);
387 end Equivalent_Key_Node;
389 ---------------------
390 -- Equivalent_Keys --
391 ---------------------
393 function Equivalent_Keys (Left, Right : Cursor)
394 return Boolean is
395 begin
396 if Left.Node = null then
397 raise Constraint_Error with
398 "Left cursor of Equivalent_Keys equals No_Element";
399 end if;
401 if Right.Node = null then
402 raise Constraint_Error with
403 "Right cursor of Equivalent_Keys equals No_Element";
404 end if;
406 pragma Assert (Vet (Left), "Left cursor of Equivalent_Keys is bad");
407 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
409 return Equivalent_Keys (Left.Node.Key, Right.Node.Key);
410 end Equivalent_Keys;
412 function Equivalent_Keys (Left : Cursor; Right : Key_Type) return Boolean is
413 begin
414 if Left.Node = null then
415 raise Constraint_Error with
416 "Left cursor of Equivalent_Keys equals No_Element";
417 end if;
419 pragma Assert (Vet (Left), "Left cursor in Equivalent_Keys is bad");
421 return Equivalent_Keys (Left.Node.Key, Right);
422 end Equivalent_Keys;
424 function Equivalent_Keys (Left : Key_Type; Right : Cursor) return Boolean is
425 begin
426 if Right.Node = null then
427 raise Constraint_Error with
428 "Right cursor of Equivalent_Keys equals No_Element";
429 end if;
431 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
433 return Equivalent_Keys (Left, Right.Node.Key);
434 end Equivalent_Keys;
436 -------------
437 -- Exclude --
438 -------------
440 procedure Exclude (Container : in out Map; Key : Key_Type) is
441 X : Node_Access;
442 begin
443 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
444 Free (X);
445 end Exclude;
447 --------------
448 -- Finalize --
449 --------------
451 procedure Finalize (Container : in out Map) is
452 begin
453 HT_Ops.Finalize (Container.HT);
454 end Finalize;
456 procedure Finalize (Object : in out Iterator) is
457 begin
458 if Object.Container /= null then
459 declare
460 B : Natural renames Object.Container.all.HT.Busy;
461 begin
462 B := B - 1;
463 end;
464 end if;
465 end Finalize;
467 procedure Finalize (Control : in out Reference_Control_Type) is
468 begin
469 if Control.Container /= null then
470 declare
471 HT : Hash_Table_Type renames Control.Container.all.HT;
472 B : Natural renames HT.Busy;
473 L : Natural renames HT.Lock;
474 begin
475 B := B - 1;
476 L := L - 1;
477 end;
479 Control.Container := null;
480 end if;
481 end Finalize;
483 ----------
484 -- Find --
485 ----------
487 function Find (Container : Map; Key : Key_Type) return Cursor is
488 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
489 Node : constant Node_Access := Key_Ops.Find (HT, Key);
491 begin
492 if Node = null then
493 return No_Element;
494 end if;
496 return Cursor'(Container'Unrestricted_Access, Node);
497 end Find;
499 --------------------
500 -- Find_Equal_Key --
501 --------------------
503 function Find_Equal_Key
504 (R_HT : Hash_Table_Type;
505 L_Node : Node_Access) return Boolean
507 R_Index : constant Hash_Type := Key_Ops.Index (R_HT, L_Node.Key);
508 R_Node : Node_Access := R_HT.Buckets (R_Index);
510 begin
511 while R_Node /= null loop
512 if Equivalent_Keys (L_Node.Key, R_Node.Key) then
513 return L_Node.Element = R_Node.Element;
514 end if;
516 R_Node := R_Node.Next;
517 end loop;
519 return False;
520 end Find_Equal_Key;
522 -----------
523 -- First --
524 -----------
526 function First (Container : Map) return Cursor is
527 Node : constant Node_Access := HT_Ops.First (Container.HT);
529 begin
530 if Node = null then
531 return No_Element;
532 end if;
534 return Cursor'(Container'Unrestricted_Access, Node);
535 end First;
537 function First (Object : Iterator) return Cursor is
538 begin
539 return Object.Container.First;
540 end First;
542 ----------
543 -- Free --
544 ----------
546 procedure Free (X : in out Node_Access) is
547 procedure Deallocate is
548 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
549 begin
550 if X /= null then
551 X.Next := X; -- detect mischief (in Vet)
552 Deallocate (X);
553 end if;
554 end Free;
556 -----------------
557 -- Has_Element --
558 -----------------
560 function Has_Element (Position : Cursor) return Boolean is
561 begin
562 pragma Assert (Vet (Position), "bad cursor in Has_Element");
563 return Position.Node /= null;
564 end Has_Element;
566 ---------------
567 -- Hash_Node --
568 ---------------
570 function Hash_Node (Node : Node_Access) return Hash_Type is
571 begin
572 return Hash (Node.Key);
573 end Hash_Node;
575 -------------
576 -- Include --
577 -------------
579 procedure Include
580 (Container : in out Map;
581 Key : Key_Type;
582 New_Item : Element_Type)
584 Position : Cursor;
585 Inserted : Boolean;
587 begin
588 Insert (Container, Key, New_Item, Position, Inserted);
590 if not Inserted then
591 if Container.HT.Lock > 0 then
592 raise Program_Error with
593 "Include attempted to tamper with elements (map is locked)";
594 end if;
596 Position.Node.Key := Key;
597 Position.Node.Element := New_Item;
598 end if;
599 end Include;
601 ------------
602 -- Insert --
603 ------------
605 procedure Insert
606 (Container : in out Map;
607 Key : Key_Type;
608 Position : out Cursor;
609 Inserted : out Boolean)
611 function New_Node (Next : Node_Access) return Node_Access;
612 pragma Inline (New_Node);
614 procedure Local_Insert is
615 new Key_Ops.Generic_Conditional_Insert (New_Node);
617 --------------
618 -- New_Node --
619 --------------
621 function New_Node (Next : Node_Access) return Node_Access is
622 begin
623 return new Node_Type'(Key => Key,
624 Element => <>,
625 Next => Next);
626 end New_Node;
628 HT : Hash_Table_Type renames Container.HT;
630 -- Start of processing for Insert
632 begin
633 if HT_Ops.Capacity (HT) = 0 then
634 HT_Ops.Reserve_Capacity (HT, 1);
635 end if;
637 Local_Insert (HT, Key, Position.Node, Inserted);
639 if Inserted
640 and then HT.Length > HT_Ops.Capacity (HT)
641 then
642 HT_Ops.Reserve_Capacity (HT, HT.Length);
643 end if;
645 Position.Container := Container'Unrestricted_Access;
646 end Insert;
648 procedure Insert
649 (Container : in out Map;
650 Key : Key_Type;
651 New_Item : Element_Type;
652 Position : out Cursor;
653 Inserted : out Boolean)
655 function New_Node (Next : Node_Access) return Node_Access;
656 pragma Inline (New_Node);
658 procedure Local_Insert is
659 new Key_Ops.Generic_Conditional_Insert (New_Node);
661 --------------
662 -- New_Node --
663 --------------
665 function New_Node (Next : Node_Access) return Node_Access is
666 begin
667 return new Node_Type'(Key, New_Item, Next);
668 end New_Node;
670 HT : Hash_Table_Type renames Container.HT;
672 -- Start of processing for Insert
674 begin
675 if HT_Ops.Capacity (HT) = 0 then
676 HT_Ops.Reserve_Capacity (HT, 1);
677 end if;
679 Local_Insert (HT, Key, Position.Node, Inserted);
681 if Inserted
682 and then HT.Length > HT_Ops.Capacity (HT)
683 then
684 HT_Ops.Reserve_Capacity (HT, HT.Length);
685 end if;
687 Position.Container := Container'Unrestricted_Access;
688 end Insert;
690 procedure Insert
691 (Container : in out Map;
692 Key : Key_Type;
693 New_Item : Element_Type)
695 Position : Cursor;
696 pragma Unreferenced (Position);
698 Inserted : Boolean;
700 begin
701 Insert (Container, Key, New_Item, Position, Inserted);
703 if not Inserted then
704 raise Constraint_Error with
705 "attempt to insert key already in map";
706 end if;
707 end Insert;
709 --------------
710 -- Is_Empty --
711 --------------
713 function Is_Empty (Container : Map) return Boolean is
714 begin
715 return Container.HT.Length = 0;
716 end Is_Empty;
718 -------------
719 -- Iterate --
720 -------------
722 procedure Iterate
723 (Container : Map;
724 Process : not null access procedure (Position : Cursor))
726 procedure Process_Node (Node : Node_Access);
727 pragma Inline (Process_Node);
729 procedure Local_Iterate is new HT_Ops.Generic_Iteration (Process_Node);
731 ------------------
732 -- Process_Node --
733 ------------------
735 procedure Process_Node (Node : Node_Access) is
736 begin
737 Process (Cursor'(Container'Unrestricted_Access, Node));
738 end Process_Node;
740 B : Natural renames Container'Unrestricted_Access.all.HT.Busy;
742 -- Start of processing for Iterate
744 begin
745 B := B + 1;
747 begin
748 Local_Iterate (Container.HT);
749 exception
750 when others =>
751 B := B - 1;
752 raise;
753 end;
755 B := B - 1;
756 end Iterate;
758 function Iterate
759 (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class
761 B : Natural renames Container'Unrestricted_Access.all.HT.Busy;
762 begin
763 return It : constant Iterator :=
764 (Limited_Controlled with Container => Container'Unrestricted_Access)
766 B := B + 1;
767 end return;
768 end Iterate;
770 ---------
771 -- Key --
772 ---------
774 function Key (Position : Cursor) return Key_Type is
775 begin
776 if Position.Node = null then
777 raise Constraint_Error with
778 "Position cursor of function Key equals No_Element";
779 end if;
781 pragma Assert (Vet (Position), "bad cursor in function Key");
783 return Position.Node.Key;
784 end Key;
786 ------------
787 -- Length --
788 ------------
790 function Length (Container : Map) return Count_Type is
791 begin
792 return Container.HT.Length;
793 end Length;
795 ----------
796 -- Move --
797 ----------
799 procedure Move
800 (Target : in out Map;
801 Source : in out Map)
803 begin
804 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
805 end Move;
807 ----------
808 -- Next --
809 ----------
811 function Next (Node : Node_Access) return Node_Access is
812 begin
813 return Node.Next;
814 end Next;
816 function Next (Position : Cursor) return Cursor is
817 begin
818 if Position.Node = null then
819 return No_Element;
820 end if;
822 pragma Assert (Vet (Position), "bad cursor in function Next");
824 declare
825 HT : Hash_Table_Type renames Position.Container.HT;
826 Node : constant Node_Access := HT_Ops.Next (HT, Position.Node);
828 begin
829 if Node = null then
830 return No_Element;
831 end if;
833 return Cursor'(Position.Container, Node);
834 end;
835 end Next;
837 procedure Next (Position : in out Cursor) is
838 begin
839 Position := Next (Position);
840 end Next;
842 function Next
843 (Object : Iterator;
844 Position : Cursor) return Cursor
846 begin
847 if Position.Container = null then
848 return No_Element;
849 end if;
851 if Position.Container /= Object.Container then
852 raise Program_Error with
853 "Position cursor of Next designates wrong map";
854 end if;
856 return Next (Position);
857 end Next;
859 -------------------
860 -- Query_Element --
861 -------------------
863 procedure Query_Element
864 (Position : Cursor;
865 Process : not null access
866 procedure (Key : Key_Type; Element : Element_Type))
868 begin
869 if Position.Node = null then
870 raise Constraint_Error with
871 "Position cursor of Query_Element equals No_Element";
872 end if;
874 pragma Assert (Vet (Position), "bad cursor in Query_Element");
876 declare
877 M : Map renames Position.Container.all;
878 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
880 B : Natural renames HT.Busy;
881 L : Natural renames HT.Lock;
883 begin
884 B := B + 1;
885 L := L + 1;
887 declare
888 K : Key_Type renames Position.Node.Key;
889 E : Element_Type renames Position.Node.Element;
891 begin
892 Process (K, E);
893 exception
894 when others =>
895 L := L - 1;
896 B := B - 1;
897 raise;
898 end;
900 L := L - 1;
901 B := B - 1;
902 end;
903 end Query_Element;
905 ----------
906 -- Read --
907 ----------
909 procedure Read
910 (Stream : not null access Root_Stream_Type'Class;
911 Container : out Map)
913 begin
914 Read_Nodes (Stream, Container.HT);
915 end Read;
917 procedure Read
918 (Stream : not null access Root_Stream_Type'Class;
919 Item : out Cursor)
921 begin
922 raise Program_Error with "attempt to stream map cursor";
923 end Read;
925 procedure Read
926 (Stream : not null access Root_Stream_Type'Class;
927 Item : out Reference_Type)
929 begin
930 raise Program_Error with "attempt to stream reference";
931 end Read;
933 procedure Read
934 (Stream : not null access Root_Stream_Type'Class;
935 Item : out Constant_Reference_Type)
937 begin
938 raise Program_Error with "attempt to stream reference";
939 end Read;
941 ---------------
942 -- Reference --
943 ---------------
945 function Reference
946 (Container : aliased in out Map;
947 Position : Cursor) return Reference_Type
949 begin
950 if Position.Container = null then
951 raise Constraint_Error with
952 "Position cursor has no element";
953 end if;
955 if Position.Container /= Container'Unrestricted_Access then
956 raise Program_Error with
957 "Position cursor designates wrong map";
958 end if;
960 pragma Assert
961 (Vet (Position),
962 "Position cursor in function Reference is bad");
964 declare
965 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
966 B : Natural renames HT.Busy;
967 L : Natural renames HT.Lock;
968 begin
969 return R : constant Reference_Type :=
970 (Element => Position.Node.Element'Access,
971 Control => (Controlled with Position.Container))
973 B := B + 1;
974 L := L + 1;
975 end return;
976 end;
977 end Reference;
979 function Reference
980 (Container : aliased in out Map;
981 Key : Key_Type) return Reference_Type
983 HT : Hash_Table_Type renames Container.HT;
984 Node : constant Node_Access := Key_Ops.Find (HT, Key);
986 begin
987 if Node = null then
988 raise Constraint_Error with "key not in map";
989 end if;
991 declare
992 B : Natural renames HT.Busy;
993 L : Natural renames HT.Lock;
994 begin
995 return R : constant Reference_Type :=
996 (Element => Node.Element'Access,
997 Control => (Controlled with Container'Unrestricted_Access))
999 B := B + 1;
1000 L := L + 1;
1001 end return;
1002 end;
1003 end Reference;
1005 ---------------
1006 -- Read_Node --
1007 ---------------
1009 function Read_Node
1010 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1012 Node : Node_Access := new Node_Type;
1014 begin
1015 Key_Type'Read (Stream, Node.Key);
1016 Element_Type'Read (Stream, Node.Element);
1017 return Node;
1019 exception
1020 when others =>
1021 Free (Node);
1022 raise;
1023 end Read_Node;
1025 -------------
1026 -- Replace --
1027 -------------
1029 procedure Replace
1030 (Container : in out Map;
1031 Key : Key_Type;
1032 New_Item : Element_Type)
1034 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
1036 begin
1037 if Node = null then
1038 raise Constraint_Error with
1039 "attempt to replace key not in map";
1040 end if;
1042 if Container.HT.Lock > 0 then
1043 raise Program_Error with
1044 "Replace attempted to tamper with elements (map is locked)";
1045 end if;
1047 Node.Key := Key;
1048 Node.Element := New_Item;
1049 end Replace;
1051 ---------------------
1052 -- Replace_Element --
1053 ---------------------
1055 procedure Replace_Element
1056 (Container : in out Map;
1057 Position : Cursor;
1058 New_Item : Element_Type)
1060 begin
1061 if Position.Node = null then
1062 raise Constraint_Error with
1063 "Position cursor of Replace_Element equals No_Element";
1064 end if;
1066 if Position.Container /= Container'Unrestricted_Access then
1067 raise Program_Error with
1068 "Position cursor of Replace_Element designates wrong map";
1069 end if;
1071 if Position.Container.HT.Lock > 0 then
1072 raise Program_Error with
1073 "Replace_Element attempted to tamper with elements (map is locked)";
1074 end if;
1076 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1078 Position.Node.Element := New_Item;
1079 end Replace_Element;
1081 ----------------------
1082 -- Reserve_Capacity --
1083 ----------------------
1085 procedure Reserve_Capacity
1086 (Container : in out Map;
1087 Capacity : Count_Type)
1089 begin
1090 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1091 end Reserve_Capacity;
1093 --------------
1094 -- Set_Next --
1095 --------------
1097 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1098 begin
1099 Node.Next := Next;
1100 end Set_Next;
1102 --------------------
1103 -- Update_Element --
1104 --------------------
1106 procedure Update_Element
1107 (Container : in out Map;
1108 Position : Cursor;
1109 Process : not null access procedure (Key : Key_Type;
1110 Element : in out Element_Type))
1112 begin
1113 if Position.Node = null then
1114 raise Constraint_Error with
1115 "Position cursor of Update_Element equals No_Element";
1116 end if;
1118 if Position.Container /= Container'Unrestricted_Access then
1119 raise Program_Error with
1120 "Position cursor of Update_Element designates wrong map";
1121 end if;
1123 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1125 declare
1126 HT : Hash_Table_Type renames Container.HT;
1127 B : Natural renames HT.Busy;
1128 L : Natural renames HT.Lock;
1130 begin
1131 B := B + 1;
1132 L := L + 1;
1134 declare
1135 K : Key_Type renames Position.Node.Key;
1136 E : Element_Type renames Position.Node.Element;
1138 begin
1139 Process (K, E);
1141 exception
1142 when others =>
1143 L := L - 1;
1144 B := B - 1;
1145 raise;
1146 end;
1148 L := L - 1;
1149 B := B - 1;
1150 end;
1151 end Update_Element;
1153 ---------
1154 -- Vet --
1155 ---------
1157 function Vet (Position : Cursor) return Boolean is
1158 begin
1159 if Position.Node = null then
1160 return Position.Container = null;
1161 end if;
1163 if Position.Container = null then
1164 return False;
1165 end if;
1167 if Position.Node.Next = Position.Node then
1168 return False;
1169 end if;
1171 declare
1172 HT : Hash_Table_Type renames Position.Container.HT;
1173 X : Node_Access;
1175 begin
1176 if HT.Length = 0 then
1177 return False;
1178 end if;
1180 if HT.Buckets = null
1181 or else HT.Buckets'Length = 0
1182 then
1183 return False;
1184 end if;
1186 X := HT.Buckets (Key_Ops.Checked_Index (HT, Position.Node.Key));
1188 for J in 1 .. HT.Length loop
1189 if X = Position.Node then
1190 return True;
1191 end if;
1193 if X = null then
1194 return False;
1195 end if;
1197 if X = X.Next then -- to prevent unnecessary looping
1198 return False;
1199 end if;
1201 X := X.Next;
1202 end loop;
1204 return False;
1205 end;
1206 end Vet;
1208 -----------
1209 -- Write --
1210 -----------
1212 procedure Write
1213 (Stream : not null access Root_Stream_Type'Class;
1214 Container : Map)
1216 begin
1217 Write_Nodes (Stream, Container.HT);
1218 end Write;
1220 procedure Write
1221 (Stream : not null access Root_Stream_Type'Class;
1222 Item : Cursor)
1224 begin
1225 raise Program_Error with "attempt to stream map cursor";
1226 end Write;
1228 procedure Write
1229 (Stream : not null access Root_Stream_Type'Class;
1230 Item : Reference_Type)
1232 begin
1233 raise Program_Error with "attempt to stream reference";
1234 end Write;
1236 procedure Write
1237 (Stream : not null access Root_Stream_Type'Class;
1238 Item : Constant_Reference_Type)
1240 begin
1241 raise Program_Error with "attempt to stream reference";
1242 end Write;
1244 ----------------
1245 -- Write_Node --
1246 ----------------
1248 procedure Write_Node
1249 (Stream : not null access Root_Stream_Type'Class;
1250 Node : Node_Access)
1252 begin
1253 Key_Type'Write (Stream, Node.Key);
1254 Element_Type'Write (Stream, Node.Element);
1255 end Write_Node;
1257 end Ada.Containers.Hashed_Maps;