1 /* Map data type implemented by a hash table.
2 Copyright (C) 2006, 2008-2019 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2018.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
21 #include "gl_hash_map.h"
23 #include <stdint.h> /* for SIZE_MAX */
29 # define uintptr_t unsigned long
32 /* --------------------------- gl_map_t Data Type --------------------------- */
34 #include "gl_anyhash1.h"
36 /* Concrete list node implementation, valid for this file only. */
37 struct gl_list_node_impl
39 struct gl_hash_entry h
; /* hash table entry fields; must be first */
43 typedef struct gl_list_node_impl
* gl_list_node_t
;
45 /* Concrete gl_map_impl type, valid for this file only. */
48 struct gl_map_impl_base base
;
49 gl_mapkey_hashcode_fn hashcode_fn
;
50 /* A hash table: managed as an array of collision lists. */
51 struct gl_hash_entry
**table
;
53 /* Number of hash table entries. */
57 #define CONTAINER_T gl_map_t
58 #define CONTAINER_COUNT(map) (map)->count
59 #include "gl_anyhash2.h"
61 /* --------------------------- gl_map_t Data Type --------------------------- */
64 gl_hash_nx_create_empty (gl_map_implementation_t implementation
,
65 gl_mapkey_equals_fn equals_fn
,
66 gl_mapkey_hashcode_fn hashcode_fn
,
67 gl_mapkey_dispose_fn kdispose_fn
,
68 gl_mapvalue_dispose_fn vdispose_fn
)
70 struct gl_map_impl
*map
=
71 (struct gl_map_impl
*) malloc (sizeof (struct gl_map_impl
));
76 map
->base
.vtable
= implementation
;
77 map
->base
.equals_fn
= equals_fn
;
78 map
->base
.kdispose_fn
= kdispose_fn
;
79 map
->base
.vdispose_fn
= vdispose_fn
;
80 map
->hashcode_fn
= hashcode_fn
;
83 (gl_hash_entry_t
*) calloc (map
->table_size
, sizeof (gl_hash_entry_t
));
84 if (map
->table
== NULL
)
95 static size_t _GL_ATTRIBUTE_PURE
96 gl_hash_size (gl_map_t map
)
101 static bool _GL_ATTRIBUTE_PURE
102 gl_hash_search (gl_map_t map
, const void *key
, const void **valuep
)
105 (map
->hashcode_fn
!= NULL
106 ? map
->hashcode_fn (key
)
107 : (size_t)(uintptr_t) key
);
108 size_t bucket
= hashcode
% map
->table_size
;
109 gl_mapkey_equals_fn equals
= map
->base
.equals_fn
;
111 /* Look for a match in the hash bucket. */
114 for (node
= (gl_list_node_t
) map
->table
[bucket
];
116 node
= (gl_list_node_t
) node
->h
.hash_next
)
117 if (node
->h
.hashcode
== hashcode
119 ? equals (key
, node
->key
)
122 *valuep
= node
->value
;
129 gl_hash_nx_getput (gl_map_t map
, const void *key
, const void *value
,
130 const void **oldvaluep
)
133 (map
->hashcode_fn
!= NULL
134 ? map
->hashcode_fn (key
)
135 : (size_t)(uintptr_t) key
);
136 size_t bucket
= hashcode
% map
->table_size
;
137 gl_mapkey_equals_fn equals
= map
->base
.equals_fn
;
139 /* Look for a match in the hash bucket. */
143 for (node
= (gl_list_node_t
) map
->table
[bucket
];
145 node
= (gl_list_node_t
) node
->h
.hash_next
)
146 if (node
->h
.hashcode
== hashcode
148 ? equals (key
, node
->key
)
151 *oldvaluep
= node
->value
;
157 /* Allocate a new node. */
158 gl_list_node_t node
=
159 (struct gl_list_node_impl
*) malloc (sizeof (struct gl_list_node_impl
));
166 node
->h
.hashcode
= hashcode
;
168 /* Add node to the hash table. */
169 node
->h
.hash_next
= map
->table
[bucket
];
170 map
->table
[bucket
] = &node
->h
;
172 /* Add node to the map. */
175 hash_resize_after_add (map
);
181 gl_hash_getremove (gl_map_t map
, const void *key
, const void **oldvaluep
)
184 (map
->hashcode_fn
!= NULL
185 ? map
->hashcode_fn (key
)
186 : (size_t)(uintptr_t) key
);
187 size_t bucket
= hashcode
% map
->table_size
;
188 gl_mapkey_equals_fn equals
= map
->base
.equals_fn
;
190 /* Look for the first match in the hash bucket. */
191 gl_list_node_t
*nodep
;
193 for (nodep
= (gl_list_node_t
*) &map
->table
[bucket
];
195 nodep
= (gl_list_node_t
*) &(*nodep
)->h
.hash_next
)
197 gl_list_node_t node
= *nodep
;
198 if (node
->h
.hashcode
== hashcode
200 ? equals (key
, node
->key
)
203 *oldvaluep
= node
->value
;
205 /* Remove node from the hash table. */
206 *nodep
= (gl_list_node_t
) node
->h
.hash_next
;
208 /* Remove node from the map. */
211 if (map
->base
.kdispose_fn
!= NULL
)
212 map
->base
.kdispose_fn (node
->key
);
222 gl_hash_free (gl_map_t map
)
226 gl_mapkey_dispose_fn kdispose
= map
->base
.kdispose_fn
;
227 gl_mapvalue_dispose_fn vdispose
= map
->base
.vdispose_fn
;
228 struct gl_hash_entry
**table
= map
->table
;
231 for (i
= map
->table_size
; i
> 0; )
233 gl_hash_entry_t node
= table
[--i
];
237 gl_hash_entry_t next
= node
->hash_next
;
239 /* Free the entry. */
240 if (vdispose
!= NULL
)
241 vdispose (((gl_list_node_t
) node
)->value
);
242 if (kdispose
!= NULL
)
243 kdispose (((gl_list_node_t
) node
)->key
);
255 /* ---------------------- gl_map_iterator_t Data Type ---------------------- */
257 /* Here we iterate through the hash buckets. Therefore the order in which the
258 pairs are returned is unpredictable. */
260 static gl_map_iterator_t
261 gl_hash_iterator (gl_map_t map
)
263 gl_map_iterator_t result
;
265 result
.vtable
= map
->base
.vtable
;
267 result
.p
= NULL
; /* runs through the nodes of a bucket */
268 result
.i
= 0; /* index of the bucket that p points into + 1 */
269 result
.j
= map
->table_size
;
270 #if defined GCC_LINT || defined lint
279 gl_hash_iterator_next (gl_map_iterator_t
*iterator
,
280 const void **keyp
, const void **valuep
)
282 if (iterator
->p
!= NULL
)
284 /* We're traversing a bucket. */
285 gl_list_node_t node
= (gl_list_node_t
) iterator
->p
;
287 *valuep
= node
->value
;
288 iterator
->p
= (gl_list_node_t
) node
->h
.hash_next
;
293 /* Find the next bucket that is not empty. */
294 size_t j
= iterator
->j
;
295 size_t i
= iterator
->i
;
299 gl_hash_entry_t
*table
= iterator
->map
->table
;
302 gl_list_node_t node
= (gl_list_node_t
) table
[i
++];
306 *valuep
= node
->value
;
307 iterator
->p
= (gl_list_node_t
) node
->h
.hash_next
;
314 /* Here iterator->p is still NULL, and i == j. */
321 gl_hash_iterator_free (gl_map_iterator_t
*iterator
)
326 const struct gl_map_implementation gl_hash_map_implementation
=
328 gl_hash_nx_create_empty
,
335 gl_hash_iterator_next
,
336 gl_hash_iterator_free