1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
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 --
9 -- Copyright (C) 2004-2013, 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
.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
.Prime_Numbers
; use Ada
.Containers
.Prime_Numbers
;
38 with System
; use type System
.Address
;
40 package body Ada
.Containers
.Bounded_Hashed_Maps
is
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 function Equivalent_Key_Node
48 Node
: Node_Type
) return Boolean;
49 pragma Inline
(Equivalent_Key_Node
);
51 function Hash_Node
(Node
: Node_Type
) return Hash_Type
;
52 pragma Inline
(Hash_Node
);
54 function Next
(Node
: Node_Type
) return Count_Type
;
57 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
);
58 pragma Inline
(Set_Next
);
60 function Vet
(Position
: Cursor
) return Boolean;
62 --------------------------
63 -- Local Instantiations --
64 --------------------------
66 package HT_Ops
is new Hash_Tables
.Generic_Bounded_Operations
67 (HT_Types
=> HT_Types
,
68 Hash_Node
=> Hash_Node
,
70 Set_Next
=> Set_Next
);
72 package Key_Ops
is new Hash_Tables
.Generic_Bounded_Keys
73 (HT_Types
=> HT_Types
,
78 Equivalent_Keys
=> Equivalent_Key_Node
);
84 function "=" (Left
, Right
: Map
) return Boolean is
85 function Find_Equal_Key
86 (R_HT
: Hash_Table_Type
'Class;
87 L_Node
: Node_Type
) return Boolean;
89 function Is_Equal
is new HT_Ops
.Generic_Equal
(Find_Equal_Key
);
95 function Find_Equal_Key
96 (R_HT
: Hash_Table_Type
'Class;
97 L_Node
: Node_Type
) return Boolean
99 R_Index
: constant Hash_Type
:= Key_Ops
.Index
(R_HT
, L_Node
.Key
);
100 R_Node
: Count_Type
:= R_HT
.Buckets
(R_Index
);
103 while R_Node
/= 0 loop
104 if Equivalent_Keys
(L_Node
.Key
, R_HT
.Nodes
(R_Node
).Key
) then
105 return L_Node
.Element
= R_HT
.Nodes
(R_Node
).Element
;
108 R_Node
:= R_HT
.Nodes
(R_Node
).Next
;
114 -- Start of processing for "="
117 return Is_Equal
(Left
, Right
);
124 procedure Assign
(Target
: in out Map
; Source
: Map
) is
125 procedure Insert_Element
(Source_Node
: Count_Type
);
127 procedure Insert_Elements
is
128 new HT_Ops
.Generic_Iteration
(Insert_Element
);
134 procedure Insert_Element
(Source_Node
: Count_Type
) is
135 N
: Node_Type
renames Source
.Nodes
(Source_Node
);
140 Insert
(Target
, N
.Key
, N
.Element
, C
, B
);
144 -- Start of processing for Assign
147 if Target
'Address = Source
'Address then
151 if Target
.Capacity
< Source
.Length
then
153 with "Target capacity is less than Source length";
156 HT_Ops
.Clear
(Target
);
157 Insert_Elements
(Source
);
164 function Capacity
(Container
: Map
) return Count_Type
is
166 return Container
.Capacity
;
173 procedure Clear
(Container
: in out Map
) is
175 HT_Ops
.Clear
(Container
);
178 ------------------------
179 -- Constant_Reference --
180 ------------------------
182 function Constant_Reference
183 (Container
: aliased Map
;
184 Position
: Cursor
) return Constant_Reference_Type
187 if Position
.Container
= null then
188 raise Constraint_Error
with
189 "Position cursor has no element";
192 if Position
.Container
/= Container
'Unrestricted_Access then
193 raise Program_Error
with
194 "Position cursor designates wrong map";
197 pragma Assert
(Vet
(Position
),
198 "Position cursor in Constant_Reference is bad");
201 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
203 return (Element
=> N
.Element
'Access);
205 end Constant_Reference
;
207 function Constant_Reference
208 (Container
: aliased Map
;
209 Key
: Key_Type
) return Constant_Reference_Type
211 Node
: constant Count_Type
:=
212 Key_Ops
.Find
(Container
'Unrestricted_Access.all, Key
);
216 raise Constraint_Error
with "key not in map";
220 N
: Node_Type
renames Container
.Nodes
(Node
);
222 return (Element
=> N
.Element
'Access);
224 end Constant_Reference
;
230 function Contains
(Container
: Map
; Key
: Key_Type
) return Boolean is
232 return Find
(Container
, Key
) /= No_Element
;
241 Capacity
: Count_Type
:= 0;
242 Modulus
: Hash_Type
:= 0) return Map
251 elsif Capacity
>= Source
.Length
then
255 raise Capacity_Error
with "Capacity value too small";
259 M
:= Default_Modulus
(C
);
264 return Target
: Map
(Capacity
=> C
, Modulus
=> M
) do
265 Assign
(Target
=> Target
, Source
=> Source
);
269 ---------------------
270 -- Default_Modulus --
271 ---------------------
273 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
is
275 return To_Prime
(Capacity
);
282 procedure Delete
(Container
: in out Map
; Key
: Key_Type
) is
286 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
289 raise Constraint_Error
with "attempt to delete key not in map";
292 HT_Ops
.Free
(Container
, X
);
295 procedure Delete
(Container
: in out Map
; Position
: in out Cursor
) is
297 if Position
.Node
= 0 then
298 raise Constraint_Error
with
299 "Position cursor of Delete equals No_Element";
302 if Position
.Container
/= Container
'Unrestricted_Access then
303 raise Program_Error
with
304 "Position cursor of Delete designates wrong map";
307 if Container
.Busy
> 0 then
308 raise Program_Error
with
309 "Delete attempted to tamper with cursors (map is busy)";
312 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
314 HT_Ops
.Delete_Node_Sans_Free
(Container
, Position
.Node
);
315 HT_Ops
.Free
(Container
, Position
.Node
);
317 Position
:= No_Element
;
324 function Element
(Container
: Map
; Key
: Key_Type
) return Element_Type
is
325 Node
: constant Count_Type
:=
326 Key_Ops
.Find
(Container
'Unrestricted_Access.all, Key
);
330 raise Constraint_Error
with
331 "no element available because key not in map";
334 return Container
.Nodes
(Node
).Element
;
337 function Element
(Position
: Cursor
) return Element_Type
is
339 if Position
.Node
= 0 then
340 raise Constraint_Error
with
341 "Position cursor of function Element equals No_Element";
344 pragma Assert
(Vet
(Position
), "bad cursor in function Element");
346 return Position
.Container
.Nodes
(Position
.Node
).Element
;
349 -------------------------
350 -- Equivalent_Key_Node --
351 -------------------------
353 function Equivalent_Key_Node
355 Node
: Node_Type
) return Boolean is
357 return Equivalent_Keys
(Key
, Node
.Key
);
358 end Equivalent_Key_Node
;
360 ---------------------
361 -- Equivalent_Keys --
362 ---------------------
364 function Equivalent_Keys
(Left
, Right
: Cursor
)
367 if Left
.Node
= 0 then
368 raise Constraint_Error
with
369 "Left cursor of Equivalent_Keys equals No_Element";
372 if Right
.Node
= 0 then
373 raise Constraint_Error
with
374 "Right cursor of Equivalent_Keys equals No_Element";
377 pragma Assert
(Vet
(Left
), "Left cursor of Equivalent_Keys is bad");
378 pragma Assert
(Vet
(Right
), "Right cursor of Equivalent_Keys is bad");
381 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
382 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
385 return Equivalent_Keys
(LN
.Key
, RN
.Key
);
389 function Equivalent_Keys
(Left
: Cursor
; Right
: Key_Type
) return Boolean is
391 if Left
.Node
= 0 then
392 raise Constraint_Error
with
393 "Left cursor of Equivalent_Keys equals No_Element";
396 pragma Assert
(Vet
(Left
), "Left cursor in Equivalent_Keys is bad");
399 LN
: Node_Type
renames Left
.Container
.Nodes
(Left
.Node
);
402 return Equivalent_Keys
(LN
.Key
, Right
);
406 function Equivalent_Keys
(Left
: Key_Type
; Right
: Cursor
) return Boolean is
408 if Right
.Node
= 0 then
409 raise Constraint_Error
with
410 "Right cursor of Equivalent_Keys equals No_Element";
413 pragma Assert
(Vet
(Right
), "Right cursor of Equivalent_Keys is bad");
416 RN
: Node_Type
renames Right
.Container
.Nodes
(Right
.Node
);
419 return Equivalent_Keys
(Left
, RN
.Key
);
427 procedure Exclude
(Container
: in out Map
; Key
: Key_Type
) is
430 Key_Ops
.Delete_Key_Sans_Free
(Container
, Key
, X
);
431 HT_Ops
.Free
(Container
, X
);
438 procedure Finalize
(Object
: in out Iterator
) is
440 if Object
.Container
/= null then
442 B
: Natural renames Object
.Container
.all.Busy
;
453 function Find
(Container
: Map
; Key
: Key_Type
) return Cursor
is
454 Node
: constant Count_Type
:=
455 Key_Ops
.Find
(Container
'Unrestricted_Access.all, Key
);
460 return Cursor
'(Container'Unrestricted_Access, Node);
468 function First (Container : Map) return Cursor is
469 Node : constant Count_Type := HT_Ops.First (Container);
474 return Cursor'(Container
'Unrestricted_Access, Node
);
478 function First
(Object
: Iterator
) return Cursor
is
480 return Object
.Container
.First
;
487 function Has_Element
(Position
: Cursor
) return Boolean is
489 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
490 return Position
.Node
/= 0;
497 function Hash_Node
(Node
: Node_Type
) return Hash_Type
is
499 return Hash
(Node
.Key
);
507 (Container
: in out Map
;
509 New_Item
: Element_Type
)
515 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
518 if Container
.Lock
> 0 then
519 raise Program_Error
with
520 "Include attempted to tamper with elements (map is locked)";
524 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
527 N
.Element
:= New_Item
;
537 (Container
: in out Map
;
539 Position
: out Cursor
;
540 Inserted
: out Boolean)
542 procedure Assign_Key
(Node
: in out Node_Type
);
543 pragma Inline
(Assign_Key
);
545 function New_Node
return Count_Type
;
546 pragma Inline
(New_Node
);
548 procedure Local_Insert
is
549 new Key_Ops
.Generic_Conditional_Insert
(New_Node
);
551 procedure Allocate
is
552 new HT_Ops
.Generic_Allocate
(Assign_Key
);
558 procedure Assign_Key
(Node
: in out Node_Type
) is
559 New_Item
: Element_Type
;
560 pragma Unmodified
(New_Item
);
561 -- Default-initialized element (ok to reference, see below)
566 -- There is no explicit element provided, but in an instance the
567 -- element type may be a scalar with a Default_Value aspect, or a
568 -- composite type with such a scalar component, or components with
569 -- default initialization, so insert a possibly initialized element
570 -- under the given key.
572 Node
.Element
:= New_Item
;
579 function New_Node
return Count_Type
is
582 Allocate
(Container
, Result
);
586 -- Start of processing for Insert
589 -- The buckets array length is specified by the user as a discriminant
590 -- of the container type, so it is possible for the buckets array to
591 -- have a length of zero. We must check for this case specifically, in
592 -- order to prevent divide-by-zero errors later, when we compute the
593 -- buckets array index value for a key, given its hash value.
595 if Container
.Buckets
'Length = 0 then
596 raise Capacity_Error
with "No capacity for insertion";
599 Local_Insert
(Container
, Key
, Position
.Node
, Inserted
);
600 Position
.Container
:= Container
'Unchecked_Access;
604 (Container
: in out Map
;
606 New_Item
: Element_Type
;
607 Position
: out Cursor
;
608 Inserted
: out Boolean)
610 procedure Assign_Key
(Node
: in out Node_Type
);
611 pragma Inline
(Assign_Key
);
613 function New_Node
return Count_Type
;
614 pragma Inline
(New_Node
);
616 procedure Local_Insert
is
617 new Key_Ops
.Generic_Conditional_Insert
(New_Node
);
619 procedure Allocate
is
620 new HT_Ops
.Generic_Allocate
(Assign_Key
);
626 procedure Assign_Key
(Node
: in out Node_Type
) is
629 Node
.Element
:= New_Item
;
636 function New_Node
return Count_Type
is
639 Allocate
(Container
, Result
);
643 -- Start of processing for Insert
646 -- The buckets array length is specified by the user as a discriminant
647 -- of the container type, so it is possible for the buckets array to
648 -- have a length of zero. We must check for this case specifically, in
649 -- order to prevent divide-by-zero errors later, when we compute the
650 -- buckets array index value for a key, given its hash value.
652 if Container
.Buckets
'Length = 0 then
653 raise Capacity_Error
with "No capacity for insertion";
656 Local_Insert
(Container
, Key
, Position
.Node
, Inserted
);
657 Position
.Container
:= Container
'Unchecked_Access;
661 (Container
: in out Map
;
663 New_Item
: Element_Type
)
666 pragma Unreferenced
(Position
);
671 Insert
(Container
, Key
, New_Item
, Position
, Inserted
);
674 raise Constraint_Error
with
675 "attempt to insert key already in map";
683 function Is_Empty
(Container
: Map
) return Boolean is
685 return Container
.Length
= 0;
694 Process
: not null access procedure (Position
: Cursor
))
696 procedure Process_Node
(Node
: Count_Type
);
697 pragma Inline
(Process_Node
);
699 procedure Local_Iterate
is new HT_Ops
.Generic_Iteration
(Process_Node
);
705 procedure Process_Node
(Node
: Count_Type
) is
707 Process
(Cursor
'(Container'Unrestricted_Access, Node));
710 B : Natural renames Container'Unrestricted_Access.all.Busy;
712 -- Start of processing for Iterate
718 Local_Iterate (Container);
729 (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class
731 B : Natural renames Container'Unrestricted_Access.all.Busy;
734 return It : constant Iterator :=
735 (Limited_Controlled with
736 Container => Container'Unrestricted_Access)
746 function Key (Position : Cursor) return Key_Type is
748 if Position.Node = 0 then
749 raise Constraint_Error with
750 "Position cursor of function Key equals No_Element";
753 pragma Assert (Vet (Position), "bad cursor in function Key");
755 return Position.Container.Nodes (Position.Node).Key;
762 function Length (Container : Map) return Count_Type is
764 return Container.Length;
772 (Target : in out Map;
776 if Target'Address = Source'Address then
780 if Source.Busy > 0 then
781 raise Program_Error with
782 "attempt to tamper with cursors (container is busy)";
785 Target.Assign (Source);
793 function Next (Node : Node_Type) return Count_Type is
798 function Next (Position : Cursor) return Cursor is
800 if Position.Node = 0 then
804 pragma Assert (Vet (Position), "bad cursor in function Next");
807 M : Map renames Position.Container.all;
808 Node : constant Count_Type := HT_Ops.Next (M, Position.Node);
813 return Cursor'(Position
.Container
, Node
);
818 procedure Next
(Position
: in out Cursor
) is
820 Position
:= Next
(Position
);
825 Position
: Cursor
) return Cursor
828 if Position
.Container
= null then
832 if Position
.Container
/= Object
.Container
then
833 raise Program_Error
with
834 "Position cursor of Next designates wrong map";
837 return Next
(Position
);
844 procedure Query_Element
846 Process
: not null access
847 procedure (Key
: Key_Type
; Element
: Element_Type
))
850 if Position
.Node
= 0 then
851 raise Constraint_Error
with
852 "Position cursor of Query_Element equals No_Element";
855 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
858 M
: Map
renames Position
.Container
.all;
859 N
: Node_Type
renames M
.Nodes
(Position
.Node
);
860 B
: Natural renames M
.Busy
;
861 L
: Natural renames M
.Lock
;
870 Process
(N
.Key
, N
.Element
);
888 (Stream
: not null access Root_Stream_Type
'Class;
892 (Stream
: not null access Root_Stream_Type
'Class) return Count_Type
;
893 -- pragma Inline (Read_Node); ???
895 procedure Read_Nodes
is new HT_Ops
.Generic_Read
(Read_Node
);
902 (Stream
: not null access Root_Stream_Type
'Class) return Count_Type
904 procedure Read_Element
(Node
: in out Node_Type
);
905 -- pragma Inline (Read_Element); ???
907 procedure Allocate
is
908 new HT_Ops
.Generic_Allocate
(Read_Element
);
910 procedure Read_Element
(Node
: in out Node_Type
) is
912 Key_Type
'Read (Stream
, Node
.Key
);
913 Element_Type
'Read (Stream
, Node
.Element
);
918 -- Start of processing for Read_Node
921 Allocate
(Container
, Node
);
925 -- Start of processing for Read
928 Read_Nodes
(Stream
, Container
);
932 (Stream
: not null access Root_Stream_Type
'Class;
936 raise Program_Error
with "attempt to stream map cursor";
940 (Stream
: not null access Root_Stream_Type
'Class;
941 Item
: out Reference_Type
)
944 raise Program_Error
with "attempt to stream reference";
948 (Stream
: not null access Root_Stream_Type
'Class;
949 Item
: out Constant_Reference_Type
)
952 raise Program_Error
with "attempt to stream reference";
960 (Container
: aliased in out Map
;
961 Position
: Cursor
) return Reference_Type
964 if Position
.Container
= null then
965 raise Constraint_Error
with
966 "Position cursor has no element";
969 if Position
.Container
/= Container
'Unrestricted_Access then
970 raise Program_Error
with
971 "Position cursor designates wrong map";
974 pragma Assert
(Vet
(Position
),
975 "Position cursor in function Reference is bad");
978 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
980 return (Element
=> N
.Element
'Access);
985 (Container
: aliased in out Map
;
986 Key
: Key_Type
) return Reference_Type
988 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
992 raise Constraint_Error
with "key not in map";
996 N
: Node_Type
renames Container
.Nodes
(Node
);
998 return (Element
=> N
.Element
'Access);
1007 (Container
: in out Map
;
1009 New_Item
: Element_Type
)
1011 Node
: constant Count_Type
:= Key_Ops
.Find
(Container
, Key
);
1015 raise Constraint_Error
with
1016 "attempt to replace key not in map";
1019 if Container
.Lock
> 0 then
1020 raise Program_Error
with
1021 "Replace attempted to tamper with elements (map is locked)";
1025 N
: Node_Type
renames Container
.Nodes
(Node
);
1029 N
.Element
:= New_Item
;
1033 ---------------------
1034 -- Replace_Element --
1035 ---------------------
1037 procedure Replace_Element
1038 (Container
: in out Map
;
1040 New_Item
: Element_Type
)
1043 if Position
.Node
= 0 then
1044 raise Constraint_Error
with
1045 "Position cursor of Replace_Element equals No_Element";
1048 if Position
.Container
/= Container
'Unrestricted_Access then
1049 raise Program_Error
with
1050 "Position cursor of Replace_Element designates wrong map";
1053 if Position
.Container
.Lock
> 0 then
1054 raise Program_Error
with
1055 "Replace_Element attempted to tamper with elements (map is locked)";
1058 pragma Assert
(Vet
(Position
), "bad cursor in Replace_Element");
1060 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
1061 end Replace_Element
;
1063 ----------------------
1064 -- Reserve_Capacity --
1065 ----------------------
1067 procedure Reserve_Capacity
1068 (Container
: in out Map
;
1069 Capacity
: Count_Type
)
1072 if Capacity
> Container
.Capacity
then
1073 raise Capacity_Error
with "requested capacity is too large";
1075 end Reserve_Capacity
;
1081 procedure Set_Next
(Node
: in out Node_Type
; Next
: Count_Type
) is
1086 --------------------
1087 -- Update_Element --
1088 --------------------
1090 procedure Update_Element
1091 (Container
: in out Map
;
1093 Process
: not null access procedure (Key
: Key_Type
;
1094 Element
: in out Element_Type
))
1097 if Position
.Node
= 0 then
1098 raise Constraint_Error
with
1099 "Position cursor of Update_Element equals No_Element";
1102 if Position
.Container
/= Container
'Unrestricted_Access then
1103 raise Program_Error
with
1104 "Position cursor of Update_Element designates wrong map";
1107 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
1110 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
1111 B
: Natural renames Container
.Busy
;
1112 L
: Natural renames Container
.Lock
;
1119 Process
(N
.Key
, N
.Element
);
1136 function Vet
(Position
: Cursor
) return Boolean is
1138 if Position
.Node
= 0 then
1139 return Position
.Container
= null;
1142 if Position
.Container
= null then
1147 M
: Map
renames Position
.Container
.all;
1151 if M
.Length
= 0 then
1155 if M
.Capacity
= 0 then
1159 if M
.Buckets
'Length = 0 then
1163 if Position
.Node
> M
.Capacity
then
1167 if M
.Nodes
(Position
.Node
).Next
= Position
.Node
then
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
1183 if X
= M
.Nodes
(X
).Next
then -- to prevent unnecessary looping
1187 X
:= M
.Nodes
(X
).Next
;
1199 (Stream
: not null access Root_Stream_Type
'Class;
1202 procedure Write_Node
1203 (Stream
: not null access Root_Stream_Type
'Class;
1205 pragma Inline
(Write_Node
);
1207 procedure Write_Nodes
is new HT_Ops
.Generic_Write
(Write_Node
);
1213 procedure Write_Node
1214 (Stream
: not null access Root_Stream_Type
'Class;
1218 Key_Type
'Write (Stream
, Node
.Key
);
1219 Element_Type
'Write (Stream
, Node
.Element
);
1222 -- Start of processing for Write
1225 Write_Nodes
(Stream
, Container
);
1229 (Stream
: not null access Root_Stream_Type
'Class;
1233 raise Program_Error
with "attempt to stream map cursor";
1237 (Stream
: not null access Root_Stream_Type
'Class;
1238 Item
: Reference_Type
)
1241 raise Program_Error
with "attempt to stream reference";
1245 (Stream
: not null access Root_Stream_Type
'Class;
1246 Item
: Constant_Reference_Type
)
1249 raise Program_Error
with "attempt to stream reference";
1252 end Ada
.Containers
.Bounded_Hashed_Maps
;