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