xref: /third_party/mesa3d/src/util/hash_table.c (revision bf215546)
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
70static inline void *
71uint_key(unsigned id)
72{
73   return (void *)(uintptr_t) id;
74}
75
76static 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 */
83static 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
124ASSERTED static inline bool
125key_pointer_is_reserved(const struct hash_table *ht, const void *key)
126{
127   return key == NULL || key == ht->deleted_key;
128}
129
130static int
131entry_is_free(const struct hash_entry *entry)
132{
133   return entry->key == NULL;
134}
135
136static int
137entry_is_deleted(const struct hash_table *ht, struct hash_entry *entry)
138{
139   return entry->key == ht->deleted_key;
140}
141
142static int
143entry_is_present(const struct hash_table *ht, struct hash_entry *entry)
144{
145   return entry->key != NULL && entry->key != ht->deleted_key;
146}
147
148bool
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
171struct hash_table *
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
194static uint32_t
195key_u32_hash(const void *key)
196{
197   uint32_t u = (uint32_t)(uintptr_t)key;
198   return _mesa_hash_uint(&u);
199}
200
201static bool
202key_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 */
208struct hash_table *
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
214struct hash_table *
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 */
242void
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
257static void
258hash_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 */
270void
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 */
302void
303_mesa_hash_table_set_deleted_key(struct hash_table *ht, const void *deleted_key)
304{
305   ht->deleted_key = deleted_key;
306}
307
308static struct hash_entry *
309hash_table_search(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 */
344struct hash_entry *
345_mesa_hash_table_search(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
351struct hash_entry *
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
359static struct hash_entry *
360hash_table_insert(struct hash_table *ht, uint32_t hash,
361                  const void *key, void *data);
362
363static void
364hash_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
388static void
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
429static struct hash_entry *
430hash_table_insert(struct hash_table *ht, uint32_t hash,
431                  const void *key, void *data)
432{
433   struct hash_entry *available_entry = NULL;
434
435   assert(!key_pointer_is_reserved(ht, key));
436
437   if (ht->entries >= ht->max_entries) {
438      _mesa_hash_table_rehash(ht, ht->size_index + 1);
439   } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
440      _mesa_hash_table_rehash(ht, ht->size_index);
441   }
442
443   uint32_t size = ht->size;
444   uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
445   uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
446                                               ht->rehash_magic);
447   uint32_t hash_address = start_hash_address;
448   do {
449      struct hash_entry *entry = ht->table + hash_address;
450
451      if (!entry_is_present(ht, entry)) {
452         /* Stash the first available entry we find */
453         if (available_entry == NULL)
454            available_entry = entry;
455         if (entry_is_free(entry))
456            break;
457      }
458
459      /* Implement replacement when another insert happens
460       * with a matching key.  This is a relatively common
461       * feature of hash tables, with the alternative
462       * generally being "insert the new value as well, and
463       * return it first when the key is searched for".
464       *
465       * Note that the hash table doesn't have a delete
466       * callback.  If freeing of old data pointers is
467       * required to avoid memory leaks, perform a search
468       * before inserting.
469       */
470      if (!entry_is_deleted(ht, entry) &&
471          entry->hash == hash &&
472          ht->key_equals_function(key, entry->key)) {
473         entry->key = key;
474         entry->data = data;
475         return entry;
476      }
477
478      hash_address += double_hash;
479      if (hash_address >= size)
480         hash_address -= size;
481   } while (hash_address != start_hash_address);
482
483   if (available_entry) {
484      if (entry_is_deleted(ht, available_entry))
485         ht->deleted_entries--;
486      available_entry->hash = hash;
487      available_entry->key = key;
488      available_entry->data = data;
489      ht->entries++;
490      return available_entry;
491   }
492
493   /* We could hit here if a required resize failed. An unchecked-malloc
494    * application could ignore this result.
495    */
496   return NULL;
497}
498
499/**
500 * Inserts the key with the given hash into the table.
501 *
502 * Note that insertion may rearrange the table on a resize or rehash,
503 * so previously found hash_entries are no longer valid after this function.
504 */
505struct hash_entry *
506_mesa_hash_table_insert(struct hash_table *ht, const void *key, void *data)
507{
508   assert(ht->key_hash_function);
509   return hash_table_insert(ht, ht->key_hash_function(key), key, data);
510}
511
512struct hash_entry *
513_mesa_hash_table_insert_pre_hashed(struct hash_table *ht, uint32_t hash,
514                                   const void *key, void *data)
515{
516   assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key));
517   return hash_table_insert(ht, hash, key, data);
518}
519
520/**
521 * This function deletes the given hash table entry.
522 *
523 * Note that deletion doesn't otherwise modify the table, so an iteration over
524 * the table deleting entries is safe.
525 */
526void
527_mesa_hash_table_remove(struct hash_table *ht,
528                        struct hash_entry *entry)
529{
530   if (!entry)
531      return;
532
533   entry->key = ht->deleted_key;
534   ht->entries--;
535   ht->deleted_entries++;
536}
537
538/**
539 * Removes the entry with the corresponding key, if exists.
540 */
541void _mesa_hash_table_remove_key(struct hash_table *ht,
542                                 const void *key)
543{
544   _mesa_hash_table_remove(ht, _mesa_hash_table_search(ht, key));
545}
546
547/**
548 * This function is an iterator over the hash_table when no deleted entries are present.
549 *
550 * Pass in NULL for the first entry, as in the start of a for loop.
551 */
552struct hash_entry *
553_mesa_hash_table_next_entry_unsafe(const struct hash_table *ht, struct hash_entry *entry)
554{
555   assert(!ht->deleted_entries);
556   if (!ht->entries)
557      return NULL;
558   if (entry == NULL)
559      entry = ht->table;
560   else
561      entry = entry + 1;
562   if (entry != ht->table + ht->size)
563      return entry->key ? entry : _mesa_hash_table_next_entry_unsafe(ht, entry);
564
565   return NULL;
566}
567
568/**
569 * This function is an iterator over the hash table.
570 *
571 * Pass in NULL for the first entry, as in the start of a for loop.  Note that
572 * an iteration over the table is O(table_size) not O(entries).
573 */
574struct hash_entry *
575_mesa_hash_table_next_entry(struct hash_table *ht,
576                            struct hash_entry *entry)
577{
578   if (entry == NULL)
579      entry = ht->table;
580   else
581      entry = entry + 1;
582
583   for (; entry != ht->table + ht->size; entry++) {
584      if (entry_is_present(ht, entry)) {
585         return entry;
586      }
587   }
588
589   return NULL;
590}
591
592/**
593 * Returns a random entry from the hash table.
594 *
595 * This may be useful in implementing random replacement (as opposed
596 * to just removing everything) in caches based on this hash table
597 * implementation.  @predicate may be used to filter entries, or may
598 * be set to NULL for no filtering.
599 */
600struct hash_entry *
601_mesa_hash_table_random_entry(struct hash_table *ht,
602                              bool (*predicate)(struct hash_entry *entry))
603{
604   struct hash_entry *entry;
605   uint32_t i = rand() % ht->size;
606
607   if (ht->entries == 0)
608      return NULL;
609
610   for (entry = ht->table + i; entry != ht->table + ht->size; entry++) {
611      if (entry_is_present(ht, entry) &&
612          (!predicate || predicate(entry))) {
613         return entry;
614      }
615   }
616
617   for (entry = ht->table; entry != ht->table + i; entry++) {
618      if (entry_is_present(ht, entry) &&
619          (!predicate || predicate(entry))) {
620         return entry;
621      }
622   }
623
624   return NULL;
625}
626
627
628uint32_t
629_mesa_hash_data(const void *data, size_t size)
630{
631   return XXH32(data, size, 0);
632}
633
634uint32_t
635_mesa_hash_data_with_seed(const void *data, size_t size, uint32_t seed)
636{
637   return XXH32(data, size, seed);
638}
639
640uint32_t
641_mesa_hash_int(const void *key)
642{
643   return XXH32(key, sizeof(int), 0);
644}
645
646uint32_t
647_mesa_hash_uint(const void *key)
648{
649   return XXH32(key, sizeof(unsigned), 0);
650}
651
652uint32_t
653_mesa_hash_u32(const void *key)
654{
655   return XXH32(key, 4, 0);
656}
657
658/** FNV-1a string hash implementation */
659uint32_t
660_mesa_hash_string(const void *_key)
661{
662   return _mesa_hash_string_with_length(_key, strlen((const char *)_key));
663}
664
665uint32_t
666_mesa_hash_string_with_length(const void *_key, unsigned length)
667{
668   uint32_t hash = 0;
669   const char *key = _key;
670#if defined(_WIN64) || defined(__x86_64__)
671   hash = (uint32_t)XXH64(key, length, hash);
672#else
673   hash = XXH32(key, length, hash);
674#endif
675   return hash;
676}
677
678uint32_t
679_mesa_hash_pointer(const void *pointer)
680{
681   uintptr_t num = (uintptr_t) pointer;
682   return (uint32_t) ((num >> 2) ^ (num >> 6) ^ (num >> 10) ^ (num >> 14));
683}
684
685bool
686_mesa_key_int_equal(const void *a, const void *b)
687{
688   return *((const int *)a) == *((const int *)b);
689}
690
691bool
692_mesa_key_uint_equal(const void *a, const void *b)
693{
694
695   return *((const unsigned *)a) == *((const unsigned *)b);
696}
697
698bool
699_mesa_key_u32_equal(const void *a, const void *b)
700{
701   return *((const uint32_t *)a) == *((const uint32_t *)b);
702}
703
704/**
705 * String compare function for use as the comparison callback in
706 * _mesa_hash_table_create().
707 */
708bool
709_mesa_key_string_equal(const void *a, const void *b)
710{
711   return strcmp(a, b) == 0;
712}
713
714bool
715_mesa_key_pointer_equal(const void *a, const void *b)
716{
717   return a == b;
718}
719
720/**
721 * Helper to create a hash table with pointer keys.
722 */
723struct hash_table *
724_mesa_pointer_hash_table_create(void *mem_ctx)
725{
726   return _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
727                                  _mesa_key_pointer_equal);
728}
729
730
731bool
732_mesa_hash_table_reserve(struct hash_table *ht, unsigned size)
733{
734   if (size < ht->max_entries)
735      return true;
736   for (unsigned i = ht->size_index + 1; i < ARRAY_SIZE(hash_sizes); i++) {
737      if (hash_sizes[i].max_entries >= size) {
738         _mesa_hash_table_rehash(ht, i);
739         break;
740      }
741   }
742   return ht->max_entries >= size;
743}
744
745/**
746 * Hash table wrapper which supports 64-bit keys.
747 *
748 * TODO: unify all hash table implementations.
749 */
750
751struct hash_key_u64 {
752   uint64_t value;
753};
754
755static uint32_t
756key_u64_hash(const void *key)
757{
758   return _mesa_hash_data(key, sizeof(struct hash_key_u64));
759}
760
761static bool
762key_u64_equals(const void *a, const void *b)
763{
764   const struct hash_key_u64 *aa = a;
765   const struct hash_key_u64 *bb = b;
766
767   return aa->value == bb->value;
768}
769
770#define FREED_KEY_VALUE 0
771
772struct hash_table_u64 *
773_mesa_hash_table_u64_create(void *mem_ctx)
774{
775   STATIC_ASSERT(FREED_KEY_VALUE != DELETED_KEY_VALUE);
776   struct hash_table_u64 *ht;
777
778   ht = CALLOC_STRUCT(hash_table_u64);
779   if (!ht)
780      return NULL;
781
782   if (sizeof(void *) == 8) {
783      ht->table = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
784                                          _mesa_key_pointer_equal);
785   } else {
786      ht->table = _mesa_hash_table_create(mem_ctx, key_u64_hash,
787                                          key_u64_equals);
788   }
789
790   if (ht->table)
791      _mesa_hash_table_set_deleted_key(ht->table, uint_key(DELETED_KEY_VALUE));
792
793   return ht;
794}
795
796static void
797_mesa_hash_table_u64_delete_key(struct hash_entry *entry)
798{
799   if (sizeof(void *) == 8)
800      return;
801
802   struct hash_key_u64 *_key = (struct hash_key_u64 *)entry->key;
803
804   if (_key)
805      free(_key);
806}
807
808void
809_mesa_hash_table_u64_clear(struct hash_table_u64 *ht)
810{
811   if (!ht)
812      return;
813
814   _mesa_hash_table_clear(ht->table, _mesa_hash_table_u64_delete_key);
815   ht->freed_key_data = NULL;
816   ht->deleted_key_data = NULL;
817}
818
819void
820_mesa_hash_table_u64_destroy(struct hash_table_u64 *ht)
821{
822   if (!ht)
823      return;
824
825   _mesa_hash_table_u64_clear(ht);
826   _mesa_hash_table_destroy(ht->table, NULL);
827   free(ht);
828}
829
830void
831_mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key,
832                            void *data)
833{
834   if (key == FREED_KEY_VALUE) {
835      ht->freed_key_data = data;
836      return;
837   }
838
839   if (key == DELETED_KEY_VALUE) {
840      ht->deleted_key_data = data;
841      return;
842   }
843
844   if (sizeof(void *) == 8) {
845      _mesa_hash_table_insert(ht->table, (void *)(uintptr_t)key, data);
846   } else {
847      struct hash_key_u64 *_key = CALLOC_STRUCT(hash_key_u64);
848
849      if (!_key)
850         return;
851      _key->value = key;
852
853      _mesa_hash_table_insert(ht->table, _key, data);
854   }
855}
856
857static struct hash_entry *
858hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
859{
860   if (sizeof(void *) == 8) {
861      return _mesa_hash_table_search(ht->table, (void *)(uintptr_t)key);
862   } else {
863      struct hash_key_u64 _key = { .value = key };
864      return _mesa_hash_table_search(ht->table, &_key);
865   }
866}
867
868void *
869_mesa_hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
870{
871   struct hash_entry *entry;
872
873   if (key == FREED_KEY_VALUE)
874      return ht->freed_key_data;
875
876   if (key == DELETED_KEY_VALUE)
877      return ht->deleted_key_data;
878
879   entry = hash_table_u64_search(ht, key);
880   if (!entry)
881      return NULL;
882
883   return entry->data;
884}
885
886void
887_mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key)
888{
889   struct hash_entry *entry;
890
891   if (key == FREED_KEY_VALUE) {
892      ht->freed_key_data = NULL;
893      return;
894   }
895
896   if (key == DELETED_KEY_VALUE) {
897      ht->deleted_key_data = NULL;
898      return;
899   }
900
901   entry = hash_table_u64_search(ht, key);
902   if (!entry)
903      return;
904
905   if (sizeof(void *) == 8) {
906      _mesa_hash_table_remove(ht->table, entry);
907   } else {
908      struct hash_key *_key = (struct hash_key *)entry->key;
909
910      _mesa_hash_table_remove(ht->table, entry);
911      free(_key);
912   }
913}
914