blob: 90fe34e62801612db8da62b89d56259e6921b2de [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;
Victor Stinner5dacbd42016-03-23 09:52:13 +0100111 _Py_HASHTABLE_READ_KEY(ht, pkey, key);
Victor Stinnerf4532212020-05-12 18:46:20 +0200112 return (Py_uhash_t)_Py_HashPointerRaw(key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100113}
114
Victor Stinner285cf0a2016-03-21 22:00:58 +0100115
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100116int
Victor Stinner5dacbd42016-03-23 09:52:13 +0100117_Py_hashtable_compare_direct(_Py_hashtable_t *ht, const void *pkey,
Victor Stinner285cf0a2016-03-21 22:00:58 +0100118 const _Py_hashtable_entry_t *entry)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100119{
Victor Stinner5dacbd42016-03-23 09:52:13 +0100120 const void *pkey2 = _Py_HASHTABLE_ENTRY_PKEY(entry);
121 return (memcmp(pkey, pkey2, ht->key_size) == 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100122}
123
Victor Stinner285cf0a2016-03-21 22:00:58 +0100124
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100125/* makes sure the real size of the buckets array is a power of 2 */
126static size_t
127round_size(size_t s)
128{
129 size_t i;
130 if (s < HASHTABLE_MIN_SIZE)
131 return HASHTABLE_MIN_SIZE;
132 i = 1;
133 while (i < s)
134 i <<= 1;
135 return i;
136}
137
Victor Stinner285cf0a2016-03-21 22:00:58 +0100138
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100139size_t
140_Py_hashtable_size(_Py_hashtable_t *ht)
141{
142 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100143
144 size = sizeof(_Py_hashtable_t);
145
146 /* buckets */
147 size += ht->num_buckets * sizeof(_Py_hashtable_entry_t *);
148
149 /* entries */
150 size += ht->entries * HASHTABLE_ITEM_SIZE(ht);
151
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100152 return size;
153}
154
Victor Stinner285cf0a2016-03-21 22:00:58 +0100155
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100156#ifdef Py_DEBUG
157void
158_Py_hashtable_print_stats(_Py_hashtable_t *ht)
159{
160 size_t size;
161 size_t chain_len, max_chain_len, total_chain_len, nchains;
162 _Py_hashtable_entry_t *entry;
163 size_t hv;
164 double load;
165
166 size = _Py_hashtable_size(ht);
167
168 load = (double)ht->entries / ht->num_buckets;
169
170 max_chain_len = 0;
171 total_chain_len = 0;
172 nchains = 0;
173 for (hv = 0; hv < ht->num_buckets; hv++) {
174 entry = TABLE_HEAD(ht, hv);
175 if (entry != NULL) {
176 chain_len = 0;
177 for (; entry; entry = ENTRY_NEXT(entry)) {
178 chain_len++;
179 }
180 if (chain_len > max_chain_len)
181 max_chain_len = chain_len;
182 total_chain_len += chain_len;
183 nchains++;
184 }
185 }
Victor Stinner293f3f52014-07-01 08:57:10 +0200186 printf("hash table %p: entries=%"
187 PY_FORMAT_SIZE_T "u/%" PY_FORMAT_SIZE_T "u (%.0f%%), ",
Zackery Spytz1a2252e2019-05-06 10:56:51 -0600188 (void *)ht, ht->entries, ht->num_buckets, load * 100.0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100189 if (nchains)
190 printf("avg_chain_len=%.1f, ", (double)total_chain_len / nchains);
Victor Stinner8c663fd2017-11-08 14:44:44 -0800191 printf("max_chain_len=%" PY_FORMAT_SIZE_T "u, %" PY_FORMAT_SIZE_T "u KiB\n",
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100192 max_chain_len, size / 1024);
193}
194#endif
195
Victor Stinner285cf0a2016-03-21 22:00:58 +0100196
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100197_Py_hashtable_entry_t *
Victor Stinner7c6e9702020-05-12 13:31:59 +0200198_Py_hashtable_get_entry_generic(_Py_hashtable_t *ht, const void *pkey)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100199{
Victor Stinner7c6e9702020-05-12 13:31:59 +0200200 Py_uhash_t key_hash = ht->hash_func(ht, pkey);
201 size_t index = key_hash & (ht->num_buckets - 1);
202 _Py_hashtable_entry_t *entry = entry = TABLE_HEAD(ht, index);
203 while (1) {
204 if (entry == NULL) {
205 return NULL;
206 }
207 if (entry->key_hash == key_hash && ht->compare_func(ht, pkey, entry)) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100208 break;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200209 }
210 entry = ENTRY_NEXT(entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100211 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100212 return entry;
213}
214
Victor Stinner285cf0a2016-03-21 22:00:58 +0100215
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100216static int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100217_Py_hashtable_pop_entry(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
218 void *data, size_t data_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100219{
220 Py_uhash_t key_hash;
221 size_t index;
222 _Py_hashtable_entry_t *entry, *previous;
223
Victor Stinner285cf0a2016-03-21 22:00:58 +0100224 assert(key_size == ht->key_size);
225
Victor Stinner5dacbd42016-03-23 09:52:13 +0100226 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100227 index = key_hash & (ht->num_buckets - 1);
228
229 previous = NULL;
230 for (entry = TABLE_HEAD(ht, index); entry != NULL; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100231 if (entry->key_hash == key_hash && ht->compare_func(ht, pkey, entry))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100232 break;
233 previous = entry;
234 }
235
236 if (entry == NULL)
237 return 0;
238
239 _Py_slist_remove(&ht->buckets[index], (_Py_slist_item_t *)previous,
240 (_Py_slist_item_t *)entry);
241 ht->entries--;
242
243 if (data != NULL)
Victor Stinner5dacbd42016-03-23 09:52:13 +0100244 ENTRY_READ_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100245 ht->alloc.free(entry);
246
247 if ((float)ht->entries / (float)ht->num_buckets < HASHTABLE_LOW)
248 hashtable_rehash(ht);
249 return 1;
250}
251
Victor Stinner285cf0a2016-03-21 22:00:58 +0100252
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100253int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100254_Py_hashtable_set(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
Victor Stinnerc9553872016-03-22 12:13:01 +0100255 size_t data_size, const void *data)
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 Stinnered3b0bc2013-11-23 12:27:24 +0100263 assert(data != NULL || data_size == 0);
264#ifndef NDEBUG
265 /* Don't write the assertion on a single line because it is interesting
266 to know the duplicated entry if the assertion failed. The entry can
267 be read using a debugger. */
Victor Stinner7c6e9702020-05-12 13:31:59 +0200268 entry = ht->get_entry_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100269 assert(entry == NULL);
270#endif
271
Victor Stinner5dacbd42016-03-23 09:52:13 +0100272 key_hash = ht->hash_func(ht, pkey);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100273 index = key_hash & (ht->num_buckets - 1);
274
275 entry = ht->alloc.malloc(HASHTABLE_ITEM_SIZE(ht));
276 if (entry == NULL) {
277 /* memory allocation failed */
278 return -1;
279 }
280
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100281 entry->key_hash = key_hash;
Christian Heimesf051e432016-09-13 20:22:02 +0200282 memcpy((void *)_Py_HASHTABLE_ENTRY_PKEY(entry), pkey, ht->key_size);
Benjamin Peterson4a757602016-09-06 19:03:40 -0700283 if (data)
Benjamin Peterson35b40c62016-09-06 19:04:37 -0700284 ENTRY_WRITE_PDATA(ht, entry, data_size, data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100285
286 _Py_slist_prepend(&ht->buckets[index], (_Py_slist_item_t*)entry);
287 ht->entries++;
288
289 if ((float)ht->entries / (float)ht->num_buckets > HASHTABLE_HIGH)
290 hashtable_rehash(ht);
291 return 0;
292}
293
Victor Stinner285cf0a2016-03-21 22:00:58 +0100294
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100295int
Victor Stinner7c6e9702020-05-12 13:31:59 +0200296_Py_hashtable_get_generic(_Py_hashtable_t *ht, const void *pkey, void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100297{
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100298 assert(data != NULL);
Victor Stinner7c6e9702020-05-12 13:31:59 +0200299 _Py_hashtable_entry_t *entry = ht->get_entry_func(ht, pkey);
300 if (entry != NULL) {
301 ENTRY_READ_PDATA(ht, entry, ht->data_size, data);
302 return 1;
303 }
304 else {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100305 return 0;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200306 }
307}
308
309
310// Specialized for:
311// key_size == sizeof(void*)
312// hash_func == _Py_hashtable_hash_ptr
313// compare_func == _Py_hashtable_compare_direct
314_Py_hashtable_entry_t *
315_Py_hashtable_get_entry_ptr(_Py_hashtable_t *ht, const void *pkey)
316{
317 Py_uhash_t key_hash = _Py_hashtable_hash_ptr(ht, pkey);
318 size_t index = key_hash & (ht->num_buckets - 1);
319 _Py_hashtable_entry_t *entry = entry = TABLE_HEAD(ht, index);
320 while (1) {
321 if (entry == NULL) {
322 return NULL;
323 }
324 if (entry->key_hash == key_hash) {
325 const void *pkey2 = _Py_HASHTABLE_ENTRY_PKEY(entry);
326 if (memcmp(pkey, pkey2, sizeof(void*)) == 0) {
327 break;
328 }
329 }
330 entry = ENTRY_NEXT(entry);
331 }
332 return entry;
333}
334
335
336// Specialized for:
337// key_size == sizeof(void*)
338// hash_func == _Py_hashtable_hash_ptr
339// compare_func == _Py_hashtable_compare_direct
340int
341_Py_hashtable_get_ptr(_Py_hashtable_t *ht, const void *pkey, void *data)
342{
343 assert(data != NULL);
344 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry_ptr(ht, pkey);
345 if (entry != NULL) {
346 ENTRY_READ_PDATA(ht, entry, ht->data_size, data);
347 return 1;
348 }
349 else {
350 return 0;
351 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100352}
353
Victor Stinner285cf0a2016-03-21 22:00:58 +0100354
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100355int
Victor Stinner285cf0a2016-03-21 22:00:58 +0100356_Py_hashtable_pop(_Py_hashtable_t *ht, size_t key_size, const void *pkey,
357 size_t data_size, void *data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100358{
359 assert(data != NULL);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100360 return _Py_hashtable_pop_entry(ht, key_size, pkey, data, data_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100361}
362
Victor Stinner285cf0a2016-03-21 22:00:58 +0100363
Victor Stinner58100052016-03-22 12:25:04 +0100364/* Code commented since the function is not needed in Python */
365#if 0
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100366void
Victor Stinner285cf0a2016-03-21 22:00:58 +0100367_Py_hashtable_delete(_Py_hashtable_t *ht, size_t key_size, const void *pkey)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100368{
369#ifndef NDEBUG
Victor Stinner285cf0a2016-03-21 22:00:58 +0100370 int found = _Py_hashtable_pop_entry(ht, key_size, pkey, NULL, 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100371 assert(found);
372#else
Victor Stinner285cf0a2016-03-21 22:00:58 +0100373 (void)_Py_hashtable_pop_entry(ht, key_size, pkey, NULL, 0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100374#endif
375}
Victor Stinner58100052016-03-22 12:25:04 +0100376#endif
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100377
Victor Stinner285cf0a2016-03-21 22:00:58 +0100378
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100379int
380_Py_hashtable_foreach(_Py_hashtable_t *ht,
Victor Stinner285cf0a2016-03-21 22:00:58 +0100381 _Py_hashtable_foreach_func func,
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100382 void *arg)
383{
384 _Py_hashtable_entry_t *entry;
385 size_t hv;
386
387 for (hv = 0; hv < ht->num_buckets; hv++) {
388 for (entry = TABLE_HEAD(ht, hv); entry; entry = ENTRY_NEXT(entry)) {
Victor Stinner285cf0a2016-03-21 22:00:58 +0100389 int res = func(ht, entry, arg);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100390 if (res)
391 return res;
392 }
393 }
394 return 0;
395}
396
Victor Stinner285cf0a2016-03-21 22:00:58 +0100397
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100398static void
399hashtable_rehash(_Py_hashtable_t *ht)
400{
401 size_t buckets_size, new_size, bucket;
402 _Py_slist_t *old_buckets = NULL;
403 size_t old_num_buckets;
404
405 new_size = round_size((size_t)(ht->entries * HASHTABLE_REHASH_FACTOR));
406 if (new_size == ht->num_buckets)
407 return;
408
409 old_num_buckets = ht->num_buckets;
410
411 buckets_size = new_size * sizeof(ht->buckets[0]);
412 old_buckets = ht->buckets;
413 ht->buckets = ht->alloc.malloc(buckets_size);
414 if (ht->buckets == NULL) {
415 /* cancel rehash on memory allocation failure */
416 ht->buckets = old_buckets ;
417 /* memory allocation failed */
418 return;
419 }
420 memset(ht->buckets, 0, buckets_size);
421
422 ht->num_buckets = new_size;
423
424 for (bucket = 0; bucket < old_num_buckets; bucket++) {
425 _Py_hashtable_entry_t *entry, *next;
426 for (entry = BUCKETS_HEAD(old_buckets[bucket]); entry != NULL; entry = next) {
427 size_t entry_index;
428
Victor Stinner285cf0a2016-03-21 22:00:58 +0100429
Victor Stinner5dacbd42016-03-23 09:52:13 +0100430 assert(ht->hash_func(ht, _Py_HASHTABLE_ENTRY_PKEY(entry)) == entry->key_hash);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100431 next = ENTRY_NEXT(entry);
432 entry_index = entry->key_hash & (new_size - 1);
433
434 _Py_slist_prepend(&ht->buckets[entry_index], (_Py_slist_item_t*)entry);
435 }
436 }
437
438 ht->alloc.free(old_buckets);
439}
440
Victor Stinner285cf0a2016-03-21 22:00:58 +0100441
Victor Stinner7c6e9702020-05-12 13:31:59 +0200442_Py_hashtable_t *
443_Py_hashtable_new_full(size_t key_size, size_t data_size,
444 size_t init_size,
445 _Py_hashtable_hash_func hash_func,
446 _Py_hashtable_compare_func compare_func,
447 _Py_hashtable_allocator_t *allocator)
448{
449 _Py_hashtable_t *ht;
450 size_t buckets_size;
451 _Py_hashtable_allocator_t alloc;
452
453 if (allocator == NULL) {
454 alloc.malloc = PyMem_Malloc;
455 alloc.free = PyMem_Free;
456 }
457 else {
458 alloc = *allocator;
459 }
460
461 ht = (_Py_hashtable_t *)alloc.malloc(sizeof(_Py_hashtable_t));
462 if (ht == NULL)
463 return ht;
464
465 ht->num_buckets = round_size(init_size);
466 ht->entries = 0;
467 ht->key_size = key_size;
468 ht->data_size = data_size;
469
470 buckets_size = ht->num_buckets * sizeof(ht->buckets[0]);
471 ht->buckets = alloc.malloc(buckets_size);
472 if (ht->buckets == NULL) {
473 alloc.free(ht);
474 return NULL;
475 }
476 memset(ht->buckets, 0, buckets_size);
477
478 ht->get_func = _Py_hashtable_get_generic;
479 ht->get_entry_func = _Py_hashtable_get_entry_generic;
480 ht->hash_func = hash_func;
481 ht->compare_func = compare_func;
482 ht->alloc = alloc;
483 if (ht->key_size == sizeof(void*)
484 && ht->hash_func == _Py_hashtable_hash_ptr
485 && ht->compare_func == _Py_hashtable_compare_direct)
486 {
487 ht->get_func = _Py_hashtable_get_ptr;
488 ht->get_entry_func = _Py_hashtable_get_entry_ptr;
489 }
490 return ht;
491}
492
493
494_Py_hashtable_t *
495_Py_hashtable_new(size_t key_size, size_t data_size,
496 _Py_hashtable_hash_func hash_func,
497 _Py_hashtable_compare_func compare_func)
498{
499 return _Py_hashtable_new_full(key_size, data_size,
500 HASHTABLE_MIN_SIZE,
501 hash_func, compare_func,
502 NULL);
503}
504
505
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100506void
507_Py_hashtable_clear(_Py_hashtable_t *ht)
508{
509 _Py_hashtable_entry_t *entry, *next;
510 size_t i;
511
512 for (i=0; i < ht->num_buckets; i++) {
513 for (entry = TABLE_HEAD(ht, i); entry != NULL; entry = next) {
514 next = ENTRY_NEXT(entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100515 ht->alloc.free(entry);
516 }
517 _Py_slist_init(&ht->buckets[i]);
518 }
519 ht->entries = 0;
520 hashtable_rehash(ht);
521}
522
Victor Stinner285cf0a2016-03-21 22:00:58 +0100523
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100524void
525_Py_hashtable_destroy(_Py_hashtable_t *ht)
526{
527 size_t i;
528
529 for (i = 0; i < ht->num_buckets; i++) {
530 _Py_slist_item_t *entry = ht->buckets[i].head;
531 while (entry) {
532 _Py_slist_item_t *entry_next = entry->next;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100533 ht->alloc.free(entry);
534 entry = entry_next;
535 }
536 }
537
538 ht->alloc.free(ht->buckets);
539 ht->alloc.free(ht);
540}
541
Victor Stinner285cf0a2016-03-21 22:00:58 +0100542
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100543_Py_hashtable_t *
544_Py_hashtable_copy(_Py_hashtable_t *src)
545{
Victor Stinner285cf0a2016-03-21 22:00:58 +0100546 const size_t key_size = src->key_size;
547 const size_t data_size = src->data_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100548 _Py_hashtable_t *dst;
549 _Py_hashtable_entry_t *entry;
550 size_t bucket;
551 int err;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100552
Victor Stinner285cf0a2016-03-21 22:00:58 +0100553 dst = _Py_hashtable_new_full(key_size, data_size,
554 src->num_buckets,
Victor Stinnerc9553872016-03-22 12:13:01 +0100555 src->hash_func,
556 src->compare_func,
557 &src->alloc);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100558 if (dst == NULL)
559 return NULL;
560
561 for (bucket=0; bucket < src->num_buckets; bucket++) {
562 entry = TABLE_HEAD(src, bucket);
563 for (; entry; entry = ENTRY_NEXT(entry)) {
Victor Stinner5dacbd42016-03-23 09:52:13 +0100564 const void *pkey = _Py_HASHTABLE_ENTRY_PKEY(entry);
565 const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(src, entry);
566 err = _Py_hashtable_set(dst, key_size, pkey, data_size, pdata);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100567 if (err) {
568 _Py_hashtable_destroy(dst);
569 return NULL;
570 }
571 }
572 }
573 return dst;
574}