blob: e9f02d8650e4f8f1f374d1a8aaff1b46ea11cdae [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"
Victor Stinnerb6179932020-05-12 02:42:19 +020048#include "pycore_hashtable.h"
Victor Stinnered3b0bc2013-11-23 12:27:24 +010049
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); \
Christian Heimesf051e432016-09-13 20:22:02 +020067 memcpy((PDATA), _Py_HASHTABLE_ENTRY_PDATA(TABLE, (ENTRY)), \
Victor Stinner5dacbd42016-03-23 09:52:13 +010068 (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); \
Christian Heimesf051e432016-09-13 20:22:02 +020074 memcpy((void *)_Py_HASHTABLE_ENTRY_PDATA((TABLE), (ENTRY)), \
Victor Stinner5dacbd42016-03-23 09:52:13 +010075 (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) {
Victor Stinnerd0919f02020-05-12 03:07:40 +0200152 alloc.malloc = PyMem_Malloc;
153 alloc.free = PyMem_Free;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100154 }
Victor Stinnerd0919f02020-05-12 03:07:40 +0200155 else {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100156 alloc = *allocator;
Victor Stinnerd0919f02020-05-12 03:07:40 +0200157 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100158
159 ht = (_Py_hashtable_t *)alloc.malloc(sizeof(_Py_hashtable_t));
160 if (ht == NULL)
161 return ht;
162
163 ht->num_buckets = round_size(init_size);
164 ht->entries = 0;
Victor Stinner285cf0a2016-03-21 22:00:58 +0100165 ht->key_size = key_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100166 ht->data_size = data_size;
167
168 buckets_size = ht->num_buckets * sizeof(ht->buckets[0]);
169 ht->buckets = alloc.malloc(buckets_size);
170 if (ht->buckets == NULL) {
171 alloc.free(ht);
172 return NULL;
173 }
174 memset(ht->buckets, 0, buckets_size);
175
176 ht->hash_func = hash_func;
177 ht->compare_func = compare_func;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100178 ht->alloc = alloc;
179 return ht;
180}
181
Victor Stinner285cf0a2016-03-21 22:00:58 +0100182
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100183_Py_hashtable_t *
Victor Stinner285cf0a2016-03-21 22:00:58 +0100184_Py_hashtable_new(size_t key_size, size_t data_size,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100185 _Py_hashtable_hash_func hash_func,
186 _Py_hashtable_compare_func compare_func)
187{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100188 return _Py_hashtable_new_full(key_size, data_size,
189 HASHTABLE_MIN_SIZE,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100190 hash_func, compare_func,
Victor Stinnerc9553872016-03-22 12:13:01 +0100191 NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100192}
193
Victor Stinner285cf0a2016-03-21 22:00:58 +0100194
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100195size_t
196_Py_hashtable_size(_Py_hashtable_t *ht)
197{
198 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100199
200 size = sizeof(_Py_hashtable_t);
201
202 /* buckets */
203 size += ht->num_buckets * sizeof(_Py_hashtable_entry_t *);
204
205 /* entries */
206 size += ht->entries * HASHTABLE_ITEM_SIZE(ht);
207
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100208 return size;
209}
210
Victor Stinner285cf0a2016-03-21 22:00:58 +0100211
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100212#ifdef Py_DEBUG
213void
214_Py_hashtable_print_stats(_Py_hashtable_t *ht)
215{
216 size_t size;
217 size_t chain_len, max_chain_len, total_chain_len, nchains;
218 _Py_hashtable_entry_t *entry;
219 size_t hv;
220 double load;
221
222 size = _Py_hashtable_size(ht);
223
224 load = (double)ht->entries / ht->num_buckets;
225
226 max_chain_len = 0;
227 total_chain_len = 0;
228 nchains = 0;
229 for (hv = 0; hv < ht->num_buckets; hv++) {
230 entry = TABLE_HEAD(ht, hv);
231 if (entry != NULL) {
232 chain_len = 0;
233 for (; entry; entry = ENTRY_NEXT(entry)) {
234 chain_len++;
235 }
236 if (chain_len > max_chain_len)
237 max_chain_len = chain_len;
238 total_chain_len += chain_len;
239 nchains++;
240 }
241 }
Victor Stinner293f3f52014-07-01 08:57:10 +0200242 printf("hash table %p: entries=%"
243 PY_FORMAT_SIZE_T "u/%" PY_FORMAT_SIZE_T "u (%.0f%%), ",
Zackery Spytz1a2252e2019-05-06 10:56:51 -0600244 (void *)ht, ht->entries, ht->num_buckets, load * 100.0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100245 if (nchains)
246 printf("avg_chain_len=%.1f, ", (double)total_chain_len / nchains);
Victor Stinner8c663fd2017-11-08 14:44:44 -0800247 printf("max_chain_len=%" PY_FORMAT_SIZE_T "u, %" PY_FORMAT_SIZE_T "u KiB\n",
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100248 max_chain_len, size / 1024);
249}
250#endif
251
Victor Stinner285cf0a2016-03-21 22:00:58 +0100252
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100253_Py_hashtable_entry_t *
Victor Stinner285cf0a2016-03-21 22:00:58 +0100254_Py_hashtable_get_entry(_Py_hashtable_t *ht,
255 size_t key_size, const void *pkey)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100256{
257 Py_uhash_t key_hash;
258 size_t index;
259 _Py_hashtable_entry_t *entry;
260
Victor Stinner285cf0a2016-03-21 22:00:58 +0100261 assert(key_size == ht->key_size);
262
Victor Stinner5dacbd42016-03-23 09:52:13 +0100263 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100264 index = key_hash & (ht->num_buckets - 1);
265
266 for (entry = TABLE_HEAD(ht, index); entry != NULL; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100267 if (entry->key_hash == key_hash && ht->compare_func(ht, pkey, entry))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100268 break;
269 }
270
271 return entry;
272}
273
Victor Stinner285cf0a2016-03-21 22:00:58 +0100274
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100275static int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100276_Py_hashtable_pop_entry(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
277 void *data, size_t data_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100278{
279 Py_uhash_t key_hash;
280 size_t index;
281 _Py_hashtable_entry_t *entry, *previous;
282
Victor Stinner285cf0a2016-03-21 22:00:58 +0100283 assert(key_size == ht->key_size);
284
Victor Stinner5dacbd42016-03-23 09:52:13 +0100285 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100286 index = key_hash & (ht->num_buckets - 1);
287
288 previous = NULL;
289 for (entry = TABLE_HEAD(ht, index); entry != NULL; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100290 if (entry->key_hash == key_hash && ht->compare_func(ht, pkey, entry))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100291 break;
292 previous = entry;
293 }
294
295 if (entry == NULL)
296 return 0;
297
298 _Py_slist_remove(&ht->buckets[index], (_Py_slist_item_t *)previous,
299 (_Py_slist_item_t *)entry);
300 ht->entries--;
301
302 if (data != NULL)
Victor Stinner5dacbd42016-03-23 09:52:13 +0100303 ENTRY_READ_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100304 ht->alloc.free(entry);
305
306 if ((float)ht->entries / (float)ht->num_buckets < HASHTABLE_LOW)
307 hashtable_rehash(ht);
308 return 1;
309}
310
Victor Stinner285cf0a2016-03-21 22:00:58 +0100311
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100312int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100313_Py_hashtable_set(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
Victor Stinnerc9553872016-03-22 12:13:01 +0100314 size_t data_size, const void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100315{
316 Py_uhash_t key_hash;
317 size_t index;
318 _Py_hashtable_entry_t *entry;
319
Victor Stinner285cf0a2016-03-21 22:00:58 +0100320 assert(key_size == ht->key_size);
321
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100322 assert(data != NULL || data_size == 0);
323#ifndef NDEBUG
324 /* Don't write the assertion on a single line because it is interesting
325 to know the duplicated entry if the assertion failed. The entry can
326 be read using a debugger. */
Victor Stinner285cf0a2016-03-21 22:00:58 +0100327 entry = _Py_hashtable_get_entry(ht, key_size, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100328 assert(entry == NULL);
329#endif
330
Victor Stinner5dacbd42016-03-23 09:52:13 +0100331 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100332 index = key_hash & (ht->num_buckets - 1);
333
334 entry = ht->alloc.malloc(HASHTABLE_ITEM_SIZE(ht));
335 if (entry == NULL) {
336 /* memory allocation failed */
337 return -1;
338 }
339
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100340 entry->key_hash = key_hash;
Christian Heimesf051e432016-09-13 20:22:02 +0200341 memcpy((void *)_Py_HASHTABLE_ENTRY_PKEY(entry), pkey, ht->key_size);
Benjamin Peterson4a757602016-09-06 19:03:40 -0700342 if (data)
Benjamin Peterson35b40c62016-09-06 19:04:37 -0700343 ENTRY_WRITE_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100344
345 _Py_slist_prepend(&ht->buckets[index], (_Py_slist_item_t*)entry);
346 ht->entries++;
347
348 if ((float)ht->entries / (float)ht->num_buckets > HASHTABLE_HIGH)
349 hashtable_rehash(ht);
350 return 0;
351}
352
Victor Stinner285cf0a2016-03-21 22:00:58 +0100353
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100354int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100355_Py_hashtable_get(_Py_hashtable_t *ht, size_t key_size,const void *pkey,
356 size_t data_size, void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100357{
358 _Py_hashtable_entry_t *entry;
359
360 assert(data != NULL);
361
Victor Stinner285cf0a2016-03-21 22:00:58 +0100362 entry = _Py_hashtable_get_entry(ht, key_size, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100363 if (entry == NULL)
364 return 0;
Victor Stinner5dacbd42016-03-23 09:52:13 +0100365 ENTRY_READ_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100366 return 1;
367}
368
Victor Stinner285cf0a2016-03-21 22:00:58 +0100369
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100370int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100371_Py_hashtable_pop(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
372 size_t data_size, void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100373{
374 assert(data != NULL);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100375 return _Py_hashtable_pop_entry(ht, key_size, pkey, data, data_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100376}
377
Victor Stinner285cf0a2016-03-21 22:00:58 +0100378
Victor Stinner58100052016-03-22 12:25:04 +0100379/* Code commented since the function is not needed in Python */
380#if 0
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100381void
Victor Stinner285cf0a2016-03-21 22:00:58 +0100382_Py_hashtable_delete(_Py_hashtable_t *ht, size_t key_size, const void *pkey)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100383{
384#ifndef NDEBUG
Victor Stinner285cf0a2016-03-21 22:00:58 +0100385 int found = _Py_hashtable_pop_entry(ht, key_size, pkey, NULL, 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100386 assert(found);
387#else
Victor Stinner285cf0a2016-03-21 22:00:58 +0100388 (void)_Py_hashtable_pop_entry(ht, key_size, pkey, NULL, 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100389#endif
390}
Victor Stinner58100052016-03-22 12:25:04 +0100391#endif
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100392
Victor Stinner285cf0a2016-03-21 22:00:58 +0100393
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100394int
395_Py_hashtable_foreach(_Py_hashtable_t *ht,
Victor Stinner285cf0a2016-03-21 22:00:58 +0100396 _Py_hashtable_foreach_func func,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100397 void *arg)
398{
399 _Py_hashtable_entry_t *entry;
400 size_t hv;
401
402 for (hv = 0; hv < ht->num_buckets; hv++) {
403 for (entry = TABLE_HEAD(ht, hv); entry; entry = ENTRY_NEXT(entry)) {
Victor Stinner285cf0a2016-03-21 22:00:58 +0100404 int res = func(ht, entry, arg);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100405 if (res)
406 return res;
407 }
408 }
409 return 0;
410}
411
Victor Stinner285cf0a2016-03-21 22:00:58 +0100412
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100413static void
414hashtable_rehash(_Py_hashtable_t *ht)
415{
416 size_t buckets_size, new_size, bucket;
417 _Py_slist_t *old_buckets = NULL;
418 size_t old_num_buckets;
419
420 new_size = round_size((size_t)(ht->entries * HASHTABLE_REHASH_FACTOR));
421 if (new_size == ht->num_buckets)
422 return;
423
424 old_num_buckets = ht->num_buckets;
425
426 buckets_size = new_size * sizeof(ht->buckets[0]);
427 old_buckets = ht->buckets;
428 ht->buckets = ht->alloc.malloc(buckets_size);
429 if (ht->buckets == NULL) {
430 /* cancel rehash on memory allocation failure */
431 ht->buckets = old_buckets ;
432 /* memory allocation failed */
433 return;
434 }
435 memset(ht->buckets, 0, buckets_size);
436
437 ht->num_buckets = new_size;
438
439 for (bucket = 0; bucket < old_num_buckets; bucket++) {
440 _Py_hashtable_entry_t *entry, *next;
441 for (entry = BUCKETS_HEAD(old_buckets[bucket]); entry != NULL; entry = next) {
442 size_t entry_index;
443
Victor Stinner285cf0a2016-03-21 22:00:58 +0100444
Victor Stinner5dacbd42016-03-23 09:52:13 +0100445 assert(ht->hash_func(ht, _Py_HASHTABLE_ENTRY_PKEY(entry)) == entry->key_hash);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100446 next = ENTRY_NEXT(entry);
447 entry_index = entry->key_hash & (new_size - 1);
448
449 _Py_slist_prepend(&ht->buckets[entry_index], (_Py_slist_item_t*)entry);
450 }
451 }
452
453 ht->alloc.free(old_buckets);
454}
455
Victor Stinner285cf0a2016-03-21 22:00:58 +0100456
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100457void
458_Py_hashtable_clear(_Py_hashtable_t *ht)
459{
460 _Py_hashtable_entry_t *entry, *next;
461 size_t i;
462
463 for (i=0; i < ht->num_buckets; i++) {
464 for (entry = TABLE_HEAD(ht, i); entry != NULL; entry = next) {
465 next = ENTRY_NEXT(entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100466 ht->alloc.free(entry);
467 }
468 _Py_slist_init(&ht->buckets[i]);
469 }
470 ht->entries = 0;
471 hashtable_rehash(ht);
472}
473
Victor Stinner285cf0a2016-03-21 22:00:58 +0100474
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100475void
476_Py_hashtable_destroy(_Py_hashtable_t *ht)
477{
478 size_t i;
479
480 for (i = 0; i < ht->num_buckets; i++) {
481 _Py_slist_item_t *entry = ht->buckets[i].head;
482 while (entry) {
483 _Py_slist_item_t *entry_next = entry->next;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100484 ht->alloc.free(entry);
485 entry = entry_next;
486 }
487 }
488
489 ht->alloc.free(ht->buckets);
490 ht->alloc.free(ht);
491}
492
Victor Stinner285cf0a2016-03-21 22:00:58 +0100493
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100494_Py_hashtable_t *
495_Py_hashtable_copy(_Py_hashtable_t *src)
496{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100497 const size_t key_size = src->key_size;
498 const size_t data_size = src->data_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100499 _Py_hashtable_t *dst;
500 _Py_hashtable_entry_t *entry;
501 size_t bucket;
502 int err;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100503
Victor Stinner285cf0a2016-03-21 22:00:58 +0100504 dst = _Py_hashtable_new_full(key_size, data_size,
505 src->num_buckets,
Victor Stinnerc9553872016-03-22 12:13:01 +0100506 src->hash_func,
507 src->compare_func,
508 &src->alloc);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100509 if (dst == NULL)
510 return NULL;
511
512 for (bucket=0; bucket < src->num_buckets; bucket++) {
513 entry = TABLE_HEAD(src, bucket);
514 for (; entry; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100515 const void *pkey = _Py_HASHTABLE_ENTRY_PKEY(entry);
516 const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(src, entry);
517 err = _Py_hashtable_set(dst, key_size, pkey, data_size, pdata);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100518 if (err) {
519 _Py_hashtable_destroy(dst);
520 return NULL;
521 }
522 }
523 }
524 return dst;
525}