1 /* Set data type implemented by a hash table with a linked list.
2 Copyright (C) 2006, 2008-2020 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_linkedhash_set.h"
23 #include <stdint.h> /* for uintptr_t, SIZE_MAX */
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 struct gl_list_node_impl
*next
;
37 struct gl_list_node_impl
*prev
;
40 typedef struct gl_list_node_impl
* gl_list_node_t
;
42 /* Concrete gl_set_impl type, valid for this file only. */
45 struct gl_set_impl_base base
;
46 gl_setelement_hashcode_fn hashcode_fn
;
47 /* A hash table: managed as an array of collision lists. */
48 struct gl_hash_entry
**table
;
50 /* A circular list anchored at root.
51 The first node is = root.next, the last node is = root.prev.
52 The root's value is unused. */
53 struct gl_list_node_impl root
;
54 /* Number of list nodes, excluding the root. */
58 #define CONTAINER_T gl_set_t
59 #define CONTAINER_COUNT(set) (set)->count
60 #include "gl_anyhash2.h"
62 /* If the symbol SIGNAL_SAFE_SET is defined, the code is compiled in such
63 a way that a gl_set_t data structure may be used from within a signal
64 handler. The operations allowed in the signal handler are:
65 gl_set_iterator, gl_set_iterator_next, gl_set_iterator_free.
66 The set and node fields that are therefore accessed from the signal handler
68 set->root, node->next, node->value.
69 We are careful to make modifications to these fields only in an order
70 that maintains the consistency of the list data structure at any moment,
71 and we use 'volatile' assignments to prevent the compiler from reordering
73 #ifdef SIGNAL_SAFE_SET
74 # define ASYNCSAFE(type) *(type volatile *)&
76 # define ASYNCSAFE(type)
79 /* --------------------------- gl_set_t Data Type --------------------------- */
82 gl_linkedhash_nx_create_empty (gl_set_implementation_t implementation
,
83 gl_setelement_equals_fn equals_fn
,
84 gl_setelement_hashcode_fn hashcode_fn
,
85 gl_setelement_dispose_fn dispose_fn
)
87 struct gl_set_impl
*set
=
88 (struct gl_set_impl
*) malloc (sizeof (struct gl_set_impl
));
93 set
->base
.vtable
= implementation
;
94 set
->base
.equals_fn
= equals_fn
;
95 set
->base
.dispose_fn
= dispose_fn
;
96 set
->hashcode_fn
= hashcode_fn
;
99 (gl_hash_entry_t
*) calloc (set
->table_size
, sizeof (gl_hash_entry_t
));
100 if (set
->table
== NULL
)
102 set
->root
.next
= &set
->root
;
103 set
->root
.prev
= &set
->root
;
113 static size_t _GL_ATTRIBUTE_PURE
114 gl_linkedhash_size (gl_set_t set
)
119 static bool _GL_ATTRIBUTE_PURE
120 gl_linkedhash_search (gl_set_t set
, const void *elt
)
123 (set
->hashcode_fn
!= NULL
124 ? set
->hashcode_fn (elt
)
125 : (size_t)(uintptr_t) elt
);
126 size_t bucket
= hashcode
% set
->table_size
;
127 gl_setelement_equals_fn equals
= set
->base
.equals_fn
;
129 /* Look for a match in the hash bucket. */
132 for (node
= (gl_list_node_t
) set
->table
[bucket
];
134 node
= (gl_list_node_t
) node
->h
.hash_next
)
135 if (node
->h
.hashcode
== hashcode
137 ? equals (elt
, node
->value
)
138 : elt
== node
->value
))
144 gl_linkedhash_nx_add (gl_set_t set
, const void *elt
)
147 (set
->hashcode_fn
!= NULL
148 ? set
->hashcode_fn (elt
)
149 : (size_t)(uintptr_t) elt
);
150 size_t bucket
= hashcode
% set
->table_size
;
151 gl_setelement_equals_fn equals
= set
->base
.equals_fn
;
153 /* Look for a match in the hash bucket. */
157 for (node
= (gl_list_node_t
) set
->table
[bucket
];
159 node
= (gl_list_node_t
) node
->h
.hash_next
)
160 if (node
->h
.hashcode
== hashcode
162 ? equals (elt
, node
->value
)
163 : elt
== node
->value
))
167 /* Allocate a new node. */
168 gl_list_node_t node
=
169 (struct gl_list_node_impl
*) malloc (sizeof (struct gl_list_node_impl
));
174 ASYNCSAFE(const void *) node
->value
= elt
;
175 node
->h
.hashcode
= hashcode
;
177 /* Add node to the hash table. */
178 node
->h
.hash_next
= set
->table
[bucket
];
179 set
->table
[bucket
] = &node
->h
;
181 /* Add node to the set. */
182 ASYNCSAFE(gl_list_node_t
) node
->next
= &set
->root
;
183 node
->prev
= set
->root
.prev
;
184 ASYNCSAFE(gl_list_node_t
) node
->prev
->next
= node
;
185 set
->root
.prev
= node
;
188 hash_resize_after_add (set
);
194 gl_linkedhash_remove (gl_set_t set
, const void *elt
)
197 (set
->hashcode_fn
!= NULL
198 ? set
->hashcode_fn (elt
)
199 : (size_t)(uintptr_t) elt
);
200 size_t bucket
= hashcode
% set
->table_size
;
201 gl_setelement_equals_fn equals
= set
->base
.equals_fn
;
203 /* Look for the first match in the hash bucket. */
204 gl_list_node_t
*nodep
;
206 for (nodep
= (gl_list_node_t
*) &set
->table
[bucket
];
208 nodep
= (gl_list_node_t
*) &(*nodep
)->h
.hash_next
)
210 gl_list_node_t node
= *nodep
;
211 if (node
->h
.hashcode
== hashcode
213 ? equals (elt
, node
->value
)
214 : elt
== node
->value
))
216 /* Remove node from the hash table. */
217 *nodep
= (gl_list_node_t
) node
->h
.hash_next
;
219 /* Remove node from the list. */
221 gl_list_node_t prev
= node
->prev
;
222 gl_list_node_t next
= node
->next
;
224 ASYNCSAFE(gl_list_node_t
) prev
->next
= next
;
229 if (set
->base
.dispose_fn
!= NULL
)
230 set
->base
.dispose_fn (node
->value
);
240 gl_linkedhash_free (gl_set_t set
)
242 gl_setelement_dispose_fn dispose
= set
->base
.dispose_fn
;
245 for (node
= set
->root
.next
; node
!= &set
->root
; )
247 gl_list_node_t next
= node
->next
;
249 dispose (node
->value
);
257 /* ---------------------- gl_set_iterator_t Data Type ---------------------- */
259 /* Iterate through the list, not through the hash buckets, so that the order
260 in which the elements are returned is predictable. */
262 static gl_set_iterator_t
263 gl_linkedhash_iterator (gl_set_t set
)
265 gl_set_iterator_t result
;
267 result
.vtable
= set
->base
.vtable
;
269 result
.p
= set
->root
.next
;
270 result
.q
= &set
->root
;
271 #if defined GCC_LINT || defined lint
281 gl_linkedhash_iterator_next (gl_set_iterator_t
*iterator
, const void **eltp
)
283 if (iterator
->p
!= iterator
->q
)
285 gl_list_node_t node
= (gl_list_node_t
) iterator
->p
;
287 iterator
->p
= node
->next
;
295 gl_linkedhash_iterator_free (gl_set_iterator_t
*iterator
)
300 const struct gl_set_implementation gl_linkedhash_set_implementation
=
302 gl_linkedhash_nx_create_empty
,
304 gl_linkedhash_search
,
305 gl_linkedhash_nx_add
,
306 gl_linkedhash_remove
,
308 gl_linkedhash_iterator
,
309 gl_linkedhash_iterator_next
,
310 gl_linkedhash_iterator_free