1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . H A S H E D _ M A P S --
9 -- Copyright (C) 2004-2023, 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/>. --
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
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 -----------------------
56 (Source
: Node_Access
) return Node_Access
;
57 pragma Inline
(Copy_Node
);
59 function Equivalent_Key_Node
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
;
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
;
86 (Stream
: not null access Root_Stream_Type
'Class;
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
,
99 Copy_Node
=> Copy_Node
,
102 package Key_Ops
is new Hash_Tables
.Generic_Keys
103 (HT_Types
=> HT_Types
,
105 Set_Next
=> Set_Next
,
106 Key_Type
=> Key_Type
,
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
);
119 function "=" (Left
, Right
: Cursor
) return Boolean is
122 Left
.Container
= Right
.Container
123 and then Left
.Node
= Right
.Node
;
126 function "=" (Left
, Right
: Map
) return Boolean is
128 return Is_Equal
(Left
.HT
, Right
.HT
);
135 procedure Adjust
(Container
: in out Map
) is
137 HT_Ops
.Adjust
(Container
.HT
);
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
);
154 procedure Insert_Item
(Node
: Node_Access
) is
156 Target
.Insert
(Key
=> Node
.Key
, New_Item
=> Node
.Element
);
159 -- Start of processing for Assign
162 if Target
'Address = Source
'Address then
168 if Target
.Capacity
< Source
.Length
then
169 Target
.Reserve_Capacity
(Source
.Length
);
172 Insert_Items
(Source
.HT
);
179 function Capacity
(Container
: Map
) return Count_Type
is
181 return HT_Ops
.Capacity
(Container
.HT
);
188 procedure Clear
(Container
: in out Map
) is
190 HT_Ops
.Clear
(Container
.HT
);
193 ------------------------
194 -- Constant_Reference --
195 ------------------------
197 function Constant_Reference
198 (Container
: aliased Map
;
199 Position
: Cursor
) return Constant_Reference_Type
202 if Checks
and then Position
.Container
= null then
203 raise Constraint_Error
with
204 "Position cursor has no element";
207 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
209 raise Program_Error
with
210 "Position cursor designates wrong map";
215 "Position cursor in Constant_Reference is bad");
218 HT
: Hash_Table_Type
renames Container
'Unrestricted_Access.all.HT
;
219 TC
: constant Tamper_Counts_Access
:=
220 HT
.TC
'Unrestricted_Access;
222 return R
: constant Constant_Reference_Type
:=
223 (Element
=> Position
.Node
.Element
'Access,
224 Control
=> (Controlled
with TC
))
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
);
239 if Checks
and then Node
= null then
240 raise Constraint_Error
with "key not in map";
244 TC
: constant Tamper_Counts_Access
:=
245 HT
.TC
'Unrestricted_Access;
247 return R
: constant Constant_Reference_Type
:=
248 (Element
=> Node
.Element
'Access,
249 Control
=> (Controlled
with TC
))
254 end Constant_Reference
;
260 function Contains
(Container
: Map
; Key
: Key_Type
) return Boolean is
262 return Find
(Container
, Key
) /= No_Element
;
271 Capacity
: Count_Type
:= 0) return Map
276 if Capacity
< Source
.Length
then
277 if Checks
and then Capacity
/= 0 then
279 with "Requested capacity is less than Source length";
287 return Target
: Map
do
288 Target
.Reserve_Capacity
(C
);
289 Target
.Assign
(Source
);
298 (Source
: Node_Access
) return Node_Access
300 Target
: constant Node_Access
:=
301 new Node_Type
'(Key => Source.Key,
302 Element => Source.Element,
312 procedure Delete (Container : in out Map; Key : Key_Type) is
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";
325 procedure Delete (Container : in out Map; Position : in out Cursor) is
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";
334 if Checks and then Position.Container /= Container'Unrestricted_Access
336 raise Program_Error with
337 "Position cursor of Delete designates wrong map";
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);
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);
359 if Checks and then Node = null then
360 raise Constraint_Error with
361 "no element available because key not in map";
367 function Element (Position : Cursor) return Element_Type is
369 if Checks and then Position.Node = null then
370 raise Constraint_Error with
371 "Position cursor of function Element equals No_Element";
374 pragma Assert (Vet (Position), "bad cursor in function Element");
376 return Position.Node.Element;
383 function Empty (Capacity : Count_Type := 1000) return Map is
385 return Result : Map do
386 Reserve_Capacity (Result, Capacity);
390 -------------------------
391 -- Equivalent_Key_Node --
392 -------------------------
394 function Equivalent_Key_Node
396 Node : Node_Access) return Boolean is
398 return Equivalent_Keys (Key, Node.Key);
399 end Equivalent_Key_Node;
401 ---------------------
402 -- Equivalent_Keys --
403 ---------------------
405 function Equivalent_Keys (Left, Right : Cursor)
408 if Checks and then Left.Node = null then
409 raise Constraint_Error with
410 "Left cursor of Equivalent_Keys equals No_Element";
413 if Checks and then Right.Node = null then
414 raise Constraint_Error with
415 "Right cursor of Equivalent_Keys equals No_Element";
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);
424 function Equivalent_Keys (Left : Cursor; Right : Key_Type) return Boolean is
426 if Checks and then Left.Node = null then
427 raise Constraint_Error with
428 "Left cursor of Equivalent_Keys equals No_Element";
431 pragma Assert (Vet (Left), "Left cursor in Equivalent_Keys is bad");
433 return Equivalent_Keys (Left.Node.Key, Right);
436 function Equivalent_Keys (Left : Key_Type; Right : Cursor) return Boolean is
438 if Checks and then Right.Node = null then
439 raise Constraint_Error with
440 "Right cursor of Equivalent_Keys equals No_Element";
443 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
445 return Equivalent_Keys (Left, Right.Node.Key);
452 procedure Exclude (Container : in out Map; Key : Key_Type) is
455 Key_Ops.Delete_Key_Sans_Free (Container.HT, Key, X);
463 procedure Finalize (Container : in out Map) is
465 HT_Ops.Finalize (Container.HT);
468 procedure Finalize (Object : in out Iterator) is
470 if Object.Container /= null then
471 Unbusy (Object.Container.HT.TC);
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);
489 (Container
'Unrestricted_Access, Node
, HT_Ops
.Index
(HT
, Node
));
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
);
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
;
509 R_Node
:= R_Node
.Next
;
519 function First
(Container
: Map
) return Cursor
is
521 Node
: constant Node_Access
:= HT_Ops
.First
(Container
.HT
, Pos
);
527 return Cursor
'(Container'Unrestricted_Access, Node, Pos);
530 function First (Object : Iterator) return Cursor is
532 return Object.Container.First;
539 procedure Free (X : in out Node_Access) is
540 procedure Deallocate is
541 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
544 X.Next := X; -- detect mischief (in Vet)
549 ------------------------
550 -- Get_Element_Access --
551 ------------------------
553 function Get_Element_Access
554 (Position : Cursor) return not null Element_Access is
556 return Position.Node.Element'Access;
557 end Get_Element_Access;
563 function Has_Element (Position : Cursor) return Boolean is
565 pragma Assert (Vet (Position), "bad cursor in Has_Element");
566 return Position.Node /= null;
573 function Hash_Node (Node : Node_Access) return Hash_Type is
575 return Hash (Node.Key);
583 (Container : in out Map;
585 New_Item : Element_Type)
591 Insert (Container, Key, New_Item, Position, Inserted);
594 TE_Check (Container.HT.TC);
596 Position.Node.Key := Key;
597 Position.Node.Element := New_Item;
606 (Container : in out Map;
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);
621 function New_Node (Next : Node_Access) return Node_Access is
623 return new Node_Type'(Key
=> Key
,
628 HT
: Hash_Table_Type
renames Container
.HT
;
630 -- Start of processing for Insert
633 if HT_Ops
.Capacity
(HT
) = 0 then
634 HT_Ops
.Reserve_Capacity
(HT
, 1);
637 Local_Insert
(HT
, Key
, Position
.Node
, Inserted
);
640 and then HT
.Length
> HT_Ops
.Capacity
(HT
)
642 HT_Ops
.Reserve_Capacity
(HT
, HT
.Length
);
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.
654 (Container
: in out Map
;
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
);
670 function New_Node
(Next
: Node_Access
) return Node_Access
is
672 return new Node_Type
'(Key, New_Item, Next);
675 HT : Hash_Table_Type renames Container.HT;
677 -- Start of processing for Insert
680 if HT_Ops.Capacity (HT) = 0 then
681 HT_Ops.Reserve_Capacity (HT, 1);
684 Local_Insert (HT, Key, Position.Node, Inserted);
687 and then HT.Length > HT_Ops.Capacity (HT)
689 HT_Ops.Reserve_Capacity (HT, HT.Length);
692 Position.Container := Container'Unrestricted_Access;
696 (Container : in out Map;
698 New_Item : Element_Type)
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";
716 function Is_Empty (Container : Map) return Boolean is
718 return Container.HT.Length = 0;
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);
739 procedure Process_Node (Node : Node_Access; Position : Hash_Type) is
741 Process (Cursor'(Container
'Unrestricted_Access, Node
, Position
));
744 Busy
: With_Busy
(Container
.HT
.TC
'Unrestricted_Access);
746 -- Start of processing for Iterate
749 Local_Iterate
(Container
.HT
);
753 (Container
: Map
) return Map_Iterator_Interfaces
.Forward_Iterator
'Class
756 return It
: constant Iterator
:=
757 (Limited_Controlled
with Container
=> Container
'Unrestricted_Access)
759 Busy
(Container
.HT
.TC
'Unrestricted_Access.all);
767 function Key
(Position
: Cursor
) return Key_Type
is
769 if Checks
and then Position
.Node
= null then
770 raise Constraint_Error
with
771 "Position cursor of function Key equals No_Element";
774 pragma Assert
(Vet
(Position
), "bad cursor in function Key");
776 return Position
.Node
.Key
;
783 function Length
(Container
: Map
) return Count_Type
is
785 return Container
.HT
.Length
;
793 (Target
: in out Map
;
797 HT_Ops
.Move
(Target
=> Target
.HT
, Source
=> Source
.HT
);
804 function Next
(Node
: Node_Access
) return Node_Access
is
809 function Next
(Position
: Cursor
) return Cursor
is
810 Node
: Node_Access
:= null;
813 -- Position of cursor's element in the map buckets.
815 if Position
.Node
= null then
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
);
829 return Cursor
'(Position.Container, Node, Pos);
833 procedure Next (Position : in out Cursor) is
835 Position := Next (Position);
840 Position : Cursor) return Cursor
843 if Position.Container = null then
847 if Checks and then Position.Container /= Object.Container then
848 raise Program_Error with
849 "Position cursor of Next designates wrong map";
852 return Next (Position);
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;
865 return R : constant Reference_Control_Type := (Controlled with TC) do
868 end Pseudo_Reference;
874 procedure Query_Element
876 Process : not null access
877 procedure (Key : Key_Type; Element : Element_Type))
880 if Checks and then Position.Node = null then
881 raise Constraint_Error with
882 "Position cursor of Query_Element equals No_Element";
885 pragma Assert (Vet (Position), "bad cursor in Query_Element");
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;
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
914 Simple_Array_Between (S);
917 Key_Type'Put_Image (S, Key (Position));
919 Element_Type'Put_Image (S, Element (Position));
924 Iterate (V, Put_Key_Value'Access);
933 (Stream : not null access Root_Stream_Type'Class;
937 Read_Nodes (Stream, Container.HT);
941 (Stream : not null access Root_Stream_Type'Class;
945 raise Program_Error with "attempt to stream map cursor";
949 (Stream : not null access Root_Stream_Type'Class;
950 Item : out Reference_Type)
953 raise Program_Error with "attempt to stream reference";
957 (Stream : not null access Root_Stream_Type'Class;
958 Item : out Constant_Reference_Type)
961 raise Program_Error with "attempt to stream reference";
969 (Container : aliased in out Map;
970 Position : Cursor) return Reference_Type
973 if Checks and then Position.Container = null then
974 raise Constraint_Error with
975 "Position cursor has no element";
978 if Checks and then Position.Container /= Container'Unrestricted_Access
980 raise Program_Error with
981 "Position cursor designates wrong map";
986 "Position cursor in function Reference is bad");
989 HT : Hash_Table_Type renames Container'Unrestricted_Access.all.HT;
990 TC : constant Tamper_Counts_Access :=
991 HT.TC'Unrestricted_Access;
993 return R : constant Reference_Type :=
994 (Element => Position.Node.Element'Access,
995 Control => (Controlled with TC))
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);
1010 if Checks and then Node = null then
1011 raise Constraint_Error with "key not in map";
1015 TC : constant Tamper_Counts_Access :=
1016 HT.TC'Unrestricted_Access;
1018 return R : constant Reference_Type :=
1019 (Element => Node.Element'Access,
1020 Control => (Controlled with TC))
1032 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1034 Node : Node_Access := new Node_Type;
1037 Key_Type'Read (Stream, Node.Key);
1038 Element_Type'Read (Stream, Node.Element);
1052 (Container : in out Map;
1054 New_Item : Element_Type)
1056 Node : constant Node_Access := Key_Ops.Find (Container.HT, Key);
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";
1067 Node.Element := New_Item;
1070 ---------------------
1071 -- Replace_Element --
1072 ---------------------
1074 procedure Replace_Element
1075 (Container : in out Map;
1077 New_Item : Element_Type)
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";
1087 if Checks and then Position.Container /= Container'Unrestricted_Access
1089 raise Program_Error with
1090 "Position cursor of Replace_Element designates wrong map";
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)
1107 HT_Ops.Reserve_Capacity (Container.HT, Capacity);
1108 end Reserve_Capacity;
1114 procedure Set_Next (Node : Node_Access; Next : Node_Access) is
1119 --------------------
1120 -- Update_Element --
1121 --------------------
1123 procedure Update_Element
1124 (Container : in out Map;
1126 Process : not null access procedure (Key : Key_Type;
1127 Element : in out Element_Type))
1130 if Checks and then Position.Node = null then
1131 raise Constraint_Error with
1132 "Position cursor of Update_Element equals No_Element";
1135 if Checks and then Position.Container /= Container'Unrestricted_Access
1137 raise Program_Error with
1138 "Position cursor of Update_Element designates wrong map";
1141 pragma Assert (Vet (Position), "bad cursor in Update_Element");
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;
1157 function Vet (Position : Cursor) return Boolean is
1159 if not Container_Checks'Enabled then
1163 if Position.Node = null then
1164 return Position.Container = null;
1167 if Position.Container = null then
1171 if Position.Node.Next = Position.Node then
1176 HT : Hash_Table_Type renames Position.Container.HT;
1180 if HT.Length = 0 then
1184 if HT.Buckets = null
1185 or else HT.Buckets'Length = 0
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
1201 if X = X.Next then -- to prevent unnecessary looping
1217 (Stream : not null access Root_Stream_Type'Class;
1221 Write_Nodes (Stream, Container.HT);
1225 (Stream : not null access Root_Stream_Type'Class;
1229 raise Program_Error with "attempt to stream map cursor";
1233 (Stream : not null access Root_Stream_Type'Class;
1234 Item : Reference_Type)
1237 raise Program_Error with "attempt to stream reference";
1241 (Stream : not null access Root_Stream_Type'Class;
1242 Item : Constant_Reference_Type)
1245 raise Program_Error with "attempt to stream reference";
1252 procedure Write_Node
1253 (Stream : not null access Root_Stream_Type'Class;
1257 Key_Type'Write (Stream, Node.Key);
1258 Element_Type'Write (Stream, Node.Element);
1261 end Ada.Containers.Hashed_Maps;