Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/util/hash_table.c
4550 views
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 *
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
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
131
entry_is_free(const struct hash_entry *entry)
132
{
133
return entry->key == NULL;
134
}
135
136
static int
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
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
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 *
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
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
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 *
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 *
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
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
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
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
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 *
309
hash_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
*/
344
struct 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
351
struct 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
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
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
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 *
430
hash_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
*/
505
struct 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
512
struct 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
*/
526
void
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
*/
541
void _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
*/
552
struct 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
*/
574
struct 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
*/
600
struct 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
628
uint32_t
629
_mesa_hash_data(const void *data, size_t size)
630
{
631
return XXH32(data, size, 0);
632
}
633
634
uint32_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
640
uint32_t
641
_mesa_hash_int(const void *key)
642
{
643
return XXH32(key, sizeof(int), 0);
644
}
645
646
uint32_t
647
_mesa_hash_uint(const void *key)
648
{
649
return XXH32(key, sizeof(unsigned), 0);
650
}
651
652
uint32_t
653
_mesa_hash_u32(const void *key)
654
{
655
return XXH32(key, 4, 0);
656
}
657
658
/** FNV-1a string hash implementation */
659
uint32_t
660
_mesa_hash_string(const void *_key)
661
{
662
uint32_t hash = 0;
663
const char *key = _key;
664
size_t len = strlen(key);
665
#if defined(_WIN64) || defined(__x86_64__)
666
hash = (uint32_t)XXH64(key, len, hash);
667
#else
668
hash = XXH32(key, len, hash);
669
#endif
670
return hash;
671
}
672
673
uint32_t
674
_mesa_hash_pointer(const void *pointer)
675
{
676
uintptr_t num = (uintptr_t) pointer;
677
return (uint32_t) ((num >> 2) ^ (num >> 6) ^ (num >> 10) ^ (num >> 14));
678
}
679
680
bool
681
_mesa_key_int_equal(const void *a, const void *b)
682
{
683
return *((const int *)a) == *((const int *)b);
684
}
685
686
bool
687
_mesa_key_uint_equal(const void *a, const void *b)
688
{
689
690
return *((const unsigned *)a) == *((const unsigned *)b);
691
}
692
693
bool
694
_mesa_key_u32_equal(const void *a, const void *b)
695
{
696
return *((const uint32_t *)a) == *((const uint32_t *)b);
697
}
698
699
/**
700
* String compare function for use as the comparison callback in
701
* _mesa_hash_table_create().
702
*/
703
bool
704
_mesa_key_string_equal(const void *a, const void *b)
705
{
706
return strcmp(a, b) == 0;
707
}
708
709
bool
710
_mesa_key_pointer_equal(const void *a, const void *b)
711
{
712
return a == b;
713
}
714
715
/**
716
* Helper to create a hash table with pointer keys.
717
*/
718
struct hash_table *
719
_mesa_pointer_hash_table_create(void *mem_ctx)
720
{
721
return _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
722
_mesa_key_pointer_equal);
723
}
724
725
726
bool
727
_mesa_hash_table_reserve(struct hash_table *ht, unsigned size)
728
{
729
if (size < ht->max_entries)
730
return true;
731
for (unsigned i = ht->size_index + 1; i < ARRAY_SIZE(hash_sizes); i++) {
732
if (hash_sizes[i].max_entries >= size) {
733
_mesa_hash_table_rehash(ht, i);
734
break;
735
}
736
}
737
return ht->max_entries >= size;
738
}
739
740
/**
741
* Hash table wrapper which supports 64-bit keys.
742
*
743
* TODO: unify all hash table implementations.
744
*/
745
746
struct hash_key_u64 {
747
uint64_t value;
748
};
749
750
static uint32_t
751
key_u64_hash(const void *key)
752
{
753
return _mesa_hash_data(key, sizeof(struct hash_key_u64));
754
}
755
756
static bool
757
key_u64_equals(const void *a, const void *b)
758
{
759
const struct hash_key_u64 *aa = a;
760
const struct hash_key_u64 *bb = b;
761
762
return aa->value == bb->value;
763
}
764
765
#define FREED_KEY_VALUE 0
766
767
struct hash_table_u64 *
768
_mesa_hash_table_u64_create(void *mem_ctx)
769
{
770
STATIC_ASSERT(FREED_KEY_VALUE != DELETED_KEY_VALUE);
771
struct hash_table_u64 *ht;
772
773
ht = CALLOC_STRUCT(hash_table_u64);
774
if (!ht)
775
return NULL;
776
777
if (sizeof(void *) == 8) {
778
ht->table = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer,
779
_mesa_key_pointer_equal);
780
} else {
781
ht->table = _mesa_hash_table_create(mem_ctx, key_u64_hash,
782
key_u64_equals);
783
}
784
785
if (ht->table)
786
_mesa_hash_table_set_deleted_key(ht->table, uint_key(DELETED_KEY_VALUE));
787
788
return ht;
789
}
790
791
static void
792
_mesa_hash_table_u64_delete_key(struct hash_entry *entry)
793
{
794
if (sizeof(void *) == 8)
795
return;
796
797
struct hash_key_u64 *_key = (struct hash_key_u64 *)entry->key;
798
799
if (_key)
800
free(_key);
801
}
802
803
void
804
_mesa_hash_table_u64_clear(struct hash_table_u64 *ht)
805
{
806
if (!ht)
807
return;
808
809
_mesa_hash_table_clear(ht->table, _mesa_hash_table_u64_delete_key);
810
}
811
812
void
813
_mesa_hash_table_u64_destroy(struct hash_table_u64 *ht)
814
{
815
if (!ht)
816
return;
817
818
_mesa_hash_table_u64_clear(ht);
819
_mesa_hash_table_destroy(ht->table, NULL);
820
free(ht);
821
}
822
823
void
824
_mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key,
825
void *data)
826
{
827
if (key == FREED_KEY_VALUE) {
828
ht->freed_key_data = data;
829
return;
830
}
831
832
if (key == DELETED_KEY_VALUE) {
833
ht->deleted_key_data = data;
834
return;
835
}
836
837
if (sizeof(void *) == 8) {
838
_mesa_hash_table_insert(ht->table, (void *)(uintptr_t)key, data);
839
} else {
840
struct hash_key_u64 *_key = CALLOC_STRUCT(hash_key_u64);
841
842
if (!_key)
843
return;
844
_key->value = key;
845
846
_mesa_hash_table_insert(ht->table, _key, data);
847
}
848
}
849
850
static struct hash_entry *
851
hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
852
{
853
if (sizeof(void *) == 8) {
854
return _mesa_hash_table_search(ht->table, (void *)(uintptr_t)key);
855
} else {
856
struct hash_key_u64 _key = { .value = key };
857
return _mesa_hash_table_search(ht->table, &_key);
858
}
859
}
860
861
void *
862
_mesa_hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key)
863
{
864
struct hash_entry *entry;
865
866
if (key == FREED_KEY_VALUE)
867
return ht->freed_key_data;
868
869
if (key == DELETED_KEY_VALUE)
870
return ht->deleted_key_data;
871
872
entry = hash_table_u64_search(ht, key);
873
if (!entry)
874
return NULL;
875
876
return entry->data;
877
}
878
879
void
880
_mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key)
881
{
882
struct hash_entry *entry;
883
884
if (key == FREED_KEY_VALUE) {
885
ht->freed_key_data = NULL;
886
return;
887
}
888
889
if (key == DELETED_KEY_VALUE) {
890
ht->deleted_key_data = NULL;
891
return;
892
}
893
894
entry = hash_table_u64_search(ht, key);
895
if (!entry)
896
return;
897
898
if (sizeof(void *) == 8) {
899
_mesa_hash_table_remove(ht->table, entry);
900
} else {
901
struct hash_key *_key = (struct hash_key *)entry->key;
902
903
_mesa_hash_table_remove(ht->table, entry);
904
free(_key);
905
}
906
}
907
908