ada: Update copyright notice
[official-gcc.git] / gcc / ada / libgnat / a-cohama.adb
blob1a124f87da76f12f852b1b949c4398c179277f06
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-2023, 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 Ada.Containers.Helpers; use Ada.Containers.Helpers;
40 with System; use type System.Address;
41 with System.Put_Images;
43 package body Ada.Containers.Hashed_Maps with
44 SPARK_Mode => Off
47 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
48 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
49 -- See comment in Ada.Containers.Helpers
51 -----------------------
52 -- Local Subprograms --
53 -----------------------
55 function Copy_Node
56 (Source : Node_Access) return Node_Access;
57 pragma Inline (Copy_Node);
59 function Equivalent_Key_Node
60 (Key : Key_Type;
61 Node : Node_Access) return Boolean;
62 pragma Inline (Equivalent_Key_Node);
64 procedure Free (X : in out Node_Access);
66 function Find_Equal_Key
67 (R_HT : Hash_Table_Type;
68 L_Node : Node_Access) return Boolean;
70 function Hash_Node (Node : Node_Access) return Hash_Type;
71 pragma Inline (Hash_Node);
73 function Next (Node : Node_Access) return Node_Access;
74 pragma Inline (Next);
76 function Read_Node
77 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
78 pragma Inline (Read_Node);
80 procedure Set_Next (Node : Node_Access; Next : Node_Access);
81 pragma Inline (Set_Next);
83 function Vet (Position : Cursor) return Boolean with Inline;
85 procedure Write_Node
86 (Stream : not null access Root_Stream_Type'Class;
87 Node : Node_Access);
88 pragma Inline (Write_Node);
90 --------------------------
91 -- Local Instantiations --
92 --------------------------
94 package HT_Ops is new Hash_Tables.Generic_Operations
95 (HT_Types => HT_Types,
96 Hash_Node => Hash_Node,
97 Next => Next,
98 Set_Next => Set_Next,
99 Copy_Node => Copy_Node,
100 Free => Free);
102 package Key_Ops is new Hash_Tables.Generic_Keys
103 (HT_Types => HT_Types,
104 Next => Next,
105 Set_Next => Set_Next,
106 Key_Type => Key_Type,
107 Hash => Hash,
108 Equivalent_Keys => Equivalent_Key_Node);
110 function Is_Equal is new HT_Ops.Generic_Equal (Find_Equal_Key);
112 procedure Read_Nodes is new HT_Ops.Generic_Read (Read_Node);
113 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
115 ---------
116 -- "=" --
117 ---------
119 function "=" (Left, Right : Cursor) return Boolean is
120 begin
121 return
122 Left.Container = Right.Container
123 and then Left.Node = Right.Node;
124 end "=";
126 function "=" (Left, Right : Map) return Boolean is
127 begin
128 return Is_Equal (Left.HT, Right.HT);
129 end "=";
131 ------------
132 -- Adjust --
133 ------------
135 procedure Adjust (Container : in out Map) is
136 begin
137 HT_Ops.Adjust (Container.HT);
138 end Adjust;
140 ------------
141 -- Assign --
142 ------------
144 procedure Assign (Target : in out Map; Source : Map) is
145 procedure Insert_Item (Node : Node_Access);
146 pragma Inline (Insert_Item);
148 procedure Insert_Items is new HT_Ops.Generic_Iteration (Insert_Item);
150 -----------------
151 -- Insert_Item --
152 -----------------
154 procedure Insert_Item (Node : Node_Access) is
155 begin
156 Target.Insert (Key => Node.Key, New_Item => Node.Element);
157 end Insert_Item;
159 -- Start of processing for Assign
161 begin
162 if Target'Address = Source'Address then
163 return;
164 end if;
166 Target.Clear;
168 if Target.Capacity < Source.Length then
169 Target.Reserve_Capacity (Source.Length);
170 end if;
172 Insert_Items (Source.HT);
173 end Assign;
175 --------------
176 -- Capacity --
177 --------------
179 function Capacity (Container : Map) return Count_Type is
180 begin
181 return HT_Ops.Capacity (Container.HT);
182 end Capacity;
184 -----------
185 -- Clear --
186 -----------
188 procedure Clear (Container : in out Map) is
189 begin
190 HT_Ops.Clear (Container.HT);
191 end Clear;
193 ------------------------
194 -- Constant_Reference --
195 ------------------------
197 function Constant_Reference
198 (Container : aliased Map;
199 Position : Cursor) return Constant_Reference_Type
201 begin
202 if Checks and then Position.Container = null then
203 raise Constraint_Error with
204 "Position cursor has no element";
205 end if;
207 if Checks and then Position.Container /= Container'Unrestricted_Access
208 then
209 raise Program_Error with
210 "Position cursor designates wrong map";
211 end if;
213 pragma Assert
214 (Vet (Position),
215 "Position cursor in Constant_Reference is bad");
217 declare
218 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
219 TC : constant Tamper_Counts_Access :=
220 HT.TC'Unrestricted_Access;
221 begin
222 return R : constant Constant_Reference_Type :=
223 (Element => Position.Node.Element'Access,
224 Control => (Controlled with TC))
226 Busy (TC.all);
227 end return;
228 end;
229 end Constant_Reference;
231 function Constant_Reference
232 (Container : aliased Map;
233 Key : Key_Type) return Constant_Reference_Type
235 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
236 Node : constant Node_Access := Key_Ops.Find (HT, Key);
238 begin
239 if Checks and then Node = null then
240 raise Constraint_Error with "key not in map";
241 end if;
243 declare
244 TC : constant Tamper_Counts_Access :=
245 HT.TC'Unrestricted_Access;
246 begin
247 return R : constant Constant_Reference_Type :=
248 (Element => Node.Element'Access,
249 Control => (Controlled with TC))
251 Busy (TC.all);
252 end return;
253 end;
254 end Constant_Reference;
256 --------------
257 -- Contains --
258 --------------
260 function Contains (Container : Map; Key : Key_Type) return Boolean is
261 begin
262 return Find (Container, Key) /= No_Element;
263 end Contains;
265 ----------
266 -- Copy --
267 ----------
269 function Copy
270 (Source : Map;
271 Capacity : Count_Type := 0) return Map
273 C : Count_Type;
275 begin
276 if Capacity < Source.Length then
277 if Checks and then Capacity /= 0 then
278 raise Capacity_Error
279 with "Requested capacity is less than Source length";
280 end if;
282 C := Source.Length;
283 else
284 C := Capacity;
285 end if;
287 return Target : Map do
288 Target.Reserve_Capacity (C);
289 Target.Assign (Source);
290 end return;
291 end Copy;
293 ---------------
294 -- Copy_Node --
295 ---------------
297 function Copy_Node
298 (Source : Node_Access) return Node_Access
300 Target : constant Node_Access :=
301 new Node_Type'(Key => Source.Key,
302 Element => Source.Element,
303 Next => null);
304 begin
305 return Target;
306 end Copy_Node;
308 ------------
309 -- Delete --
310 ------------
312 procedure Delete (Container : in out Map; Key : Key_Type) is
313 X : Node_Access;
315 begin
316 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
318 if Checks and then X = null then
319 raise Constraint_Error with "attempt to delete key not in map";
320 end if;
322 Free (X);
323 end Delete;
325 procedure Delete (Container : in out Map; Position : in out Cursor) is
326 begin
327 TC_Check (Container.HT.TC);
329 if Checks and then Position.Node = null then
330 raise Constraint_Error with
331 "Position cursor of Delete equals No_Element";
332 end if;
334 if Checks and then Position.Container /= Container'Unrestricted_Access
335 then
336 raise Program_Error with
337 "Position cursor of Delete designates wrong map";
338 end if;
340 pragma Assert (Vet (Position), "bad cursor in Delete");
342 HT_Ops.Delete_Node_Sans_Free (Container.HT, Position.Node);
344 Free (Position.Node);
345 Position.Container := null;
346 Position.Position := No_Element.Position;
347 pragma Assert (Position = No_Element);
348 end Delete;
350 -------------
351 -- Element --
352 -------------
354 function Element (Container : Map; Key : Key_Type) return Element_Type is
355 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
356 Node : constant Node_Access := Key_Ops.Find (HT, Key);
358 begin
359 if Checks and then Node = null then
360 raise Constraint_Error with
361 "no element available because key not in map";
362 end if;
364 return Node.Element;
365 end Element;
367 function Element (Position : Cursor) return Element_Type is
368 begin
369 if Checks and then Position.Node = null then
370 raise Constraint_Error with
371 "Position cursor of function Element equals No_Element";
372 end if;
374 pragma Assert (Vet (Position), "bad cursor in function Element");
376 return Position.Node.Element;
377 end Element;
379 -----------
380 -- Empty --
381 -----------
383 function Empty (Capacity : Count_Type := 1000) return Map is
384 begin
385 return Result : Map do
386 Reserve_Capacity (Result, Capacity);
387 end return;
388 end Empty;
390 -------------------------
391 -- Equivalent_Key_Node --
392 -------------------------
394 function Equivalent_Key_Node
395 (Key : Key_Type;
396 Node : Node_Access) return Boolean is
397 begin
398 return Equivalent_Keys (Key, Node.Key);
399 end Equivalent_Key_Node;
401 ---------------------
402 -- Equivalent_Keys --
403 ---------------------
405 function Equivalent_Keys (Left, Right : Cursor)
406 return Boolean is
407 begin
408 if Checks and then Left.Node = null then
409 raise Constraint_Error with
410 "Left cursor of Equivalent_Keys equals No_Element";
411 end if;
413 if Checks and then Right.Node = null then
414 raise Constraint_Error with
415 "Right cursor of Equivalent_Keys equals No_Element";
416 end if;
418 pragma Assert (Vet (Left), "Left cursor of Equivalent_Keys is bad");
419 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
421 return Equivalent_Keys (Left.Node.Key, Right.Node.Key);
422 end Equivalent_Keys;
424 function Equivalent_Keys (Left : Cursor; Right : Key_Type) return Boolean is
425 begin
426 if Checks and then Left.Node = null then
427 raise Constraint_Error with
428 "Left cursor of Equivalent_Keys equals No_Element";
429 end if;
431 pragma Assert (Vet (Left), "Left cursor in Equivalent_Keys is bad");
433 return Equivalent_Keys (Left.Node.Key, Right);
434 end Equivalent_Keys;
436 function Equivalent_Keys (Left : Key_Type; Right : Cursor) return Boolean is
437 begin
438 if Checks and then Right.Node = null then
439 raise Constraint_Error with
440 "Right cursor of Equivalent_Keys equals No_Element";
441 end if;
443 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
445 return Equivalent_Keys (Left, Right.Node.Key);
446 end Equivalent_Keys;
448 -------------
449 -- Exclude --
450 -------------
452 procedure Exclude (Container : in out Map; Key : Key_Type) is
453 X : Node_Access;
454 begin
455 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
456 Free (X);
457 end Exclude;
459 --------------
460 -- Finalize --
461 --------------
463 procedure Finalize (Container : in out Map) is
464 begin
465 HT_Ops.Finalize (Container.HT);
466 end Finalize;
468 procedure Finalize (Object : in out Iterator) is
469 begin
470 if Object.Container /= null then
471 Unbusy (Object.Container.HT.TC);
472 end if;
473 end Finalize;
475 ----------
476 -- Find --
477 ----------
479 function Find (Container : Map; Key : Key_Type) return Cursor is
480 HT : Hash_Table_Type renames Container'Unrestricted_Access.HT;
481 Node : constant Node_Access := Key_Ops.Find (HT, Key);
483 begin
484 if Node = null then
485 return No_Element;
486 end if;
488 return Cursor'
489 (Container'Unrestricted_Access, Node, HT_Ops.Index (HT, Node));
490 end Find;
492 --------------------
493 -- Find_Equal_Key --
494 --------------------
496 function Find_Equal_Key
497 (R_HT : Hash_Table_Type;
498 L_Node : Node_Access) return Boolean
500 R_Index : constant Hash_Type := Key_Ops.Index (R_HT, L_Node.Key);
501 R_Node : Node_Access := R_HT.Buckets (R_Index);
503 begin
504 while R_Node /= null loop
505 if Equivalent_Keys (L_Node.Key, R_Node.Key) then
506 return L_Node.Element = R_Node.Element;
507 end if;
509 R_Node := R_Node.Next;
510 end loop;
512 return False;
513 end Find_Equal_Key;
515 -----------
516 -- First --
517 -----------
519 function First (Container : Map) return Cursor is
520 Pos : Hash_Type;
521 Node : constant Node_Access := HT_Ops.First (Container.HT, Pos);
522 begin
523 if Node = null then
524 return No_Element;
525 end if;
527 return Cursor'(Container'Unrestricted_Access, Node, Pos);
528 end First;
530 function First (Object : Iterator) return Cursor is
531 begin
532 return Object.Container.First;
533 end First;
535 ----------
536 -- Free --
537 ----------
539 procedure Free (X : in out Node_Access) is
540 procedure Deallocate is
541 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
542 begin
543 if X /= null then
544 X.Next := X; -- detect mischief (in Vet)
545 Deallocate (X);
546 end if;
547 end Free;
549 ------------------------
550 -- Get_Element_Access --
551 ------------------------
553 function Get_Element_Access
554 (Position : Cursor) return not null Element_Access is
555 begin
556 return Position.Node.Element'Access;
557 end Get_Element_Access;
559 -----------------
560 -- Has_Element --
561 -----------------
563 function Has_Element (Position : Cursor) return Boolean is
564 begin
565 pragma Assert (Vet (Position), "bad cursor in Has_Element");
566 return Position.Node /= null;
567 end Has_Element;
569 ---------------
570 -- Hash_Node --
571 ---------------
573 function Hash_Node (Node : Node_Access) return Hash_Type is
574 begin
575 return Hash (Node.Key);
576 end Hash_Node;
578 -------------
579 -- Include --
580 -------------
582 procedure Include
583 (Container : in out Map;
584 Key : Key_Type;
585 New_Item : Element_Type)
587 Position : Cursor;
588 Inserted : Boolean;
590 begin
591 Insert (Container, Key, New_Item, Position, Inserted);
593 if not Inserted then
594 TE_Check (Container.HT.TC);
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;
647 -- Note that we do not set the Position component of the cursor,
648 -- because it may become incorrect on subsequent insertions/deletions
649 -- from the container. This will lose some optimizations but prevents
650 -- anomalies when the underlying hash-table is expanded or shrunk.
651 end Insert;
653 procedure Insert
654 (Container : in out Map;
655 Key : Key_Type;
656 New_Item : Element_Type;
657 Position : out Cursor;
658 Inserted : out Boolean)
660 function New_Node (Next : Node_Access) return Node_Access;
661 pragma Inline (New_Node);
663 procedure Local_Insert is
664 new Key_Ops.Generic_Conditional_Insert (New_Node);
666 --------------
667 -- New_Node --
668 --------------
670 function New_Node (Next : Node_Access) return Node_Access is
671 begin
672 return new Node_Type'(Key, New_Item, Next);
673 end New_Node;
675 HT : Hash_Table_Type renames Container.HT;
677 -- Start of processing for Insert
679 begin
680 if HT_Ops.Capacity (HT) = 0 then
681 HT_Ops.Reserve_Capacity (HT, 1);
682 end if;
684 Local_Insert (HT, Key, Position.Node, Inserted);
686 if Inserted
687 and then HT.Length > HT_Ops.Capacity (HT)
688 then
689 HT_Ops.Reserve_Capacity (HT, HT.Length);
690 end if;
692 Position.Container := Container'Unrestricted_Access;
693 end Insert;
695 procedure Insert
696 (Container : in out Map;
697 Key : Key_Type;
698 New_Item : Element_Type)
700 Position : Cursor;
701 Inserted : Boolean;
703 begin
704 Insert (Container, Key, New_Item, Position, Inserted);
706 if Checks and then not Inserted then
707 raise Constraint_Error with
708 "attempt to insert key already in map";
709 end if;
710 end Insert;
712 --------------
713 -- Is_Empty --
714 --------------
716 function Is_Empty (Container : Map) return Boolean is
717 begin
718 return Container.HT.Length = 0;
719 end Is_Empty;
721 -------------
722 -- Iterate --
723 -------------
725 procedure Iterate
726 (Container : Map;
727 Process : not null access procedure (Position : Cursor))
729 procedure Process_Node (Node : Node_Access; Position : Hash_Type);
730 pragma Inline (Process_Node);
732 procedure Local_Iterate is
733 new HT_Ops.Generic_Iteration_With_Position (Process_Node);
735 ------------------
736 -- Process_Node --
737 ------------------
739 procedure Process_Node (Node : Node_Access; Position : Hash_Type) is
740 begin
741 Process (Cursor'(Container'Unrestricted_Access, Node, Position));
742 end Process_Node;
744 Busy : With_Busy (Container.HT.TC'Unrestricted_Access);
746 -- Start of processing for Iterate
748 begin
749 Local_Iterate (Container.HT);
750 end Iterate;
752 function Iterate
753 (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class
755 begin
756 return It : constant Iterator :=
757 (Limited_Controlled with Container => Container'Unrestricted_Access)
759 Busy (Container.HT.TC'Unrestricted_Access.all);
760 end return;
761 end Iterate;
763 ---------
764 -- Key --
765 ---------
767 function Key (Position : Cursor) return Key_Type is
768 begin
769 if Checks and then Position.Node = null then
770 raise Constraint_Error with
771 "Position cursor of function Key equals No_Element";
772 end if;
774 pragma Assert (Vet (Position), "bad cursor in function Key");
776 return Position.Node.Key;
777 end Key;
779 ------------
780 -- Length --
781 ------------
783 function Length (Container : Map) return Count_Type is
784 begin
785 return Container.HT.Length;
786 end Length;
788 ----------
789 -- Move --
790 ----------
792 procedure Move
793 (Target : in out Map;
794 Source : in out Map)
796 begin
797 HT_Ops.Move (Target => Target.HT, Source => Source.HT);
798 end Move;
800 ----------
801 -- Next --
802 ----------
804 function Next (Node : Node_Access) return Node_Access is
805 begin
806 return Node.Next;
807 end Next;
809 function Next (Position : Cursor) return Cursor is
810 Node : Node_Access := null;
812 Pos : Hash_Type;
813 -- Position of cursor's element in the map buckets.
814 begin
815 if Position.Node = null then
816 return No_Element;
817 end if;
819 pragma Assert (Vet (Position), "bad cursor in function Next");
821 -- Initialize to current position, so that HT_Ops.Next can use it
822 Pos := Position.Position;
824 Node := HT_Ops.Next (Position.Container.HT, Position.Node, Pos);
826 if Node = null then
827 return No_Element;
828 else
829 return Cursor'(Position.Container, Node, Pos);
830 end if;
831 end Next;
833 procedure Next (Position : in out Cursor) is
834 begin
835 Position := Next (Position);
836 end Next;
838 function Next
839 (Object : Iterator;
840 Position : Cursor) return Cursor
842 begin
843 if Position.Container = null then
844 return No_Element;
845 end if;
847 if Checks and then Position.Container /= Object.Container then
848 raise Program_Error with
849 "Position cursor of Next designates wrong map";
850 end if;
852 return Next (Position);
853 end Next;
855 ----------------------
856 -- Pseudo_Reference --
857 ----------------------
859 function Pseudo_Reference
860 (Container : aliased Map'Class) return Reference_Control_Type
862 TC : constant Tamper_Counts_Access :=
863 Container.HT.TC'Unrestricted_Access;
864 begin
865 return R : constant Reference_Control_Type := (Controlled with TC) do
866 Busy (TC.all);
867 end return;
868 end Pseudo_Reference;
870 -------------------
871 -- Query_Element --
872 -------------------
874 procedure Query_Element
875 (Position : Cursor;
876 Process : not null access
877 procedure (Key : Key_Type; Element : Element_Type))
879 begin
880 if Checks and then Position.Node = null then
881 raise Constraint_Error with
882 "Position cursor of Query_Element equals No_Element";
883 end if;
885 pragma Assert (Vet (Position), "bad cursor in Query_Element");
887 declare
888 M : Map renames Position.Container.all;
889 HT : Hash_Table_Type renames M.HT'Unrestricted_Access.all;
890 Lock : With_Lock (HT.TC'Unrestricted_Access);
891 K : Key_Type renames Position.Node.Key;
892 E : Element_Type renames Position.Node.Element;
893 begin
894 Process (K, E);
895 end;
896 end Query_Element;
898 ---------------
899 -- Put_Image --
900 ---------------
902 procedure Put_Image
903 (S : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; V : Map)
905 First_Time : Boolean := True;
906 use System.Put_Images;
908 procedure Put_Key_Value (Position : Cursor);
909 procedure Put_Key_Value (Position : Cursor) is
910 begin
911 if First_Time then
912 First_Time := False;
913 else
914 Simple_Array_Between (S);
915 end if;
917 Key_Type'Put_Image (S, Key (Position));
918 Put_Arrow (S);
919 Element_Type'Put_Image (S, Element (Position));
920 end Put_Key_Value;
922 begin
923 Array_Before (S);
924 Iterate (V, Put_Key_Value'Access);
925 Array_After (S);
926 end Put_Image;
928 ----------
929 -- Read --
930 ----------
932 procedure Read
933 (Stream : not null access Root_Stream_Type'Class;
934 Container : out Map)
936 begin
937 Read_Nodes (Stream, Container.HT);
938 end Read;
940 procedure Read
941 (Stream : not null access Root_Stream_Type'Class;
942 Item : out Cursor)
944 begin
945 raise Program_Error with "attempt to stream map cursor";
946 end Read;
948 procedure Read
949 (Stream : not null access Root_Stream_Type'Class;
950 Item : out Reference_Type)
952 begin
953 raise Program_Error with "attempt to stream reference";
954 end Read;
956 procedure Read
957 (Stream : not null access Root_Stream_Type'Class;
958 Item : out Constant_Reference_Type)
960 begin
961 raise Program_Error with "attempt to stream reference";
962 end Read;
964 ---------------
965 -- Reference --
966 ---------------
968 function Reference
969 (Container : aliased in out Map;
970 Position : Cursor) return Reference_Type
972 begin
973 if Checks and then Position.Container = null then
974 raise Constraint_Error with
975 "Position cursor has no element";
976 end if;
978 if Checks and then Position.Container /= Container'Unrestricted_Access
979 then
980 raise Program_Error with
981 "Position cursor designates wrong map";
982 end if;
984 pragma Assert
985 (Vet (Position),
986 "Position cursor in function Reference is bad");
988 declare
989 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
990 TC : constant Tamper_Counts_Access :=
991 HT.TC'Unrestricted_Access;
992 begin
993 return R : constant Reference_Type :=
994 (Element => Position.Node.Element'Access,
995 Control => (Controlled with TC))
997 Busy (TC.all);
998 end return;
999 end;
1000 end Reference;
1002 function Reference
1003 (Container : aliased in out Map;
1004 Key : Key_Type) return Reference_Type
1006 HT : Hash_Table_Type renames Container.HT;
1007 Node : constant Node_Access := Key_Ops.Find (HT, Key);
1009 begin
1010 if Checks and then Node = null then
1011 raise Constraint_Error with "key not in map";
1012 end if;
1014 declare
1015 TC : constant Tamper_Counts_Access :=
1016 HT.TC'Unrestricted_Access;
1017 begin
1018 return R : constant Reference_Type :=
1019 (Element => Node.Element'Access,
1020 Control => (Controlled with TC))
1022 Busy (TC.all);
1023 end return;
1024 end;
1025 end Reference;
1027 ---------------
1028 -- Read_Node --
1029 ---------------
1031 function Read_Node
1032 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1034 Node : Node_Access := new Node_Type;
1036 begin
1037 Key_Type'Read (Stream, Node.Key);
1038 Element_Type'Read (Stream, Node.Element);
1039 return Node;
1041 exception
1042 when others =>
1043 Free (Node);
1044 raise;
1045 end Read_Node;
1047 -------------
1048 -- Replace --
1049 -------------
1051 procedure Replace
1052 (Container : in out Map;
1053 Key : Key_Type;
1054 New_Item : Element_Type)
1056 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
1058 begin
1059 TE_Check (Container.HT.TC);
1061 if Checks and then Node = null then
1062 raise Constraint_Error with
1063 "attempt to replace key not in map";
1064 end if;
1066 Node.Key := Key;
1067 Node.Element := New_Item;
1068 end Replace;
1070 ---------------------
1071 -- Replace_Element --
1072 ---------------------
1074 procedure Replace_Element
1075 (Container : in out Map;
1076 Position : Cursor;
1077 New_Item : Element_Type)
1079 begin
1080 TE_Check (Position.Container.HT.TC);
1082 if Checks and then Position.Node = null then
1083 raise Constraint_Error with
1084 "Position cursor of Replace_Element equals No_Element";
1085 end if;
1087 if Checks and then Position.Container /= Container'Unrestricted_Access
1088 then
1089 raise Program_Error with
1090 "Position cursor of Replace_Element designates wrong map";
1091 end if;
1093 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1095 Position.Node.Element := New_Item;
1096 end Replace_Element;
1098 ----------------------
1099 -- Reserve_Capacity --
1100 ----------------------
1102 procedure Reserve_Capacity
1103 (Container : in out Map;
1104 Capacity : Count_Type)
1106 begin
1107 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1108 end Reserve_Capacity;
1110 --------------
1111 -- Set_Next --
1112 --------------
1114 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1115 begin
1116 Node.Next := Next;
1117 end Set_Next;
1119 --------------------
1120 -- Update_Element --
1121 --------------------
1123 procedure Update_Element
1124 (Container : in out Map;
1125 Position : Cursor;
1126 Process : not null access procedure (Key : Key_Type;
1127 Element : in out Element_Type))
1129 begin
1130 if Checks and then Position.Node = null then
1131 raise Constraint_Error with
1132 "Position cursor of Update_Element equals No_Element";
1133 end if;
1135 if Checks and then Position.Container /= Container'Unrestricted_Access
1136 then
1137 raise Program_Error with
1138 "Position cursor of Update_Element designates wrong map";
1139 end if;
1141 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1143 declare
1144 HT : Hash_Table_Type renames Container.HT;
1145 Lock : With_Lock (HT.TC'Unrestricted_Access);
1146 K : Key_Type renames Position.Node.Key;
1147 E : Element_Type renames Position.Node.Element;
1148 begin
1149 Process (K, E);
1150 end;
1151 end Update_Element;
1153 ---------
1154 -- Vet --
1155 ---------
1157 function Vet (Position : Cursor) return Boolean is
1158 begin
1159 if not Container_Checks'Enabled then
1160 return True;
1161 end if;
1163 if Position.Node = null then
1164 return Position.Container = null;
1165 end if;
1167 if Position.Container = null then
1168 return False;
1169 end if;
1171 if Position.Node.Next = Position.Node then
1172 return False;
1173 end if;
1175 declare
1176 HT : Hash_Table_Type renames Position.Container.HT;
1177 X : Node_Access;
1179 begin
1180 if HT.Length = 0 then
1181 return False;
1182 end if;
1184 if HT.Buckets = null
1185 or else HT.Buckets'Length = 0
1186 then
1187 return False;
1188 end if;
1190 X := HT.Buckets (Key_Ops.Checked_Index (HT, Position.Node.Key));
1192 for J in 1 .. HT.Length loop
1193 if X = Position.Node then
1194 return True;
1195 end if;
1197 if X = null then
1198 return False;
1199 end if;
1201 if X = X.Next then -- to prevent unnecessary looping
1202 return False;
1203 end if;
1205 X := X.Next;
1206 end loop;
1208 return False;
1209 end;
1210 end Vet;
1212 -----------
1213 -- Write --
1214 -----------
1216 procedure Write
1217 (Stream : not null access Root_Stream_Type'Class;
1218 Container : Map)
1220 begin
1221 Write_Nodes (Stream, Container.HT);
1222 end Write;
1224 procedure Write
1225 (Stream : not null access Root_Stream_Type'Class;
1226 Item : Cursor)
1228 begin
1229 raise Program_Error with "attempt to stream map cursor";
1230 end Write;
1232 procedure Write
1233 (Stream : not null access Root_Stream_Type'Class;
1234 Item : Reference_Type)
1236 begin
1237 raise Program_Error with "attempt to stream reference";
1238 end Write;
1240 procedure Write
1241 (Stream : not null access Root_Stream_Type'Class;
1242 Item : Constant_Reference_Type)
1244 begin
1245 raise Program_Error with "attempt to stream reference";
1246 end Write;
1248 ----------------
1249 -- Write_Node --
1250 ----------------
1252 procedure Write_Node
1253 (Stream : not null access Root_Stream_Type'Class;
1254 Node : Node_Access)
1256 begin
1257 Key_Type'Write (Stream, Node.Key);
1258 Element_Type'Write (Stream, Node.Element);
1259 end Write_Node;
1261 end Ada.Containers.Hashed_Maps;