blob: d1467ad94ed55ce9f0f3a51cc3a5c3f388ce5370 [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))
Victor Stinner5dacbd42016-03-23 09:52:13 +010061
Victor Stinnered3b0bc2013-11-23 12:27:24 +010062/* Forward declaration */
63static void hashtable_rehash(_Py_hashtable_t *ht);
64
65static void
66_Py_slist_init(_Py_slist_t *list)
67{
68 list->head = NULL;
69}
70
Victor Stinner285cf0a2016-03-21 22:00:58 +010071
Victor Stinnered3b0bc2013-11-23 12:27:24 +010072static void
73_Py_slist_prepend(_Py_slist_t *list, _Py_slist_item_t *item)
74{
75 item->next = list->head;
76 list->head = item;
77}
78
Victor Stinner285cf0a2016-03-21 22:00:58 +010079
Victor Stinnered3b0bc2013-11-23 12:27:24 +010080static void
81_Py_slist_remove(_Py_slist_t *list, _Py_slist_item_t *previous,
82 _Py_slist_item_t *item)
83{
84 if (previous != NULL)
85 previous->next = item->next;
86 else
87 list->head = item->next;
88}
89
Victor Stinnered3b0bc2013-11-23 12:27:24 +010090
Victor Stinner322bc122016-03-21 14:36:39 +010091Py_uhash_t
Victor Stinnerf9b3b582020-05-13 02:26:02 +020092_Py_hashtable_hash_ptr(const void *key)
Victor Stinner322bc122016-03-21 14:36:39 +010093{
Victor Stinnerf4532212020-05-12 18:46:20 +020094 return (Py_uhash_t)_Py_HashPointerRaw(key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +010095}
96
Victor Stinner285cf0a2016-03-21 22:00:58 +010097
Victor Stinnered3b0bc2013-11-23 12:27:24 +010098int
Victor Stinnerf9b3b582020-05-13 02:26:02 +020099_Py_hashtable_compare_direct(const void *key1, const void *key2)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100100{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200101 return (key1 == key2);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100102}
103
Victor Stinner285cf0a2016-03-21 22:00:58 +0100104
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100105/* makes sure the real size of the buckets array is a power of 2 */
106static size_t
107round_size(size_t s)
108{
109 size_t i;
110 if (s < HASHTABLE_MIN_SIZE)
111 return HASHTABLE_MIN_SIZE;
112 i = 1;
113 while (i < s)
114 i <<= 1;
115 return i;
116}
117
Victor Stinner285cf0a2016-03-21 22:00:58 +0100118
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100119size_t
Victor Stinner5b0a3032020-05-13 04:40:30 +0200120_Py_hashtable_size(const _Py_hashtable_t *ht)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100121{
122 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100123
124 size = sizeof(_Py_hashtable_t);
125
126 /* buckets */
127 size += ht->num_buckets * sizeof(_Py_hashtable_entry_t *);
128
129 /* entries */
Victor Stinner5b0a3032020-05-13 04:40:30 +0200130 size += ht->entries * sizeof(_Py_hashtable_entry_t);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100131
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100132 return size;
133}
134
Victor Stinner285cf0a2016-03-21 22:00:58 +0100135
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100136#ifdef Py_DEBUG
137void
138_Py_hashtable_print_stats(_Py_hashtable_t *ht)
139{
140 size_t size;
141 size_t chain_len, max_chain_len, total_chain_len, nchains;
142 _Py_hashtable_entry_t *entry;
143 size_t hv;
144 double load;
145
146 size = _Py_hashtable_size(ht);
147
148 load = (double)ht->entries / ht->num_buckets;
149
150 max_chain_len = 0;
151 total_chain_len = 0;
152 nchains = 0;
153 for (hv = 0; hv < ht->num_buckets; hv++) {
154 entry = TABLE_HEAD(ht, hv);
155 if (entry != NULL) {
156 chain_len = 0;
157 for (; entry; entry = ENTRY_NEXT(entry)) {
158 chain_len++;
159 }
160 if (chain_len > max_chain_len)
161 max_chain_len = chain_len;
162 total_chain_len += chain_len;
163 nchains++;
164 }
165 }
Victor Stinner293f3f52014-07-01 08:57:10 +0200166 printf("hash table %p: entries=%"
167 PY_FORMAT_SIZE_T "u/%" PY_FORMAT_SIZE_T "u (%.0f%%), ",
Zackery Spytz1a2252e2019-05-06 10:56:51 -0600168 (void *)ht, ht->entries, ht->num_buckets, load * 100.0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100169 if (nchains)
170 printf("avg_chain_len=%.1f, ", (double)total_chain_len / nchains);
Victor Stinner8c663fd2017-11-08 14:44:44 -0800171 printf("max_chain_len=%" PY_FORMAT_SIZE_T "u, %" PY_FORMAT_SIZE_T "u KiB\n",
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100172 max_chain_len, size / 1024);
173}
174#endif
175
Victor Stinner285cf0a2016-03-21 22:00:58 +0100176
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100177_Py_hashtable_entry_t *
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200178_Py_hashtable_get_entry_generic(_Py_hashtable_t *ht, const void *key)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100179{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200180 Py_uhash_t key_hash = ht->hash_func(key);
Victor Stinner7c6e9702020-05-12 13:31:59 +0200181 size_t index = key_hash & (ht->num_buckets - 1);
182 _Py_hashtable_entry_t *entry = entry = TABLE_HEAD(ht, index);
183 while (1) {
184 if (entry == NULL) {
185 return NULL;
186 }
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200187 if (entry->key_hash == key_hash && ht->compare_func(key, entry->key)) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100188 break;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200189 }
190 entry = ENTRY_NEXT(entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100191 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100192 return entry;
193}
194
Victor Stinner285cf0a2016-03-21 22:00:58 +0100195
Victor Stinner42bae3a2020-05-13 05:36:23 +0200196// Specialized for:
197// hash_func == _Py_hashtable_hash_ptr
198// compare_func == _Py_hashtable_compare_direct
199static _Py_hashtable_entry_t *
200_Py_hashtable_get_entry_ptr(_Py_hashtable_t *ht, const void *key)
201{
202 Py_uhash_t key_hash = _Py_hashtable_hash_ptr(key);
203 size_t index = key_hash & (ht->num_buckets - 1);
204 _Py_hashtable_entry_t *entry = entry = TABLE_HEAD(ht, index);
205 while (1) {
206 if (entry == NULL) {
207 return NULL;
208 }
209 // Compare directly keys (ignore entry->key_hash)
210 if (entry->key == key) {
211 break;
212 }
213 entry = ENTRY_NEXT(entry);
214 }
215 return entry;
216}
217
218
Victor Stinner5b0a3032020-05-13 04:40:30 +0200219void*
220_Py_hashtable_steal(_Py_hashtable_t *ht, const void *key)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100221{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200222 Py_uhash_t key_hash = ht->hash_func(key);
223 size_t index = key_hash & (ht->num_buckets - 1);
Victor Stinner285cf0a2016-03-21 22:00:58 +0100224
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200225 _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, index);
226 _Py_hashtable_entry_t *previous = NULL;
227 while (1) {
228 if (entry == NULL) {
229 // not found
Victor Stinner5b0a3032020-05-13 04:40:30 +0200230 return NULL;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200231 }
232 if (entry->key_hash == key_hash && ht->compare_func(key, entry->key)) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100233 break;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200234 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100235 previous = entry;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200236 entry = ENTRY_NEXT(entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100237 }
238
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100239 _Py_slist_remove(&ht->buckets[index], (_Py_slist_item_t *)previous,
240 (_Py_slist_item_t *)entry);
241 ht->entries--;
242
Victor Stinner5b0a3032020-05-13 04:40:30 +0200243 void *value = entry->value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100244 ht->alloc.free(entry);
245
Victor Stinner5b0a3032020-05-13 04:40:30 +0200246 if ((float)ht->entries / (float)ht->num_buckets < HASHTABLE_LOW) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100247 hashtable_rehash(ht);
Victor Stinner5b0a3032020-05-13 04:40:30 +0200248 }
249 return value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100250}
251
Victor Stinner285cf0a2016-03-21 22:00:58 +0100252
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100253int
Victor Stinner5b0a3032020-05-13 04:40:30 +0200254_Py_hashtable_set(_Py_hashtable_t *ht, const void *key, void *value)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100255{
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100256 _Py_hashtable_entry_t *entry;
257
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100258#ifndef NDEBUG
259 /* Don't write the assertion on a single line because it is interesting
260 to know the duplicated entry if the assertion failed. The entry can
261 be read using a debugger. */
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200262 entry = ht->get_entry_func(ht, key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100263 assert(entry == NULL);
264#endif
265
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200266 Py_uhash_t key_hash = ht->hash_func(key);
267 size_t index = key_hash & (ht->num_buckets - 1);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100268
Victor Stinner5b0a3032020-05-13 04:40:30 +0200269 entry = ht->alloc.malloc(sizeof(_Py_hashtable_entry_t));
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100270 if (entry == NULL) {
271 /* memory allocation failed */
272 return -1;
273 }
274
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100275 entry->key_hash = key_hash;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200276 entry->key = (void *)key;
Victor Stinner5b0a3032020-05-13 04:40:30 +0200277 entry->value = value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100278
279 _Py_slist_prepend(&ht->buckets[index], (_Py_slist_item_t*)entry);
280 ht->entries++;
281
282 if ((float)ht->entries / (float)ht->num_buckets > HASHTABLE_HIGH)
283 hashtable_rehash(ht);
284 return 0;
285}
286
Victor Stinner285cf0a2016-03-21 22:00:58 +0100287
Victor Stinner5b0a3032020-05-13 04:40:30 +0200288void*
289_Py_hashtable_get(_Py_hashtable_t *ht, const void *key)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100290{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200291 _Py_hashtable_entry_t *entry = ht->get_entry_func(ht, key);
Victor Stinner7c6e9702020-05-12 13:31:59 +0200292 if (entry != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +0200293 return entry->value;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200294 }
295 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +0200296 return NULL;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200297 }
298}
299
300
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100301int
302_Py_hashtable_foreach(_Py_hashtable_t *ht,
Victor Stinner285cf0a2016-03-21 22:00:58 +0100303 _Py_hashtable_foreach_func func,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200304 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100305{
306 _Py_hashtable_entry_t *entry;
307 size_t hv;
308
309 for (hv = 0; hv < ht->num_buckets; hv++) {
310 for (entry = TABLE_HEAD(ht, hv); entry; entry = ENTRY_NEXT(entry)) {
Victor Stinner5b0a3032020-05-13 04:40:30 +0200311 int res = func(ht, entry->key, entry->value, user_data);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100312 if (res)
313 return res;
314 }
315 }
316 return 0;
317}
318
Victor Stinner285cf0a2016-03-21 22:00:58 +0100319
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100320static void
321hashtable_rehash(_Py_hashtable_t *ht)
322{
323 size_t buckets_size, new_size, bucket;
324 _Py_slist_t *old_buckets = NULL;
325 size_t old_num_buckets;
326
327 new_size = round_size((size_t)(ht->entries * HASHTABLE_REHASH_FACTOR));
328 if (new_size == ht->num_buckets)
329 return;
330
331 old_num_buckets = ht->num_buckets;
332
333 buckets_size = new_size * sizeof(ht->buckets[0]);
334 old_buckets = ht->buckets;
335 ht->buckets = ht->alloc.malloc(buckets_size);
336 if (ht->buckets == NULL) {
337 /* cancel rehash on memory allocation failure */
338 ht->buckets = old_buckets ;
339 /* memory allocation failed */
340 return;
341 }
342 memset(ht->buckets, 0, buckets_size);
343
344 ht->num_buckets = new_size;
345
346 for (bucket = 0; bucket < old_num_buckets; bucket++) {
347 _Py_hashtable_entry_t *entry, *next;
348 for (entry = BUCKETS_HEAD(old_buckets[bucket]); entry != NULL; entry = next) {
349 size_t entry_index;
350
Victor Stinner285cf0a2016-03-21 22:00:58 +0100351
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200352 assert(ht->hash_func(entry->key) == entry->key_hash);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100353 next = ENTRY_NEXT(entry);
354 entry_index = entry->key_hash & (new_size - 1);
355
356 _Py_slist_prepend(&ht->buckets[entry_index], (_Py_slist_item_t*)entry);
357 }
358 }
359
360 ht->alloc.free(old_buckets);
361}
362
Victor Stinner285cf0a2016-03-21 22:00:58 +0100363
Victor Stinner7c6e9702020-05-12 13:31:59 +0200364_Py_hashtable_t *
Victor Stinner5b0a3032020-05-13 04:40:30 +0200365_Py_hashtable_new_full(_Py_hashtable_hash_func hash_func,
Victor Stinner7c6e9702020-05-12 13:31:59 +0200366 _Py_hashtable_compare_func compare_func,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200367 _Py_hashtable_destroy_func key_destroy_func,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200368 _Py_hashtable_destroy_func value_destroy_func,
Victor Stinner7c6e9702020-05-12 13:31:59 +0200369 _Py_hashtable_allocator_t *allocator)
370{
371 _Py_hashtable_t *ht;
372 size_t buckets_size;
373 _Py_hashtable_allocator_t alloc;
374
375 if (allocator == NULL) {
376 alloc.malloc = PyMem_Malloc;
377 alloc.free = PyMem_Free;
378 }
379 else {
380 alloc = *allocator;
381 }
382
383 ht = (_Py_hashtable_t *)alloc.malloc(sizeof(_Py_hashtable_t));
384 if (ht == NULL)
385 return ht;
386
Victor Stinner5b0a3032020-05-13 04:40:30 +0200387 ht->num_buckets = HASHTABLE_MIN_SIZE;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200388 ht->entries = 0;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200389
390 buckets_size = ht->num_buckets * sizeof(ht->buckets[0]);
391 ht->buckets = alloc.malloc(buckets_size);
392 if (ht->buckets == NULL) {
393 alloc.free(ht);
394 return NULL;
395 }
396 memset(ht->buckets, 0, buckets_size);
397
Victor Stinner7c6e9702020-05-12 13:31:59 +0200398 ht->get_entry_func = _Py_hashtable_get_entry_generic;
399 ht->hash_func = hash_func;
400 ht->compare_func = compare_func;
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200401 ht->key_destroy_func = key_destroy_func;
402 ht->value_destroy_func = value_destroy_func;
Victor Stinner7c6e9702020-05-12 13:31:59 +0200403 ht->alloc = alloc;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200404 if (ht->hash_func == _Py_hashtable_hash_ptr
Victor Stinner7c6e9702020-05-12 13:31:59 +0200405 && ht->compare_func == _Py_hashtable_compare_direct)
406 {
Victor Stinner7c6e9702020-05-12 13:31:59 +0200407 ht->get_entry_func = _Py_hashtable_get_entry_ptr;
408 }
409 return ht;
410}
411
412
413_Py_hashtable_t *
Victor Stinner5b0a3032020-05-13 04:40:30 +0200414_Py_hashtable_new(_Py_hashtable_hash_func hash_func,
Victor Stinner7c6e9702020-05-12 13:31:59 +0200415 _Py_hashtable_compare_func compare_func)
416{
Victor Stinner5b0a3032020-05-13 04:40:30 +0200417 return _Py_hashtable_new_full(hash_func, compare_func,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200418 NULL, NULL, NULL);
Victor Stinner7c6e9702020-05-12 13:31:59 +0200419}
420
421
Victor Stinner5b0a3032020-05-13 04:40:30 +0200422static void
423_Py_hashtable_destroy_entry(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry)
424{
425 if (ht->key_destroy_func) {
426 ht->key_destroy_func(entry->key);
427 }
428 if (ht->value_destroy_func) {
429 ht->value_destroy_func(entry->value);
430 }
431 ht->alloc.free(entry);
432}
433
434
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100435void
436_Py_hashtable_clear(_Py_hashtable_t *ht)
437{
438 _Py_hashtable_entry_t *entry, *next;
439 size_t i;
440
441 for (i=0; i < ht->num_buckets; i++) {
442 for (entry = TABLE_HEAD(ht, i); entry != NULL; entry = next) {
443 next = ENTRY_NEXT(entry);
Victor Stinner5b0a3032020-05-13 04:40:30 +0200444 _Py_hashtable_destroy_entry(ht, entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100445 }
446 _Py_slist_init(&ht->buckets[i]);
447 }
448 ht->entries = 0;
449 hashtable_rehash(ht);
450}
451
Victor Stinner285cf0a2016-03-21 22:00:58 +0100452
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100453void
454_Py_hashtable_destroy(_Py_hashtable_t *ht)
455{
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200456 for (size_t i = 0; i < ht->num_buckets; i++) {
457 _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, i);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100458 while (entry) {
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200459 _Py_hashtable_entry_t *entry_next = ENTRY_NEXT(entry);
460 _Py_hashtable_destroy_entry(ht, entry);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100461 entry = entry_next;
462 }
463 }
464
465 ht->alloc.free(ht->buckets);
466 ht->alloc.free(ht);
467}