2016-04-18 Ed Schonberg <schonberg@adacore.com>
[official-gcc.git] / gcc / ada / a-cbhama.adb
blob86c57e737ad0787a22cf22599d95521215c163e0
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ H A S H E D _ M A P S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2015, 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_Bounded_Operations;
31 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
33 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
34 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
36 with Ada.Containers.Helpers; use Ada.Containers.Helpers;
38 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
40 with System; use type System.Address;
42 package body Ada.Containers.Bounded_Hashed_Maps is
44 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
45 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
46 -- See comment in Ada.Containers.Helpers
48 -----------------------
49 -- Local Subprograms --
50 -----------------------
52 function Equivalent_Key_Node
53 (Key : Key_Type;
54 Node : Node_Type) return Boolean;
55 pragma Inline (Equivalent_Key_Node);
57 function Hash_Node (Node : Node_Type) return Hash_Type;
58 pragma Inline (Hash_Node);
60 function Next (Node : Node_Type) return Count_Type;
61 pragma Inline (Next);
63 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
64 pragma Inline (Set_Next);
66 function Vet (Position : Cursor) return Boolean;
68 --------------------------
69 -- Local Instantiations --
70 --------------------------
72 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
73 (HT_Types => HT_Types,
74 Hash_Node => Hash_Node,
75 Next => Next,
76 Set_Next => Set_Next);
78 package Key_Ops is new Hash_Tables.Generic_Bounded_Keys
79 (HT_Types => HT_Types,
80 Next => Next,
81 Set_Next => Set_Next,
82 Key_Type => Key_Type,
83 Hash => Hash,
84 Equivalent_Keys => Equivalent_Key_Node);
86 ---------
87 -- "=" --
88 ---------
90 function "=" (Left, Right : Map) return Boolean is
91 function Find_Equal_Key
92 (R_HT : Hash_Table_Type'Class;
93 L_Node : Node_Type) return Boolean;
95 function Is_Equal is new HT_Ops.Generic_Equal (Find_Equal_Key);
97 --------------------
98 -- Find_Equal_Key --
99 --------------------
101 function Find_Equal_Key
102 (R_HT : Hash_Table_Type'Class;
103 L_Node : Node_Type) return Boolean
105 R_Index : constant Hash_Type := Key_Ops.Index (R_HT, L_Node.Key);
106 R_Node : Count_Type := R_HT.Buckets (R_Index);
108 begin
109 while R_Node /= 0 loop
110 if Equivalent_Keys (L_Node.Key, R_HT.Nodes (R_Node).Key) then
111 return L_Node.Element = R_HT.Nodes (R_Node).Element;
112 end if;
114 R_Node := R_HT.Nodes (R_Node).Next;
115 end loop;
117 return False;
118 end Find_Equal_Key;
120 -- Start of processing for "="
122 begin
123 return Is_Equal (Left, Right);
124 end "=";
126 ------------
127 -- Assign --
128 ------------
130 procedure Assign (Target : in out Map; Source : Map) is
131 procedure Insert_Element (Source_Node : Count_Type);
133 procedure Insert_Elements is
134 new HT_Ops.Generic_Iteration (Insert_Element);
136 --------------------
137 -- Insert_Element --
138 --------------------
140 procedure Insert_Element (Source_Node : Count_Type) is
141 N : Node_Type renames Source.Nodes (Source_Node);
142 C : Cursor;
143 B : Boolean;
145 begin
146 Insert (Target, N.Key, N.Element, C, B);
147 pragma Assert (B);
148 end Insert_Element;
150 -- Start of processing for Assign
152 begin
153 if Target'Address = Source'Address then
154 return;
155 end if;
157 if Checks and then Target.Capacity < Source.Length then
158 raise Capacity_Error
159 with "Target capacity is less than Source length";
160 end if;
162 HT_Ops.Clear (Target);
163 Insert_Elements (Source);
164 end Assign;
166 --------------
167 -- Capacity --
168 --------------
170 function Capacity (Container : Map) return Count_Type is
171 begin
172 return Container.Capacity;
173 end Capacity;
175 -----------
176 -- Clear --
177 -----------
179 procedure Clear (Container : in out Map) is
180 begin
181 HT_Ops.Clear (Container);
182 end Clear;
184 ------------------------
185 -- Constant_Reference --
186 ------------------------
188 function Constant_Reference
189 (Container : aliased Map;
190 Position : Cursor) return Constant_Reference_Type
192 begin
193 if Checks and then Position.Container = null then
194 raise Constraint_Error with
195 "Position cursor has no element";
196 end if;
198 if Checks and then Position.Container /= Container'Unrestricted_Access
199 then
200 raise Program_Error with
201 "Position cursor designates wrong map";
202 end if;
204 pragma Assert (Vet (Position),
205 "Position cursor in Constant_Reference is bad");
207 declare
208 N : Node_Type renames Container.Nodes (Position.Node);
209 TC : constant Tamper_Counts_Access :=
210 Container.TC'Unrestricted_Access;
211 begin
212 return R : constant Constant_Reference_Type :=
213 (Element => N.Element'Access,
214 Control => (Controlled with TC))
216 Lock (TC.all);
217 end return;
218 end;
219 end Constant_Reference;
221 function Constant_Reference
222 (Container : aliased Map;
223 Key : Key_Type) return Constant_Reference_Type
225 Node : constant Count_Type :=
226 Key_Ops.Find (Container'Unrestricted_Access.all, Key);
228 begin
229 if Checks and then Node = 0 then
230 raise Constraint_Error with "key not in map";
231 end if;
233 declare
234 N : Node_Type renames Container.Nodes (Node);
235 TC : constant Tamper_Counts_Access :=
236 Container.TC'Unrestricted_Access;
237 begin
238 return R : constant Constant_Reference_Type :=
239 (Element => N.Element'Access,
240 Control => (Controlled with TC))
242 Lock (TC.all);
243 end return;
244 end;
245 end Constant_Reference;
247 --------------
248 -- Contains --
249 --------------
251 function Contains (Container : Map; Key : Key_Type) return Boolean is
252 begin
253 return Find (Container, Key) /= No_Element;
254 end Contains;
256 ----------
257 -- Copy --
258 ----------
260 function Copy
261 (Source : Map;
262 Capacity : Count_Type := 0;
263 Modulus : Hash_Type := 0) return Map
265 C : Count_Type;
266 M : Hash_Type;
268 begin
269 if Capacity = 0 then
270 C := Source.Length;
272 elsif Capacity >= Source.Length then
273 C := Capacity;
275 elsif Checks then
276 raise Capacity_Error with "Capacity value too small";
277 end if;
279 if Modulus = 0 then
280 M := Default_Modulus (C);
281 else
282 M := Modulus;
283 end if;
285 return Target : Map (Capacity => C, Modulus => M) do
286 Assign (Target => Target, Source => Source);
287 end return;
288 end Copy;
290 ---------------------
291 -- Default_Modulus --
292 ---------------------
294 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
295 begin
296 return To_Prime (Capacity);
297 end Default_Modulus;
299 ------------
300 -- Delete --
301 ------------
303 procedure Delete (Container : in out Map; Key : Key_Type) is
304 X : Count_Type;
306 begin
307 Key_Ops.Delete_Key_Sans_Free (Container, Key, X);
309 if Checks and then X = 0 then
310 raise Constraint_Error with "attempt to delete key not in map";
311 end if;
313 HT_Ops.Free (Container, X);
314 end Delete;
316 procedure Delete (Container : in out Map; Position : in out Cursor) is
317 begin
318 if Checks and then Position.Node = 0 then
319 raise Constraint_Error with
320 "Position cursor of Delete equals No_Element";
321 end if;
323 if Checks and then Position.Container /= Container'Unrestricted_Access
324 then
325 raise Program_Error with
326 "Position cursor of Delete designates wrong map";
327 end if;
329 TC_Check (Container.TC);
331 pragma Assert (Vet (Position), "bad cursor in Delete");
333 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
334 HT_Ops.Free (Container, Position.Node);
336 Position := No_Element;
337 end Delete;
339 -------------
340 -- Element --
341 -------------
343 function Element (Container : Map; Key : Key_Type) return Element_Type is
344 Node : constant Count_Type :=
345 Key_Ops.Find (Container'Unrestricted_Access.all, Key);
347 begin
348 if Checks and then Node = 0 then
349 raise Constraint_Error with
350 "no element available because key not in map";
351 end if;
353 return Container.Nodes (Node).Element;
354 end Element;
356 function Element (Position : Cursor) return Element_Type is
357 begin
358 if Checks and then Position.Node = 0 then
359 raise Constraint_Error with
360 "Position cursor of function Element equals No_Element";
361 end if;
363 pragma Assert (Vet (Position), "bad cursor in function Element");
365 return Position.Container.Nodes (Position.Node).Element;
366 end Element;
368 -------------------------
369 -- Equivalent_Key_Node --
370 -------------------------
372 function Equivalent_Key_Node
373 (Key : Key_Type;
374 Node : Node_Type) return Boolean is
375 begin
376 return Equivalent_Keys (Key, Node.Key);
377 end Equivalent_Key_Node;
379 ---------------------
380 -- Equivalent_Keys --
381 ---------------------
383 function Equivalent_Keys (Left, Right : Cursor)
384 return Boolean is
385 begin
386 if Checks and then Left.Node = 0 then
387 raise Constraint_Error with
388 "Left cursor of Equivalent_Keys equals No_Element";
389 end if;
391 if Checks and then Right.Node = 0 then
392 raise Constraint_Error with
393 "Right cursor of Equivalent_Keys equals No_Element";
394 end if;
396 pragma Assert (Vet (Left), "Left cursor of Equivalent_Keys is bad");
397 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
399 declare
400 LN : Node_Type renames Left.Container.Nodes (Left.Node);
401 RN : Node_Type renames Right.Container.Nodes (Right.Node);
403 begin
404 return Equivalent_Keys (LN.Key, RN.Key);
405 end;
406 end Equivalent_Keys;
408 function Equivalent_Keys (Left : Cursor; Right : Key_Type) return Boolean is
409 begin
410 if Checks and then Left.Node = 0 then
411 raise Constraint_Error with
412 "Left cursor of Equivalent_Keys equals No_Element";
413 end if;
415 pragma Assert (Vet (Left), "Left cursor in Equivalent_Keys is bad");
417 declare
418 LN : Node_Type renames Left.Container.Nodes (Left.Node);
420 begin
421 return Equivalent_Keys (LN.Key, Right);
422 end;
423 end Equivalent_Keys;
425 function Equivalent_Keys (Left : Key_Type; Right : Cursor) return Boolean is
426 begin
427 if Checks and then Right.Node = 0 then
428 raise Constraint_Error with
429 "Right cursor of Equivalent_Keys equals No_Element";
430 end if;
432 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
434 declare
435 RN : Node_Type renames Right.Container.Nodes (Right.Node);
437 begin
438 return Equivalent_Keys (Left, RN.Key);
439 end;
440 end Equivalent_Keys;
442 -------------
443 -- Exclude --
444 -------------
446 procedure Exclude (Container : in out Map; Key : Key_Type) is
447 X : Count_Type;
448 begin
449 Key_Ops.Delete_Key_Sans_Free (Container, Key, X);
450 HT_Ops.Free (Container, X);
451 end Exclude;
453 --------------
454 -- Finalize --
455 --------------
457 procedure Finalize (Object : in out Iterator) is
458 begin
459 if Object.Container /= null then
460 Unbusy (Object.Container.TC);
461 end if;
462 end Finalize;
464 ----------
465 -- Find --
466 ----------
468 function Find (Container : Map; Key : Key_Type) return Cursor is
469 Node : constant Count_Type :=
470 Key_Ops.Find (Container'Unrestricted_Access.all, Key);
471 begin
472 if Node = 0 then
473 return No_Element;
474 else
475 return Cursor'(Container'Unrestricted_Access, Node);
476 end if;
477 end Find;
479 -----------
480 -- First --
481 -----------
483 function First (Container : Map) return Cursor is
484 Node : constant Count_Type := HT_Ops.First (Container);
485 begin
486 if Node = 0 then
487 return No_Element;
488 else
489 return Cursor'(Container'Unrestricted_Access, Node);
490 end if;
491 end First;
493 function First (Object : Iterator) return Cursor is
494 begin
495 return Object.Container.First;
496 end First;
498 ------------------------
499 -- Get_Element_Access --
500 ------------------------
502 function Get_Element_Access
503 (Position : Cursor) return not null Element_Access is
504 begin
505 return Position.Container.Nodes (Position.Node).Element'Access;
506 end Get_Element_Access;
508 -----------------
509 -- Has_Element --
510 -----------------
512 function Has_Element (Position : Cursor) return Boolean is
513 begin
514 pragma Assert (Vet (Position), "bad cursor in Has_Element");
515 return Position.Node /= 0;
516 end Has_Element;
518 ---------------
519 -- Hash_Node --
520 ---------------
522 function Hash_Node (Node : Node_Type) return Hash_Type is
523 begin
524 return Hash (Node.Key);
525 end Hash_Node;
527 -------------
528 -- Include --
529 -------------
531 procedure Include
532 (Container : in out Map;
533 Key : Key_Type;
534 New_Item : Element_Type)
536 Position : Cursor;
537 Inserted : Boolean;
539 begin
540 Insert (Container, Key, New_Item, Position, Inserted);
542 if not Inserted then
543 TE_Check (Container.TC);
545 declare
546 N : Node_Type renames Container.Nodes (Position.Node);
547 begin
548 N.Key := Key;
549 N.Element := New_Item;
550 end;
551 end if;
552 end Include;
554 ------------
555 -- Insert --
556 ------------
558 procedure Insert
559 (Container : in out Map;
560 Key : Key_Type;
561 Position : out Cursor;
562 Inserted : out Boolean)
564 procedure Assign_Key (Node : in out Node_Type);
565 pragma Inline (Assign_Key);
567 function New_Node return Count_Type;
568 pragma Inline (New_Node);
570 procedure Local_Insert is
571 new Key_Ops.Generic_Conditional_Insert (New_Node);
573 procedure Allocate is
574 new HT_Ops.Generic_Allocate (Assign_Key);
576 -----------------
577 -- Assign_Key --
578 -----------------
580 procedure Assign_Key (Node : in out Node_Type) is
581 New_Item : Element_Type;
582 pragma Unmodified (New_Item);
583 -- Default-initialized element (ok to reference, see below)
585 begin
586 Node.Key := Key;
588 -- There is no explicit element provided, but in an instance the
589 -- element type may be a scalar with a Default_Value aspect, or a
590 -- composite type with such a scalar component, or components with
591 -- default initialization, so insert a possibly initialized element
592 -- under the given key.
594 Node.Element := New_Item;
595 end Assign_Key;
597 --------------
598 -- New_Node --
599 --------------
601 function New_Node return Count_Type is
602 Result : Count_Type;
603 begin
604 Allocate (Container, Result);
605 return Result;
606 end New_Node;
608 -- Start of processing for Insert
610 begin
611 -- The buckets array length is specified by the user as a discriminant
612 -- of the container type, so it is possible for the buckets array to
613 -- have a length of zero. We must check for this case specifically, in
614 -- order to prevent divide-by-zero errors later, when we compute the
615 -- buckets array index value for a key, given its hash value.
617 if Checks and then Container.Buckets'Length = 0 then
618 raise Capacity_Error with "No capacity for insertion";
619 end if;
621 Local_Insert (Container, Key, Position.Node, Inserted);
622 Position.Container := Container'Unchecked_Access;
623 end Insert;
625 procedure Insert
626 (Container : in out Map;
627 Key : Key_Type;
628 New_Item : Element_Type;
629 Position : out Cursor;
630 Inserted : out Boolean)
632 procedure Assign_Key (Node : in out Node_Type);
633 pragma Inline (Assign_Key);
635 function New_Node return Count_Type;
636 pragma Inline (New_Node);
638 procedure Local_Insert is
639 new Key_Ops.Generic_Conditional_Insert (New_Node);
641 procedure Allocate is
642 new HT_Ops.Generic_Allocate (Assign_Key);
644 -----------------
645 -- Assign_Key --
646 -----------------
648 procedure Assign_Key (Node : in out Node_Type) is
649 begin
650 Node.Key := Key;
651 Node.Element := New_Item;
652 end Assign_Key;
654 --------------
655 -- New_Node --
656 --------------
658 function New_Node return Count_Type is
659 Result : Count_Type;
660 begin
661 Allocate (Container, Result);
662 return Result;
663 end New_Node;
665 -- Start of processing for Insert
667 begin
668 -- The buckets array length is specified by the user as a discriminant
669 -- of the container type, so it is possible for the buckets array to
670 -- have a length of zero. We must check for this case specifically, in
671 -- order to prevent divide-by-zero errors later, when we compute the
672 -- buckets array index value for a key, given its hash value.
674 if Checks and then Container.Buckets'Length = 0 then
675 raise Capacity_Error with "No capacity for insertion";
676 end if;
678 Local_Insert (Container, Key, Position.Node, Inserted);
679 Position.Container := Container'Unchecked_Access;
680 end Insert;
682 procedure Insert
683 (Container : in out Map;
684 Key : Key_Type;
685 New_Item : Element_Type)
687 Position : Cursor;
688 pragma Unreferenced (Position);
690 Inserted : Boolean;
692 begin
693 Insert (Container, Key, New_Item, Position, Inserted);
695 if Checks and then not Inserted then
696 raise Constraint_Error with
697 "attempt to insert key already in map";
698 end if;
699 end Insert;
701 --------------
702 -- Is_Empty --
703 --------------
705 function Is_Empty (Container : Map) return Boolean is
706 begin
707 return Container.Length = 0;
708 end Is_Empty;
710 -------------
711 -- Iterate --
712 -------------
714 procedure Iterate
715 (Container : Map;
716 Process : not null access procedure (Position : Cursor))
718 procedure Process_Node (Node : Count_Type);
719 pragma Inline (Process_Node);
721 procedure Local_Iterate is new HT_Ops.Generic_Iteration (Process_Node);
723 ------------------
724 -- Process_Node --
725 ------------------
727 procedure Process_Node (Node : Count_Type) is
728 begin
729 Process (Cursor'(Container'Unrestricted_Access, Node));
730 end Process_Node;
732 Busy : With_Busy (Container.TC'Unrestricted_Access);
734 -- Start of processing for Iterate
736 begin
737 Local_Iterate (Container);
738 end Iterate;
740 function Iterate
741 (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class
743 begin
744 return It : constant Iterator :=
745 (Limited_Controlled with
746 Container => Container'Unrestricted_Access)
748 Busy (Container.TC'Unrestricted_Access.all);
749 end return;
750 end Iterate;
752 ---------
753 -- Key --
754 ---------
756 function Key (Position : Cursor) return Key_Type is
757 begin
758 if Checks and then Position.Node = 0 then
759 raise Constraint_Error with
760 "Position cursor of function Key equals No_Element";
761 end if;
763 pragma Assert (Vet (Position), "bad cursor in function Key");
765 return Position.Container.Nodes (Position.Node).Key;
766 end Key;
768 ------------
769 -- Length --
770 ------------
772 function Length (Container : Map) return Count_Type is
773 begin
774 return Container.Length;
775 end Length;
777 ----------
778 -- Move --
779 ----------
781 procedure Move
782 (Target : in out Map;
783 Source : in out Map)
785 begin
786 if Target'Address = Source'Address then
787 return;
788 end if;
790 TC_Check (Source.TC);
792 Target.Assign (Source);
793 Source.Clear;
794 end Move;
796 ----------
797 -- Next --
798 ----------
800 function Next (Node : Node_Type) return Count_Type is
801 begin
802 return Node.Next;
803 end Next;
805 function Next (Position : Cursor) return Cursor is
806 begin
807 if Position.Node = 0 then
808 return No_Element;
809 end if;
811 pragma Assert (Vet (Position), "bad cursor in function Next");
813 declare
814 M : Map renames Position.Container.all;
815 Node : constant Count_Type := HT_Ops.Next (M, Position.Node);
816 begin
817 if Node = 0 then
818 return No_Element;
819 else
820 return Cursor'(Position.Container, Node);
821 end if;
822 end;
823 end Next;
825 procedure Next (Position : in out Cursor) is
826 begin
827 Position := Next (Position);
828 end Next;
830 function Next
831 (Object : Iterator;
832 Position : Cursor) return Cursor
834 begin
835 if Position.Container = null then
836 return No_Element;
837 end if;
839 if Checks and then Position.Container /= Object.Container then
840 raise Program_Error with
841 "Position cursor of Next designates wrong map";
842 end if;
844 return Next (Position);
845 end Next;
847 ----------------------
848 -- Pseudo_Reference --
849 ----------------------
851 function Pseudo_Reference
852 (Container : aliased Map'Class) return Reference_Control_Type
854 TC : constant Tamper_Counts_Access :=
855 Container.TC'Unrestricted_Access;
856 begin
857 return R : constant Reference_Control_Type := (Controlled with TC) do
858 Lock (TC.all);
859 end return;
860 end Pseudo_Reference;
862 -------------------
863 -- Query_Element --
864 -------------------
866 procedure Query_Element
867 (Position : Cursor;
868 Process : not null access
869 procedure (Key : Key_Type; Element : Element_Type))
871 begin
872 if Checks and then Position.Node = 0 then
873 raise Constraint_Error with
874 "Position cursor of Query_Element equals No_Element";
875 end if;
877 pragma Assert (Vet (Position), "bad cursor in Query_Element");
879 declare
880 M : Map renames Position.Container.all;
881 N : Node_Type renames M.Nodes (Position.Node);
882 Lock : With_Lock (M.TC'Unrestricted_Access);
883 begin
884 Process (N.Key, N.Element);
885 end;
886 end Query_Element;
888 ----------
889 -- Read --
890 ----------
892 procedure Read
893 (Stream : not null access Root_Stream_Type'Class;
894 Container : out Map)
896 function Read_Node
897 (Stream : not null access Root_Stream_Type'Class) return Count_Type;
898 -- pragma Inline (Read_Node); ???
900 procedure Read_Nodes is new HT_Ops.Generic_Read (Read_Node);
902 ---------------
903 -- Read_Node --
904 ---------------
906 function Read_Node
907 (Stream : not null access Root_Stream_Type'Class) return Count_Type
909 procedure Read_Element (Node : in out Node_Type);
910 -- pragma Inline (Read_Element); ???
912 procedure Allocate is
913 new HT_Ops.Generic_Allocate (Read_Element);
915 procedure Read_Element (Node : in out Node_Type) is
916 begin
917 Key_Type'Read (Stream, Node.Key);
918 Element_Type'Read (Stream, Node.Element);
919 end Read_Element;
921 Node : Count_Type;
923 -- Start of processing for Read_Node
925 begin
926 Allocate (Container, Node);
927 return Node;
928 end Read_Node;
930 -- Start of processing for Read
932 begin
933 Read_Nodes (Stream, Container);
934 end Read;
936 procedure Read
937 (Stream : not null access Root_Stream_Type'Class;
938 Item : out Cursor)
940 begin
941 raise Program_Error with "attempt to stream map cursor";
942 end Read;
944 procedure Read
945 (Stream : not null access Root_Stream_Type'Class;
946 Item : out Reference_Type)
948 begin
949 raise Program_Error with "attempt to stream reference";
950 end Read;
952 procedure Read
953 (Stream : not null access Root_Stream_Type'Class;
954 Item : out Constant_Reference_Type)
956 begin
957 raise Program_Error with "attempt to stream reference";
958 end Read;
960 ---------------
961 -- Reference --
962 ---------------
964 function Reference
965 (Container : aliased in out Map;
966 Position : Cursor) return Reference_Type
968 begin
969 if Checks and then Position.Container = null then
970 raise Constraint_Error with
971 "Position cursor has no element";
972 end if;
974 if Checks and then Position.Container /= Container'Unrestricted_Access
975 then
976 raise Program_Error with
977 "Position cursor designates wrong map";
978 end if;
980 pragma Assert (Vet (Position),
981 "Position cursor in function Reference is bad");
983 declare
984 N : Node_Type renames Container.Nodes (Position.Node);
985 TC : constant Tamper_Counts_Access :=
986 Container.TC'Unrestricted_Access;
987 begin
988 return R : constant Reference_Type :=
989 (Element => N.Element'Access,
990 Control => (Controlled with TC))
992 Lock (TC.all);
993 end return;
994 end;
995 end Reference;
997 function Reference
998 (Container : aliased in out Map;
999 Key : Key_Type) return Reference_Type
1001 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1003 begin
1004 if Checks and then Node = 0 then
1005 raise Constraint_Error with "key not in map";
1006 end if;
1008 declare
1009 N : Node_Type renames Container.Nodes (Node);
1010 TC : constant Tamper_Counts_Access :=
1011 Container.TC'Unrestricted_Access;
1012 begin
1013 return R : constant Reference_Type :=
1014 (Element => N.Element'Access,
1015 Control => (Controlled with TC))
1017 Lock (TC.all);
1018 end return;
1019 end;
1020 end Reference;
1022 -------------
1023 -- Replace --
1024 -------------
1026 procedure Replace
1027 (Container : in out Map;
1028 Key : Key_Type;
1029 New_Item : Element_Type)
1031 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1033 begin
1034 if Checks and then Node = 0 then
1035 raise Constraint_Error with
1036 "attempt to replace key not in map";
1037 end if;
1039 TE_Check (Container.TC);
1041 declare
1042 N : Node_Type renames Container.Nodes (Node);
1043 begin
1044 N.Key := Key;
1045 N.Element := New_Item;
1046 end;
1047 end Replace;
1049 ---------------------
1050 -- Replace_Element --
1051 ---------------------
1053 procedure Replace_Element
1054 (Container : in out Map;
1055 Position : Cursor;
1056 New_Item : Element_Type)
1058 begin
1059 if Checks and then Position.Node = 0 then
1060 raise Constraint_Error with
1061 "Position cursor of Replace_Element equals No_Element";
1062 end if;
1064 if Checks and then Position.Container /= Container'Unrestricted_Access
1065 then
1066 raise Program_Error with
1067 "Position cursor of Replace_Element designates wrong map";
1068 end if;
1070 TE_Check (Position.Container.TC);
1072 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1074 Container.Nodes (Position.Node).Element := New_Item;
1075 end Replace_Element;
1077 ----------------------
1078 -- Reserve_Capacity --
1079 ----------------------
1081 procedure Reserve_Capacity
1082 (Container : in out Map;
1083 Capacity : Count_Type)
1085 begin
1086 if Checks and then Capacity > Container.Capacity then
1087 raise Capacity_Error with "requested capacity is too large";
1088 end if;
1089 end Reserve_Capacity;
1091 --------------
1092 -- Set_Next --
1093 --------------
1095 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1096 begin
1097 Node.Next := Next;
1098 end Set_Next;
1100 --------------------
1101 -- Update_Element --
1102 --------------------
1104 procedure Update_Element
1105 (Container : in out Map;
1106 Position : Cursor;
1107 Process : not null access procedure (Key : Key_Type;
1108 Element : in out Element_Type))
1110 begin
1111 if Checks and then Position.Node = 0 then
1112 raise Constraint_Error with
1113 "Position cursor of Update_Element equals No_Element";
1114 end if;
1116 if Checks and then Position.Container /= Container'Unrestricted_Access
1117 then
1118 raise Program_Error with
1119 "Position cursor of Update_Element designates wrong map";
1120 end if;
1122 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1124 declare
1125 N : Node_Type renames Container.Nodes (Position.Node);
1126 Lock : With_Lock (Container.TC'Unrestricted_Access);
1127 begin
1128 Process (N.Key, N.Element);
1129 end;
1130 end Update_Element;
1132 ---------
1133 -- Vet --
1134 ---------
1136 function Vet (Position : Cursor) return Boolean is
1137 begin
1138 if Position.Node = 0 then
1139 return Position.Container = null;
1140 end if;
1142 if Position.Container = null then
1143 return False;
1144 end if;
1146 declare
1147 M : Map renames Position.Container.all;
1148 X : Count_Type;
1150 begin
1151 if M.Length = 0 then
1152 return False;
1153 end if;
1155 if M.Capacity = 0 then
1156 return False;
1157 end if;
1159 if M.Buckets'Length = 0 then
1160 return False;
1161 end if;
1163 if Position.Node > M.Capacity then
1164 return False;
1165 end if;
1167 if M.Nodes (Position.Node).Next = Position.Node then
1168 return False;
1169 end if;
1171 X := M.Buckets (Key_Ops.Checked_Index
1172 (M, M.Nodes (Position.Node).Key));
1174 for J in 1 .. M.Length loop
1175 if X = Position.Node then
1176 return True;
1177 end if;
1179 if X = 0 then
1180 return False;
1181 end if;
1183 if X = M.Nodes (X).Next then -- to prevent unnecessary looping
1184 return False;
1185 end if;
1187 X := M.Nodes (X).Next;
1188 end loop;
1190 return False;
1191 end;
1192 end Vet;
1194 -----------
1195 -- Write --
1196 -----------
1198 procedure Write
1199 (Stream : not null access Root_Stream_Type'Class;
1200 Container : Map)
1202 procedure Write_Node
1203 (Stream : not null access Root_Stream_Type'Class;
1204 Node : Node_Type);
1205 pragma Inline (Write_Node);
1207 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
1209 ----------------
1210 -- Write_Node --
1211 ----------------
1213 procedure Write_Node
1214 (Stream : not null access Root_Stream_Type'Class;
1215 Node : Node_Type)
1217 begin
1218 Key_Type'Write (Stream, Node.Key);
1219 Element_Type'Write (Stream, Node.Element);
1220 end Write_Node;
1222 -- Start of processing for Write
1224 begin
1225 Write_Nodes (Stream, Container);
1226 end Write;
1228 procedure Write
1229 (Stream : not null access Root_Stream_Type'Class;
1230 Item : Cursor)
1232 begin
1233 raise Program_Error with "attempt to stream map cursor";
1234 end Write;
1236 procedure Write
1237 (Stream : not null access Root_Stream_Type'Class;
1238 Item : Reference_Type)
1240 begin
1241 raise Program_Error with "attempt to stream reference";
1242 end Write;
1244 procedure Write
1245 (Stream : not null access Root_Stream_Type'Class;
1246 Item : Constant_Reference_Type)
1248 begin
1249 raise Program_Error with "attempt to stream reference";
1250 end Write;
1252 end Ada.Containers.Bounded_Hashed_Maps;