1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.HASH_TABLES.GENERIC_KEYS --
9 -- Copyright (C) 2004-2015, 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 package body Ada
.Containers
.Hash_Tables
.Generic_Keys
is
32 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
33 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
34 -- See comment in Ada.Containers.Helpers
36 -----------------------------
37 -- Checked_Equivalent_Keys --
38 -----------------------------
40 function Checked_Equivalent_Keys
41 (HT
: aliased in out Hash_Table_Type
;
43 Node
: Node_Access
) return Boolean
45 Lock
: With_Lock
(HT
.TC
'Unrestricted_Access);
47 return Equivalent_Keys
(Key
, Node
);
48 end Checked_Equivalent_Keys
;
54 function Checked_Index
55 (HT
: aliased in out Hash_Table_Type
;
56 Key
: Key_Type
) return Hash_Type
58 Lock
: With_Lock
(HT
.TC
'Unrestricted_Access);
60 return Hash
(Key
) mod HT
.Buckets
'Length;
63 --------------------------
64 -- Delete_Key_Sans_Free --
65 --------------------------
67 procedure Delete_Key_Sans_Free
68 (HT
: in out Hash_Table_Type
;
81 -- Per AI05-0022, the container implementation is required to detect
82 -- element tampering by a generic actual subprogram.
86 Indx
:= Checked_Index
(HT
, Key
);
87 X
:= HT
.Buckets
(Indx
);
93 if Checked_Equivalent_Keys
(HT
, Key
, X
) then
95 HT
.Buckets
(Indx
) := Next
(X
);
96 HT
.Length
:= HT
.Length
- 1;
108 if Checked_Equivalent_Keys
(HT
, Key
, X
) then
110 Set_Next
(Node
=> Prev
, Next
=> Next
(X
));
111 HT
.Length
:= HT
.Length
- 1;
115 end Delete_Key_Sans_Free
;
122 (HT
: aliased in out Hash_Table_Type
;
123 Key
: Key_Type
) return Node_Access
129 if HT
.Length
= 0 then
133 Indx
:= Checked_Index
(HT
, Key
);
135 Node
:= HT
.Buckets
(Indx
);
136 while Node
/= null loop
137 if Checked_Equivalent_Keys
(HT
, Key
, Node
) then
146 --------------------------------
147 -- Generic_Conditional_Insert --
148 --------------------------------
150 procedure Generic_Conditional_Insert
151 (HT
: in out Hash_Table_Type
;
153 Node
: out Node_Access
;
154 Inserted
: out Boolean)
159 -- Per AI05-0022, the container implementation is required to detect
160 -- element tampering by a generic actual subprogram.
164 Indx
:= Checked_Index
(HT
, Key
);
165 Node
:= HT
.Buckets
(Indx
);
168 if Checks
and then HT
.Length
= Count_Type
'Last then
169 raise Constraint_Error
;
172 Node
:= New_Node
(Next
=> null);
175 HT
.Buckets
(Indx
) := Node
;
176 HT
.Length
:= HT
.Length
+ 1;
182 if Checked_Equivalent_Keys
(HT
, Key
, Node
) then
189 exit when Node
= null;
192 if Checks
and then HT
.Length
= Count_Type
'Last then
193 raise Constraint_Error
;
196 Node
:= New_Node
(Next
=> HT
.Buckets
(Indx
));
199 HT
.Buckets
(Indx
) := Node
;
200 HT
.Length
:= HT
.Length
+ 1;
201 end Generic_Conditional_Insert
;
203 -----------------------------
204 -- Generic_Replace_Element --
205 -----------------------------
207 procedure Generic_Replace_Element
208 (HT
: in out Hash_Table_Type
;
212 pragma Assert
(HT
.Length
> 0);
213 pragma Assert
(Node
/= null);
215 Old_Indx
: Hash_Type
;
216 New_Indx
: constant Hash_Type
:= Checked_Index
(HT
, Key
);
218 New_Bucket
: Node_Access
renames HT
.Buckets
(New_Indx
);
222 -- Per AI05-0022, the container implementation is required to detect
223 -- element tampering by a generic actual subprogram.
226 Lock
: With_Lock
(HT
.TC
'Unrestricted_Access);
228 Old_Indx
:= Hash
(Node
) mod HT
.Buckets
'Length;
231 if Checked_Equivalent_Keys
(HT
, Key
, Node
) then
234 -- We can change a node's key to Key (that's what Assign is for), but
235 -- only if Key is not already in the hash table. (In a unique-key
236 -- hash table as this one a key is mapped to exactly one node only.)
237 -- The exception is when Key is mapped to Node, in which case the
238 -- change is allowed.
244 -- Key is not equivalent to Node, so we now have to determine if it's
245 -- equivalent to some other node in the hash table. This is the case
246 -- irrespective of whether Key is in the same or a different bucket from
251 if Checks
and then Checked_Equivalent_Keys
(HT
, Key
, N
) then
252 pragma Assert
(N
/= Node
);
253 raise Program_Error
with
254 "attempt to replace existing element";
260 -- We have determined that Key is not already in the hash table, so
261 -- the change is tentatively allowed. We now perform the standard
262 -- checks to determine whether the hash table is locked (because you
263 -- cannot change an element while it's in use by Query_Element or
264 -- Update_Element), or if the container is busy (because moving a
265 -- node to a different bucket would interfere with iteration).
267 if Old_Indx
= New_Indx
then
268 -- The node is already in the bucket implied by Key. In this case
269 -- we merely change its value without moving it.
277 -- The node is a bucket different from the bucket implied by Key
281 -- Do the assignment first, before moving the node, so that if Assign
282 -- propagates an exception, then the hash table will not have been
283 -- modified (except for any possible side-effect Assign had on Node).
287 -- Now we can safely remove the node from its current bucket
289 N
:= HT
.Buckets
(Old_Indx
);
290 pragma Assert
(N
/= null);
293 HT
.Buckets
(Old_Indx
) := Next
(Node
);
296 pragma Assert
(HT
.Length
> 1);
300 pragma Assert
(M
/= null);
303 Set_Next
(Node
=> N
, Next
=> Next
(Node
));
311 -- Now we link the node into its new bucket (corresponding to Key)
313 Set_Next
(Node
=> Node
, Next
=> New_Bucket
);
315 end Generic_Replace_Element
;
322 (HT
: Hash_Table_Type
;
323 Key
: Key_Type
) return Hash_Type
326 return Hash
(Key
) mod HT
.Buckets
'Length;
329 end Ada
.Containers
.Hash_Tables
.Generic_Keys
;