Mark a few static inline helpers with ASSERTED
[mesa.git] / src / util / hash_table.c
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 "main/hash.h"
51 #include "fast_urem_by_const.h"
52
53 #define XXH_INLINE_ALL
54 #include "xxhash.h"
55
56 static const uint32_t deleted_key_value;
57
58 /**
59 * From Knuth -- a good choice for hash/rehash values is p, p-2 where
60 * p and p-2 are both prime. These tables are sized to have an extra 10%
61 * free to avoid exponential performance degradation as the hash table fills
62 */
63 static const struct {
64 uint32_t max_entries, size, rehash;
65 uint64_t size_magic, rehash_magic;
66 } hash_sizes[] = {
67 #define ENTRY(max_entries, size, rehash) \
68 { max_entries, size, rehash, \
69 REMAINDER_MAGIC(size), REMAINDER_MAGIC(rehash) }
70
71 ENTRY(2, 5, 3 ),
72 ENTRY(4, 7, 5 ),
73 ENTRY(8, 13, 11 ),
74 ENTRY(16, 19, 17 ),
75 ENTRY(32, 43, 41 ),
76 ENTRY(64, 73, 71 ),
77 ENTRY(128, 151, 149 ),
78 ENTRY(256, 283, 281 ),
79 ENTRY(512, 571, 569 ),
80 ENTRY(1024, 1153, 1151 ),
81 ENTRY(2048, 2269, 2267 ),
82 ENTRY(4096, 4519, 4517 ),
83 ENTRY(8192, 9013, 9011 ),
84 ENTRY(16384, 18043, 18041 ),
85 ENTRY(32768, 36109, 36107 ),
86 ENTRY(65536, 72091, 72089 ),
87 ENTRY(131072, 144409, 144407 ),
88 ENTRY(262144, 288361, 288359 ),
89 ENTRY(524288, 576883, 576881 ),
90 ENTRY(1048576, 1153459, 1153457 ),
91 ENTRY(2097152, 2307163, 2307161 ),
92 ENTRY(4194304, 4613893, 4613891 ),
93 ENTRY(8388608, 9227641, 9227639 ),
94 ENTRY(16777216, 18455029, 18455027 ),
95 ENTRY(33554432, 36911011, 36911009 ),
96 ENTRY(67108864, 73819861, 73819859 ),
97 ENTRY(134217728, 147639589, 147639587 ),
98 ENTRY(268435456, 295279081, 295279079 ),
99 ENTRY(536870912, 590559793, 590559791 ),
100 ENTRY(1073741824, 1181116273, 1181116271 ),
101 ENTRY(2147483648ul, 2362232233ul, 2362232231ul )
102 };
103
104 ASSERTED static inline bool
105 key_pointer_is_reserved(const struct hash_table *ht, const void *key)
106 {
107 return key == NULL || key == ht->deleted_key;
108 }
109
110 static int
111 entry_is_free(const struct hash_entry *entry)
112 {
113 return entry->key == NULL;
114 }
115
116 static int
117 entry_is_deleted(const struct hash_table *ht, struct hash_entry *entry)
118 {
119 return entry->key == ht->deleted_key;
120 }
121
122 static int
123 entry_is_present(const struct hash_table *ht, struct hash_entry *entry)
124 {
125 return entry->key != NULL && entry->key != ht->deleted_key;
126 }
127
128 bool
129 _mesa_hash_table_init(struct hash_table *ht,
130 void *mem_ctx,
131 uint32_t (*key_hash_function)(const void *key),
132 bool (*key_equals_function)(const void *a,
133 const void *b))
134 {
135 ht->size_index = 0;
136 ht->size = hash_sizes[ht->size_index].size;
137 ht->rehash = hash_sizes[ht->size_index].rehash;
138 ht->size_magic = hash_sizes[ht->size_index].size_magic;
139 ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic;
140 ht->max_entries = hash_sizes[ht->size_index].max_entries;
141 ht->key_hash_function = key_hash_function;
142 ht->key_equals_function = key_equals_function;
143 ht->table = rzalloc_array(mem_ctx, struct hash_entry, ht->size);
144 ht->entries = 0;
145 ht->deleted_entries = 0;
146 ht->deleted_key = &deleted_key_value;
147
148 return ht->table != NULL;
149 }
150
151 struct hash_table *
152 _mesa_hash_table_create(void *mem_ctx,
153 uint32_t (*key_hash_function)(const void *key),
154 bool (*key_equals_function)(const void *a,
155 const void *b))
156 {
157 struct hash_table *ht;
158
159 /* mem_ctx is used to allocate the hash table, but the hash table is used
160 * to allocate all of the suballocations.
161 */
162 ht = ralloc(mem_ctx, struct hash_table);
163 if (ht == NULL)
164 return NULL;
165
166 if (!_mesa_hash_table_init(ht, ht, key_hash_function, key_equals_function)) {
167 ralloc_free(ht);
168 return NULL;
169 }
170
171 return ht;
172 }
173
174 struct hash_table *
175 _mesa_hash_table_clone(struct hash_table *src, void *dst_mem_ctx)
176 {
177 struct hash_table *ht;
178
179 ht = ralloc(dst_mem_ctx, struct hash_table);
180 if (ht == NULL)
181 return NULL;
182
183 memcpy(ht, src, sizeof(struct hash_table));
184
185 ht->table = ralloc_array(ht, struct hash_entry, ht->size);
186 if (ht->table == NULL) {
187 ralloc_free(ht);
188 return NULL;
189 }
190
191 memcpy(ht->table, src->table, ht->size * sizeof(struct hash_entry));
192
193 return ht;
194 }
195
196 /**
197 * Frees the given hash table.
198 *
199 * If delete_function is passed, it gets called on each entry present before
200 * freeing.
201 */
202 void
203 _mesa_hash_table_destroy(struct hash_table *ht,
204 void (*delete_function)(struct hash_entry *entry))
205 {
206 if (!ht)
207 return;
208
209 if (delete_function) {
210 hash_table_foreach(ht, entry) {
211 delete_function(entry);
212 }
213 }
214 ralloc_free(ht);
215 }
216
217 /**
218 * Deletes all entries of the given hash table without deleting the table
219 * itself or changing its structure.
220 *
221 * If delete_function is passed, it gets called on each entry present.
222 */
223 void
224 _mesa_hash_table_clear(struct hash_table *ht,
225 void (*delete_function)(struct hash_entry *entry))
226 {
227 struct hash_entry *entry;
228
229 for (entry = ht->table; entry != ht->table + ht->size; entry++) {
230 if (entry->key == NULL)
231 continue;
232
233 if (delete_function != NULL && entry->key != ht->deleted_key)
234 delete_function(entry);
235
236 entry->key = NULL;
237 }
238
239 ht->entries = 0;
240 ht->deleted_entries = 0;
241 }
242
243 /** Sets the value of the key pointer used for deleted entries in the table.
244 *
245 * The assumption is that usually keys are actual pointers, so we use a
246 * default value of a pointer to an arbitrary piece of storage in the library.
247 * But in some cases a consumer wants to store some other sort of value in the
248 * table, like a uint32_t, in which case that pointer may conflict with one of
249 * their valid keys. This lets that user select a safe value.
250 *
251 * This must be called before any keys are actually deleted from the table.
252 */
253 void
254 _mesa_hash_table_set_deleted_key(struct hash_table *ht, const void *deleted_key)
255 {
256 ht->deleted_key = deleted_key;
257 }
258
259 static struct hash_entry *
260 hash_table_search(struct hash_table *ht, uint32_t hash, const void *key)
261 {
262 assert(!key_pointer_is_reserved(ht, key));
263
264 uint32_t size = ht->size;
265 uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
266 uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
267 ht->rehash_magic);
268 uint32_t hash_address = start_hash_address;
269
270 do {
271 struct hash_entry *entry = ht->table + hash_address;
272
273 if (entry_is_free(entry)) {
274 return NULL;
275 } else if (entry_is_present(ht, entry) && entry->hash == hash) {
276 if (ht->key_equals_function(key, entry->key)) {
277 return entry;
278 }
279 }
280
281 hash_address += double_hash;
282 if (hash_address >= size)
283 hash_address -= size;
284 } while (hash_address != start_hash_address);
285
286 return NULL;
287 }
288
289 /**
290 * Finds a hash table entry with the given key and hash of that key.
291 *
292 * Returns NULL if no entry is found. Note that the data pointer may be
293 * modified by the user.
294 */
295 struct hash_entry *
296 _mesa_hash_table_search(struct hash_table *ht, const void *key)
297 {
298 assert(ht->key_hash_function);
299 return hash_table_search(ht, ht->key_hash_function(key), key);
300 }
301
302 struct hash_entry *
303 _mesa_hash_table_search_pre_hashed(struct hash_table *ht, uint32_t hash,
304 const void *key)
305 {
306 assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key));
307 return hash_table_search(ht, hash, key);
308 }
309
310 static struct hash_entry *
311 hash_table_insert(struct hash_table *ht, uint32_t hash,
312 const void *key, void *data);
313
314 static void
315 hash_table_insert_rehash(struct hash_table *ht, uint32_t hash,
316 const void *key, void *data)
317 {
318 uint32_t size = ht->size;
319 uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
320 uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
321 ht->rehash_magic);
322 uint32_t hash_address = start_hash_address;
323 do {
324 struct hash_entry *entry = ht->table + hash_address;
325
326 if (likely(entry->key == NULL)) {
327 entry->hash = hash;
328 entry->key = key;
329 entry->data = data;
330 return;
331 }
332
333 hash_address += double_hash;
334 if (hash_address >= size)
335 hash_address -= size;
336 } while (true);
337 }
338
339 static void
340 _mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index)
341 {
342 struct hash_table old_ht;
343 struct hash_entry *table;
344
345 if (new_size_index >= ARRAY_SIZE(hash_sizes))
346 return;
347
348 table = rzalloc_array(ralloc_parent(ht->table), struct hash_entry,
349 hash_sizes[new_size_index].size);
350 if (table == NULL)
351 return;
352
353 old_ht = *ht;
354
355 ht->table = table;
356 ht->size_index = new_size_index;
357 ht->size = hash_sizes[ht->size_index].size;
358 ht->rehash = hash_sizes[ht->size_index].rehash;
359 ht->size_magic = hash_sizes[ht->size_index].size_magic;
360 ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic;
361 ht->max_entries = hash_sizes[ht->size_index].max_entries;
362 ht->entries = 0;
363 ht->deleted_entries = 0;
364
365 hash_table_foreach(&old_ht, entry) {
366 hash_table_insert_rehash(ht, entry->hash, entry->key, entry->data);
367 }
368
369 ht->entries = old_ht.entries;
370
371 ralloc_free(old_ht.table);
372 }
373
374 static struct hash_entry *
375 hash_table_insert(struct hash_table *ht, uint32_t hash,
376 const void *key, void *data)
377 {
378 struct hash_entry *available_entry = NULL;
379
380 assert(!key_pointer_is_reserved(ht, key));
381
382 if (ht->entries >= ht->max_entries) {
383 _mesa_hash_table_rehash(ht, ht->size_index + 1);
384 } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
385 _mesa_hash_table_rehash(ht, ht->size_index);
386 }
387
388 uint32_t size = ht->size;
389 uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic);
390 uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash,
391 ht->rehash_magic);
392 uint32_t hash_address = start_hash_address;
393 do {
394 struct hash_entry *entry = ht->table + hash_address;
395
396 if (!entry_is_present(ht, entry)) {
397 /* Stash the first available entry we find */
398 if (available_entry == NULL)
399 available_entry = entry;
400 if (entry_is_free(entry))
401 break;
402 }
403
404 /* Implement replacement when another insert happens
405 * with a matching key. This is a relatively common
406 * feature of hash tables, with the alternative
407 * generally being "insert the new value as well, and
408 * return it first when the key is searched for".
409 *
410 * Note that the hash table doesn't have a delete
411 * callback. If freeing of old data pointers is
412 * required to avoid memory leaks, perform a search
413 * before inserting.
414 */
415 if (!entry_is_deleted(ht, entry) &&
416 entry->hash == hash &&
417 ht->key_equals_function(key, entry->key)) {
418 entry->key = key;
419 entry->data = data;
420 return entry;
421 }
422
423 hash_address += double_hash;
424 if (hash_address >= size)
425 hash_address -= size;
426 } while (hash_address != start_hash_address);
427
428 if (available_entry) {
429 if (entry_is_deleted(ht, available_entry))
430 ht->deleted_entries--;
431 available_entry->hash = hash;
432 available_entry->key = key;
433 available_entry->data = data;
434 ht->entries++;
435 return available_entry;
436 }
437
438 /* We could hit here if a required resize failed. An unchecked-malloc
439 * application could ignore this result.
440 */
441 return NULL;
442 }
443
444 /**
445 * Inserts the key with the given hash into the table.
446 *
447 * Note that insertion may rearrange the table on a resize or rehash,
448 * so previously found hash_entries are no longer valid after this function.
449 */
450 struct hash_entry *
451 _mesa_hash_table_insert(struct hash_table *ht, const void *key, void *data)
452 {
453 assert(ht->key_hash_function);
454 return hash_table_insert(ht, ht->key_hash_function(key), key, data);
455 }
456
457 struct hash_entry *
458 _mesa_hash_table_insert_pre_hashed(struct hash_table *ht, uint32_t hash,
459 const void *key, void *data)
460 {
461 assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key));
462 return hash_table_insert(ht, hash, key, data);
463 }
464
465 /**
466 * This function deletes the given hash table entry.
467 *
468 * Note that deletion doesn't otherwise modify the table, so an iteration over
469 * the table deleting entries is safe.
470 */
471 void
472 _mesa_hash_table_remove(struct hash_table *ht,
473 struct hash_entry *entry)
474 {
475 if (!entry)
476 return;
477
478 entry->key = ht->deleted_key;
479 ht->entries--;
480 ht->deleted_entries++;
481 }
482
483 /**
484 * Removes the entry with the corresponding key, if exists.
485 */
486 void _mesa_hash_table_remove_key(struct hash_table *ht,
487 const void *key)
488 {
489 _mesa_hash_table_remove(ht, _mesa_hash_table_search(ht, key));
490 }
491
492 /**
493 * This function is an iterator over the hash table.
494 *
495 * Pass in NULL for the first entry, as in the start of a for loop. Note that
496 * an iteration over the table is O(table_size) not O(entries).
497 */
498 struct hash_entry *
499 _mesa_hash_table_next_entry(struct hash_table *ht,
500 struct hash_entry *entry)
501 {
502 if (entry == NULL)
503 entry = ht->table;
504 else
505 entry = entry + 1;
506
507 for (; entry != ht->table + ht->size; entry++) {
508 if (entry_is_present(ht, entry)) {
509 return entry;
510 }
511 }
512
513 return NULL;
514 }
515
516 /**
517 * Returns a random entry from the hash table.
518 *
519 * This may be useful in implementing random replacement (as opposed
520 * to just removing everything) in caches based on this hash table
521 * implementation. @predicate may be used to filter entries, or may
522 * be set to NULL for no filtering.
523 */
524 struct hash_entry *
525 _mesa_hash_table_random_entry(struct hash_table *ht,
526 bool (*predicate)(struct hash_entry *entry))
527 {
528 struct hash_entry *entry;
529 uint32_t i = rand() % ht->size;
530
531 if (ht->entries == 0)
532 return NULL;
533
534 for (entry = ht->table + i; entry != ht->table + ht->size; entry++) {
535 if (entry_is_present(ht, entry) &&
536 (!predicate || predicate(entry))) {
537 return entry;
538 }
539 }
540
541 for (entry = ht->table; entry != ht->table + i; entry++) {
542 if (entry_is_present(ht, entry) &&
543 (!predicate || predicate(entry))) {
544 return entry;
545 }
546 }
547
548 return NULL;
549 }
550
551
552 uint32_t
553 _mesa_hash_data(const void *data, size_t size)
554 {
555 return XXH32(data, size, 0);
556 }
557
558 uint32_t
559 _mesa_hash_int(const void *key)
560 {
561 return XXH32(key, sizeof(int), 0);
562 }
563
564 uint32_t
565 _mesa_hash_uint(const void *key)
566 {
567 return XXH32(key, sizeof(unsigned), 0);
568 }
569
570 uint32_t
571 _mesa_hash_u32(const void *key)
572 {
573 return XXH32(key, 4, 0);
574 }
575
576 /** FNV-1a string hash implementation */
577 uint32_t
578 _mesa_hash_string(const void *_key)
579 {
580 uint32_t hash = _mesa_fnv32_1a_offset_bias;
581 const char *key = _key;
582
583 while (*key != 0) {
584 hash = _mesa_fnv32_1a_accumulate(hash, *key);
585 key++;
586 }
587
588 return hash;
589 }
590
591 uint32_t
592 _mesa_hash_pointer(const void *pointer)
593 {
594 uintptr_t num = (uintptr_t) pointer;
595 return (uint32_t) ((num >> 2) ^ (num >> 6) ^ (num >> 10) ^ (num >> 14));
596 }
597
598 bool
599 _mesa_key_int_equal(const void *a, const void *b)
600 {
601 return *((const int *)a) == *((const int *)b);
602 }
603
604 bool
605 _mesa_key_uint_equal(const void *a, const void *b)
606 {
607
608 return *((const unsigned *)a) == *((const unsigned *)b);
609 }
610
611 bool
612 _mesa_key_u32_equal(const void *a, const void *b)
613 {
614 return *((const uint32_t *)a) == *((const uint32_t *)b);
615 }
616
617 /**
618 * String compare function for use as the comparison callback in
619 * _mesa_hash_table_create().
620 */
621 bool
622 _mesa_key_string_equal(const void *a, const void *b)
623 {
624 return strcmp(a, b) == 0;
625 }
626
627 bool
628 _mesa_key_pointer_equal(const void *a, const void *b)
629 {
630 return a == b;
631 }
632
633 /**
634 * Helper to create a hash table with pointer keys.
635 */
636 struct hash_table *
637 _mesa_pointer_hash_table_create(void *mem_ctx)
638 {
639 return _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
640 _mesa_key_pointer_equal);
641 }
642
643 /**
644 * Hash table wrapper which supports 64-bit keys.
645 *
646 * TODO: unify all hash table implementations.
647 */
648
649 struct hash_key_u64 {
650 uint64_t value;
651 };
652
653 static uint32_t
654 key_u64_hash(const void *key)
655 {
656 return _mesa_hash_data(key, sizeof(struct hash_key_u64));
657 }
658
659 static bool
660 key_u64_equals(const void *a, const void *b)
661 {
662 const struct hash_key_u64 *aa = a;
663 const struct hash_key_u64 *bb = b;
664
665 return aa->value == bb->value;
666 }
667
668 #define FREED_KEY_VALUE 0
669
670 struct hash_table_u64 *
671 _mesa_hash_table_u64_create(void *mem_ctx)
672 {
673 STATIC_ASSERT(FREED_KEY_VALUE != DELETED_KEY_VALUE);
674 struct hash_table_u64 *ht;
675
676 ht = CALLOC_STRUCT(hash_table_u64);
677 if (!ht)
678 return NULL;
679
680 if (sizeof(void *) == 8) {
681 ht->table = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
682 _mesa_key_pointer_equal);
683 } else {
684 ht->table = _mesa_hash_table_create(mem_ctx, key_u64_hash,
685 key_u64_equals);
686 }
687
688 if (ht->table)
689 _mesa_hash_table_set_deleted_key(ht->table, uint_key(DELETED_KEY_VALUE));
690
691 return ht;
692 }
693
694 void
695 _mesa_hash_table_u64_clear(struct hash_table_u64 *ht,
696 void (*delete_function)(struct hash_entry *entry))
697 {
698 if (!ht)
699 return;
700
701 if (ht->deleted_key_data) {
702 if (delete_function) {
703 struct hash_table *table = ht->table;
704 struct hash_entry entry;
705
706 /* Create a fake entry for the delete function. */
707 if (sizeof(void *) == 8) {
708 entry.hash = table->key_hash_function(table->deleted_key);
709 } else {
710 struct hash_key_u64 _key = { .value = (uintptr_t)table->deleted_key };
711 entry.hash = table->key_hash_function(&_key);
712 }
713 entry.key = table->deleted_key;
714 entry.data = ht->deleted_key_data;
715
716 delete_function(&entry);
717 }
718 ht->deleted_key_data = NULL;
719 }
720
721 if (ht->freed_key_data) {
722 if (delete_function) {
723 struct hash_table *table = ht->table;
724 struct hash_entry entry;
725
726 /* Create a fake entry for the delete function. */
727 if (sizeof(void *) == 8) {
728 entry.hash = table->key_hash_function(uint_key(FREED_KEY_VALUE));
729 } else {
730 struct hash_key_u64 _key = { .value = (uintptr_t)FREED_KEY_VALUE };
731 entry.hash = table->key_hash_function(&_key);
732 }
733 entry.key = uint_key(FREED_KEY_VALUE);
734 entry.data = ht->freed_key_data;
735
736 delete_function(&entry);
737 }
738 ht->freed_key_data = NULL;
739 }
740
741 _mesa_hash_table_clear(ht->table, delete_function);
742 }
743
744 void
745 _mesa_hash_table_u64_destroy(struct hash_table_u64 *ht,
746 void (*delete_function)(struct hash_entry *entry))
747 {
748 if (!ht)
749 return;
750
751 _mesa_hash_table_u64_clear(ht, delete_function);
752 _mesa_hash_table_destroy(ht->table, delete_function);
753 free(ht);
754 }
755
756 void
757 _mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key,
758 void *data)
759 {
760 if (key == FREED_KEY_VALUE) {
761 ht->freed_key_data = data;
762 return;
763 }
764
765 if (key == DELETED_KEY_VALUE) {
766 ht->deleted_key_data = data;
767 return;
768 }
769
770 if (sizeof(void *) == 8) {
771 _mesa_hash_table_insert(ht->table, (void *)(uintptr_t)key, data);
772 } else {
773 struct hash_key_u64 *_key = CALLOC_STRUCT(hash_key_u64);
774
775 if (!_key)
776 return;
777 _key->value = key;
778
779 _mesa_hash_table_insert(ht->table, _key, data);
780 }
781 }
782
783 static struct hash_entry *
784 hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
785 {
786 if (sizeof(void *) == 8) {
787 return _mesa_hash_table_search(ht->table, (void *)(uintptr_t)key);
788 } else {
789 struct hash_key_u64 _key = { .value = key };
790 return _mesa_hash_table_search(ht->table, &_key);
791 }
792 }
793
794 void *
795 _mesa_hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
796 {
797 struct hash_entry *entry;
798
799 if (key == FREED_KEY_VALUE)
800 return ht->freed_key_data;
801
802 if (key == DELETED_KEY_VALUE)
803 return ht->deleted_key_data;
804
805 entry = hash_table_u64_search(ht, key);
806 if (!entry)
807 return NULL;
808
809 return entry->data;
810 }
811
812 void
813 _mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key)
814 {
815 struct hash_entry *entry;
816
817 if (key == FREED_KEY_VALUE) {
818 ht->freed_key_data = NULL;
819 return;
820 }
821
822 if (key == DELETED_KEY_VALUE) {
823 ht->deleted_key_data = NULL;
824 return;
825 }
826
827 entry = hash_table_u64_search(ht, key);
828 if (!entry)
829 return;
830
831 if (sizeof(void *) == 8) {
832 _mesa_hash_table_remove(ht->table, entry);
833 } else {
834 struct hash_key *_key = (struct hash_key *)entry->key;
835
836 _mesa_hash_table_remove(ht->table, entry);
837 free(_key);
838 }
839 }