1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . F O R M A L _ H A S H E D _ M A P S --
9 -- Copyright (C) 2010, Free Software Foundation, Inc. --
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. --
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. --
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 ------------------------------------------------------------------------------
28 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
29 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
31 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
32 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
34 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
36 with System; use type System.Address;
38 package body Ada.Containers.Formal_Hashed_Maps is
40 -----------------------
41 -- Local Subprograms --
42 -----------------------
44 function Equivalent_Keys
46 Node : Node_Type) return Boolean;
47 pragma Inline (Equivalent_Keys);
50 (HT : Hash_Table_Type;
53 To : Count_Type) return Count_Type;
56 (HT : in out Hash_Table_Type;
60 with procedure Set_Element (Node : in out Node_Type);
61 procedure Generic_Allocate
62 (HT : in out Hash_Table_Type;
63 Node : out Count_Type);
65 function Hash_Node (Node : Node_Type) return Hash_Type;
66 pragma Inline (Hash_Node);
68 function Next_Unchecked
70 Position : Cursor) return Cursor;
72 function Next (Node : Node_Type) return Count_Type;
75 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
76 pragma Inline (Set_Next);
78 function Vet (Container : Map; Position : Cursor) return Boolean;
80 --------------------------
81 -- Local Instantiations --
82 --------------------------
85 new Hash_Tables.Generic_Bounded_Operations
86 (HT_Types => HT_Types,
87 Hash_Node => Hash_Node,
89 Set_Next => Set_Next);
92 new Hash_Tables.Generic_Bounded_Keys
93 (HT_Types => HT_Types,
98 Equivalent_Keys => Equivalent_Keys);
104 function "=" (Left, Right : Map) return Boolean is
107 if Length (Left) /= Length (Right) then
111 if Length (Left) = 0 then
116 Node : Count_Type := First (Left).Node;
121 if Left.K = Plain then
124 Last := HT_Ops.Next (Left.HT.all, Left.Last);
127 while Node /= Last loop
128 ENode := Find (Container => Right,
129 Key => Left.HT.Nodes (Node).Key).Node;
131 Right.HT.Nodes (ENode).Element /= Left.HT.Nodes (Node).Element
136 Node := HT_Ops.Next (Left.HT.all, Node);
149 procedure Assign (Target : in out Map; Source : Map) is
150 procedure Insert_Element (Source_Node : Count_Type);
151 pragma Inline (Insert_Element);
153 procedure Insert_Elements is
154 new HT_Ops.Generic_Iteration (Insert_Element);
160 procedure Insert_Element (Source_Node : Count_Type) is
161 N : Node_Type renames Source.HT.Nodes (Source_Node);
163 Target.Insert (N.Key, N.Element);
166 -- Start of processing for Assign
169 if Target.K /= Plain then
170 raise Constraint_Error
171 with "Can't modify part of container";
174 if Target'Address = Source'Address then
178 if Target.Capacity < Length (Source) then
179 raise Constraint_Error with -- correct exception ???
180 "Source length exceeds Target capacity";
183 Clear (Target); -- checks busy bits
187 Insert_Elements (Source.HT.all);
190 N : Count_Type := Source.First;
192 while N /= HT_Ops.Next (Source.HT.all, Source.Last) loop
194 N := HT_Ops.Next (Source.HT.all, N);
204 function Capacity (Container : Map) return Count_Type is
206 return Container.HT.Nodes'Length;
213 procedure Clear (Container : in out Map) is
216 if Container.K /= Plain then
217 raise Constraint_Error
218 with "Can't modify part of container";
221 HT_Ops.Clear (Container.HT.all);
228 function Contains (Container : Map; Key : Key_Type) return Boolean is
230 return Find (Container, Key) /= No_Element;
239 Capacity : Count_Type := 0) return Map
241 C : constant Count_Type :=
242 Count_Type'Max (Capacity, Source.Capacity);
245 Target : Map (C, Source.Modulus);
248 if (Source.K = Part and Source.Length = 0) or
249 Source.HT.Length = 0 then
253 Target.HT.Length := Source.HT.Length;
254 Target.HT.Free := Source.HT.Free;
255 while H <= Source.Modulus loop
256 Target.HT.Buckets (H) := Source.HT.Buckets (H);
259 while N <= Source.Capacity loop
260 Target.HT.Nodes (N) := Source.HT.Nodes (N);
265 Free (Target.HT.all, Cu.Node);
268 if Source.K = Part then
269 N := HT_Ops.First (Target.HT.all);
270 while N /= Source.First loop
272 N := HT_Ops.Next (Target.HT.all, N);
275 N := HT_Ops.Next (Target.HT.all, Source.Last);
278 N := HT_Ops.Next (Target.HT.all, N);
285 ---------------------
286 -- Default_Modulus --
287 ---------------------
289 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
291 return To_Prime (Capacity);
298 procedure Delete (Container : in out Map; Key : Key_Type) is
303 if Container.K /= Plain then
304 raise Constraint_Error
305 with "Can't modify part of container";
308 Key_Ops.Delete_Key_Sans_Free (Container.HT.all, Key, X);
311 raise Constraint_Error with "attempt to delete key not in map";
314 Free (Container.HT.all, X);
317 procedure Delete (Container : in out Map; Position : in out Cursor) is
320 if Container.K /= Plain then
321 raise Constraint_Error
322 with "Can't modify part of container";
325 if not Has_Element (Container, Position) then
326 raise Constraint_Error with
327 "Position cursor of Delete has no element";
330 if Container.HT.Busy > 0 then
331 raise Program_Error with
332 "Delete attempted to tamper with elements (map is busy)";
335 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
337 HT_Ops.Delete_Node_Sans_Free (Container.HT.all, Position.Node);
339 Free (Container.HT.all, Position.Node);
346 function Element (Container : Map; Key : Key_Type) return Element_Type is
347 Node : constant Count_Type := Find (Container, Key).Node;
351 raise Constraint_Error with
352 "no element available because key not in map";
355 return Container.HT.Nodes (Node).Element;
358 function Element (Container : Map; Position : Cursor) return Element_Type is
360 if not Has_Element (Container, Position) then
361 raise Constraint_Error with "Position cursor equals No_Element";
364 pragma Assert (Vet (Container, Position),
365 "bad cursor in function Element");
367 return Container.HT.Nodes (Position.Node).Element;
370 ---------------------
371 -- Equivalent_Keys --
372 ---------------------
374 function Equivalent_Keys
376 Node : Node_Type) return Boolean is
378 return Equivalent_Keys (Key, Node.Key);
381 function Equivalent_Keys (Left : Map; CLeft : Cursor;
382 Right : Map; CRight : Cursor)
385 if not Has_Element (Left, CLeft) then
386 raise Constraint_Error with
387 "Left cursor of Equivalent_Keys has no element";
390 if not Has_Element (Right, CRight) then
391 raise Constraint_Error with
392 "Right cursor of Equivalent_Keys has no element";
395 pragma Assert (Vet (Left, CLeft),
396 "Left cursor of Equivalent_Keys is bad");
397 pragma Assert (Vet (Right, CRight),
398 "Right cursor of Equivalent_Keys is bad");
401 LT : Hash_Table_Type renames Left.HT.all;
402 RT : Hash_Table_Type renames Right.HT.all;
404 LN : Node_Type renames LT.Nodes (CLeft.Node);
405 RN : Node_Type renames RT.Nodes (CRight.Node);
408 return Equivalent_Keys (LN.Key, RN.Key);
412 function Equivalent_Keys
415 Right : Key_Type) return Boolean is
417 if not Has_Element (Left, CLeft) then
418 raise Constraint_Error with
419 "Left cursor of Equivalent_Keys has no element";
422 pragma Assert (Vet (Left, CLeft),
423 "Left cursor in Equivalent_Keys is bad");
426 LT : Hash_Table_Type renames Left.HT.all;
427 LN : Node_Type renames LT.Nodes (CLeft.Node);
430 return Equivalent_Keys (LN.Key, Right);
434 function Equivalent_Keys
437 CRight : Cursor) return Boolean is
439 if Has_Element (Right, CRight) then
440 raise Constraint_Error with
441 "Right cursor of Equivalent_Keys has no element";
444 pragma Assert (Vet (Right, CRight),
445 "Right cursor of Equivalent_Keys is bad");
448 RT : Hash_Table_Type renames Right.HT.all;
449 RN : Node_Type renames RT.Nodes (CRight.Node);
452 return Equivalent_Keys (Left, RN.Key);
460 procedure Exclude (Container : in out Map; Key : Key_Type) is
464 if Container.K /= Plain then
465 raise Constraint_Error
466 with "Can't modify part of container";
469 Key_Ops.Delete_Key_Sans_Free (Container.HT.all, Key, X);
470 Free (Container.HT.all, X);
476 function Find_Between
477 (HT : Hash_Table_Type;
480 To : Count_Type) return Count_Type is
483 Indx_From : constant Hash_Type :=
484 Key_Ops.Index (HT, HT.Nodes (From).Key);
485 Indx_To : constant Hash_Type :=
486 Key_Ops.Index (HT, HT.Nodes (To).Key);
488 To_Node : Count_Type;
492 Indx := Key_Ops.Index (HT, Key);
494 if Indx < Indx_From or Indx > Indx_To then
498 if Indx = Indx_From then
501 Node := HT.Buckets (Indx);
504 if Indx = Indx_To then
505 To_Node := HT.Nodes (To).Next;
510 while Node /= To_Node loop
511 if Equivalent_Keys (Key, HT.Nodes (Node)) then
514 Node := HT.Nodes (Node).Next;
519 function Find (Container : Map; Key : Key_Type) return Cursor is
524 Node : constant Count_Type :=
525 Key_Ops.Find (Container.HT.all, Key);
532 return (Node => Node);
535 if Container.Length = 0 then
539 return (Node => Find_Between (Container.HT.all, Key,
540 Container.First, Container.Last));
548 function First (Container : Map) return Cursor is
553 Node : constant Count_Type := HT_Ops.First (Container.HT.all);
560 return (Node => Node);
564 Node : constant Count_Type := Container.First;
571 return (Node => Node);
581 (HT : in out Hash_Table_Type;
585 HT.Nodes (X).Has_Element := False;
589 ----------------------
590 -- Generic_Allocate --
591 ----------------------
593 procedure Generic_Allocate
594 (HT : in out Hash_Table_Type;
595 Node : out Count_Type)
598 procedure Allocate is
599 new HT_Ops.Generic_Allocate (Set_Element);
603 HT.Nodes (Node).Has_Element := True;
604 end Generic_Allocate;
610 function Has_Element (Container : Map; Position : Cursor) return Boolean is
612 if Position.Node = 0 or else
613 not Container.HT.Nodes (Position.Node).Has_Element then
617 if Container.K = Plain then
622 Lst_Index : constant Hash_Type :=
623 Key_Ops.Index (Container.HT.all,
624 Container.HT.Nodes (Container.Last).Key);
625 Fst_Index : constant Hash_Type :=
626 Key_Ops.Index (Container.HT.all,
627 Container.HT.Nodes (Container.First).Key);
628 Index : constant Hash_Type :=
629 Key_Ops.Index (Container.HT.all,
630 Container.HT.Nodes (Position.Node).Key);
631 Lst_Node : Count_Type;
635 if Index < Fst_Index or Index > Lst_Index then
639 if Index > Fst_Index and Index < Lst_Index then
643 if Index = Fst_Index then
644 Node := Container.First;
646 Node := Container.HT.Buckets (Index);
649 if Index = Lst_Index then
650 Lst_Node := Container.HT.Nodes (Container.Last).Next;
655 while Node /= Lst_Node loop
656 if Position.Node = Node then
659 Node := HT_Ops.Next (Container.HT.all, Node);
671 (Node : Node_Type) return Hash_Type is
673 return Hash (Node.Key);
681 (Container : in out Map;
683 New_Item : Element_Type)
689 Insert (Container, Key, New_Item, Position, Inserted);
692 if Container.HT.Lock > 0 then
693 raise Program_Error with
694 "Include attempted to tamper with cursors (map is locked)";
698 N : Node_Type renames Container.HT.Nodes (Position.Node);
701 N.Element := New_Item;
711 (Container : in out Map;
713 Position : out Cursor;
714 Inserted : out Boolean)
718 if Container.K /= Plain then
719 raise Constraint_Error
720 with "Can't modify part of container";
723 procedure Assign_Key (Node : in out Node_Type);
724 pragma Inline (Assign_Key);
726 function New_Node return Count_Type;
727 pragma Inline (New_Node);
729 procedure Local_Insert is
730 new Key_Ops.Generic_Conditional_Insert (New_Node);
732 procedure Allocate is
733 new Generic_Allocate (Assign_Key);
739 procedure Assign_Key (Node : in out Node_Type) is
742 -- Node.Element := New_Item;
749 function New_Node return Count_Type is
752 Allocate (Container.HT.all, Result);
756 -- Start of processing for Insert
760 Local_Insert (Container.HT.all, Key, Position.Node, Inserted);
765 (Container : in out Map;
767 New_Item : Element_Type;
768 Position : out Cursor;
769 Inserted : out Boolean)
773 if Container.K /= Plain then
774 raise Constraint_Error
775 with "Can't modify part of container";
778 procedure Assign_Key (Node : in out Node_Type);
779 pragma Inline (Assign_Key);
781 function New_Node return Count_Type;
782 pragma Inline (New_Node);
784 procedure Local_Insert is
785 new Key_Ops.Generic_Conditional_Insert (New_Node);
787 procedure Allocate is
788 new Generic_Allocate (Assign_Key);
794 procedure Assign_Key (Node : in out Node_Type) is
797 Node.Element := New_Item;
804 function New_Node return Count_Type is
807 Allocate (Container.HT.all, Result);
811 -- Start of processing for Insert
815 Local_Insert (Container.HT.all, Key, Position.Node, Inserted);
820 (Container : in out Map;
822 New_Item : Element_Type)
825 pragma Unreferenced (Position);
830 Insert (Container, Key, New_Item, Position, Inserted);
833 raise Constraint_Error with
834 "attempt to insert key already in map";
842 function Is_Empty (Container : Map) return Boolean is
844 return Length (Container) = 0;
854 not null access procedure (Container : Map; Position : Cursor))
856 procedure Process_Node (Node : Count_Type);
857 pragma Inline (Process_Node);
859 procedure Local_Iterate is new HT_Ops.Generic_Iteration (Process_Node);
865 procedure Process_Node (Node : Count_Type) is
867 Process (Container, (Node => Node));
870 B : Natural renames Container'Unrestricted_Access.HT.Busy;
872 -- Start of processing for Iterate
880 Local_Iterate (Container.HT.all);
883 if Container.Length = 0 then
888 Node : Count_Type := Container.First;
890 while Node /= Container.HT.Nodes (Container.Last).Next loop
892 Node := HT_Ops.Next (Container.HT.all, Node);
909 function Key (Container : Map; Position : Cursor) return Key_Type is
911 if not Has_Element (Container, Position) then
912 raise Constraint_Error with
913 "Position cursor of function Key has no element";
916 pragma Assert (Vet (Container, Position), "bad cursor in function Key");
918 return Container.HT.Nodes (Position.Node).Key;
925 function Left (Container : Map; Position : Cursor) return Map is
927 Fst : constant Count_Type := First (Container).Node;
929 C : Count_Type := Fst;
931 while C /= Position.Node loop
932 if C = 0 or C = Container.Last then
933 raise Constraint_Error with
934 "Position cursor has no element";
937 C := HT_Ops.Next (Container.HT.all, C);
941 return (Capacity => Container.Capacity,
942 Modulus => Container.Modulus,
949 return (Capacity => Container.Capacity,
950 Modulus => Container.Modulus,
963 function Length (Container : Map) return Count_Type is
967 return Container.HT.Length;
969 return Container.Length;
978 (Target : in out Map;
981 HT : HT_Types.Hash_Table_Type renames Source.HT.all;
982 NN : HT_Types.Nodes_Type renames HT.Nodes;
987 if Target.K /= Plain or Source.K /= Plain then
988 raise Constraint_Error
989 with "Can't modify part of container";
992 if Target'Address = Source'Address then
996 if Target.Capacity < Length (Source) then
997 raise Constraint_Error with -- ???
998 "Source length exceeds Target capacity";
1002 raise Program_Error with
1003 "attempt to tamper with cursors of Source (list is busy)";
1008 if HT.Length = 0 then
1012 X := HT_Ops.First (HT);
1014 Insert (Target, NN (X).Key, NN (X).Element); -- optimize???
1016 Y := HT_Ops.Next (HT, X);
1018 HT_Ops.Delete_Node_Sans_Free (HT, X);
1029 function Next (Node : Node_Type) return Count_Type is
1034 function Next_Unchecked
1036 Position : Cursor) return Cursor
1038 HT : Hash_Table_Type renames Container.HT.all;
1039 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
1046 if Container.K = Part and then Container.Last = Position.Node then
1050 return (Node => Node);
1053 function Next (Container : Map; Position : Cursor) return Cursor is
1055 if Position.Node = 0 then
1059 if not Has_Element (Container, Position) then
1060 raise Constraint_Error
1061 with "Position has no element";
1064 pragma Assert (Vet (Container, Position), "bad cursor in function Next");
1066 return Next_Unchecked (Container, Position);
1069 procedure Next (Container : Map; Position : in out Cursor) is
1071 Position := Next (Container, Position);
1078 function Overlap (Left, Right : Map) return Boolean is
1079 Left_Node : Count_Type;
1080 Left_Nodes : Nodes_Type renames Left.HT.Nodes;
1081 To_Node : Count_Type;
1083 if Length (Right) = 0 or Length (Left) = 0 then
1087 if Left'Address = Right'Address then
1091 Left_Node := First (Left).Node;
1093 if Left.K = Plain then
1096 To_Node := Left.HT.Nodes (Left.Last).Next;
1099 while Left_Node /= To_Node loop
1101 N : Node_Type renames Left_Nodes (Left_Node);
1102 E : Key_Type renames N.Key;
1105 if Find (Right, E).Node /= 0 then
1110 Left_Node := HT_Ops.Next (Left.HT.all, Left_Node);
1120 procedure Query_Element
1121 (Container : in out Map;
1123 Process : not null access
1124 procedure (Key : Key_Type; Element : Element_Type))
1127 if Container.K /= Plain then
1128 raise Constraint_Error
1129 with "Can't modify part of container";
1132 if not Has_Element (Container, Position) then
1133 raise Constraint_Error with
1134 "Position cursor of Query_Element has no element";
1137 pragma Assert (Vet (Container, Position), "bad cursor in Query_Element");
1140 HT : Hash_Table_Type renames Container.HT.all;
1141 N : Node_Type renames HT.Nodes (Position.Node);
1143 B : Natural renames HT.Busy;
1144 L : Natural renames HT.Lock;
1151 K : Key_Type renames N.Key;
1152 E : Element_Type renames N.Element;
1173 (Stream : not null access Root_Stream_Type'Class;
1174 Container : out Map)
1176 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1179 procedure Read_Nodes is
1180 new HT_Ops.Generic_Read (Read_Node);
1186 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1189 procedure Read_Element (Node : in out Node_Type);
1190 pragma Inline (Read_Element);
1192 procedure Allocate is
1193 new Generic_Allocate (Read_Element);
1195 procedure Read_Element (Node : in out Node_Type) is
1197 Element_Type'Read (Stream, Node.Element);
1202 -- Start of processing for Read_Node
1205 Allocate (Container.HT.all, Node);
1209 -- Start of processing for Read
1212 if Container.K /= Plain then
1213 raise Constraint_Error;
1216 if Container.HT = null then
1217 Result := new HT_Types.Hash_Table_Type (Container.Capacity,
1220 Result := Container.HT;
1223 Read_Nodes (Stream, Result.all);
1224 Container.HT := Result;
1228 (Stream : not null access Root_Stream_Type'Class;
1232 raise Program_Error with "attempt to stream set cursor";
1240 (Container : in out Map;
1242 New_Item : Element_Type)
1244 Node : constant Count_Type := Key_Ops.Find (Container.HT.all, Key);
1247 if Container.K /= Plain then
1248 raise Constraint_Error
1249 with "Can't modify part of container";
1253 raise Constraint_Error with
1254 "attempt to replace key not in map";
1257 if Container.HT.Lock > 0 then
1258 raise Program_Error with
1259 "Replace attempted to tamper with cursors (map is locked)";
1263 N : Node_Type renames Container.HT.Nodes (Node);
1266 N.Element := New_Item;
1270 ---------------------
1271 -- Replace_Element --
1272 ---------------------
1274 procedure Replace_Element
1275 (Container : in out Map;
1277 New_Item : Element_Type)
1280 if Container.K /= Plain then
1281 raise Constraint_Error
1282 with "Can't modify part of container";
1285 if not Has_Element (Container, Position) then
1286 raise Constraint_Error with
1287 "Position cursor of Replace_Element has no element";
1290 if Container.HT.Lock > 0 then
1291 raise Program_Error with
1292 "Replace_Element attempted to tamper with cursors (map is locked)";
1295 pragma Assert (Vet (Container, Position),
1296 "bad cursor in Replace_Element");
1298 Container.HT.Nodes (Position.Node).Element := New_Item;
1299 end Replace_Element;
1301 ----------------------
1302 -- Reserve_Capacity --
1303 ----------------------
1305 procedure Reserve_Capacity
1306 (Container : in out Map;
1307 Capacity : Count_Type)
1310 if Container.K /= Plain then
1311 raise Constraint_Error
1312 with "Can't modify part of container";
1315 if Capacity > Container.Capacity then
1316 raise Capacity_Error with "requested capacity is too large";
1318 end Reserve_Capacity;
1324 function Right (Container : Map; Position : Cursor) return Map is
1327 L : Count_Type := 0;
1328 C : Count_Type := Position.Node;
1332 return (Capacity => Container.Capacity,
1333 Modulus => Container.Modulus,
1341 if Container.K = Plain then
1344 Lst := HT_Ops.Next (Container.HT.all, Container.Last);
1348 raise Constraint_Error with
1349 "Position cursor has no element";
1354 raise Constraint_Error with
1355 "Position cursor has no element";
1358 C := HT_Ops.Next (Container.HT.all, C);
1362 return (Capacity => Container.Capacity,
1363 Modulus => Container.Modulus,
1367 First => Position.Node,
1375 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1384 function Strict_Equal (Left, Right : Map) return Boolean is
1385 CuL : Cursor := First (Left);
1386 CuR : Cursor := First (Right);
1388 if Length (Left) /= Length (Right) then
1392 while CuL.Node /= 0 or CuR.Node /= 0 loop
1393 if CuL.Node /= CuR.Node or else
1394 (Left.HT.Nodes (CuL.Node).Element /=
1395 Right.HT.Nodes (CuR.Node).Element or
1396 Left.HT.Nodes (CuL.Node).Key /=
1397 Right.HT.Nodes (CuR.Node).Key) then
1400 CuL := Next_Unchecked (Left, CuL);
1401 CuR := Next_Unchecked (Right, CuR);
1407 --------------------
1408 -- Update_Element --
1409 --------------------
1411 procedure Update_Element
1412 (Container : in out Map;
1414 Process : not null access procedure (Key : Key_Type;
1415 Element : in out Element_Type))
1418 if Container.K /= Plain then
1419 raise Constraint_Error
1420 with "Can't modify part of container";
1423 if not Has_Element (Container, Position) then
1424 raise Constraint_Error with
1425 "Position cursor of Update_Element has no element";
1428 pragma Assert (Vet (Container, Position),
1429 "bad cursor in Update_Element");
1432 HT : Hash_Table_Type renames Container.HT.all;
1433 B : Natural renames HT.Busy;
1434 L : Natural renames HT.Lock;
1441 N : Node_Type renames HT.Nodes (Position.Node);
1442 K : Key_Type renames N.Key;
1443 E : Element_Type renames N.Element;
1463 function Vet (Container : Map; Position : Cursor) return Boolean is
1465 if Position.Node = 0 then
1470 M : HT_Types.Hash_Table_Type renames Container.HT.all;
1474 if M.Length = 0 then
1478 if M.Capacity = 0 then
1482 if M.Buckets'Length = 0 then
1486 if Position.Node > M.Capacity then
1490 if M.Nodes (Position.Node).Next = Position.Node then
1494 X := M.Buckets (Key_Ops.Index (M, M.Nodes (Position.Node).Key));
1496 for J in 1 .. M.Length loop
1497 if X = Position.Node then
1505 if X = M.Nodes (X).Next then -- to prevent unnecessary looping
1509 X := M.Nodes (X).Next;
1521 (Stream : not null access Root_Stream_Type'Class;
1524 procedure Write_Node
1525 (Stream : not null access Root_Stream_Type'Class;
1527 pragma Inline (Write_Node);
1529 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
1535 procedure Write_Node
1536 (Stream : not null access Root_Stream_Type'Class;
1540 Key_Type'Write (Stream, Node.Key);
1541 Element_Type'Write (Stream, Node.Element);
1544 -- Start of processing for Write
1547 Write_Nodes (Stream, Container.HT.all);
1551 (Stream : not null access Root_Stream_Type'Class;
1555 raise Program_Error with "attempt to stream map cursor";
1558 end Ada.Containers.Formal_Hashed_Maps;