openat: don’t close (-1)
[gnulib.git] / lib / gl_hash_set.c
blob8e135238ae7fbb28a589b59b65c4772a5f06ab4f
1 /* Set data type implemented by a hash table.
2 Copyright (C) 2006, 2008-2024 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/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "gl_hash_set.h"
23 #include <stdint.h> /* for uintptr_t, SIZE_MAX */
24 #include <stdlib.h>
26 #include "xsize.h"
28 /* --------------------------- gl_set_t Data Type --------------------------- */
30 #include "gl_anyhash1.h"
32 /* Concrete list node implementation, valid for this file only. */
33 struct gl_list_node_impl
35 struct gl_hash_entry h; /* hash table entry fields; must be first */
36 const void *value;
38 typedef struct gl_list_node_impl * gl_list_node_t;
40 /* Concrete gl_set_impl type, valid for this file only. */
41 struct gl_set_impl
43 struct gl_set_impl_base base;
44 gl_setelement_hashcode_fn hashcode_fn;
45 /* A hash table: managed as an array of collision lists. */
46 struct gl_hash_entry **table;
47 size_t table_size;
48 /* Number of hash table entries. */
49 size_t count;
52 #define CONTAINER_T gl_set_t
53 #define CONTAINER_COUNT(set) (set)->count
54 #include "gl_anyhash2.h"
56 /* --------------------------- gl_set_t Data Type --------------------------- */
58 static gl_set_t
59 gl_hash_nx_create_empty (gl_set_implementation_t implementation,
60 gl_setelement_equals_fn equals_fn,
61 gl_setelement_hashcode_fn hashcode_fn,
62 gl_setelement_dispose_fn dispose_fn)
64 struct gl_set_impl *set =
65 (struct gl_set_impl *) malloc (sizeof (struct gl_set_impl));
67 if (set == NULL)
68 return NULL;
70 set->base.vtable = implementation;
71 set->base.equals_fn = equals_fn;
72 set->base.dispose_fn = dispose_fn;
73 set->hashcode_fn = hashcode_fn;
74 set->table_size = 11;
75 set->table =
76 (gl_hash_entry_t *) calloc (set->table_size, sizeof (gl_hash_entry_t));
77 if (set->table == NULL)
78 goto fail;
79 set->count = 0;
81 return set;
83 fail:
84 free (set);
85 return NULL;
88 static size_t _GL_ATTRIBUTE_PURE
89 gl_hash_size (gl_set_t set)
91 return set->count;
94 static bool _GL_ATTRIBUTE_PURE
95 gl_hash_search (gl_set_t set, const void *elt)
97 size_t hashcode =
98 (set->hashcode_fn != NULL
99 ? set->hashcode_fn (elt)
100 : (size_t)(uintptr_t) elt);
101 size_t bucket = hashcode % set->table_size;
102 gl_setelement_equals_fn equals = set->base.equals_fn;
104 /* Look for a match in the hash bucket. */
105 gl_list_node_t node;
107 for (node = (gl_list_node_t) set->table[bucket];
108 node != NULL;
109 node = (gl_list_node_t) node->h.hash_next)
110 if (node->h.hashcode == hashcode
111 && (equals != NULL
112 ? equals (elt, node->value)
113 : elt == node->value))
114 return true;
115 return false;
118 static int
119 gl_hash_nx_add (gl_set_t set, const void *elt)
121 size_t hashcode =
122 (set->hashcode_fn != NULL
123 ? set->hashcode_fn (elt)
124 : (size_t)(uintptr_t) elt);
125 size_t bucket = hashcode % set->table_size;
126 gl_setelement_equals_fn equals = set->base.equals_fn;
128 /* Look for a match in the hash bucket. */
130 gl_list_node_t node;
132 for (node = (gl_list_node_t) set->table[bucket];
133 node != NULL;
134 node = (gl_list_node_t) node->h.hash_next)
135 if (node->h.hashcode == hashcode
136 && (equals != NULL
137 ? equals (elt, node->value)
138 : elt == node->value))
139 return 0;
142 /* Allocate a new node. */
143 gl_list_node_t node =
144 (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
146 if (node == NULL)
147 return -1;
149 node->value = elt;
150 node->h.hashcode = hashcode;
152 /* Add node to the hash table. */
153 node->h.hash_next = set->table[bucket];
154 set->table[bucket] = &node->h;
156 /* Add node to the set. */
157 set->count++;
159 hash_resize_after_add (set);
161 return 1;
164 static bool
165 gl_hash_remove (gl_set_t set, const void *elt)
167 size_t hashcode =
168 (set->hashcode_fn != NULL
169 ? set->hashcode_fn (elt)
170 : (size_t)(uintptr_t) elt);
171 size_t bucket = hashcode % set->table_size;
172 gl_setelement_equals_fn equals = set->base.equals_fn;
174 /* Look for the first match in the hash bucket. */
175 gl_list_node_t *nodep;
177 for (nodep = (gl_list_node_t *) &set->table[bucket];
178 *nodep != NULL;
179 nodep = (gl_list_node_t *) &(*nodep)->h.hash_next)
181 gl_list_node_t node = *nodep;
182 if (node->h.hashcode == hashcode
183 && (equals != NULL
184 ? equals (elt, node->value)
185 : elt == node->value))
187 /* Remove node from the hash table. */
188 *nodep = (gl_list_node_t) node->h.hash_next;
190 /* Remove node from the set. */
191 set->count--;
193 if (set->base.dispose_fn != NULL)
194 set->base.dispose_fn (node->value);
195 free (node);
196 return true;
200 return false;
203 static void
204 gl_hash_free (gl_set_t set)
206 if (set->count > 0)
208 gl_setelement_dispose_fn dispose = set->base.dispose_fn;
209 struct gl_hash_entry **table = set->table;
210 size_t i;
212 for (i = set->table_size; i > 0; )
214 gl_hash_entry_t node = table[--i];
216 while (node != NULL)
218 gl_hash_entry_t next = node->hash_next;
220 /* Free the entry. */
221 if (dispose != NULL)
222 dispose (((gl_list_node_t) node)->value);
223 free (node);
225 node = next;
230 free (set->table);
231 free (set);
234 /* ---------------------- gl_set_iterator_t Data Type ---------------------- */
236 /* Here we iterate through the hash buckets. Therefore the order in which the
237 elements are returned is unpredictable. */
239 static gl_set_iterator_t
240 gl_hash_iterator (gl_set_t set)
242 gl_set_iterator_t result;
244 result.vtable = set->base.vtable;
245 result.set = set;
246 result.p = NULL; /* runs through the nodes of a bucket */
247 result.i = 0; /* index of the bucket that p points into + 1 */
248 result.j = set->table_size;
249 #if defined GCC_LINT || defined lint
250 result.q = NULL;
251 result.count = 0;
252 #endif
254 return result;
257 static bool
258 gl_hash_iterator_next (gl_set_iterator_t *iterator, const void **eltp)
260 if (iterator->p != NULL)
262 /* We're traversing a bucket. */
263 gl_list_node_t node = (gl_list_node_t) iterator->p;
264 *eltp = node->value;
265 iterator->p = (gl_list_node_t) node->h.hash_next;
266 return true;
268 else
270 /* Find the next bucket that is not empty. */
271 size_t j = iterator->j;
272 size_t i = iterator->i;
274 if (i < j)
276 gl_hash_entry_t *table = iterator->set->table;
279 gl_list_node_t node = (gl_list_node_t) table[i++];
280 if (node != NULL)
282 *eltp = node->value;
283 iterator->p = (gl_list_node_t) node->h.hash_next;
284 iterator->i = i;
285 return true;
288 while (i < j);
290 /* Here iterator->p is still NULL, and i == j. */
291 iterator->i = j;
292 return false;
296 static void
297 gl_hash_iterator_free (gl_set_iterator_t *iterator)
302 const struct gl_set_implementation gl_hash_set_implementation =
304 gl_hash_nx_create_empty,
305 gl_hash_size,
306 gl_hash_search,
307 gl_hash_nx_add,
308 gl_hash_remove,
309 gl_hash_free,
310 gl_hash_iterator,
311 gl_hash_iterator_next,
312 gl_hash_iterator_free