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 -- This specification is derived from the Ada Reference Manual for use with --
12 -- GNAT. The copyright notice above, and the license provisions that follow --
13 -- apply solely to the contents of the part following the private keyword. --
15 -- GNAT is free software; you can redistribute it and/or modify it under --
16 -- terms of the GNU General Public License as published by the Free Soft- --
17 -- ware Foundation; either version 3, or (at your option) any later ver- --
18 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
19 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
20 -- or FITNESS FOR A PARTICULAR PURPOSE. --
22 -- As a special exception under Section 7 of GPL version 3, you are granted --
23 -- additional permissions described in the GCC Runtime Library Exception, --
24 -- version 3.1, as published by the Free Software Foundation. --
26 -- You should have received a copy of the GNU General Public License and --
27 -- a copy of the GCC Runtime Library Exception along with this program; --
28 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
29 -- <http://www.gnu.org/licenses/>. --
30 ------------------------------------------------------------------------------
32 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
33 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
35 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
36 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
38 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
40 with System; use type System.Address;
42 package body Ada.Containers.Formal_Hashed_Maps is
44 -----------------------
45 -- Local Subprograms --
46 -----------------------
48 function Equivalent_Keys
50 Node : Node_Type) return Boolean;
51 pragma Inline (Equivalent_Keys);
54 (HT : Hash_Table_Type;
57 To : Count_Type) return Count_Type;
60 (HT : in out Hash_Table_Type;
64 with procedure Set_Element (Node : in out Node_Type);
65 procedure Generic_Allocate
66 (HT : in out Hash_Table_Type;
67 Node : out Count_Type);
69 function Hash_Node (Node : Node_Type) return Hash_Type;
70 pragma Inline (Hash_Node);
72 function Next_Unchecked
74 Position : Cursor) return Cursor;
76 function Next (Node : Node_Type) return Count_Type;
79 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
80 pragma Inline (Set_Next);
82 function Vet (Container : Map; Position : Cursor) return Boolean;
84 --------------------------
85 -- Local Instantiations --
86 --------------------------
89 new Hash_Tables.Generic_Bounded_Operations
90 (HT_Types => HT_Types,
91 Hash_Node => Hash_Node,
93 Set_Next => Set_Next);
96 new Hash_Tables.Generic_Bounded_Keys
97 (HT_Types => HT_Types,
100 Key_Type => Key_Type,
102 Equivalent_Keys => Equivalent_Keys);
108 function "=" (Left, Right : Map) return Boolean is
111 if Length (Left) /= Length (Right) then
115 if Length (Left) = 0 then
120 Node : Count_Type := First (Left).Node;
125 if Left.K = Plain then
128 Last := HT_Ops.Next (Left.HT.all, Left.Last);
131 while Node /= Last loop
132 ENode := Find (Container => Right,
133 Key => Left.HT.Nodes (Node).Key).Node;
135 Right.HT.Nodes (ENode).Element /= Left.HT.Nodes (Node).Element
140 Node := HT_Ops.Next (Left.HT.all, Node);
153 procedure Assign (Target : in out Map; Source : Map) is
154 procedure Insert_Element (Source_Node : Count_Type);
155 pragma Inline (Insert_Element);
157 procedure Insert_Elements is
158 new HT_Ops.Generic_Iteration (Insert_Element);
164 procedure Insert_Element (Source_Node : Count_Type) is
165 N : Node_Type renames Source.HT.Nodes (Source_Node);
167 Target.Insert (N.Key, N.Element);
170 -- Start of processing for Assign
173 if Target.K /= Plain then
174 raise Constraint_Error
175 with "Can't modify part of container";
178 if Target'Address = Source'Address then
182 if Target.Capacity < Length (Source) then
183 raise Constraint_Error with -- correct exception ???
184 "Source length exceeds Target capacity";
187 Clear (Target); -- checks busy bits
191 Insert_Elements (Source.HT.all);
194 N : Count_Type := Source.First;
196 while N /= HT_Ops.Next (Source.HT.all, Source.Last) loop
198 N := HT_Ops.Next (Source.HT.all, N);
208 function Capacity (Container : Map) return Count_Type is
210 return Container.HT.Nodes'Length;
217 procedure Clear (Container : in out Map) is
220 if Container.K /= Plain then
221 raise Constraint_Error
222 with "Can't modify part of container";
225 HT_Ops.Clear (Container.HT.all);
232 function Contains (Container : Map; Key : Key_Type) return Boolean is
234 return Find (Container, Key) /= No_Element;
243 Capacity : Count_Type := 0) return Map
245 C : constant Count_Type :=
246 Count_Type'Max (Capacity, Source.Capacity);
249 Target : Map (C, Source.Modulus);
252 if (Source.K = Part and Source.Length = 0) or
253 Source.HT.Length = 0 then
257 Target.HT.Length := Source.HT.Length;
258 Target.HT.Free := Source.HT.Free;
259 while H <= Source.Modulus loop
260 Target.HT.Buckets (H) := Source.HT.Buckets (H);
263 while N <= Source.Capacity loop
264 Target.HT.Nodes (N) := Source.HT.Nodes (N);
269 Free (Target.HT.all, Cu.Node);
272 if Source.K = Part then
273 N := HT_Ops.First (Target.HT.all);
274 while N /= Source.First loop
276 N := HT_Ops.Next (Target.HT.all, N);
279 N := HT_Ops.Next (Target.HT.all, Source.Last);
282 N := HT_Ops.Next (Target.HT.all, N);
289 ---------------------
290 -- Default_Modulus --
291 ---------------------
293 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
295 return To_Prime (Capacity);
302 procedure Delete (Container : in out Map; Key : Key_Type) is
307 if Container.K /= Plain then
308 raise Constraint_Error
309 with "Can't modify part of container";
312 Key_Ops.Delete_Key_Sans_Free (Container.HT.all, Key, X);
315 raise Constraint_Error with "attempt to delete key not in map";
318 Free (Container.HT.all, X);
321 procedure Delete (Container : in out Map; Position : in out Cursor) is
324 if Container.K /= Plain then
325 raise Constraint_Error
326 with "Can't modify part of container";
329 if not Has_Element (Container, Position) then
330 raise Constraint_Error with
331 "Position cursor of Delete has no element";
334 if Container.HT.Busy > 0 then
335 raise Program_Error with
336 "Delete attempted to tamper with elements (map is busy)";
339 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
341 HT_Ops.Delete_Node_Sans_Free (Container.HT.all, Position.Node);
343 Free (Container.HT.all, Position.Node);
350 function Element (Container : Map; Key : Key_Type) return Element_Type is
351 Node : constant Count_Type := Find (Container, Key).Node;
355 raise Constraint_Error with
356 "no element available because key not in map";
359 return Container.HT.Nodes (Node).Element;
362 function Element (Container : Map; Position : Cursor) return Element_Type is
364 if not Has_Element (Container, Position) then
365 raise Constraint_Error with "Position cursor equals No_Element";
368 pragma Assert (Vet (Container, Position),
369 "bad cursor in function Element");
371 return Container.HT.Nodes (Position.Node).Element;
374 ---------------------
375 -- Equivalent_Keys --
376 ---------------------
378 function Equivalent_Keys
380 Node : Node_Type) return Boolean is
382 return Equivalent_Keys (Key, Node.Key);
385 function Equivalent_Keys (Left : Map; CLeft : Cursor;
386 Right : Map; CRight : Cursor)
389 if not Has_Element (Left, CLeft) then
390 raise Constraint_Error with
391 "Left cursor of Equivalent_Keys has no element";
394 if not Has_Element (Right, CRight) then
395 raise Constraint_Error with
396 "Right cursor of Equivalent_Keys has no element";
399 pragma Assert (Vet (Left, CLeft),
400 "Left cursor of Equivalent_Keys is bad");
401 pragma Assert (Vet (Right, CRight),
402 "Right cursor of Equivalent_Keys is bad");
405 LT : Hash_Table_Type renames Left.HT.all;
406 RT : Hash_Table_Type renames Right.HT.all;
408 LN : Node_Type renames LT.Nodes (CLeft.Node);
409 RN : Node_Type renames RT.Nodes (CRight.Node);
412 return Equivalent_Keys (LN.Key, RN.Key);
416 function Equivalent_Keys
419 Right : Key_Type) return Boolean is
421 if not Has_Element (Left, CLeft) then
422 raise Constraint_Error with
423 "Left cursor of Equivalent_Keys has no element";
426 pragma Assert (Vet (Left, CLeft),
427 "Left cursor in Equivalent_Keys is bad");
430 LT : Hash_Table_Type renames Left.HT.all;
431 LN : Node_Type renames LT.Nodes (CLeft.Node);
434 return Equivalent_Keys (LN.Key, Right);
438 function Equivalent_Keys
441 CRight : Cursor) return Boolean is
443 if Has_Element (Right, CRight) then
444 raise Constraint_Error with
445 "Right cursor of Equivalent_Keys has no element";
448 pragma Assert (Vet (Right, CRight),
449 "Right cursor of Equivalent_Keys is bad");
452 RT : Hash_Table_Type renames Right.HT.all;
453 RN : Node_Type renames RT.Nodes (CRight.Node);
456 return Equivalent_Keys (Left, RN.Key);
464 procedure Exclude (Container : in out Map; Key : Key_Type) is
468 if Container.K /= Plain then
469 raise Constraint_Error
470 with "Can't modify part of container";
473 Key_Ops.Delete_Key_Sans_Free (Container.HT.all, Key, X);
474 Free (Container.HT.all, X);
480 function Find_Between
481 (HT : Hash_Table_Type;
484 To : Count_Type) return Count_Type is
487 Indx_From : constant Hash_Type :=
488 Key_Ops.Index (HT, HT.Nodes (From).Key);
489 Indx_To : constant Hash_Type :=
490 Key_Ops.Index (HT, HT.Nodes (To).Key);
492 To_Node : Count_Type;
496 Indx := Key_Ops.Index (HT, Key);
498 if Indx < Indx_From or Indx > Indx_To then
502 if Indx = Indx_From then
505 Node := HT.Buckets (Indx);
508 if Indx = Indx_To then
509 To_Node := HT.Nodes (To).Next;
514 while Node /= To_Node loop
515 if Equivalent_Keys (Key, HT.Nodes (Node)) then
518 Node := HT.Nodes (Node).Next;
523 function Find (Container : Map; Key : Key_Type) return Cursor is
528 Node : constant Count_Type :=
529 Key_Ops.Find (Container.HT.all, Key);
536 return (Node => Node);
539 if Container.Length = 0 then
543 return (Node => Find_Between (Container.HT.all, Key,
544 Container.First, Container.Last));
552 function First (Container : Map) return Cursor is
557 Node : constant Count_Type := HT_Ops.First (Container.HT.all);
564 return (Node => Node);
568 Node : constant Count_Type := Container.First;
575 return (Node => Node);
585 (HT : in out Hash_Table_Type;
589 HT.Nodes (X).Has_Element := False;
593 ----------------------
594 -- Generic_Allocate --
595 ----------------------
597 procedure Generic_Allocate
598 (HT : in out Hash_Table_Type;
599 Node : out Count_Type)
602 procedure Allocate is
603 new HT_Ops.Generic_Allocate (Set_Element);
607 HT.Nodes (Node).Has_Element := True;
608 end Generic_Allocate;
614 function Has_Element (Container : Map; Position : Cursor) return Boolean is
616 if Position.Node = 0 or else
617 not Container.HT.Nodes (Position.Node).Has_Element then
621 if Container.K = Plain then
626 Lst_Index : constant Hash_Type :=
627 Key_Ops.Index (Container.HT.all,
628 Container.HT.Nodes (Container.Last).Key);
629 Fst_Index : constant Hash_Type :=
630 Key_Ops.Index (Container.HT.all,
631 Container.HT.Nodes (Container.First).Key);
632 Index : constant Hash_Type :=
633 Key_Ops.Index (Container.HT.all,
634 Container.HT.Nodes (Position.Node).Key);
635 Lst_Node : Count_Type;
639 if Index < Fst_Index or Index > Lst_Index then
643 if Index > Fst_Index and Index < Lst_Index then
647 if Index = Fst_Index then
648 Node := Container.First;
650 Node := Container.HT.Buckets (Index);
653 if Index = Lst_Index then
654 Lst_Node := Container.HT.Nodes (Container.Last).Next;
659 while Node /= Lst_Node loop
660 if Position.Node = Node then
663 Node := HT_Ops.Next (Container.HT.all, Node);
675 (Node : Node_Type) return Hash_Type is
677 return Hash (Node.Key);
685 (Container : in out Map;
687 New_Item : Element_Type)
693 Insert (Container, Key, New_Item, Position, Inserted);
696 if Container.HT.Lock > 0 then
697 raise Program_Error with
698 "Include attempted to tamper with cursors (map is locked)";
702 N : Node_Type renames Container.HT.Nodes (Position.Node);
705 N.Element := New_Item;
715 (Container : in out Map;
717 Position : out Cursor;
718 Inserted : out Boolean)
722 if Container.K /= Plain then
723 raise Constraint_Error
724 with "Can't modify part of container";
727 procedure Assign_Key (Node : in out Node_Type);
728 pragma Inline (Assign_Key);
730 function New_Node return Count_Type;
731 pragma Inline (New_Node);
733 procedure Local_Insert is
734 new Key_Ops.Generic_Conditional_Insert (New_Node);
736 procedure Allocate is
737 new Generic_Allocate (Assign_Key);
743 procedure Assign_Key (Node : in out Node_Type) is
746 -- Node.Element := New_Item;
753 function New_Node return Count_Type is
756 Allocate (Container.HT.all, Result);
760 -- Start of processing for Insert
764 Local_Insert (Container.HT.all, Key, Position.Node, Inserted);
769 (Container : in out Map;
771 New_Item : Element_Type;
772 Position : out Cursor;
773 Inserted : out Boolean)
777 if Container.K /= Plain then
778 raise Constraint_Error
779 with "Can't modify part of container";
782 procedure Assign_Key (Node : in out Node_Type);
783 pragma Inline (Assign_Key);
785 function New_Node return Count_Type;
786 pragma Inline (New_Node);
788 procedure Local_Insert is
789 new Key_Ops.Generic_Conditional_Insert (New_Node);
791 procedure Allocate is
792 new Generic_Allocate (Assign_Key);
798 procedure Assign_Key (Node : in out Node_Type) is
801 Node.Element := New_Item;
808 function New_Node return Count_Type is
811 Allocate (Container.HT.all, Result);
815 -- Start of processing for Insert
819 Local_Insert (Container.HT.all, Key, Position.Node, Inserted);
824 (Container : in out Map;
826 New_Item : Element_Type)
829 pragma Unreferenced (Position);
834 Insert (Container, Key, New_Item, Position, Inserted);
837 raise Constraint_Error with
838 "attempt to insert key already in map";
846 function Is_Empty (Container : Map) return Boolean is
848 return Length (Container) = 0;
858 not null access procedure (Container : Map; Position : Cursor))
860 procedure Process_Node (Node : Count_Type);
861 pragma Inline (Process_Node);
863 procedure Local_Iterate is new HT_Ops.Generic_Iteration (Process_Node);
869 procedure Process_Node (Node : Count_Type) is
871 Process (Container, (Node => Node));
874 B : Natural renames Container'Unrestricted_Access.HT.Busy;
876 -- Start of processing for Iterate
884 Local_Iterate (Container.HT.all);
887 if Container.Length = 0 then
892 Node : Count_Type := Container.First;
894 while Node /= Container.HT.Nodes (Container.Last).Next loop
896 Node := HT_Ops.Next (Container.HT.all, Node);
913 function Key (Container : Map; Position : Cursor) return Key_Type is
915 if not Has_Element (Container, Position) then
916 raise Constraint_Error with
917 "Position cursor of function Key has no element";
920 pragma Assert (Vet (Container, Position), "bad cursor in function Key");
922 return Container.HT.Nodes (Position.Node).Key;
929 function Left (Container : Map; Position : Cursor) return Map is
931 Fst : constant Count_Type := First (Container).Node;
933 C : Count_Type := Fst;
935 while C /= Position.Node loop
936 if C = 0 or C = Container.Last then
937 raise Constraint_Error with
938 "Position cursor has no element";
941 C := HT_Ops.Next (Container.HT.all, C);
945 return (Capacity => Container.Capacity,
946 Modulus => Container.Modulus,
953 return (Capacity => Container.Capacity,
954 Modulus => Container.Modulus,
967 function Length (Container : Map) return Count_Type is
971 return Container.HT.Length;
973 return Container.Length;
982 (Target : in out Map;
985 HT : HT_Types.Hash_Table_Type renames Source.HT.all;
986 NN : HT_Types.Nodes_Type renames HT.Nodes;
991 if Target.K /= Plain or Source.K /= Plain then
992 raise Constraint_Error
993 with "Can't modify part of container";
996 if Target'Address = Source'Address then
1000 if Target.Capacity < Length (Source) then
1001 raise Constraint_Error with -- ???
1002 "Source length exceeds Target capacity";
1006 raise Program_Error with
1007 "attempt to tamper with cursors of Source (list is busy)";
1012 if HT.Length = 0 then
1016 X := HT_Ops.First (HT);
1018 Insert (Target, NN (X).Key, NN (X).Element); -- optimize???
1020 Y := HT_Ops.Next (HT, X);
1022 HT_Ops.Delete_Node_Sans_Free (HT, X);
1033 function Next (Node : Node_Type) return Count_Type is
1038 function Next_Unchecked
1040 Position : Cursor) return Cursor
1042 HT : Hash_Table_Type renames Container.HT.all;
1043 Node : constant Count_Type := HT_Ops.Next (HT, Position.Node);
1050 if Container.K = Part and then Container.Last = Position.Node then
1054 return (Node => Node);
1057 function Next (Container : Map; Position : Cursor) return Cursor is
1059 if Position.Node = 0 then
1063 if not Has_Element (Container, Position) then
1064 raise Constraint_Error
1065 with "Position has no element";
1068 pragma Assert (Vet (Container, Position), "bad cursor in function Next");
1070 return Next_Unchecked (Container, Position);
1073 procedure Next (Container : Map; Position : in out Cursor) is
1075 Position := Next (Container, Position);
1082 function Overlap (Left, Right : Map) return Boolean is
1083 Left_Node : Count_Type;
1084 Left_Nodes : Nodes_Type renames Left.HT.Nodes;
1085 To_Node : Count_Type;
1087 if Length (Right) = 0 or Length (Left) = 0 then
1091 if Left'Address = Right'Address then
1095 Left_Node := First (Left).Node;
1097 if Left.K = Plain then
1100 To_Node := Left.HT.Nodes (Left.Last).Next;
1103 while Left_Node /= To_Node loop
1105 N : Node_Type renames Left_Nodes (Left_Node);
1106 E : Key_Type renames N.Key;
1109 if Find (Right, E).Node /= 0 then
1114 Left_Node := HT_Ops.Next (Left.HT.all, Left_Node);
1124 procedure Query_Element
1125 (Container : in out Map;
1127 Process : not null access
1128 procedure (Key : Key_Type; Element : Element_Type))
1131 if Container.K /= Plain then
1132 raise Constraint_Error
1133 with "Can't modify part of container";
1136 if not Has_Element (Container, Position) then
1137 raise Constraint_Error with
1138 "Position cursor of Query_Element has no element";
1141 pragma Assert (Vet (Container, Position), "bad cursor in Query_Element");
1144 HT : Hash_Table_Type renames Container.HT.all;
1145 N : Node_Type renames HT.Nodes (Position.Node);
1147 B : Natural renames HT.Busy;
1148 L : Natural renames HT.Lock;
1155 K : Key_Type renames N.Key;
1156 E : Element_Type renames N.Element;
1177 (Stream : not null access Root_Stream_Type'Class;
1178 Container : out Map)
1180 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1183 procedure Read_Nodes is
1184 new HT_Ops.Generic_Read (Read_Node);
1190 function Read_Node (Stream : not null access Root_Stream_Type'Class)
1193 procedure Read_Element (Node : in out Node_Type);
1194 pragma Inline (Read_Element);
1196 procedure Allocate is
1197 new Generic_Allocate (Read_Element);
1199 procedure Read_Element (Node : in out Node_Type) is
1201 Element_Type'Read (Stream, Node.Element);
1206 -- Start of processing for Read_Node
1209 Allocate (Container.HT.all, Node);
1213 -- Start of processing for Read
1216 if Container.K /= Plain then
1217 raise Constraint_Error;
1220 if Container.HT = null then
1221 Result := new HT_Types.Hash_Table_Type (Container.Capacity,
1224 Result := Container.HT;
1227 Read_Nodes (Stream, Result.all);
1228 Container.HT := Result;
1232 (Stream : not null access Root_Stream_Type'Class;
1236 raise Program_Error with "attempt to stream set cursor";
1244 (Container : in out Map;
1246 New_Item : Element_Type)
1248 Node : constant Count_Type := Key_Ops.Find (Container.HT.all, Key);
1251 if Container.K /= Plain then
1252 raise Constraint_Error
1253 with "Can't modify part of container";
1257 raise Constraint_Error with
1258 "attempt to replace key not in map";
1261 if Container.HT.Lock > 0 then
1262 raise Program_Error with
1263 "Replace attempted to tamper with cursors (map is locked)";
1267 N : Node_Type renames Container.HT.Nodes (Node);
1270 N.Element := New_Item;
1274 ---------------------
1275 -- Replace_Element --
1276 ---------------------
1278 procedure Replace_Element
1279 (Container : in out Map;
1281 New_Item : Element_Type)
1284 if Container.K /= Plain then
1285 raise Constraint_Error
1286 with "Can't modify part of container";
1289 if not Has_Element (Container, Position) then
1290 raise Constraint_Error with
1291 "Position cursor of Replace_Element has no element";
1294 if Container.HT.Lock > 0 then
1295 raise Program_Error with
1296 "Replace_Element attempted to tamper with cursors (map is locked)";
1299 pragma Assert (Vet (Container, Position),
1300 "bad cursor in Replace_Element");
1302 Container.HT.Nodes (Position.Node).Element := New_Item;
1303 end Replace_Element;
1305 ----------------------
1306 -- Reserve_Capacity --
1307 ----------------------
1309 procedure Reserve_Capacity
1310 (Container : in out Map;
1311 Capacity : Count_Type)
1314 if Container.K /= Plain then
1315 raise Constraint_Error
1316 with "Can't modify part of container";
1319 if Capacity > Container.Capacity then
1320 raise Capacity_Error with "requested capacity is too large";
1322 end Reserve_Capacity;
1328 function Right (Container : Map; Position : Cursor) return Map is
1331 L : Count_Type := 0;
1332 C : Count_Type := Position.Node;
1336 return (Capacity => Container.Capacity,
1337 Modulus => Container.Modulus,
1345 if Container.K = Plain then
1348 Lst := HT_Ops.Next (Container.HT.all, Container.Last);
1352 raise Constraint_Error with
1353 "Position cursor has no element";
1358 raise Constraint_Error with
1359 "Position cursor has no element";
1362 C := HT_Ops.Next (Container.HT.all, C);
1366 return (Capacity => Container.Capacity,
1367 Modulus => Container.Modulus,
1371 First => Position.Node,
1379 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1388 function Strict_Equal (Left, Right : Map) return Boolean is
1389 CuL : Cursor := First (Left);
1390 CuR : Cursor := First (Right);
1392 if Length (Left) /= Length (Right) then
1396 while CuL.Node /= 0 or CuR.Node /= 0 loop
1397 if CuL.Node /= CuR.Node or else
1398 (Left.HT.Nodes (CuL.Node).Element /=
1399 Right.HT.Nodes (CuR.Node).Element or
1400 Left.HT.Nodes (CuL.Node).Key /=
1401 Right.HT.Nodes (CuR.Node).Key) then
1404 CuL := Next_Unchecked (Left, CuL);
1405 CuR := Next_Unchecked (Right, CuR);
1411 --------------------
1412 -- Update_Element --
1413 --------------------
1415 procedure Update_Element
1416 (Container : in out Map;
1418 Process : not null access procedure (Key : Key_Type;
1419 Element : in out Element_Type))
1422 if Container.K /= Plain then
1423 raise Constraint_Error
1424 with "Can't modify part of container";
1427 if not Has_Element (Container, Position) then
1428 raise Constraint_Error with
1429 "Position cursor of Update_Element has no element";
1432 pragma Assert (Vet (Container, Position),
1433 "bad cursor in Update_Element");
1436 HT : Hash_Table_Type renames Container.HT.all;
1437 B : Natural renames HT.Busy;
1438 L : Natural renames HT.Lock;
1445 N : Node_Type renames HT.Nodes (Position.Node);
1446 K : Key_Type renames N.Key;
1447 E : Element_Type renames N.Element;
1467 function Vet (Container : Map; Position : Cursor) return Boolean is
1469 if Position.Node = 0 then
1474 M : HT_Types.Hash_Table_Type renames Container.HT.all;
1478 if M.Length = 0 then
1482 if M.Capacity = 0 then
1486 if M.Buckets'Length = 0 then
1490 if Position.Node > M.Capacity then
1494 if M.Nodes (Position.Node).Next = Position.Node then
1498 X := M.Buckets (Key_Ops.Index (M, M.Nodes (Position.Node).Key));
1500 for J in 1 .. M.Length loop
1501 if X = Position.Node then
1509 if X = M.Nodes (X).Next then -- to prevent unnecessary looping
1513 X := M.Nodes (X).Next;
1525 (Stream : not null access Root_Stream_Type'Class;
1528 procedure Write_Node
1529 (Stream : not null access Root_Stream_Type'Class;
1531 pragma Inline (Write_Node);
1533 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
1539 procedure Write_Node
1540 (Stream : not null access Root_Stream_Type'Class;
1544 Key_Type'Write (Stream, Node.Key);
1545 Element_Type'Write (Stream, Node.Element);
1548 -- Start of processing for Write
1551 Write_Nodes (Stream, Container.HT.all);
1555 (Stream : not null access Root_Stream_Type'Class;
1559 raise Program_Error with "attempt to stream map cursor";
1562 end Ada.Containers.Formal_Hashed_Maps;