blob: b53cc2408326ae371cd3d3b9a7dc03f5ba9ae27b [file] [log] [blame]
Victor Stinner285cf0a2016-03-21 22:00:58 +01001/* The implementation of the hash table (_Py_hashtable_t) is based on the
2 cfuhash project:
Victor Stinnered3b0bc2013-11-23 12:27:24 +01003 http://sourceforge.net/projects/libcfu/
4
5 Copyright of cfuhash:
6 ----------------------------------
7 Creation date: 2005-06-24 21:22:40
8 Authors: Don
9 Change log:
10
11 Copyright (c) 2005 Don Owens
12 All rights reserved.
13
14 This code is released under the BSD license:
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 * Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
22
23 * Redistributions in binary form must reproduce the above
24 copyright notice, this list of conditions and the following
25 disclaimer in the documentation and/or other materials provided
26 with the distribution.
27
28 * Neither the name of the author nor the names of its
29 contributors may be used to endorse or promote products derived
30 from this software without specific prior written permission.
31
32 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
36 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
37 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43 OF THE POSSIBILITY OF SUCH DAMAGE.
44 ----------------------------------
45*/
46
47#include "Python.h"
48#include "hashtable.h"
49
50#define HASHTABLE_MIN_SIZE 16
51#define HASHTABLE_HIGH 0.50
52#define HASHTABLE_LOW 0.10
53#define HASHTABLE_REHASH_FACTOR 2.0 / (HASHTABLE_LOW + HASHTABLE_HIGH)
54
55#define BUCKETS_HEAD(SLIST) \
56 ((_Py_hashtable_entry_t *)_Py_SLIST_HEAD(&(SLIST)))
57#define TABLE_HEAD(HT, BUCKET) \
58 ((_Py_hashtable_entry_t *)_Py_SLIST_HEAD(&(HT)->buckets[BUCKET]))
59#define ENTRY_NEXT(ENTRY) \
60 ((_Py_hashtable_entry_t *)_Py_SLIST_ITEM_NEXT(ENTRY))
61#define HASHTABLE_ITEM_SIZE(HT) \
Victor Stinner285cf0a2016-03-21 22:00:58 +010062 (sizeof(_Py_hashtable_entry_t) + (HT)->key_size + (HT)->data_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010063
Victor Stinner5dacbd42016-03-23 09:52:13 +010064#define ENTRY_READ_PDATA(TABLE, ENTRY, DATA_SIZE, PDATA) \
65 do { \
66 assert((DATA_SIZE) == (TABLE)->data_size); \
67 Py_MEMCPY((PDATA), _Py_HASHTABLE_ENTRY_PDATA(TABLE, (ENTRY)), \
68 (DATA_SIZE)); \
69 } while (0)
70
71#define ENTRY_WRITE_PDATA(TABLE, ENTRY, DATA_SIZE, PDATA) \
72 do { \
73 assert((DATA_SIZE) == (TABLE)->data_size); \
74 Py_MEMCPY((void *)_Py_HASHTABLE_ENTRY_PDATA((TABLE), (ENTRY)), \
75 (PDATA), (DATA_SIZE)); \
76 } while (0)
77
Victor Stinnered3b0bc2013-11-23 12:27:24 +010078/* Forward declaration */
79static void hashtable_rehash(_Py_hashtable_t *ht);
80
81static void
82_Py_slist_init(_Py_slist_t *list)
83{
84 list->head = NULL;
85}
86
Victor Stinner285cf0a2016-03-21 22:00:58 +010087
Victor Stinnered3b0bc2013-11-23 12:27:24 +010088static void
89_Py_slist_prepend(_Py_slist_t *list, _Py_slist_item_t *item)
90{
91 item->next = list->head;
92 list->head = item;
93}
94
Victor Stinner285cf0a2016-03-21 22:00:58 +010095
Victor Stinnered3b0bc2013-11-23 12:27:24 +010096static void
97_Py_slist_remove(_Py_slist_t *list, _Py_slist_item_t *previous,
98 _Py_slist_item_t *item)
99{
100 if (previous != NULL)
101 previous->next = item->next;
102 else
103 list->head = item->next;
104}
105
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100106
Victor Stinner322bc122016-03-21 14:36:39 +0100107Py_uhash_t
Victor Stinner5dacbd42016-03-23 09:52:13 +0100108_Py_hashtable_hash_ptr(struct _Py_hashtable_t *ht, const void *pkey)
Victor Stinner322bc122016-03-21 14:36:39 +0100109{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100110 void *key;
111
Victor Stinner5dacbd42016-03-23 09:52:13 +0100112 _Py_HASHTABLE_READ_KEY(ht, pkey, key);
113 return (Py_uhash_t)_Py_HashPointer(key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100114}
115
Victor Stinner285cf0a2016-03-21 22:00:58 +0100116
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100117int
Victor Stinner5dacbd42016-03-23 09:52:13 +0100118_Py_hashtable_compare_direct(_Py_hashtable_t *ht, const void *pkey,
Victor Stinner285cf0a2016-03-21 22:00:58 +0100119 const _Py_hashtable_entry_t *entry)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100120{
Victor Stinner5dacbd42016-03-23 09:52:13 +0100121 const void *pkey2 = _Py_HASHTABLE_ENTRY_PKEY(entry);
122 return (memcmp(pkey, pkey2, ht->key_size) == 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100123}
124
Victor Stinner285cf0a2016-03-21 22:00:58 +0100125
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100126/* makes sure the real size of the buckets array is a power of 2 */
127static size_t
128round_size(size_t s)
129{
130 size_t i;
131 if (s < HASHTABLE_MIN_SIZE)
132 return HASHTABLE_MIN_SIZE;
133 i = 1;
134 while (i < s)
135 i <<= 1;
136 return i;
137}
138
Victor Stinner285cf0a2016-03-21 22:00:58 +0100139
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100140_Py_hashtable_t *
Victor Stinner285cf0a2016-03-21 22:00:58 +0100141_Py_hashtable_new_full(size_t key_size, size_t data_size,
142 size_t init_size,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100143 _Py_hashtable_hash_func hash_func,
144 _Py_hashtable_compare_func compare_func,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100145 _Py_hashtable_allocator_t *allocator)
146{
147 _Py_hashtable_t *ht;
148 size_t buckets_size;
149 _Py_hashtable_allocator_t alloc;
150
151 if (allocator == NULL) {
152 alloc.malloc = PyMem_RawMalloc;
153 alloc.free = PyMem_RawFree;
154 }
155 else
156 alloc = *allocator;
157
158 ht = (_Py_hashtable_t *)alloc.malloc(sizeof(_Py_hashtable_t));
159 if (ht == NULL)
160 return ht;
161
162 ht->num_buckets = round_size(init_size);
163 ht->entries = 0;
Victor Stinner285cf0a2016-03-21 22:00:58 +0100164 ht->key_size = key_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100165 ht->data_size = data_size;
166
167 buckets_size = ht->num_buckets * sizeof(ht->buckets[0]);
168 ht->buckets = alloc.malloc(buckets_size);
169 if (ht->buckets == NULL) {
170 alloc.free(ht);
171 return NULL;
172 }
173 memset(ht->buckets, 0, buckets_size);
174
175 ht->hash_func = hash_func;
176 ht->compare_func = compare_func;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100177 ht->alloc = alloc;
178 return ht;
179}
180
Victor Stinner285cf0a2016-03-21 22:00:58 +0100181
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100182_Py_hashtable_t *
Victor Stinner285cf0a2016-03-21 22:00:58 +0100183_Py_hashtable_new(size_t key_size, size_t data_size,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100184 _Py_hashtable_hash_func hash_func,
185 _Py_hashtable_compare_func compare_func)
186{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100187 return _Py_hashtable_new_full(key_size, data_size,
188 HASHTABLE_MIN_SIZE,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100189 hash_func, compare_func,
Victor Stinnerc9553872016-03-22 12:13:01 +0100190 NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100191}
192
Victor Stinner285cf0a2016-03-21 22:00:58 +0100193
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100194size_t
195_Py_hashtable_size(_Py_hashtable_t *ht)
196{
197 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100198
199 size = sizeof(_Py_hashtable_t);
200
201 /* buckets */
202 size += ht->num_buckets * sizeof(_Py_hashtable_entry_t *);
203
204 /* entries */
205 size += ht->entries * HASHTABLE_ITEM_SIZE(ht);
206
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100207 return size;
208}
209
Victor Stinner285cf0a2016-03-21 22:00:58 +0100210
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100211#ifdef Py_DEBUG
212void
213_Py_hashtable_print_stats(_Py_hashtable_t *ht)
214{
215 size_t size;
216 size_t chain_len, max_chain_len, total_chain_len, nchains;
217 _Py_hashtable_entry_t *entry;
218 size_t hv;
219 double load;
220
221 size = _Py_hashtable_size(ht);
222
223 load = (double)ht->entries / ht->num_buckets;
224
225 max_chain_len = 0;
226 total_chain_len = 0;
227 nchains = 0;
228 for (hv = 0; hv < ht->num_buckets; hv++) {
229 entry = TABLE_HEAD(ht, hv);
230 if (entry != NULL) {
231 chain_len = 0;
232 for (; entry; entry = ENTRY_NEXT(entry)) {
233 chain_len++;
234 }
235 if (chain_len > max_chain_len)
236 max_chain_len = chain_len;
237 total_chain_len += chain_len;
238 nchains++;
239 }
240 }
Victor Stinner293f3f52014-07-01 08:57:10 +0200241 printf("hash table %p: entries=%"
242 PY_FORMAT_SIZE_T "u/%" PY_FORMAT_SIZE_T "u (%.0f%%), ",
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100243 ht, ht->entries, ht->num_buckets, load * 100.0);
244 if (nchains)
245 printf("avg_chain_len=%.1f, ", (double)total_chain_len / nchains);
Victor Stinner293f3f52014-07-01 08:57:10 +0200246 printf("max_chain_len=%" PY_FORMAT_SIZE_T "u, %" PY_FORMAT_SIZE_T "u kB\n",
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100247 max_chain_len, size / 1024);
248}
249#endif
250
Victor Stinner285cf0a2016-03-21 22:00:58 +0100251
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100252_Py_hashtable_entry_t *
Victor Stinner285cf0a2016-03-21 22:00:58 +0100253_Py_hashtable_get_entry(_Py_hashtable_t *ht,
254 size_t key_size, const void *pkey)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100255{
256 Py_uhash_t key_hash;
257 size_t index;
258 _Py_hashtable_entry_t *entry;
259
Victor Stinner285cf0a2016-03-21 22:00:58 +0100260 assert(key_size == ht->key_size);
261
Victor Stinner5dacbd42016-03-23 09:52:13 +0100262 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100263 index = key_hash & (ht->num_buckets - 1);
264
265 for (entry = TABLE_HEAD(ht, index); entry != NULL; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100266 if (entry->key_hash == key_hash && ht->compare_func(ht, pkey, entry))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100267 break;
268 }
269
270 return entry;
271}
272
Victor Stinner285cf0a2016-03-21 22:00:58 +0100273
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100274static int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100275_Py_hashtable_pop_entry(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
276 void *data, size_t data_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100277{
278 Py_uhash_t key_hash;
279 size_t index;
280 _Py_hashtable_entry_t *entry, *previous;
281
Victor Stinner285cf0a2016-03-21 22:00:58 +0100282 assert(key_size == ht->key_size);
283
Victor Stinner5dacbd42016-03-23 09:52:13 +0100284 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100285 index = key_hash & (ht->num_buckets - 1);
286
287 previous = NULL;
288 for (entry = TABLE_HEAD(ht, index); entry != NULL; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100289 if (entry->key_hash == key_hash && ht->compare_func(ht, pkey, entry))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100290 break;
291 previous = entry;
292 }
293
294 if (entry == NULL)
295 return 0;
296
297 _Py_slist_remove(&ht->buckets[index], (_Py_slist_item_t *)previous,
298 (_Py_slist_item_t *)entry);
299 ht->entries--;
300
301 if (data != NULL)
Victor Stinner5dacbd42016-03-23 09:52:13 +0100302 ENTRY_READ_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100303 ht->alloc.free(entry);
304
305 if ((float)ht->entries / (float)ht->num_buckets < HASHTABLE_LOW)
306 hashtable_rehash(ht);
307 return 1;
308}
309
Victor Stinner285cf0a2016-03-21 22:00:58 +0100310
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100311int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100312_Py_hashtable_set(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
Victor Stinnerc9553872016-03-22 12:13:01 +0100313 size_t data_size, const void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100314{
315 Py_uhash_t key_hash;
316 size_t index;
317 _Py_hashtable_entry_t *entry;
318
Victor Stinner285cf0a2016-03-21 22:00:58 +0100319 assert(key_size == ht->key_size);
320
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100321 assert(data != NULL || data_size == 0);
322#ifndef NDEBUG
323 /* Don't write the assertion on a single line because it is interesting
324 to know the duplicated entry if the assertion failed. The entry can
325 be read using a debugger. */
Victor Stinner285cf0a2016-03-21 22:00:58 +0100326 entry = _Py_hashtable_get_entry(ht, key_size, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100327 assert(entry == NULL);
328#endif
329
Victor Stinner5dacbd42016-03-23 09:52:13 +0100330 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100331 index = key_hash & (ht->num_buckets - 1);
332
333 entry = ht->alloc.malloc(HASHTABLE_ITEM_SIZE(ht));
334 if (entry == NULL) {
335 /* memory allocation failed */
336 return -1;
337 }
338
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100339 entry->key_hash = key_hash;
Victor Stinner5dacbd42016-03-23 09:52:13 +0100340 Py_MEMCPY((void *)_Py_HASHTABLE_ENTRY_PKEY(entry), pkey, ht->key_size);
341 ENTRY_WRITE_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100342
343 _Py_slist_prepend(&ht->buckets[index], (_Py_slist_item_t*)entry);
344 ht->entries++;
345
346 if ((float)ht->entries / (float)ht->num_buckets > HASHTABLE_HIGH)
347 hashtable_rehash(ht);
348 return 0;
349}
350
Victor Stinner285cf0a2016-03-21 22:00:58 +0100351
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100352int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100353_Py_hashtable_get(_Py_hashtable_t *ht, size_t key_size,const void *pkey,
354 size_t data_size, void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100355{
356 _Py_hashtable_entry_t *entry;
357
358 assert(data != NULL);
359
Victor Stinner285cf0a2016-03-21 22:00:58 +0100360 entry = _Py_hashtable_get_entry(ht, key_size, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100361 if (entry == NULL)
362 return 0;
Victor Stinner5dacbd42016-03-23 09:52:13 +0100363 ENTRY_READ_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100364 return 1;
365}
366
Victor Stinner285cf0a2016-03-21 22:00:58 +0100367
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100368int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100369_Py_hashtable_pop(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
370 size_t data_size, void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100371{
372 assert(data != NULL);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100373 return _Py_hashtable_pop_entry(ht, key_size, pkey, data, data_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100374}
375
Victor Stinner285cf0a2016-03-21 22:00:58 +0100376
Victor Stinner58100052016-03-22 12:25:04 +0100377/* Code commented since the function is not needed in Python */
378#if 0
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100379void
Victor Stinner285cf0a2016-03-21 22:00:58 +0100380_Py_hashtable_delete(_Py_hashtable_t *ht, size_t key_size, const void *pkey)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100381{
382#ifndef NDEBUG
Victor Stinner285cf0a2016-03-21 22:00:58 +0100383 int found = _Py_hashtable_pop_entry(ht, key_size, pkey, NULL, 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100384 assert(found);
385#else
Victor Stinner285cf0a2016-03-21 22:00:58 +0100386 (void)_Py_hashtable_pop_entry(ht, key_size, pkey, NULL, 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100387#endif
388}
Victor Stinner58100052016-03-22 12:25:04 +0100389#endif
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100390
Victor Stinner285cf0a2016-03-21 22:00:58 +0100391
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100392int
393_Py_hashtable_foreach(_Py_hashtable_t *ht,
Victor Stinner285cf0a2016-03-21 22:00:58 +0100394 _Py_hashtable_foreach_func func,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100395 void *arg)
396{
397 _Py_hashtable_entry_t *entry;
398 size_t hv;
399
400 for (hv = 0; hv < ht->num_buckets; hv++) {
401 for (entry = TABLE_HEAD(ht, hv); entry; entry = ENTRY_NEXT(entry)) {
Victor Stinner285cf0a2016-03-21 22:00:58 +0100402 int res = func(ht, entry, arg);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100403 if (res)
404 return res;
405 }
406 }
407 return 0;
408}
409
Victor Stinner285cf0a2016-03-21 22:00:58 +0100410
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100411static void
412hashtable_rehash(_Py_hashtable_t *ht)
413{
414 size_t buckets_size, new_size, bucket;
415 _Py_slist_t *old_buckets = NULL;
416 size_t old_num_buckets;
417
418 new_size = round_size((size_t)(ht->entries * HASHTABLE_REHASH_FACTOR));
419 if (new_size == ht->num_buckets)
420 return;
421
422 old_num_buckets = ht->num_buckets;
423
424 buckets_size = new_size * sizeof(ht->buckets[0]);
425 old_buckets = ht->buckets;
426 ht->buckets = ht->alloc.malloc(buckets_size);
427 if (ht->buckets == NULL) {
428 /* cancel rehash on memory allocation failure */
429 ht->buckets = old_buckets ;
430 /* memory allocation failed */
431 return;
432 }
433 memset(ht->buckets, 0, buckets_size);
434
435 ht->num_buckets = new_size;
436
437 for (bucket = 0; bucket < old_num_buckets; bucket++) {
438 _Py_hashtable_entry_t *entry, *next;
439 for (entry = BUCKETS_HEAD(old_buckets[bucket]); entry != NULL; entry = next) {
440 size_t entry_index;
441
Victor Stinner285cf0a2016-03-21 22:00:58 +0100442
Victor Stinner5dacbd42016-03-23 09:52:13 +0100443 assert(ht->hash_func(ht, _Py_HASHTABLE_ENTRY_PKEY(entry)) == entry->key_hash);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100444 next = ENTRY_NEXT(entry);
445 entry_index = entry->key_hash & (new_size - 1);
446
447 _Py_slist_prepend(&ht->buckets[entry_index], (_Py_slist_item_t*)entry);
448 }
449 }
450
451 ht->alloc.free(old_buckets);
452}
453
Victor Stinner285cf0a2016-03-21 22:00:58 +0100454
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100455void
456_Py_hashtable_clear(_Py_hashtable_t *ht)
457{
458 _Py_hashtable_entry_t *entry, *next;
459 size_t i;
460
461 for (i=0; i < ht->num_buckets; i++) {
462 for (entry = TABLE_HEAD(ht, i); entry != NULL; entry = next) {
463 next = ENTRY_NEXT(entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100464 ht->alloc.free(entry);
465 }
466 _Py_slist_init(&ht->buckets[i]);
467 }
468 ht->entries = 0;
469 hashtable_rehash(ht);
470}
471
Victor Stinner285cf0a2016-03-21 22:00:58 +0100472
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100473void
474_Py_hashtable_destroy(_Py_hashtable_t *ht)
475{
476 size_t i;
477
478 for (i = 0; i < ht->num_buckets; i++) {
479 _Py_slist_item_t *entry = ht->buckets[i].head;
480 while (entry) {
481 _Py_slist_item_t *entry_next = entry->next;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100482 ht->alloc.free(entry);
483 entry = entry_next;
484 }
485 }
486
487 ht->alloc.free(ht->buckets);
488 ht->alloc.free(ht);
489}
490
Victor Stinner285cf0a2016-03-21 22:00:58 +0100491
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100492_Py_hashtable_t *
493_Py_hashtable_copy(_Py_hashtable_t *src)
494{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100495 const size_t key_size = src->key_size;
496 const size_t data_size = src->data_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100497 _Py_hashtable_t *dst;
498 _Py_hashtable_entry_t *entry;
499 size_t bucket;
500 int err;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100501
Victor Stinner285cf0a2016-03-21 22:00:58 +0100502 dst = _Py_hashtable_new_full(key_size, data_size,
503 src->num_buckets,
Victor Stinnerc9553872016-03-22 12:13:01 +0100504 src->hash_func,
505 src->compare_func,
506 &src->alloc);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100507 if (dst == NULL)
508 return NULL;
509
510 for (bucket=0; bucket < src->num_buckets; bucket++) {
511 entry = TABLE_HEAD(src, bucket);
512 for (; entry; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100513 const void *pkey = _Py_HASHTABLE_ENTRY_PKEY(entry);
514 const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(src, entry);
515 err = _Py_hashtable_set(dst, key_size, pkey, data_size, pdata);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100516 if (err) {
517 _Py_hashtable_destroy(dst);
518 return NULL;
519 }
520 }
521 }
522 return dst;
523}