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 <eric@anholt.net>
32  *    Keith Packard <keithp@keithp.com>
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 struct hash_table *
_mesa_hash_table_clone(struct hash_table * src,void * dst_mem_ctx)195 _mesa_hash_table_clone(struct hash_table *src, void *dst_mem_ctx)
196 {
197    struct hash_table *ht;
198 
199    ht = ralloc(dst_mem_ctx, struct hash_table);
200    if (ht == NULL)
201       return NULL;
202 
203    memcpy(ht, src, sizeof(struct hash_table));
204 
205    ht->table = ralloc_array(ht, struct hash_entry, ht->size);
206    if (ht->table == NULL) {
207       ralloc_free(ht);
208       return NULL;
209    }
210 
211    memcpy(ht->table, src->table, ht->size * sizeof(struct hash_entry));
212 
213    return ht;
214 }
215 
216 /**
217  * Frees the given hash table.
218  *
219  * If delete_function is passed, it gets called on each entry present before
220  * freeing.
221  */
222 void
_mesa_hash_table_destroy(struct hash_table * ht,void (* delete_function)(struct hash_entry * entry))223 _mesa_hash_table_destroy(struct hash_table *ht,
224                          void (*delete_function)(struct hash_entry *entry))
225 {
226    if (!ht)
227       return;
228 
229    if (delete_function) {
230       hash_table_foreach(ht, entry) {
231          delete_function(entry);
232       }
233    }
234    ralloc_free(ht);
235 }
236 
237 /**
238  * Deletes all entries of the given hash table without deleting the table
239  * itself or changing its structure.
240  *
241  * If delete_function is passed, it gets called on each entry present.
242  */
243 void
_mesa_hash_table_clear(struct hash_table * ht,void (* delete_function)(struct hash_entry * entry))244 _mesa_hash_table_clear(struct hash_table *ht,
245                        void (*delete_function)(struct hash_entry *entry))
246 {
247    struct hash_entry *entry;
248 
249    for (entry = ht->table; entry != ht->table + ht->size; entry++) {
250       if (entry->key == NULL)
251          continue;
252 
253       if (delete_function != NULL && entry->key != ht->deleted_key)
254          delete_function(entry);
255 
256       entry->key = NULL;
257    }
258 
259    ht->entries = 0;
260    ht->deleted_entries = 0;
261 }
262 
263 /** Sets the value of the key pointer used for deleted entries in the table.
264  *
265  * The assumption is that usually keys are actual pointers, so we use a
266  * default value of a pointer to an arbitrary piece of storage in the library.
267  * But in some cases a consumer wants to store some other sort of value in the
268  * table, like a uint32_t, in which case that pointer may conflict with one of
269  * their valid keys.  This lets that user select a safe value.
270  *
271  * This must be called before any keys are actually deleted from the table.
272  */
273 void
_mesa_hash_table_set_deleted_key(struct hash_table * ht,const void * deleted_key)274 _mesa_hash_table_set_deleted_key(struct hash_table *ht, const void *deleted_key)
275 {
276    ht->deleted_key = deleted_key;
277 }
278 
279 static struct hash_entry *
hash_table_search(struct hash_table * ht,uint32_t hash,const void * key)280 hash_table_search(struct hash_table *ht, uint32_t hash, const void *key)
281 {
282    assert(!key_pointer_is_reserved(ht, key));
283 
284    uint32_t size = ht->size;
285    uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
286    uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
287                                                ht->rehash_magic);
288    uint32_t hash_address = start_hash_address;
289 
290    do {
291       struct hash_entry *entry = ht->table + hash_address;
292 
293       if (entry_is_free(entry)) {
294          return NULL;
295       } else if (entry_is_present(ht, entry) && entry->hash == hash) {
296          if (ht->key_equals_function(key, entry->key)) {
297             return entry;
298          }
299       }
300 
301       hash_address += double_hash;
302       if (hash_address >= size)
303          hash_address -= size;
304    } while (hash_address != start_hash_address);
305 
306    return NULL;
307 }
308 
309 /**
310  * Finds a hash table entry with the given key and hash of that key.
311  *
312  * Returns NULL if no entry is found.  Note that the data pointer may be
313  * modified by the user.
314  */
315 struct hash_entry *
_mesa_hash_table_search(struct hash_table * ht,const void * key)316 _mesa_hash_table_search(struct hash_table *ht, const void *key)
317 {
318    assert(ht->key_hash_function);
319    return hash_table_search(ht, ht->key_hash_function(key), key);
320 }
321 
322 struct hash_entry *
_mesa_hash_table_search_pre_hashed(struct hash_table * ht,uint32_t hash,const void * key)323 _mesa_hash_table_search_pre_hashed(struct hash_table *ht, uint32_t hash,
324                                   const void *key)
325 {
326    assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key));
327    return hash_table_search(ht, hash, key);
328 }
329 
330 static struct hash_entry *
331 hash_table_insert(struct hash_table *ht, uint32_t hash,
332                   const void *key, void *data);
333 
334 static void
hash_table_insert_rehash(struct hash_table * ht,uint32_t hash,const void * key,void * data)335 hash_table_insert_rehash(struct hash_table *ht, uint32_t hash,
336                          const void *key, void *data)
337 {
338    uint32_t size = ht->size;
339    uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
340    uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
341                                                ht->rehash_magic);
342    uint32_t hash_address = start_hash_address;
343    do {
344       struct hash_entry *entry = ht->table + hash_address;
345 
346       if (likely(entry->key == NULL)) {
347          entry->hash = hash;
348          entry->key = key;
349          entry->data = data;
350          return;
351       }
352 
353       hash_address += double_hash;
354       if (hash_address >= size)
355          hash_address -= size;
356    } while (true);
357 }
358 
359 static void
_mesa_hash_table_rehash(struct hash_table * ht,unsigned new_size_index)360 _mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index)
361 {
362    struct hash_table old_ht;
363    struct hash_entry *table;
364 
365    if (new_size_index >= ARRAY_SIZE(hash_sizes))
366       return;
367 
368    table = rzalloc_array(ralloc_parent(ht->table), struct hash_entry,
369                          hash_sizes[new_size_index].size);
370    if (table == NULL)
371       return;
372 
373    old_ht = *ht;
374 
375    ht->table = table;
376    ht->size_index = new_size_index;
377    ht->size = hash_sizes[ht->size_index].size;
378    ht->rehash = hash_sizes[ht->size_index].rehash;
379    ht->size_magic = hash_sizes[ht->size_index].size_magic;
380    ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic;
381    ht->max_entries = hash_sizes[ht->size_index].max_entries;
382    ht->entries = 0;
383    ht->deleted_entries = 0;
384 
385    hash_table_foreach(&old_ht, entry) {
386       hash_table_insert_rehash(ht, entry->hash, entry->key, entry->data);
387    }
388 
389    ht->entries = old_ht.entries;
390 
391    ralloc_free(old_ht.table);
392 }
393 
394 static struct hash_entry *
hash_table_insert(struct hash_table * ht,uint32_t hash,const void * key,void * data)395 hash_table_insert(struct hash_table *ht, uint32_t hash,
396                   const void *key, void *data)
397 {
398    struct hash_entry *available_entry = NULL;
399 
400    assert(!key_pointer_is_reserved(ht, key));
401 
402    if (ht->entries >= ht->max_entries) {
403       _mesa_hash_table_rehash(ht, ht->size_index + 1);
404    } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
405       _mesa_hash_table_rehash(ht, ht->size_index);
406    }
407 
408    uint32_t size = ht->size;
409    uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
410    uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
411                                                ht->rehash_magic);
412    uint32_t hash_address = start_hash_address;
413    do {
414       struct hash_entry *entry = ht->table + hash_address;
415 
416       if (!entry_is_present(ht, entry)) {
417          /* Stash the first available entry we find */
418          if (available_entry == NULL)
419             available_entry = entry;
420          if (entry_is_free(entry))
421             break;
422       }
423 
424       /* Implement replacement when another insert happens
425        * with a matching key.  This is a relatively common
426        * feature of hash tables, with the alternative
427        * generally being "insert the new value as well, and
428        * return it first when the key is searched for".
429        *
430        * Note that the hash table doesn't have a delete
431        * callback.  If freeing of old data pointers is
432        * required to avoid memory leaks, perform a search
433        * before inserting.
434        */
435       if (!entry_is_deleted(ht, entry) &&
436           entry->hash == hash &&
437           ht->key_equals_function(key, entry->key)) {
438          entry->key = key;
439          entry->data = data;
440          return entry;
441       }
442 
443       hash_address += double_hash;
444       if (hash_address >= size)
445          hash_address -= size;
446    } while (hash_address != start_hash_address);
447 
448    if (available_entry) {
449       if (entry_is_deleted(ht, available_entry))
450          ht->deleted_entries--;
451       available_entry->hash = hash;
452       available_entry->key = key;
453       available_entry->data = data;
454       ht->entries++;
455       return available_entry;
456    }
457 
458    /* We could hit here if a required resize failed. An unchecked-malloc
459     * application could ignore this result.
460     */
461    return NULL;
462 }
463 
464 /**
465  * Inserts the key with the given hash into the table.
466  *
467  * Note that insertion may rearrange the table on a resize or rehash,
468  * so previously found hash_entries are no longer valid after this function.
469  */
470 struct hash_entry *
_mesa_hash_table_insert(struct hash_table * ht,const void * key,void * data)471 _mesa_hash_table_insert(struct hash_table *ht, const void *key, void *data)
472 {
473    assert(ht->key_hash_function);
474    return hash_table_insert(ht, ht->key_hash_function(key), key, data);
475 }
476 
477 struct hash_entry *
_mesa_hash_table_insert_pre_hashed(struct hash_table * ht,uint32_t hash,const void * key,void * data)478 _mesa_hash_table_insert_pre_hashed(struct hash_table *ht, uint32_t hash,
479                                    const void *key, void *data)
480 {
481    assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key));
482    return hash_table_insert(ht, hash, key, data);
483 }
484 
485 /**
486  * This function deletes the given hash table entry.
487  *
488  * Note that deletion doesn't otherwise modify the table, so an iteration over
489  * the table deleting entries is safe.
490  */
491 void
_mesa_hash_table_remove(struct hash_table * ht,struct hash_entry * entry)492 _mesa_hash_table_remove(struct hash_table *ht,
493                         struct hash_entry *entry)
494 {
495    if (!entry)
496       return;
497 
498    entry->key = ht->deleted_key;
499    ht->entries--;
500    ht->deleted_entries++;
501 }
502 
503 /**
504  * Removes the entry with the corresponding key, if exists.
505  */
_mesa_hash_table_remove_key(struct hash_table * ht,const void * key)506 void _mesa_hash_table_remove_key(struct hash_table *ht,
507                                  const void *key)
508 {
509    _mesa_hash_table_remove(ht, _mesa_hash_table_search(ht, key));
510 }
511 
512 /**
513  * This function is an iterator over the hash table.
514  *
515  * Pass in NULL for the first entry, as in the start of a for loop.  Note that
516  * an iteration over the table is O(table_size) not O(entries).
517  */
518 struct hash_entry *
_mesa_hash_table_next_entry(struct hash_table * ht,struct hash_entry * entry)519 _mesa_hash_table_next_entry(struct hash_table *ht,
520                             struct hash_entry *entry)
521 {
522    if (entry == NULL)
523       entry = ht->table;
524    else
525       entry = entry + 1;
526 
527    for (; entry != ht->table + ht->size; entry++) {
528       if (entry_is_present(ht, entry)) {
529          return entry;
530       }
531    }
532 
533    return NULL;
534 }
535 
536 /**
537  * Returns a random entry from the hash table.
538  *
539  * This may be useful in implementing random replacement (as opposed
540  * to just removing everything) in caches based on this hash table
541  * implementation.  @predicate may be used to filter entries, or may
542  * be set to NULL for no filtering.
543  */
544 struct hash_entry *
_mesa_hash_table_random_entry(struct hash_table * ht,bool (* predicate)(struct hash_entry * entry))545 _mesa_hash_table_random_entry(struct hash_table *ht,
546                               bool (*predicate)(struct hash_entry *entry))
547 {
548    struct hash_entry *entry;
549    uint32_t i = rand() % ht->size;
550 
551    if (ht->entries == 0)
552       return NULL;
553 
554    for (entry = ht->table + i; entry != ht->table + ht->size; entry++) {
555       if (entry_is_present(ht, entry) &&
556           (!predicate || predicate(entry))) {
557          return entry;
558       }
559    }
560 
561    for (entry = ht->table; entry != ht->table + i; entry++) {
562       if (entry_is_present(ht, entry) &&
563           (!predicate || predicate(entry))) {
564          return entry;
565       }
566    }
567 
568    return NULL;
569 }
570 
571 
572 uint32_t
_mesa_hash_data(const void * data,size_t size)573 _mesa_hash_data(const void *data, size_t size)
574 {
575    return XXH32(data, size, 0);
576 }
577 
578 uint32_t
_mesa_hash_int(const void * key)579 _mesa_hash_int(const void *key)
580 {
581    return XXH32(key, sizeof(int), 0);
582 }
583 
584 uint32_t
_mesa_hash_uint(const void * key)585 _mesa_hash_uint(const void *key)
586 {
587    return XXH32(key, sizeof(unsigned), 0);
588 }
589 
590 uint32_t
_mesa_hash_u32(const void * key)591 _mesa_hash_u32(const void *key)
592 {
593    return XXH32(key, 4, 0);
594 }
595 
596 /** FNV-1a string hash implementation */
597 uint32_t
_mesa_hash_string(const void * _key)598 _mesa_hash_string(const void *_key)
599 {
600    uint32_t hash = 0;
601    const char *key = _key;
602    size_t len = strlen(key);
603 #if defined(_WIN64) || defined(__x86_64__)
604    hash = (uint32_t)XXH64(key, len, hash);
605 #else
606    hash = XXH32(key, len, hash);
607 #endif
608    return hash;
609 }
610 
611 uint32_t
_mesa_hash_pointer(const void * pointer)612 _mesa_hash_pointer(const void *pointer)
613 {
614    uintptr_t num = (uintptr_t) pointer;
615    return (uint32_t) ((num >> 2) ^ (num >> 6) ^ (num >> 10) ^ (num >> 14));
616 }
617 
618 bool
_mesa_key_int_equal(const void * a,const void * b)619 _mesa_key_int_equal(const void *a, const void *b)
620 {
621    return *((const int *)a) == *((const int *)b);
622 }
623 
624 bool
_mesa_key_uint_equal(const void * a,const void * b)625 _mesa_key_uint_equal(const void *a, const void *b)
626 {
627 
628    return *((const unsigned *)a) == *((const unsigned *)b);
629 }
630 
631 bool
_mesa_key_u32_equal(const void * a,const void * b)632 _mesa_key_u32_equal(const void *a, const void *b)
633 {
634    return *((const uint32_t *)a) == *((const uint32_t *)b);
635 }
636 
637 /**
638  * String compare function for use as the comparison callback in
639  * _mesa_hash_table_create().
640  */
641 bool
_mesa_key_string_equal(const void * a,const void * b)642 _mesa_key_string_equal(const void *a, const void *b)
643 {
644    return strcmp(a, b) == 0;
645 }
646 
647 bool
_mesa_key_pointer_equal(const void * a,const void * b)648 _mesa_key_pointer_equal(const void *a, const void *b)
649 {
650    return a == b;
651 }
652 
653 /**
654  * Helper to create a hash table with pointer keys.
655  */
656 struct hash_table *
_mesa_pointer_hash_table_create(void * mem_ctx)657 _mesa_pointer_hash_table_create(void *mem_ctx)
658 {
659    return _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
660                                   _mesa_key_pointer_equal);
661 }
662 
663 
664 bool
_mesa_hash_table_reserve(struct hash_table * ht,unsigned size)665 _mesa_hash_table_reserve(struct hash_table *ht, unsigned size)
666 {
667    if (size < ht->max_entries)
668       return true;
669    for (unsigned i = ht->size_index + 1; i < ARRAY_SIZE(hash_sizes); i++) {
670       if (hash_sizes[i].max_entries >= size) {
671          _mesa_hash_table_rehash(ht, i);
672          break;
673       }
674    }
675    return ht->max_entries >= size;
676 }
677 
678 /**
679  * Hash table wrapper which supports 64-bit keys.
680  *
681  * TODO: unify all hash table implementations.
682  */
683 
684 struct hash_key_u64 {
685    uint64_t value;
686 };
687 
688 static uint32_t
key_u64_hash(const void * key)689 key_u64_hash(const void *key)
690 {
691    return _mesa_hash_data(key, sizeof(struct hash_key_u64));
692 }
693 
694 static bool
key_u64_equals(const void * a,const void * b)695 key_u64_equals(const void *a, const void *b)
696 {
697    const struct hash_key_u64 *aa = a;
698    const struct hash_key_u64 *bb = b;
699 
700    return aa->value == bb->value;
701 }
702 
703 #define FREED_KEY_VALUE 0
704 
705 struct hash_table_u64 *
_mesa_hash_table_u64_create(void * mem_ctx)706 _mesa_hash_table_u64_create(void *mem_ctx)
707 {
708    STATIC_ASSERT(FREED_KEY_VALUE != DELETED_KEY_VALUE);
709    struct hash_table_u64 *ht;
710 
711    ht = CALLOC_STRUCT(hash_table_u64);
712    if (!ht)
713       return NULL;
714 
715    if (sizeof(void *) == 8) {
716       ht->table = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
717                                           _mesa_key_pointer_equal);
718    } else {
719       ht->table = _mesa_hash_table_create(mem_ctx, key_u64_hash,
720                                           key_u64_equals);
721    }
722 
723    if (ht->table)
724       _mesa_hash_table_set_deleted_key(ht->table, uint_key(DELETED_KEY_VALUE));
725 
726    return ht;
727 }
728 
729 void
_mesa_hash_table_u64_clear(struct hash_table_u64 * ht,void (* delete_function)(struct hash_entry * entry))730 _mesa_hash_table_u64_clear(struct hash_table_u64 *ht,
731                            void (*delete_function)(struct hash_entry *entry))
732 {
733    if (!ht)
734       return;
735 
736    if (ht->deleted_key_data) {
737       if (delete_function) {
738          struct hash_table *table = ht->table;
739          struct hash_entry entry;
740 
741          /* Create a fake entry for the delete function. */
742          if (sizeof(void *) == 8) {
743             entry.hash = table->key_hash_function(table->deleted_key);
744          } else {
745             struct hash_key_u64 _key = { .value = (uintptr_t)table->deleted_key };
746             entry.hash = table->key_hash_function(&_key);
747          }
748          entry.key = table->deleted_key;
749          entry.data = ht->deleted_key_data;
750 
751          delete_function(&entry);
752       }
753       ht->deleted_key_data = NULL;
754    }
755 
756    if (ht->freed_key_data) {
757       if (delete_function) {
758          struct hash_table *table = ht->table;
759          struct hash_entry entry;
760 
761          /* Create a fake entry for the delete function. */
762          if (sizeof(void *) == 8) {
763             entry.hash = table->key_hash_function(uint_key(FREED_KEY_VALUE));
764          } else {
765             struct hash_key_u64 _key = { .value = (uintptr_t)FREED_KEY_VALUE };
766             entry.hash = table->key_hash_function(&_key);
767          }
768          entry.key = uint_key(FREED_KEY_VALUE);
769          entry.data = ht->freed_key_data;
770 
771          delete_function(&entry);
772       }
773       ht->freed_key_data = NULL;
774    }
775 
776    _mesa_hash_table_clear(ht->table, delete_function);
777 }
778 
779 void
_mesa_hash_table_u64_destroy(struct hash_table_u64 * ht,void (* delete_function)(struct hash_entry * entry))780 _mesa_hash_table_u64_destroy(struct hash_table_u64 *ht,
781                              void (*delete_function)(struct hash_entry *entry))
782 {
783    if (!ht)
784       return;
785 
786    _mesa_hash_table_u64_clear(ht, delete_function);
787    _mesa_hash_table_destroy(ht->table, delete_function);
788    free(ht);
789 }
790 
791 void
_mesa_hash_table_u64_insert(struct hash_table_u64 * ht,uint64_t key,void * data)792 _mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key,
793                             void *data)
794 {
795    if (key == FREED_KEY_VALUE) {
796       ht->freed_key_data = data;
797       return;
798    }
799 
800    if (key == DELETED_KEY_VALUE) {
801       ht->deleted_key_data = data;
802       return;
803    }
804 
805    if (sizeof(void *) == 8) {
806       _mesa_hash_table_insert(ht->table, (void *)(uintptr_t)key, data);
807    } else {
808       struct hash_key_u64 *_key = CALLOC_STRUCT(hash_key_u64);
809 
810       if (!_key)
811          return;
812       _key->value = key;
813 
814       _mesa_hash_table_insert(ht->table, _key, data);
815    }
816 }
817 
818 static struct hash_entry *
hash_table_u64_search(struct hash_table_u64 * ht,uint64_t key)819 hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
820 {
821    if (sizeof(void *) == 8) {
822       return _mesa_hash_table_search(ht->table, (void *)(uintptr_t)key);
823    } else {
824       struct hash_key_u64 _key = { .value = key };
825       return _mesa_hash_table_search(ht->table, &_key);
826    }
827 }
828 
829 void *
_mesa_hash_table_u64_search(struct hash_table_u64 * ht,uint64_t key)830 _mesa_hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
831 {
832    struct hash_entry *entry;
833 
834    if (key == FREED_KEY_VALUE)
835       return ht->freed_key_data;
836 
837    if (key == DELETED_KEY_VALUE)
838       return ht->deleted_key_data;
839 
840    entry = hash_table_u64_search(ht, key);
841    if (!entry)
842       return NULL;
843 
844    return entry->data;
845 }
846 
847 void
_mesa_hash_table_u64_remove(struct hash_table_u64 * ht,uint64_t key)848 _mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key)
849 {
850    struct hash_entry *entry;
851 
852    if (key == FREED_KEY_VALUE) {
853       ht->freed_key_data = NULL;
854       return;
855    }
856 
857    if (key == DELETED_KEY_VALUE) {
858       ht->deleted_key_data = NULL;
859       return;
860    }
861 
862    entry = hash_table_u64_search(ht, key);
863    if (!entry)
864       return;
865 
866    if (sizeof(void *) == 8) {
867       _mesa_hash_table_remove(ht->table, entry);
868    } else {
869       struct hash_key *_key = (struct hash_key *)entry->key;
870 
871       _mesa_hash_table_remove(ht->table, entry);
872       free(_key);
873    }
874 }
875