xref: /aosp_15_r20/external/mesa3d/src/util/hash_table.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2009,2012 Intel Corporation
3  * Copyright © 1988-2004 Keith Packard and Bart Massey.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Except as contained in this notice, the names of the authors
25  * or their institutions shall not be used in advertising or
26  * otherwise to promote the sale, use or other dealings in this
27  * Software without prior written authorization from the
28  * authors.
29  *
30  * Authors:
31  *    Eric Anholt <[email protected]>
32  *    Keith Packard <[email protected]>
33  */
34 
35 /**
36  * Implements an open-addressing, linear-reprobing hash table.
37  *
38  * For more information, see:
39  *
40  * http://cgit.freedesktop.org/~anholt/hash_table/tree/README
41  */
42 
43 #include <stdlib.h>
44 #include <string.h>
45 #include <assert.h>
46 
47 #include "hash_table.h"
48 #include "ralloc.h"
49 #include "macros.h"
50 #include "u_memory.h"
51 #include "fast_urem_by_const.h"
52 #include "util/u_memory.h"
53 
54 #define XXH_INLINE_ALL
55 #include "xxhash.h"
56 
57 /**
58  * Magic number that gets stored outside of the struct hash_table.
59  *
60  * The hash table needs a particular pointer to be the marker for a key that
61  * was deleted from the table, along with NULL for the "never allocated in the
62  * table" marker.  Legacy GL allows any GLuint to be used as a GL object name,
63  * and we use a 1:1 mapping from GLuints to key pointers, so we need to be
64  * able to track a GLuint that happens to match the deleted key outside of
65  * struct hash_table.  We tell the hash table to use "1" as the deleted key
66  * value, so that we test the deleted-key-in-the-table path as best we can.
67  */
68 #define DELETED_KEY_VALUE 1
69 
70 static inline void *
uint_key(unsigned id)71 uint_key(unsigned id)
72 {
73    return (void *)(uintptr_t) id;
74 }
75 
76 static const uint32_t deleted_key_value;
77 
78 /**
79  * From Knuth -- a good choice for hash/rehash values is p, p-2 where
80  * p and p-2 are both prime.  These tables are sized to have an extra 10%
81  * free to avoid exponential performance degradation as the hash table fills
82  */
83 static const struct {
84    uint32_t max_entries, size, rehash;
85    uint64_t size_magic, rehash_magic;
86 } hash_sizes[] = {
87 #define ENTRY(max_entries, size, rehash) \
88    { max_entries, size, rehash, \
89       REMAINDER_MAGIC(size), REMAINDER_MAGIC(rehash) }
90 
91    ENTRY(2,            5,            3            ),
92    ENTRY(4,            7,            5            ),
93    ENTRY(8,            13,           11           ),
94    ENTRY(16,           19,           17           ),
95    ENTRY(32,           43,           41           ),
96    ENTRY(64,           73,           71           ),
97    ENTRY(128,          151,          149          ),
98    ENTRY(256,          283,          281          ),
99    ENTRY(512,          571,          569          ),
100    ENTRY(1024,         1153,         1151         ),
101    ENTRY(2048,         2269,         2267         ),
102    ENTRY(4096,         4519,         4517         ),
103    ENTRY(8192,         9013,         9011         ),
104    ENTRY(16384,        18043,        18041        ),
105    ENTRY(32768,        36109,        36107        ),
106    ENTRY(65536,        72091,        72089        ),
107    ENTRY(131072,       144409,       144407       ),
108    ENTRY(262144,       288361,       288359       ),
109    ENTRY(524288,       576883,       576881       ),
110    ENTRY(1048576,      1153459,      1153457      ),
111    ENTRY(2097152,      2307163,      2307161      ),
112    ENTRY(4194304,      4613893,      4613891      ),
113    ENTRY(8388608,      9227641,      9227639      ),
114    ENTRY(16777216,     18455029,     18455027     ),
115    ENTRY(33554432,     36911011,     36911009     ),
116    ENTRY(67108864,     73819861,     73819859     ),
117    ENTRY(134217728,    147639589,    147639587    ),
118    ENTRY(268435456,    295279081,    295279079    ),
119    ENTRY(536870912,    590559793,    590559791    ),
120    ENTRY(1073741824,   1181116273,   1181116271   ),
121    ENTRY(2147483648ul, 2362232233ul, 2362232231ul )
122 };
123 
124 ASSERTED static inline bool
key_pointer_is_reserved(const struct hash_table * ht,const void * key)125 key_pointer_is_reserved(const struct hash_table *ht, const void *key)
126 {
127    return key == NULL || key == ht->deleted_key;
128 }
129 
130 static int
entry_is_free(const struct hash_entry * entry)131 entry_is_free(const struct hash_entry *entry)
132 {
133    return entry->key == NULL;
134 }
135 
136 static int
entry_is_deleted(const struct hash_table * ht,struct hash_entry * entry)137 entry_is_deleted(const struct hash_table *ht, struct hash_entry *entry)
138 {
139    return entry->key == ht->deleted_key;
140 }
141 
142 static int
entry_is_present(const struct hash_table * ht,struct hash_entry * entry)143 entry_is_present(const struct hash_table *ht, struct hash_entry *entry)
144 {
145    return entry->key != NULL && entry->key != ht->deleted_key;
146 }
147 
148 bool
_mesa_hash_table_init(struct hash_table * ht,void * mem_ctx,uint32_t (* key_hash_function)(const void * key),bool (* key_equals_function)(const void * a,const void * b))149 _mesa_hash_table_init(struct hash_table *ht,
150                       void *mem_ctx,
151                       uint32_t (*key_hash_function)(const void *key),
152                       bool (*key_equals_function)(const void *a,
153                                                   const void *b))
154 {
155    ht->size_index = 0;
156    ht->size = hash_sizes[ht->size_index].size;
157    ht->rehash = hash_sizes[ht->size_index].rehash;
158    ht->size_magic = hash_sizes[ht->size_index].size_magic;
159    ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic;
160    ht->max_entries = hash_sizes[ht->size_index].max_entries;
161    ht->key_hash_function = key_hash_function;
162    ht->key_equals_function = key_equals_function;
163    ht->table = rzalloc_array(mem_ctx, struct hash_entry, ht->size);
164    ht->entries = 0;
165    ht->deleted_entries = 0;
166    ht->deleted_key = &deleted_key_value;
167 
168    return ht->table != NULL;
169 }
170 
171 struct hash_table *
_mesa_hash_table_create(void * mem_ctx,uint32_t (* key_hash_function)(const void * key),bool (* key_equals_function)(const void * a,const void * b))172 _mesa_hash_table_create(void *mem_ctx,
173                         uint32_t (*key_hash_function)(const void *key),
174                         bool (*key_equals_function)(const void *a,
175                                                     const void *b))
176 {
177    struct hash_table *ht;
178 
179    /* mem_ctx is used to allocate the hash table, but the hash table is used
180     * to allocate all of the suballocations.
181     */
182    ht = ralloc(mem_ctx, struct hash_table);
183    if (ht == NULL)
184       return NULL;
185 
186    if (!_mesa_hash_table_init(ht, ht, key_hash_function, key_equals_function)) {
187       ralloc_free(ht);
188       return NULL;
189    }
190 
191    return ht;
192 }
193 
194 static uint32_t
key_u32_hash(const void * key)195 key_u32_hash(const void *key)
196 {
197    uint32_t u = (uint32_t)(uintptr_t)key;
198    return _mesa_hash_uint(&u);
199 }
200 
201 static bool
key_u32_equals(const void * a,const void * b)202 key_u32_equals(const void *a, const void *b)
203 {
204    return (uint32_t)(uintptr_t)a == (uint32_t)(uintptr_t)b;
205 }
206 
207 /* key == 0 and key == deleted_key are not allowed */
208 struct hash_table *
_mesa_hash_table_create_u32_keys(void * mem_ctx)209 _mesa_hash_table_create_u32_keys(void *mem_ctx)
210 {
211    return _mesa_hash_table_create(mem_ctx, key_u32_hash, key_u32_equals);
212 }
213 
214 struct hash_table *
_mesa_hash_table_clone(struct hash_table * src,void * dst_mem_ctx)215 _mesa_hash_table_clone(struct hash_table *src, void *dst_mem_ctx)
216 {
217    struct hash_table *ht;
218 
219    ht = ralloc(dst_mem_ctx, struct hash_table);
220    if (ht == NULL)
221       return NULL;
222 
223    memcpy(ht, src, sizeof(struct hash_table));
224 
225    ht->table = ralloc_array(ht, struct hash_entry, ht->size);
226    if (ht->table == NULL) {
227       ralloc_free(ht);
228       return NULL;
229    }
230 
231    memcpy(ht->table, src->table, ht->size * sizeof(struct hash_entry));
232 
233    return ht;
234 }
235 
236 /**
237  * Frees the given hash table.
238  *
239  * If delete_function is passed, it gets called on each entry present before
240  * freeing.
241  */
242 void
_mesa_hash_table_destroy(struct hash_table * ht,void (* delete_function)(struct hash_entry * entry))243 _mesa_hash_table_destroy(struct hash_table *ht,
244                          void (*delete_function)(struct hash_entry *entry))
245 {
246    if (!ht)
247       return;
248 
249    if (delete_function) {
250       hash_table_foreach(ht, entry) {
251          delete_function(entry);
252       }
253    }
254    ralloc_free(ht);
255 }
256 
257 static void
hash_table_clear_fast(struct hash_table * ht)258 hash_table_clear_fast(struct hash_table *ht)
259 {
260    memset(ht->table, 0, sizeof(struct hash_entry) * hash_sizes[ht->size_index].size);
261    ht->entries = ht->deleted_entries = 0;
262 }
263 
264 /**
265  * Deletes all entries of the given hash table without deleting the table
266  * itself or changing its structure.
267  *
268  * If delete_function is passed, it gets called on each entry present.
269  */
270 void
_mesa_hash_table_clear(struct hash_table * ht,void (* delete_function)(struct hash_entry * entry))271 _mesa_hash_table_clear(struct hash_table *ht,
272                        void (*delete_function)(struct hash_entry *entry))
273 {
274    if (!ht)
275       return;
276 
277    struct hash_entry *entry;
278 
279    if (delete_function) {
280       for (entry = ht->table; entry != ht->table + ht->size; entry++) {
281          if (entry_is_present(ht, entry))
282             delete_function(entry);
283 
284          entry->key = NULL;
285       }
286       ht->entries = 0;
287       ht->deleted_entries = 0;
288    } else
289       hash_table_clear_fast(ht);
290 }
291 
292 /** Sets the value of the key pointer used for deleted entries in the table.
293  *
294  * The assumption is that usually keys are actual pointers, so we use a
295  * default value of a pointer to an arbitrary piece of storage in the library.
296  * But in some cases a consumer wants to store some other sort of value in the
297  * table, like a uint32_t, in which case that pointer may conflict with one of
298  * their valid keys.  This lets that user select a safe value.
299  *
300  * This must be called before any keys are actually deleted from the table.
301  */
302 void
_mesa_hash_table_set_deleted_key(struct hash_table * ht,const void * deleted_key)303 _mesa_hash_table_set_deleted_key(struct hash_table *ht, const void *deleted_key)
304 {
305    ht->deleted_key = deleted_key;
306 }
307 
308 static struct hash_entry *
hash_table_search(const struct hash_table * ht,uint32_t hash,const void * key)309 hash_table_search(const struct hash_table *ht, uint32_t hash, const void *key)
310 {
311    assert(!key_pointer_is_reserved(ht, key));
312 
313    uint32_t size = ht->size;
314    uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
315    uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
316                                                ht->rehash_magic);
317    uint32_t hash_address = start_hash_address;
318 
319    do {
320       struct hash_entry *entry = ht->table + hash_address;
321 
322       if (entry_is_free(entry)) {
323          return NULL;
324       } else if (entry_is_present(ht, entry) && entry->hash == hash) {
325          if (ht->key_equals_function(key, entry->key)) {
326             return entry;
327          }
328       }
329 
330       hash_address += double_hash;
331       if (hash_address >= size)
332          hash_address -= size;
333    } while (hash_address != start_hash_address);
334 
335    return NULL;
336 }
337 
338 /**
339  * Finds a hash table entry with the given key and hash of that key.
340  *
341  * Returns NULL if no entry is found.  Note that the data pointer may be
342  * modified by the user.
343  */
344 struct hash_entry *
_mesa_hash_table_search(const struct hash_table * ht,const void * key)345 _mesa_hash_table_search(const struct hash_table *ht, const void *key)
346 {
347    assert(ht->key_hash_function);
348    return hash_table_search(ht, ht->key_hash_function(key), key);
349 }
350 
351 struct hash_entry *
_mesa_hash_table_search_pre_hashed(struct hash_table * ht,uint32_t hash,const void * key)352 _mesa_hash_table_search_pre_hashed(struct hash_table *ht, uint32_t hash,
353                                   const void *key)
354 {
355    assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key));
356    return hash_table_search(ht, hash, key);
357 }
358 
359 static struct hash_entry *
360 hash_table_insert(struct hash_table *ht, uint32_t hash,
361                   const void *key, void *data);
362 
363 static void
hash_table_insert_rehash(struct hash_table * ht,uint32_t hash,const void * key,void * data)364 hash_table_insert_rehash(struct hash_table *ht, uint32_t hash,
365                          const void *key, void *data)
366 {
367    uint32_t size = ht->size;
368    uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
369    uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
370                                                ht->rehash_magic);
371    uint32_t hash_address = start_hash_address;
372    do {
373       struct hash_entry *entry = ht->table + hash_address;
374 
375       if (likely(entry->key == NULL)) {
376          entry->hash = hash;
377          entry->key = key;
378          entry->data = data;
379          return;
380       }
381 
382       hash_address += double_hash;
383       if (hash_address >= size)
384          hash_address -= size;
385    } while (true);
386 }
387 
388 static void
_mesa_hash_table_rehash(struct hash_table * ht,unsigned new_size_index)389 _mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index)
390 {
391    struct hash_table old_ht;
392    struct hash_entry *table;
393 
394    if (ht->size_index == new_size_index && ht->deleted_entries == ht->max_entries) {
395       hash_table_clear_fast(ht);
396       assert(!ht->entries);
397       return;
398    }
399 
400    if (new_size_index >= ARRAY_SIZE(hash_sizes))
401       return;
402 
403    table = rzalloc_array(ralloc_parent(ht->table), struct hash_entry,
404                          hash_sizes[new_size_index].size);
405    if (table == NULL)
406       return;
407 
408    old_ht = *ht;
409 
410    ht->table = table;
411    ht->size_index = new_size_index;
412    ht->size = hash_sizes[ht->size_index].size;
413    ht->rehash = hash_sizes[ht->size_index].rehash;
414    ht->size_magic = hash_sizes[ht->size_index].size_magic;
415    ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic;
416    ht->max_entries = hash_sizes[ht->size_index].max_entries;
417    ht->entries = 0;
418    ht->deleted_entries = 0;
419 
420    hash_table_foreach(&old_ht, entry) {
421       hash_table_insert_rehash(ht, entry->hash, entry->key, entry->data);
422    }
423 
424    ht->entries = old_ht.entries;
425 
426    ralloc_free(old_ht.table);
427 }
428 
429 static struct hash_entry *
hash_table_get_entry(struct hash_table * ht,uint32_t hash,const void * key)430 hash_table_get_entry(struct hash_table *ht, uint32_t hash, const void *key)
431 {
432    struct hash_entry *available_entry = NULL;
433 
434    assert(!key_pointer_is_reserved(ht, key));
435 
436    if (ht->entries >= ht->max_entries) {
437       _mesa_hash_table_rehash(ht, ht->size_index + 1);
438    } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
439       _mesa_hash_table_rehash(ht, ht->size_index);
440    }
441 
442    uint32_t size = ht->size;
443    uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
444    uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
445                                                ht->rehash_magic);
446    uint32_t hash_address = start_hash_address;
447    do {
448       struct hash_entry *entry = ht->table + hash_address;
449 
450       if (!entry_is_present(ht, entry)) {
451          /* Stash the first available entry we find */
452          if (available_entry == NULL)
453             available_entry = entry;
454          if (entry_is_free(entry))
455             break;
456       }
457 
458       /* Implement replacement when another insert happens
459        * with a matching key.  This is a relatively common
460        * feature of hash tables, with the alternative
461        * generally being "insert the new value as well, and
462        * return it first when the key is searched for".
463        *
464        * Note that the hash table doesn't have a delete
465        * callback.  If freeing of old data pointers is
466        * required to avoid memory leaks, perform a search
467        * before inserting.
468        */
469       if (!entry_is_deleted(ht, entry) &&
470           entry->hash == hash &&
471           ht->key_equals_function(key, entry->key))
472          return entry;
473 
474       hash_address += double_hash;
475       if (hash_address >= size)
476          hash_address -= size;
477    } while (hash_address != start_hash_address);
478 
479    if (available_entry) {
480       if (entry_is_deleted(ht, available_entry))
481          ht->deleted_entries--;
482       available_entry->hash = hash;
483       ht->entries++;
484       return available_entry;
485    }
486 
487    /* We could hit here if a required resize failed. An unchecked-malloc
488     * application could ignore this result.
489     */
490    return NULL;
491 }
492 
493 static struct hash_entry *
hash_table_insert(struct hash_table * ht,uint32_t hash,const void * key,void * data)494 hash_table_insert(struct hash_table *ht, uint32_t hash,
495                   const void *key, void *data)
496 {
497    struct hash_entry *entry = hash_table_get_entry(ht, hash, key);
498 
499    if (entry) {
500       entry->key = key;
501       entry->data = data;
502    }
503 
504    return entry;
505 }
506 
507 /**
508  * Inserts the key with the given hash into the table.
509  *
510  * Note that insertion may rearrange the table on a resize or rehash,
511  * so previously found hash_entries are no longer valid after this function.
512  */
513 struct hash_entry *
_mesa_hash_table_insert(struct hash_table * ht,const void * key,void * data)514 _mesa_hash_table_insert(struct hash_table *ht, const void *key, void *data)
515 {
516    assert(ht->key_hash_function);
517    return hash_table_insert(ht, ht->key_hash_function(key), key, data);
518 }
519 
520 struct hash_entry *
_mesa_hash_table_insert_pre_hashed(struct hash_table * ht,uint32_t hash,const void * key,void * data)521 _mesa_hash_table_insert_pre_hashed(struct hash_table *ht, uint32_t hash,
522                                    const void *key, void *data)
523 {
524    assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key));
525    return hash_table_insert(ht, hash, key, data);
526 }
527 
528 /**
529  * This function deletes the given hash table entry.
530  *
531  * Note that deletion doesn't otherwise modify the table, so an iteration over
532  * the table deleting entries is safe.
533  */
534 void
_mesa_hash_table_remove(struct hash_table * ht,struct hash_entry * entry)535 _mesa_hash_table_remove(struct hash_table *ht,
536                         struct hash_entry *entry)
537 {
538    if (!entry)
539       return;
540 
541    entry->key = ht->deleted_key;
542    ht->entries--;
543    ht->deleted_entries++;
544 }
545 
546 /**
547  * Removes the entry with the corresponding key, if exists.
548  */
_mesa_hash_table_remove_key(struct hash_table * ht,const void * key)549 void _mesa_hash_table_remove_key(struct hash_table *ht,
550                                  const void *key)
551 {
552    _mesa_hash_table_remove(ht, _mesa_hash_table_search(ht, key));
553 }
554 
555 /**
556  * This function is an iterator over the hash_table when no deleted entries are present.
557  *
558  * Pass in NULL for the first entry, as in the start of a for loop.
559  */
560 struct hash_entry *
_mesa_hash_table_next_entry_unsafe(const struct hash_table * ht,struct hash_entry * entry)561 _mesa_hash_table_next_entry_unsafe(const struct hash_table *ht, struct hash_entry *entry)
562 {
563    assert(!ht->deleted_entries);
564    if (!ht->entries)
565       return NULL;
566    if (entry == NULL)
567       entry = ht->table;
568    else
569       entry = entry + 1;
570    if (entry != ht->table + ht->size)
571       return entry->key ? entry : _mesa_hash_table_next_entry_unsafe(ht, entry);
572 
573    return NULL;
574 }
575 
576 /**
577  * This function is an iterator over the hash table.
578  *
579  * Pass in NULL for the first entry, as in the start of a for loop.  Note that
580  * an iteration over the table is O(table_size) not O(entries).
581  */
582 struct hash_entry *
_mesa_hash_table_next_entry(struct hash_table * ht,struct hash_entry * entry)583 _mesa_hash_table_next_entry(struct hash_table *ht,
584                             struct hash_entry *entry)
585 {
586    if (entry == NULL)
587       entry = ht->table;
588    else
589       entry = entry + 1;
590 
591    for (; entry != ht->table + ht->size; entry++) {
592       if (entry_is_present(ht, entry)) {
593          return entry;
594       }
595    }
596 
597    return NULL;
598 }
599 
600 /**
601  * Returns a random entry from the hash table.
602  *
603  * This may be useful in implementing random replacement (as opposed
604  * to just removing everything) in caches based on this hash table
605  * implementation.  @predicate may be used to filter entries, or may
606  * be set to NULL for no filtering.
607  */
608 struct hash_entry *
_mesa_hash_table_random_entry(struct hash_table * ht,bool (* predicate)(struct hash_entry * entry))609 _mesa_hash_table_random_entry(struct hash_table *ht,
610                               bool (*predicate)(struct hash_entry *entry))
611 {
612    struct hash_entry *entry;
613    uint32_t i = rand() % ht->size;
614 
615    if (ht->entries == 0)
616       return NULL;
617 
618    for (entry = ht->table + i; entry != ht->table + ht->size; entry++) {
619       if (entry_is_present(ht, entry) &&
620           (!predicate || predicate(entry))) {
621          return entry;
622       }
623    }
624 
625    for (entry = ht->table; entry != ht->table + i; entry++) {
626       if (entry_is_present(ht, entry) &&
627           (!predicate || predicate(entry))) {
628          return entry;
629       }
630    }
631 
632    return NULL;
633 }
634 
635 
636 uint32_t
_mesa_hash_data(const void * data,size_t size)637 _mesa_hash_data(const void *data, size_t size)
638 {
639    return XXH32(data, size, 0);
640 }
641 
642 uint32_t
_mesa_hash_data_with_seed(const void * data,size_t size,uint32_t seed)643 _mesa_hash_data_with_seed(const void *data, size_t size, uint32_t seed)
644 {
645    return XXH32(data, size, seed);
646 }
647 
648 uint32_t
_mesa_hash_int(const void * key)649 _mesa_hash_int(const void *key)
650 {
651    return XXH32(key, sizeof(int), 0);
652 }
653 
654 uint32_t
_mesa_hash_uint(const void * key)655 _mesa_hash_uint(const void *key)
656 {
657    return XXH32(key, sizeof(unsigned), 0);
658 }
659 
660 uint32_t
_mesa_hash_u32(const void * key)661 _mesa_hash_u32(const void *key)
662 {
663    return XXH32(key, 4, 0);
664 }
665 
666 /** FNV-1a string hash implementation */
667 uint32_t
_mesa_hash_string(const void * _key)668 _mesa_hash_string(const void *_key)
669 {
670    return _mesa_hash_string_with_length(_key, strlen((const char *)_key));
671 }
672 
673 uint32_t
_mesa_hash_string_with_length(const void * _key,unsigned length)674 _mesa_hash_string_with_length(const void *_key, unsigned length)
675 {
676    uint32_t hash = 0;
677    const char *key = _key;
678 #if defined(_WIN64) || defined(__x86_64__)
679    hash = (uint32_t)XXH64(key, length, hash);
680 #else
681    hash = XXH32(key, length, hash);
682 #endif
683    return hash;
684 }
685 
686 uint32_t
_mesa_hash_pointer(const void * pointer)687 _mesa_hash_pointer(const void *pointer)
688 {
689    uintptr_t num = (uintptr_t) pointer;
690    return (uint32_t) ((num >> 2) ^ (num >> 6) ^ (num >> 10) ^ (num >> 14));
691 }
692 
693 bool
_mesa_key_int_equal(const void * a,const void * b)694 _mesa_key_int_equal(const void *a, const void *b)
695 {
696    return *((const int *)a) == *((const int *)b);
697 }
698 
699 bool
_mesa_key_uint_equal(const void * a,const void * b)700 _mesa_key_uint_equal(const void *a, const void *b)
701 {
702 
703    return *((const unsigned *)a) == *((const unsigned *)b);
704 }
705 
706 bool
_mesa_key_u32_equal(const void * a,const void * b)707 _mesa_key_u32_equal(const void *a, const void *b)
708 {
709    return *((const uint32_t *)a) == *((const uint32_t *)b);
710 }
711 
712 /**
713  * String compare function for use as the comparison callback in
714  * _mesa_hash_table_create().
715  */
716 bool
_mesa_key_string_equal(const void * a,const void * b)717 _mesa_key_string_equal(const void *a, const void *b)
718 {
719    return strcmp(a, b) == 0;
720 }
721 
722 bool
_mesa_key_pointer_equal(const void * a,const void * b)723 _mesa_key_pointer_equal(const void *a, const void *b)
724 {
725    return a == b;
726 }
727 
728 /**
729  * Helper to create a hash table with pointer keys.
730  */
731 struct hash_table *
_mesa_pointer_hash_table_create(void * mem_ctx)732 _mesa_pointer_hash_table_create(void *mem_ctx)
733 {
734    return _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
735                                   _mesa_key_pointer_equal);
736 }
737 
738 
739 bool
_mesa_hash_table_reserve(struct hash_table * ht,unsigned size)740 _mesa_hash_table_reserve(struct hash_table *ht, unsigned size)
741 {
742    if (size < ht->max_entries)
743       return true;
744    for (unsigned i = ht->size_index + 1; i < ARRAY_SIZE(hash_sizes); i++) {
745       if (hash_sizes[i].max_entries >= size) {
746          _mesa_hash_table_rehash(ht, i);
747          break;
748       }
749    }
750    return ht->max_entries >= size;
751 }
752 
753 /**
754  * Hash table wrapper which supports 64-bit keys.
755  *
756  * TODO: unify all hash table implementations.
757  */
758 
759 struct hash_key_u64 {
760    uint64_t value;
761 };
762 
763 static uint32_t
key_u64_hash(const void * key)764 key_u64_hash(const void *key)
765 {
766    return _mesa_hash_data(key, sizeof(struct hash_key_u64));
767 }
768 
769 static bool
key_u64_equals(const void * a,const void * b)770 key_u64_equals(const void *a, const void *b)
771 {
772    const struct hash_key_u64 *aa = a;
773    const struct hash_key_u64 *bb = b;
774 
775    return aa->value == bb->value;
776 }
777 
778 #define FREED_KEY_VALUE 0
779 
_mesa_hash_table_u64_delete_keys(void * data)780 static void _mesa_hash_table_u64_delete_keys(void *data)
781 {
782    struct hash_table_u64 *ht = ralloc_parent(data);
783 
784    _mesa_hash_table_u64_clear(ht);
785 }
786 
787 struct hash_table_u64 *
_mesa_hash_table_u64_create(void * mem_ctx)788 _mesa_hash_table_u64_create(void *mem_ctx)
789 {
790    STATIC_ASSERT(FREED_KEY_VALUE != DELETED_KEY_VALUE);
791    struct hash_table_u64 *ht;
792 
793    ht = rzalloc(mem_ctx, struct hash_table_u64);
794    if (!ht)
795       return NULL;
796 
797    if (sizeof(void *) == 8) {
798       ht->table = _mesa_hash_table_create(ht, _mesa_hash_pointer,
799                                           _mesa_key_pointer_equal);
800    } else {
801       ht->table = _mesa_hash_table_create(ht, key_u64_hash,
802                                           key_u64_equals);
803 
804       /* Allocate a ralloc sub-context which takes the u64 hash table
805        * as a parent and attach a destructor to it so we can free the
806        * hash_key_u64 objects that were allocated by
807        * _mesa_hash_table_u64_insert().
808        *
809        * The order of creation of this sub-context is crucial: it needs
810        * to happen after the _mesa_hash_table_create() call to guarantee
811        * that the destructor is called before ht->table and its children
812        * are freed, otherwise the _mesa_hash_table_u64_clear() call in the
813        * destructor leads to a use-after-free situation.
814        */
815       if (ht->table) {
816          void *dummy_ctx = ralloc_context(ht);
817 
818          /* If we can't allocate a sub-context, free the hash table
819           * immediately and return NULL to avoid future leaks.
820           */
821          if (!dummy_ctx) {
822             ralloc_free(ht);
823             return NULL;
824          }
825 
826          ralloc_set_destructor(dummy_ctx, _mesa_hash_table_u64_delete_keys);
827       }
828    }
829 
830    if (ht->table)
831       _mesa_hash_table_set_deleted_key(ht->table, uint_key(DELETED_KEY_VALUE));
832 
833    return ht;
834 }
835 
836 static void
_mesa_hash_table_u64_delete_key(struct hash_entry * entry)837 _mesa_hash_table_u64_delete_key(struct hash_entry *entry)
838 {
839    if (sizeof(void *) == 8)
840       return;
841 
842    struct hash_key_u64 *_key = (struct hash_key_u64 *)entry->key;
843 
844    if (_key)
845       FREE(_key);
846 }
847 
848 void
_mesa_hash_table_u64_clear(struct hash_table_u64 * ht)849 _mesa_hash_table_u64_clear(struct hash_table_u64 *ht)
850 {
851    if (!ht)
852       return;
853 
854    _mesa_hash_table_clear(ht->table, _mesa_hash_table_u64_delete_key);
855    ht->freed_key_data = NULL;
856    ht->deleted_key_data = NULL;
857 }
858 
859 void
_mesa_hash_table_u64_destroy(struct hash_table_u64 * ht)860 _mesa_hash_table_u64_destroy(struct hash_table_u64 *ht)
861 {
862    if (!ht)
863       return;
864    ralloc_free(ht);
865 }
866 
867 void
_mesa_hash_table_u64_insert(struct hash_table_u64 * ht,uint64_t key,void * data)868 _mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key,
869                             void *data)
870 {
871    if (key == FREED_KEY_VALUE) {
872       ht->freed_key_data = data;
873       return;
874    }
875 
876    if (key == DELETED_KEY_VALUE) {
877       ht->deleted_key_data = data;
878       return;
879    }
880 
881    if (sizeof(void *) == 8) {
882       _mesa_hash_table_insert(ht->table, (void *)(uintptr_t)key, data);
883    } else {
884       struct hash_key_u64 *_key = CALLOC_STRUCT(hash_key_u64);
885 
886       if (!_key)
887          return;
888       _key->value = key;
889 
890       struct hash_entry *entry =
891          hash_table_get_entry(ht->table, key_u64_hash(_key), _key);
892 
893       if (!entry) {
894          FREE(_key);
895          return;
896       }
897 
898       entry->data = data;
899       if (!entry_is_present(ht->table, entry))
900          entry->key = _key;
901       else
902          FREE(_key);
903    }
904 }
905 
906 static struct hash_entry *
hash_table_u64_search(struct hash_table_u64 * ht,uint64_t key)907 hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
908 {
909    if (sizeof(void *) == 8) {
910       return _mesa_hash_table_search(ht->table, (void *)(uintptr_t)key);
911    } else {
912       struct hash_key_u64 _key = { .value = key };
913       return _mesa_hash_table_search(ht->table, &_key);
914    }
915 }
916 
917 void *
_mesa_hash_table_u64_search(struct hash_table_u64 * ht,uint64_t key)918 _mesa_hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
919 {
920    struct hash_entry *entry;
921 
922    if (key == FREED_KEY_VALUE)
923       return ht->freed_key_data;
924 
925    if (key == DELETED_KEY_VALUE)
926       return ht->deleted_key_data;
927 
928    entry = hash_table_u64_search(ht, key);
929    if (!entry)
930       return NULL;
931 
932    return entry->data;
933 }
934 
935 void
_mesa_hash_table_u64_remove(struct hash_table_u64 * ht,uint64_t key)936 _mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key)
937 {
938    struct hash_entry *entry;
939 
940    if (key == FREED_KEY_VALUE) {
941       ht->freed_key_data = NULL;
942       return;
943    }
944 
945    if (key == DELETED_KEY_VALUE) {
946       ht->deleted_key_data = NULL;
947       return;
948    }
949 
950    entry = hash_table_u64_search(ht, key);
951    if (!entry)
952       return;
953 
954    if (sizeof(void *) == 8) {
955       _mesa_hash_table_remove(ht->table, entry);
956    } else {
957       struct hash_key *_key = (struct hash_key *)entry->key;
958 
959       _mesa_hash_table_remove(ht->table, entry);
960       FREE(_key);
961    }
962 }
963 
964 
965 /*
966  * Iterates in order ("freed key", "deleted key", regular entries...)
967  */
968 struct hash_entry_u64
_mesa_hash_table_u64_next_entry(struct hash_table_u64 * ht,struct hash_entry_u64 * ent)969 _mesa_hash_table_u64_next_entry(struct hash_table_u64 *ht,
970                                 struct hash_entry_u64 *ent)
971 {
972    /* First entry: freed key */
973    if (!ent && ht->freed_key_data) {
974       return (struct hash_entry_u64){
975          .key = FREED_KEY_VALUE,
976          .data = ht->freed_key_data,
977       };
978    }
979 
980    /* Second entry: deleted key */
981    if ((!ent || ent->key == FREED_KEY_VALUE) && ht->deleted_key_data) {
982       return (struct hash_entry_u64){
983          .key = DELETED_KEY_VALUE,
984          .data = ht->deleted_key_data,
985       };
986    }
987 
988    /* All other entries: regular */
989    struct hash_entry *next =
990       _mesa_hash_table_next_entry(ht->table, ent ? ent->_entry : NULL);
991 
992    if (!next)
993       return (struct hash_entry_u64){.data = NULL};
994 
995    uint64_t key;
996    if (sizeof(void *) == 8) {
997       key = (uintptr_t)next->key;
998    } else {
999       const struct hash_key_u64 *_key = next->key;
1000       key = _key->value;
1001    }
1002 
1003    return (struct hash_entry_u64){
1004       .key = key,
1005       .data = next->data,
1006       ._entry = next,
1007    };
1008 }
1009