1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2009,2012 Intel Corporation 3bf215546Sopenharmony_ci * Copyright © 1988-2004 Keith Packard and Bart Massey. 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22bf215546Sopenharmony_ci * IN THE SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci * Except as contained in this notice, the names of the authors 25bf215546Sopenharmony_ci * or their institutions shall not be used in advertising or 26bf215546Sopenharmony_ci * otherwise to promote the sale, use or other dealings in this 27bf215546Sopenharmony_ci * Software without prior written authorization from the 28bf215546Sopenharmony_ci * authors. 29bf215546Sopenharmony_ci * 30bf215546Sopenharmony_ci * Authors: 31bf215546Sopenharmony_ci * Eric Anholt <eric@anholt.net> 32bf215546Sopenharmony_ci * Keith Packard <keithp@keithp.com> 33bf215546Sopenharmony_ci */ 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci/** 36bf215546Sopenharmony_ci * Implements an open-addressing, linear-reprobing hash table. 37bf215546Sopenharmony_ci * 38bf215546Sopenharmony_ci * For more information, see: 39bf215546Sopenharmony_ci * 40bf215546Sopenharmony_ci * http://cgit.freedesktop.org/~anholt/hash_table/tree/README 41bf215546Sopenharmony_ci */ 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci#include <stdlib.h> 44bf215546Sopenharmony_ci#include <string.h> 45bf215546Sopenharmony_ci#include <assert.h> 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci#include "hash_table.h" 48bf215546Sopenharmony_ci#include "ralloc.h" 49bf215546Sopenharmony_ci#include "macros.h" 50bf215546Sopenharmony_ci#include "u_memory.h" 51bf215546Sopenharmony_ci#include "fast_urem_by_const.h" 52bf215546Sopenharmony_ci#include "util/u_memory.h" 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci#define XXH_INLINE_ALL 55bf215546Sopenharmony_ci#include "xxhash.h" 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci/** 58bf215546Sopenharmony_ci * Magic number that gets stored outside of the struct hash_table. 59bf215546Sopenharmony_ci * 60bf215546Sopenharmony_ci * The hash table needs a particular pointer to be the marker for a key that 61bf215546Sopenharmony_ci * was deleted from the table, along with NULL for the "never allocated in the 62bf215546Sopenharmony_ci * table" marker. Legacy GL allows any GLuint to be used as a GL object name, 63bf215546Sopenharmony_ci * and we use a 1:1 mapping from GLuints to key pointers, so we need to be 64bf215546Sopenharmony_ci * able to track a GLuint that happens to match the deleted key outside of 65bf215546Sopenharmony_ci * struct hash_table. We tell the hash table to use "1" as the deleted key 66bf215546Sopenharmony_ci * value, so that we test the deleted-key-in-the-table path as best we can. 67bf215546Sopenharmony_ci */ 68bf215546Sopenharmony_ci#define DELETED_KEY_VALUE 1 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_cistatic inline void * 71bf215546Sopenharmony_ciuint_key(unsigned id) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci return (void *)(uintptr_t) id; 74bf215546Sopenharmony_ci} 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cistatic const uint32_t deleted_key_value; 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci/** 79bf215546Sopenharmony_ci * From Knuth -- a good choice for hash/rehash values is p, p-2 where 80bf215546Sopenharmony_ci * p and p-2 are both prime. These tables are sized to have an extra 10% 81bf215546Sopenharmony_ci * free to avoid exponential performance degradation as the hash table fills 82bf215546Sopenharmony_ci */ 83bf215546Sopenharmony_cistatic const struct { 84bf215546Sopenharmony_ci uint32_t max_entries, size, rehash; 85bf215546Sopenharmony_ci uint64_t size_magic, rehash_magic; 86bf215546Sopenharmony_ci} hash_sizes[] = { 87bf215546Sopenharmony_ci#define ENTRY(max_entries, size, rehash) \ 88bf215546Sopenharmony_ci { max_entries, size, rehash, \ 89bf215546Sopenharmony_ci REMAINDER_MAGIC(size), REMAINDER_MAGIC(rehash) } 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci ENTRY(2, 5, 3 ), 92bf215546Sopenharmony_ci ENTRY(4, 7, 5 ), 93bf215546Sopenharmony_ci ENTRY(8, 13, 11 ), 94bf215546Sopenharmony_ci ENTRY(16, 19, 17 ), 95bf215546Sopenharmony_ci ENTRY(32, 43, 41 ), 96bf215546Sopenharmony_ci ENTRY(64, 73, 71 ), 97bf215546Sopenharmony_ci ENTRY(128, 151, 149 ), 98bf215546Sopenharmony_ci ENTRY(256, 283, 281 ), 99bf215546Sopenharmony_ci ENTRY(512, 571, 569 ), 100bf215546Sopenharmony_ci ENTRY(1024, 1153, 1151 ), 101bf215546Sopenharmony_ci ENTRY(2048, 2269, 2267 ), 102bf215546Sopenharmony_ci ENTRY(4096, 4519, 4517 ), 103bf215546Sopenharmony_ci ENTRY(8192, 9013, 9011 ), 104bf215546Sopenharmony_ci ENTRY(16384, 18043, 18041 ), 105bf215546Sopenharmony_ci ENTRY(32768, 36109, 36107 ), 106bf215546Sopenharmony_ci ENTRY(65536, 72091, 72089 ), 107bf215546Sopenharmony_ci ENTRY(131072, 144409, 144407 ), 108bf215546Sopenharmony_ci ENTRY(262144, 288361, 288359 ), 109bf215546Sopenharmony_ci ENTRY(524288, 576883, 576881 ), 110bf215546Sopenharmony_ci ENTRY(1048576, 1153459, 1153457 ), 111bf215546Sopenharmony_ci ENTRY(2097152, 2307163, 2307161 ), 112bf215546Sopenharmony_ci ENTRY(4194304, 4613893, 4613891 ), 113bf215546Sopenharmony_ci ENTRY(8388608, 9227641, 9227639 ), 114bf215546Sopenharmony_ci ENTRY(16777216, 18455029, 18455027 ), 115bf215546Sopenharmony_ci ENTRY(33554432, 36911011, 36911009 ), 116bf215546Sopenharmony_ci ENTRY(67108864, 73819861, 73819859 ), 117bf215546Sopenharmony_ci ENTRY(134217728, 147639589, 147639587 ), 118bf215546Sopenharmony_ci ENTRY(268435456, 295279081, 295279079 ), 119bf215546Sopenharmony_ci ENTRY(536870912, 590559793, 590559791 ), 120bf215546Sopenharmony_ci ENTRY(1073741824, 1181116273, 1181116271 ), 121bf215546Sopenharmony_ci ENTRY(2147483648ul, 2362232233ul, 2362232231ul ) 122bf215546Sopenharmony_ci}; 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ciASSERTED static inline bool 125bf215546Sopenharmony_cikey_pointer_is_reserved(const struct hash_table *ht, const void *key) 126bf215546Sopenharmony_ci{ 127bf215546Sopenharmony_ci return key == NULL || key == ht->deleted_key; 128bf215546Sopenharmony_ci} 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_cistatic int 131bf215546Sopenharmony_cientry_is_free(const struct hash_entry *entry) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci return entry->key == NULL; 134bf215546Sopenharmony_ci} 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_cistatic int 137bf215546Sopenharmony_cientry_is_deleted(const struct hash_table *ht, struct hash_entry *entry) 138bf215546Sopenharmony_ci{ 139bf215546Sopenharmony_ci return entry->key == ht->deleted_key; 140bf215546Sopenharmony_ci} 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_cistatic int 143bf215546Sopenharmony_cientry_is_present(const struct hash_table *ht, struct hash_entry *entry) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci return entry->key != NULL && entry->key != ht->deleted_key; 146bf215546Sopenharmony_ci} 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_cibool 149bf215546Sopenharmony_ci_mesa_hash_table_init(struct hash_table *ht, 150bf215546Sopenharmony_ci void *mem_ctx, 151bf215546Sopenharmony_ci uint32_t (*key_hash_function)(const void *key), 152bf215546Sopenharmony_ci bool (*key_equals_function)(const void *a, 153bf215546Sopenharmony_ci const void *b)) 154bf215546Sopenharmony_ci{ 155bf215546Sopenharmony_ci ht->size_index = 0; 156bf215546Sopenharmony_ci ht->size = hash_sizes[ht->size_index].size; 157bf215546Sopenharmony_ci ht->rehash = hash_sizes[ht->size_index].rehash; 158bf215546Sopenharmony_ci ht->size_magic = hash_sizes[ht->size_index].size_magic; 159bf215546Sopenharmony_ci ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic; 160bf215546Sopenharmony_ci ht->max_entries = hash_sizes[ht->size_index].max_entries; 161bf215546Sopenharmony_ci ht->key_hash_function = key_hash_function; 162bf215546Sopenharmony_ci ht->key_equals_function = key_equals_function; 163bf215546Sopenharmony_ci ht->table = rzalloc_array(mem_ctx, struct hash_entry, ht->size); 164bf215546Sopenharmony_ci ht->entries = 0; 165bf215546Sopenharmony_ci ht->deleted_entries = 0; 166bf215546Sopenharmony_ci ht->deleted_key = &deleted_key_value; 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci return ht->table != NULL; 169bf215546Sopenharmony_ci} 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_cistruct hash_table * 172bf215546Sopenharmony_ci_mesa_hash_table_create(void *mem_ctx, 173bf215546Sopenharmony_ci uint32_t (*key_hash_function)(const void *key), 174bf215546Sopenharmony_ci bool (*key_equals_function)(const void *a, 175bf215546Sopenharmony_ci const void *b)) 176bf215546Sopenharmony_ci{ 177bf215546Sopenharmony_ci struct hash_table *ht; 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci /* mem_ctx is used to allocate the hash table, but the hash table is used 180bf215546Sopenharmony_ci * to allocate all of the suballocations. 181bf215546Sopenharmony_ci */ 182bf215546Sopenharmony_ci ht = ralloc(mem_ctx, struct hash_table); 183bf215546Sopenharmony_ci if (ht == NULL) 184bf215546Sopenharmony_ci return NULL; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci if (!_mesa_hash_table_init(ht, ht, key_hash_function, key_equals_function)) { 187bf215546Sopenharmony_ci ralloc_free(ht); 188bf215546Sopenharmony_ci return NULL; 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci return ht; 192bf215546Sopenharmony_ci} 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_cistatic uint32_t 195bf215546Sopenharmony_cikey_u32_hash(const void *key) 196bf215546Sopenharmony_ci{ 197bf215546Sopenharmony_ci uint32_t u = (uint32_t)(uintptr_t)key; 198bf215546Sopenharmony_ci return _mesa_hash_uint(&u); 199bf215546Sopenharmony_ci} 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_cistatic bool 202bf215546Sopenharmony_cikey_u32_equals(const void *a, const void *b) 203bf215546Sopenharmony_ci{ 204bf215546Sopenharmony_ci return (uint32_t)(uintptr_t)a == (uint32_t)(uintptr_t)b; 205bf215546Sopenharmony_ci} 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci/* key == 0 and key == deleted_key are not allowed */ 208bf215546Sopenharmony_cistruct hash_table * 209bf215546Sopenharmony_ci_mesa_hash_table_create_u32_keys(void *mem_ctx) 210bf215546Sopenharmony_ci{ 211bf215546Sopenharmony_ci return _mesa_hash_table_create(mem_ctx, key_u32_hash, key_u32_equals); 212bf215546Sopenharmony_ci} 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_cistruct hash_table * 215bf215546Sopenharmony_ci_mesa_hash_table_clone(struct hash_table *src, void *dst_mem_ctx) 216bf215546Sopenharmony_ci{ 217bf215546Sopenharmony_ci struct hash_table *ht; 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci ht = ralloc(dst_mem_ctx, struct hash_table); 220bf215546Sopenharmony_ci if (ht == NULL) 221bf215546Sopenharmony_ci return NULL; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci memcpy(ht, src, sizeof(struct hash_table)); 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci ht->table = ralloc_array(ht, struct hash_entry, ht->size); 226bf215546Sopenharmony_ci if (ht->table == NULL) { 227bf215546Sopenharmony_ci ralloc_free(ht); 228bf215546Sopenharmony_ci return NULL; 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci memcpy(ht->table, src->table, ht->size * sizeof(struct hash_entry)); 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci return ht; 234bf215546Sopenharmony_ci} 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci/** 237bf215546Sopenharmony_ci * Frees the given hash table. 238bf215546Sopenharmony_ci * 239bf215546Sopenharmony_ci * If delete_function is passed, it gets called on each entry present before 240bf215546Sopenharmony_ci * freeing. 241bf215546Sopenharmony_ci */ 242bf215546Sopenharmony_civoid 243bf215546Sopenharmony_ci_mesa_hash_table_destroy(struct hash_table *ht, 244bf215546Sopenharmony_ci void (*delete_function)(struct hash_entry *entry)) 245bf215546Sopenharmony_ci{ 246bf215546Sopenharmony_ci if (!ht) 247bf215546Sopenharmony_ci return; 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci if (delete_function) { 250bf215546Sopenharmony_ci hash_table_foreach(ht, entry) { 251bf215546Sopenharmony_ci delete_function(entry); 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci } 254bf215546Sopenharmony_ci ralloc_free(ht); 255bf215546Sopenharmony_ci} 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_cistatic void 258bf215546Sopenharmony_cihash_table_clear_fast(struct hash_table *ht) 259bf215546Sopenharmony_ci{ 260bf215546Sopenharmony_ci memset(ht->table, 0, sizeof(struct hash_entry) * hash_sizes[ht->size_index].size); 261bf215546Sopenharmony_ci ht->entries = ht->deleted_entries = 0; 262bf215546Sopenharmony_ci} 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci/** 265bf215546Sopenharmony_ci * Deletes all entries of the given hash table without deleting the table 266bf215546Sopenharmony_ci * itself or changing its structure. 267bf215546Sopenharmony_ci * 268bf215546Sopenharmony_ci * If delete_function is passed, it gets called on each entry present. 269bf215546Sopenharmony_ci */ 270bf215546Sopenharmony_civoid 271bf215546Sopenharmony_ci_mesa_hash_table_clear(struct hash_table *ht, 272bf215546Sopenharmony_ci void (*delete_function)(struct hash_entry *entry)) 273bf215546Sopenharmony_ci{ 274bf215546Sopenharmony_ci if (!ht) 275bf215546Sopenharmony_ci return; 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci struct hash_entry *entry; 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci if (delete_function) { 280bf215546Sopenharmony_ci for (entry = ht->table; entry != ht->table + ht->size; entry++) { 281bf215546Sopenharmony_ci if (entry_is_present(ht, entry)) 282bf215546Sopenharmony_ci delete_function(entry); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci entry->key = NULL; 285bf215546Sopenharmony_ci } 286bf215546Sopenharmony_ci ht->entries = 0; 287bf215546Sopenharmony_ci ht->deleted_entries = 0; 288bf215546Sopenharmony_ci } else 289bf215546Sopenharmony_ci hash_table_clear_fast(ht); 290bf215546Sopenharmony_ci} 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci/** Sets the value of the key pointer used for deleted entries in the table. 293bf215546Sopenharmony_ci * 294bf215546Sopenharmony_ci * The assumption is that usually keys are actual pointers, so we use a 295bf215546Sopenharmony_ci * default value of a pointer to an arbitrary piece of storage in the library. 296bf215546Sopenharmony_ci * But in some cases a consumer wants to store some other sort of value in the 297bf215546Sopenharmony_ci * table, like a uint32_t, in which case that pointer may conflict with one of 298bf215546Sopenharmony_ci * their valid keys. This lets that user select a safe value. 299bf215546Sopenharmony_ci * 300bf215546Sopenharmony_ci * This must be called before any keys are actually deleted from the table. 301bf215546Sopenharmony_ci */ 302bf215546Sopenharmony_civoid 303bf215546Sopenharmony_ci_mesa_hash_table_set_deleted_key(struct hash_table *ht, const void *deleted_key) 304bf215546Sopenharmony_ci{ 305bf215546Sopenharmony_ci ht->deleted_key = deleted_key; 306bf215546Sopenharmony_ci} 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_cistatic struct hash_entry * 309bf215546Sopenharmony_cihash_table_search(struct hash_table *ht, uint32_t hash, const void *key) 310bf215546Sopenharmony_ci{ 311bf215546Sopenharmony_ci assert(!key_pointer_is_reserved(ht, key)); 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci uint32_t size = ht->size; 314bf215546Sopenharmony_ci uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic); 315bf215546Sopenharmony_ci uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash, 316bf215546Sopenharmony_ci ht->rehash_magic); 317bf215546Sopenharmony_ci uint32_t hash_address = start_hash_address; 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci do { 320bf215546Sopenharmony_ci struct hash_entry *entry = ht->table + hash_address; 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci if (entry_is_free(entry)) { 323bf215546Sopenharmony_ci return NULL; 324bf215546Sopenharmony_ci } else if (entry_is_present(ht, entry) && entry->hash == hash) { 325bf215546Sopenharmony_ci if (ht->key_equals_function(key, entry->key)) { 326bf215546Sopenharmony_ci return entry; 327bf215546Sopenharmony_ci } 328bf215546Sopenharmony_ci } 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci hash_address += double_hash; 331bf215546Sopenharmony_ci if (hash_address >= size) 332bf215546Sopenharmony_ci hash_address -= size; 333bf215546Sopenharmony_ci } while (hash_address != start_hash_address); 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci return NULL; 336bf215546Sopenharmony_ci} 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci/** 339bf215546Sopenharmony_ci * Finds a hash table entry with the given key and hash of that key. 340bf215546Sopenharmony_ci * 341bf215546Sopenharmony_ci * Returns NULL if no entry is found. Note that the data pointer may be 342bf215546Sopenharmony_ci * modified by the user. 343bf215546Sopenharmony_ci */ 344bf215546Sopenharmony_cistruct hash_entry * 345bf215546Sopenharmony_ci_mesa_hash_table_search(struct hash_table *ht, const void *key) 346bf215546Sopenharmony_ci{ 347bf215546Sopenharmony_ci assert(ht->key_hash_function); 348bf215546Sopenharmony_ci return hash_table_search(ht, ht->key_hash_function(key), key); 349bf215546Sopenharmony_ci} 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_cistruct hash_entry * 352bf215546Sopenharmony_ci_mesa_hash_table_search_pre_hashed(struct hash_table *ht, uint32_t hash, 353bf215546Sopenharmony_ci const void *key) 354bf215546Sopenharmony_ci{ 355bf215546Sopenharmony_ci assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key)); 356bf215546Sopenharmony_ci return hash_table_search(ht, hash, key); 357bf215546Sopenharmony_ci} 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_cistatic struct hash_entry * 360bf215546Sopenharmony_cihash_table_insert(struct hash_table *ht, uint32_t hash, 361bf215546Sopenharmony_ci const void *key, void *data); 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_cistatic void 364bf215546Sopenharmony_cihash_table_insert_rehash(struct hash_table *ht, uint32_t hash, 365bf215546Sopenharmony_ci const void *key, void *data) 366bf215546Sopenharmony_ci{ 367bf215546Sopenharmony_ci uint32_t size = ht->size; 368bf215546Sopenharmony_ci uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic); 369bf215546Sopenharmony_ci uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash, 370bf215546Sopenharmony_ci ht->rehash_magic); 371bf215546Sopenharmony_ci uint32_t hash_address = start_hash_address; 372bf215546Sopenharmony_ci do { 373bf215546Sopenharmony_ci struct hash_entry *entry = ht->table + hash_address; 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci if (likely(entry->key == NULL)) { 376bf215546Sopenharmony_ci entry->hash = hash; 377bf215546Sopenharmony_ci entry->key = key; 378bf215546Sopenharmony_ci entry->data = data; 379bf215546Sopenharmony_ci return; 380bf215546Sopenharmony_ci } 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci hash_address += double_hash; 383bf215546Sopenharmony_ci if (hash_address >= size) 384bf215546Sopenharmony_ci hash_address -= size; 385bf215546Sopenharmony_ci } while (true); 386bf215546Sopenharmony_ci} 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_cistatic void 389bf215546Sopenharmony_ci_mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index) 390bf215546Sopenharmony_ci{ 391bf215546Sopenharmony_ci struct hash_table old_ht; 392bf215546Sopenharmony_ci struct hash_entry *table; 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci if (ht->size_index == new_size_index && ht->deleted_entries == ht->max_entries) { 395bf215546Sopenharmony_ci hash_table_clear_fast(ht); 396bf215546Sopenharmony_ci assert(!ht->entries); 397bf215546Sopenharmony_ci return; 398bf215546Sopenharmony_ci } 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci if (new_size_index >= ARRAY_SIZE(hash_sizes)) 401bf215546Sopenharmony_ci return; 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci table = rzalloc_array(ralloc_parent(ht->table), struct hash_entry, 404bf215546Sopenharmony_ci hash_sizes[new_size_index].size); 405bf215546Sopenharmony_ci if (table == NULL) 406bf215546Sopenharmony_ci return; 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci old_ht = *ht; 409bf215546Sopenharmony_ci 410bf215546Sopenharmony_ci ht->table = table; 411bf215546Sopenharmony_ci ht->size_index = new_size_index; 412bf215546Sopenharmony_ci ht->size = hash_sizes[ht->size_index].size; 413bf215546Sopenharmony_ci ht->rehash = hash_sizes[ht->size_index].rehash; 414bf215546Sopenharmony_ci ht->size_magic = hash_sizes[ht->size_index].size_magic; 415bf215546Sopenharmony_ci ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic; 416bf215546Sopenharmony_ci ht->max_entries = hash_sizes[ht->size_index].max_entries; 417bf215546Sopenharmony_ci ht->entries = 0; 418bf215546Sopenharmony_ci ht->deleted_entries = 0; 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_ci hash_table_foreach(&old_ht, entry) { 421bf215546Sopenharmony_ci hash_table_insert_rehash(ht, entry->hash, entry->key, entry->data); 422bf215546Sopenharmony_ci } 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci ht->entries = old_ht.entries; 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci ralloc_free(old_ht.table); 427bf215546Sopenharmony_ci} 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_cistatic struct hash_entry * 430bf215546Sopenharmony_cihash_table_insert(struct hash_table *ht, uint32_t hash, 431bf215546Sopenharmony_ci const void *key, void *data) 432bf215546Sopenharmony_ci{ 433bf215546Sopenharmony_ci struct hash_entry *available_entry = NULL; 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_ci assert(!key_pointer_is_reserved(ht, key)); 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci if (ht->entries >= ht->max_entries) { 438bf215546Sopenharmony_ci _mesa_hash_table_rehash(ht, ht->size_index + 1); 439bf215546Sopenharmony_ci } else if (ht->deleted_entries + ht->entries >= ht->max_entries) { 440bf215546Sopenharmony_ci _mesa_hash_table_rehash(ht, ht->size_index); 441bf215546Sopenharmony_ci } 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci uint32_t size = ht->size; 444bf215546Sopenharmony_ci uint32_t start_hash_address = util_fast_urem32(hash, size, ht->size_magic); 445bf215546Sopenharmony_ci uint32_t double_hash = 1 + util_fast_urem32(hash, ht->rehash, 446bf215546Sopenharmony_ci ht->rehash_magic); 447bf215546Sopenharmony_ci uint32_t hash_address = start_hash_address; 448bf215546Sopenharmony_ci do { 449bf215546Sopenharmony_ci struct hash_entry *entry = ht->table + hash_address; 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci if (!entry_is_present(ht, entry)) { 452bf215546Sopenharmony_ci /* Stash the first available entry we find */ 453bf215546Sopenharmony_ci if (available_entry == NULL) 454bf215546Sopenharmony_ci available_entry = entry; 455bf215546Sopenharmony_ci if (entry_is_free(entry)) 456bf215546Sopenharmony_ci break; 457bf215546Sopenharmony_ci } 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci /* Implement replacement when another insert happens 460bf215546Sopenharmony_ci * with a matching key. This is a relatively common 461bf215546Sopenharmony_ci * feature of hash tables, with the alternative 462bf215546Sopenharmony_ci * generally being "insert the new value as well, and 463bf215546Sopenharmony_ci * return it first when the key is searched for". 464bf215546Sopenharmony_ci * 465bf215546Sopenharmony_ci * Note that the hash table doesn't have a delete 466bf215546Sopenharmony_ci * callback. If freeing of old data pointers is 467bf215546Sopenharmony_ci * required to avoid memory leaks, perform a search 468bf215546Sopenharmony_ci * before inserting. 469bf215546Sopenharmony_ci */ 470bf215546Sopenharmony_ci if (!entry_is_deleted(ht, entry) && 471bf215546Sopenharmony_ci entry->hash == hash && 472bf215546Sopenharmony_ci ht->key_equals_function(key, entry->key)) { 473bf215546Sopenharmony_ci entry->key = key; 474bf215546Sopenharmony_ci entry->data = data; 475bf215546Sopenharmony_ci return entry; 476bf215546Sopenharmony_ci } 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci hash_address += double_hash; 479bf215546Sopenharmony_ci if (hash_address >= size) 480bf215546Sopenharmony_ci hash_address -= size; 481bf215546Sopenharmony_ci } while (hash_address != start_hash_address); 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci if (available_entry) { 484bf215546Sopenharmony_ci if (entry_is_deleted(ht, available_entry)) 485bf215546Sopenharmony_ci ht->deleted_entries--; 486bf215546Sopenharmony_ci available_entry->hash = hash; 487bf215546Sopenharmony_ci available_entry->key = key; 488bf215546Sopenharmony_ci available_entry->data = data; 489bf215546Sopenharmony_ci ht->entries++; 490bf215546Sopenharmony_ci return available_entry; 491bf215546Sopenharmony_ci } 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci /* We could hit here if a required resize failed. An unchecked-malloc 494bf215546Sopenharmony_ci * application could ignore this result. 495bf215546Sopenharmony_ci */ 496bf215546Sopenharmony_ci return NULL; 497bf215546Sopenharmony_ci} 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_ci/** 500bf215546Sopenharmony_ci * Inserts the key with the given hash into the table. 501bf215546Sopenharmony_ci * 502bf215546Sopenharmony_ci * Note that insertion may rearrange the table on a resize or rehash, 503bf215546Sopenharmony_ci * so previously found hash_entries are no longer valid after this function. 504bf215546Sopenharmony_ci */ 505bf215546Sopenharmony_cistruct hash_entry * 506bf215546Sopenharmony_ci_mesa_hash_table_insert(struct hash_table *ht, const void *key, void *data) 507bf215546Sopenharmony_ci{ 508bf215546Sopenharmony_ci assert(ht->key_hash_function); 509bf215546Sopenharmony_ci return hash_table_insert(ht, ht->key_hash_function(key), key, data); 510bf215546Sopenharmony_ci} 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_cistruct hash_entry * 513bf215546Sopenharmony_ci_mesa_hash_table_insert_pre_hashed(struct hash_table *ht, uint32_t hash, 514bf215546Sopenharmony_ci const void *key, void *data) 515bf215546Sopenharmony_ci{ 516bf215546Sopenharmony_ci assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key)); 517bf215546Sopenharmony_ci return hash_table_insert(ht, hash, key, data); 518bf215546Sopenharmony_ci} 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci/** 521bf215546Sopenharmony_ci * This function deletes the given hash table entry. 522bf215546Sopenharmony_ci * 523bf215546Sopenharmony_ci * Note that deletion doesn't otherwise modify the table, so an iteration over 524bf215546Sopenharmony_ci * the table deleting entries is safe. 525bf215546Sopenharmony_ci */ 526bf215546Sopenharmony_civoid 527bf215546Sopenharmony_ci_mesa_hash_table_remove(struct hash_table *ht, 528bf215546Sopenharmony_ci struct hash_entry *entry) 529bf215546Sopenharmony_ci{ 530bf215546Sopenharmony_ci if (!entry) 531bf215546Sopenharmony_ci return; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci entry->key = ht->deleted_key; 534bf215546Sopenharmony_ci ht->entries--; 535bf215546Sopenharmony_ci ht->deleted_entries++; 536bf215546Sopenharmony_ci} 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci/** 539bf215546Sopenharmony_ci * Removes the entry with the corresponding key, if exists. 540bf215546Sopenharmony_ci */ 541bf215546Sopenharmony_civoid _mesa_hash_table_remove_key(struct hash_table *ht, 542bf215546Sopenharmony_ci const void *key) 543bf215546Sopenharmony_ci{ 544bf215546Sopenharmony_ci _mesa_hash_table_remove(ht, _mesa_hash_table_search(ht, key)); 545bf215546Sopenharmony_ci} 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci/** 548bf215546Sopenharmony_ci * This function is an iterator over the hash_table when no deleted entries are present. 549bf215546Sopenharmony_ci * 550bf215546Sopenharmony_ci * Pass in NULL for the first entry, as in the start of a for loop. 551bf215546Sopenharmony_ci */ 552bf215546Sopenharmony_cistruct hash_entry * 553bf215546Sopenharmony_ci_mesa_hash_table_next_entry_unsafe(const struct hash_table *ht, struct hash_entry *entry) 554bf215546Sopenharmony_ci{ 555bf215546Sopenharmony_ci assert(!ht->deleted_entries); 556bf215546Sopenharmony_ci if (!ht->entries) 557bf215546Sopenharmony_ci return NULL; 558bf215546Sopenharmony_ci if (entry == NULL) 559bf215546Sopenharmony_ci entry = ht->table; 560bf215546Sopenharmony_ci else 561bf215546Sopenharmony_ci entry = entry + 1; 562bf215546Sopenharmony_ci if (entry != ht->table + ht->size) 563bf215546Sopenharmony_ci return entry->key ? entry : _mesa_hash_table_next_entry_unsafe(ht, entry); 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci return NULL; 566bf215546Sopenharmony_ci} 567bf215546Sopenharmony_ci 568bf215546Sopenharmony_ci/** 569bf215546Sopenharmony_ci * This function is an iterator over the hash table. 570bf215546Sopenharmony_ci * 571bf215546Sopenharmony_ci * Pass in NULL for the first entry, as in the start of a for loop. Note that 572bf215546Sopenharmony_ci * an iteration over the table is O(table_size) not O(entries). 573bf215546Sopenharmony_ci */ 574bf215546Sopenharmony_cistruct hash_entry * 575bf215546Sopenharmony_ci_mesa_hash_table_next_entry(struct hash_table *ht, 576bf215546Sopenharmony_ci struct hash_entry *entry) 577bf215546Sopenharmony_ci{ 578bf215546Sopenharmony_ci if (entry == NULL) 579bf215546Sopenharmony_ci entry = ht->table; 580bf215546Sopenharmony_ci else 581bf215546Sopenharmony_ci entry = entry + 1; 582bf215546Sopenharmony_ci 583bf215546Sopenharmony_ci for (; entry != ht->table + ht->size; entry++) { 584bf215546Sopenharmony_ci if (entry_is_present(ht, entry)) { 585bf215546Sopenharmony_ci return entry; 586bf215546Sopenharmony_ci } 587bf215546Sopenharmony_ci } 588bf215546Sopenharmony_ci 589bf215546Sopenharmony_ci return NULL; 590bf215546Sopenharmony_ci} 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_ci/** 593bf215546Sopenharmony_ci * Returns a random entry from the hash table. 594bf215546Sopenharmony_ci * 595bf215546Sopenharmony_ci * This may be useful in implementing random replacement (as opposed 596bf215546Sopenharmony_ci * to just removing everything) in caches based on this hash table 597bf215546Sopenharmony_ci * implementation. @predicate may be used to filter entries, or may 598bf215546Sopenharmony_ci * be set to NULL for no filtering. 599bf215546Sopenharmony_ci */ 600bf215546Sopenharmony_cistruct hash_entry * 601bf215546Sopenharmony_ci_mesa_hash_table_random_entry(struct hash_table *ht, 602bf215546Sopenharmony_ci bool (*predicate)(struct hash_entry *entry)) 603bf215546Sopenharmony_ci{ 604bf215546Sopenharmony_ci struct hash_entry *entry; 605bf215546Sopenharmony_ci uint32_t i = rand() % ht->size; 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ci if (ht->entries == 0) 608bf215546Sopenharmony_ci return NULL; 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci for (entry = ht->table + i; entry != ht->table + ht->size; entry++) { 611bf215546Sopenharmony_ci if (entry_is_present(ht, entry) && 612bf215546Sopenharmony_ci (!predicate || predicate(entry))) { 613bf215546Sopenharmony_ci return entry; 614bf215546Sopenharmony_ci } 615bf215546Sopenharmony_ci } 616bf215546Sopenharmony_ci 617bf215546Sopenharmony_ci for (entry = ht->table; entry != ht->table + i; entry++) { 618bf215546Sopenharmony_ci if (entry_is_present(ht, entry) && 619bf215546Sopenharmony_ci (!predicate || predicate(entry))) { 620bf215546Sopenharmony_ci return entry; 621bf215546Sopenharmony_ci } 622bf215546Sopenharmony_ci } 623bf215546Sopenharmony_ci 624bf215546Sopenharmony_ci return NULL; 625bf215546Sopenharmony_ci} 626bf215546Sopenharmony_ci 627bf215546Sopenharmony_ci 628bf215546Sopenharmony_ciuint32_t 629bf215546Sopenharmony_ci_mesa_hash_data(const void *data, size_t size) 630bf215546Sopenharmony_ci{ 631bf215546Sopenharmony_ci return XXH32(data, size, 0); 632bf215546Sopenharmony_ci} 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ciuint32_t 635bf215546Sopenharmony_ci_mesa_hash_data_with_seed(const void *data, size_t size, uint32_t seed) 636bf215546Sopenharmony_ci{ 637bf215546Sopenharmony_ci return XXH32(data, size, seed); 638bf215546Sopenharmony_ci} 639bf215546Sopenharmony_ci 640bf215546Sopenharmony_ciuint32_t 641bf215546Sopenharmony_ci_mesa_hash_int(const void *key) 642bf215546Sopenharmony_ci{ 643bf215546Sopenharmony_ci return XXH32(key, sizeof(int), 0); 644bf215546Sopenharmony_ci} 645bf215546Sopenharmony_ci 646bf215546Sopenharmony_ciuint32_t 647bf215546Sopenharmony_ci_mesa_hash_uint(const void *key) 648bf215546Sopenharmony_ci{ 649bf215546Sopenharmony_ci return XXH32(key, sizeof(unsigned), 0); 650bf215546Sopenharmony_ci} 651bf215546Sopenharmony_ci 652bf215546Sopenharmony_ciuint32_t 653bf215546Sopenharmony_ci_mesa_hash_u32(const void *key) 654bf215546Sopenharmony_ci{ 655bf215546Sopenharmony_ci return XXH32(key, 4, 0); 656bf215546Sopenharmony_ci} 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_ci/** FNV-1a string hash implementation */ 659bf215546Sopenharmony_ciuint32_t 660bf215546Sopenharmony_ci_mesa_hash_string(const void *_key) 661bf215546Sopenharmony_ci{ 662bf215546Sopenharmony_ci return _mesa_hash_string_with_length(_key, strlen((const char *)_key)); 663bf215546Sopenharmony_ci} 664bf215546Sopenharmony_ci 665bf215546Sopenharmony_ciuint32_t 666bf215546Sopenharmony_ci_mesa_hash_string_with_length(const void *_key, unsigned length) 667bf215546Sopenharmony_ci{ 668bf215546Sopenharmony_ci uint32_t hash = 0; 669bf215546Sopenharmony_ci const char *key = _key; 670bf215546Sopenharmony_ci#if defined(_WIN64) || defined(__x86_64__) 671bf215546Sopenharmony_ci hash = (uint32_t)XXH64(key, length, hash); 672bf215546Sopenharmony_ci#else 673bf215546Sopenharmony_ci hash = XXH32(key, length, hash); 674bf215546Sopenharmony_ci#endif 675bf215546Sopenharmony_ci return hash; 676bf215546Sopenharmony_ci} 677bf215546Sopenharmony_ci 678bf215546Sopenharmony_ciuint32_t 679bf215546Sopenharmony_ci_mesa_hash_pointer(const void *pointer) 680bf215546Sopenharmony_ci{ 681bf215546Sopenharmony_ci uintptr_t num = (uintptr_t) pointer; 682bf215546Sopenharmony_ci return (uint32_t) ((num >> 2) ^ (num >> 6) ^ (num >> 10) ^ (num >> 14)); 683bf215546Sopenharmony_ci} 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_cibool 686bf215546Sopenharmony_ci_mesa_key_int_equal(const void *a, const void *b) 687bf215546Sopenharmony_ci{ 688bf215546Sopenharmony_ci return *((const int *)a) == *((const int *)b); 689bf215546Sopenharmony_ci} 690bf215546Sopenharmony_ci 691bf215546Sopenharmony_cibool 692bf215546Sopenharmony_ci_mesa_key_uint_equal(const void *a, const void *b) 693bf215546Sopenharmony_ci{ 694bf215546Sopenharmony_ci 695bf215546Sopenharmony_ci return *((const unsigned *)a) == *((const unsigned *)b); 696bf215546Sopenharmony_ci} 697bf215546Sopenharmony_ci 698bf215546Sopenharmony_cibool 699bf215546Sopenharmony_ci_mesa_key_u32_equal(const void *a, const void *b) 700bf215546Sopenharmony_ci{ 701bf215546Sopenharmony_ci return *((const uint32_t *)a) == *((const uint32_t *)b); 702bf215546Sopenharmony_ci} 703bf215546Sopenharmony_ci 704bf215546Sopenharmony_ci/** 705bf215546Sopenharmony_ci * String compare function for use as the comparison callback in 706bf215546Sopenharmony_ci * _mesa_hash_table_create(). 707bf215546Sopenharmony_ci */ 708bf215546Sopenharmony_cibool 709bf215546Sopenharmony_ci_mesa_key_string_equal(const void *a, const void *b) 710bf215546Sopenharmony_ci{ 711bf215546Sopenharmony_ci return strcmp(a, b) == 0; 712bf215546Sopenharmony_ci} 713bf215546Sopenharmony_ci 714bf215546Sopenharmony_cibool 715bf215546Sopenharmony_ci_mesa_key_pointer_equal(const void *a, const void *b) 716bf215546Sopenharmony_ci{ 717bf215546Sopenharmony_ci return a == b; 718bf215546Sopenharmony_ci} 719bf215546Sopenharmony_ci 720bf215546Sopenharmony_ci/** 721bf215546Sopenharmony_ci * Helper to create a hash table with pointer keys. 722bf215546Sopenharmony_ci */ 723bf215546Sopenharmony_cistruct hash_table * 724bf215546Sopenharmony_ci_mesa_pointer_hash_table_create(void *mem_ctx) 725bf215546Sopenharmony_ci{ 726bf215546Sopenharmony_ci return _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer, 727bf215546Sopenharmony_ci _mesa_key_pointer_equal); 728bf215546Sopenharmony_ci} 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_ci 731bf215546Sopenharmony_cibool 732bf215546Sopenharmony_ci_mesa_hash_table_reserve(struct hash_table *ht, unsigned size) 733bf215546Sopenharmony_ci{ 734bf215546Sopenharmony_ci if (size < ht->max_entries) 735bf215546Sopenharmony_ci return true; 736bf215546Sopenharmony_ci for (unsigned i = ht->size_index + 1; i < ARRAY_SIZE(hash_sizes); i++) { 737bf215546Sopenharmony_ci if (hash_sizes[i].max_entries >= size) { 738bf215546Sopenharmony_ci _mesa_hash_table_rehash(ht, i); 739bf215546Sopenharmony_ci break; 740bf215546Sopenharmony_ci } 741bf215546Sopenharmony_ci } 742bf215546Sopenharmony_ci return ht->max_entries >= size; 743bf215546Sopenharmony_ci} 744bf215546Sopenharmony_ci 745bf215546Sopenharmony_ci/** 746bf215546Sopenharmony_ci * Hash table wrapper which supports 64-bit keys. 747bf215546Sopenharmony_ci * 748bf215546Sopenharmony_ci * TODO: unify all hash table implementations. 749bf215546Sopenharmony_ci */ 750bf215546Sopenharmony_ci 751bf215546Sopenharmony_cistruct hash_key_u64 { 752bf215546Sopenharmony_ci uint64_t value; 753bf215546Sopenharmony_ci}; 754bf215546Sopenharmony_ci 755bf215546Sopenharmony_cistatic uint32_t 756bf215546Sopenharmony_cikey_u64_hash(const void *key) 757bf215546Sopenharmony_ci{ 758bf215546Sopenharmony_ci return _mesa_hash_data(key, sizeof(struct hash_key_u64)); 759bf215546Sopenharmony_ci} 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_cistatic bool 762bf215546Sopenharmony_cikey_u64_equals(const void *a, const void *b) 763bf215546Sopenharmony_ci{ 764bf215546Sopenharmony_ci const struct hash_key_u64 *aa = a; 765bf215546Sopenharmony_ci const struct hash_key_u64 *bb = b; 766bf215546Sopenharmony_ci 767bf215546Sopenharmony_ci return aa->value == bb->value; 768bf215546Sopenharmony_ci} 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci#define FREED_KEY_VALUE 0 771bf215546Sopenharmony_ci 772bf215546Sopenharmony_cistruct hash_table_u64 * 773bf215546Sopenharmony_ci_mesa_hash_table_u64_create(void *mem_ctx) 774bf215546Sopenharmony_ci{ 775bf215546Sopenharmony_ci STATIC_ASSERT(FREED_KEY_VALUE != DELETED_KEY_VALUE); 776bf215546Sopenharmony_ci struct hash_table_u64 *ht; 777bf215546Sopenharmony_ci 778bf215546Sopenharmony_ci ht = CALLOC_STRUCT(hash_table_u64); 779bf215546Sopenharmony_ci if (!ht) 780bf215546Sopenharmony_ci return NULL; 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci if (sizeof(void *) == 8) { 783bf215546Sopenharmony_ci ht->table = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer, 784bf215546Sopenharmony_ci _mesa_key_pointer_equal); 785bf215546Sopenharmony_ci } else { 786bf215546Sopenharmony_ci ht->table = _mesa_hash_table_create(mem_ctx, key_u64_hash, 787bf215546Sopenharmony_ci key_u64_equals); 788bf215546Sopenharmony_ci } 789bf215546Sopenharmony_ci 790bf215546Sopenharmony_ci if (ht->table) 791bf215546Sopenharmony_ci _mesa_hash_table_set_deleted_key(ht->table, uint_key(DELETED_KEY_VALUE)); 792bf215546Sopenharmony_ci 793bf215546Sopenharmony_ci return ht; 794bf215546Sopenharmony_ci} 795bf215546Sopenharmony_ci 796bf215546Sopenharmony_cistatic void 797bf215546Sopenharmony_ci_mesa_hash_table_u64_delete_key(struct hash_entry *entry) 798bf215546Sopenharmony_ci{ 799bf215546Sopenharmony_ci if (sizeof(void *) == 8) 800bf215546Sopenharmony_ci return; 801bf215546Sopenharmony_ci 802bf215546Sopenharmony_ci struct hash_key_u64 *_key = (struct hash_key_u64 *)entry->key; 803bf215546Sopenharmony_ci 804bf215546Sopenharmony_ci if (_key) 805bf215546Sopenharmony_ci free(_key); 806bf215546Sopenharmony_ci} 807bf215546Sopenharmony_ci 808bf215546Sopenharmony_civoid 809bf215546Sopenharmony_ci_mesa_hash_table_u64_clear(struct hash_table_u64 *ht) 810bf215546Sopenharmony_ci{ 811bf215546Sopenharmony_ci if (!ht) 812bf215546Sopenharmony_ci return; 813bf215546Sopenharmony_ci 814bf215546Sopenharmony_ci _mesa_hash_table_clear(ht->table, _mesa_hash_table_u64_delete_key); 815bf215546Sopenharmony_ci ht->freed_key_data = NULL; 816bf215546Sopenharmony_ci ht->deleted_key_data = NULL; 817bf215546Sopenharmony_ci} 818bf215546Sopenharmony_ci 819bf215546Sopenharmony_civoid 820bf215546Sopenharmony_ci_mesa_hash_table_u64_destroy(struct hash_table_u64 *ht) 821bf215546Sopenharmony_ci{ 822bf215546Sopenharmony_ci if (!ht) 823bf215546Sopenharmony_ci return; 824bf215546Sopenharmony_ci 825bf215546Sopenharmony_ci _mesa_hash_table_u64_clear(ht); 826bf215546Sopenharmony_ci _mesa_hash_table_destroy(ht->table, NULL); 827bf215546Sopenharmony_ci free(ht); 828bf215546Sopenharmony_ci} 829bf215546Sopenharmony_ci 830bf215546Sopenharmony_civoid 831bf215546Sopenharmony_ci_mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key, 832bf215546Sopenharmony_ci void *data) 833bf215546Sopenharmony_ci{ 834bf215546Sopenharmony_ci if (key == FREED_KEY_VALUE) { 835bf215546Sopenharmony_ci ht->freed_key_data = data; 836bf215546Sopenharmony_ci return; 837bf215546Sopenharmony_ci } 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci if (key == DELETED_KEY_VALUE) { 840bf215546Sopenharmony_ci ht->deleted_key_data = data; 841bf215546Sopenharmony_ci return; 842bf215546Sopenharmony_ci } 843bf215546Sopenharmony_ci 844bf215546Sopenharmony_ci if (sizeof(void *) == 8) { 845bf215546Sopenharmony_ci _mesa_hash_table_insert(ht->table, (void *)(uintptr_t)key, data); 846bf215546Sopenharmony_ci } else { 847bf215546Sopenharmony_ci struct hash_key_u64 *_key = CALLOC_STRUCT(hash_key_u64); 848bf215546Sopenharmony_ci 849bf215546Sopenharmony_ci if (!_key) 850bf215546Sopenharmony_ci return; 851bf215546Sopenharmony_ci _key->value = key; 852bf215546Sopenharmony_ci 853bf215546Sopenharmony_ci _mesa_hash_table_insert(ht->table, _key, data); 854bf215546Sopenharmony_ci } 855bf215546Sopenharmony_ci} 856bf215546Sopenharmony_ci 857bf215546Sopenharmony_cistatic struct hash_entry * 858bf215546Sopenharmony_cihash_table_u64_search(struct hash_table_u64 *ht, uint64_t key) 859bf215546Sopenharmony_ci{ 860bf215546Sopenharmony_ci if (sizeof(void *) == 8) { 861bf215546Sopenharmony_ci return _mesa_hash_table_search(ht->table, (void *)(uintptr_t)key); 862bf215546Sopenharmony_ci } else { 863bf215546Sopenharmony_ci struct hash_key_u64 _key = { .value = key }; 864bf215546Sopenharmony_ci return _mesa_hash_table_search(ht->table, &_key); 865bf215546Sopenharmony_ci } 866bf215546Sopenharmony_ci} 867bf215546Sopenharmony_ci 868bf215546Sopenharmony_civoid * 869bf215546Sopenharmony_ci_mesa_hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key) 870bf215546Sopenharmony_ci{ 871bf215546Sopenharmony_ci struct hash_entry *entry; 872bf215546Sopenharmony_ci 873bf215546Sopenharmony_ci if (key == FREED_KEY_VALUE) 874bf215546Sopenharmony_ci return ht->freed_key_data; 875bf215546Sopenharmony_ci 876bf215546Sopenharmony_ci if (key == DELETED_KEY_VALUE) 877bf215546Sopenharmony_ci return ht->deleted_key_data; 878bf215546Sopenharmony_ci 879bf215546Sopenharmony_ci entry = hash_table_u64_search(ht, key); 880bf215546Sopenharmony_ci if (!entry) 881bf215546Sopenharmony_ci return NULL; 882bf215546Sopenharmony_ci 883bf215546Sopenharmony_ci return entry->data; 884bf215546Sopenharmony_ci} 885bf215546Sopenharmony_ci 886bf215546Sopenharmony_civoid 887bf215546Sopenharmony_ci_mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key) 888bf215546Sopenharmony_ci{ 889bf215546Sopenharmony_ci struct hash_entry *entry; 890bf215546Sopenharmony_ci 891bf215546Sopenharmony_ci if (key == FREED_KEY_VALUE) { 892bf215546Sopenharmony_ci ht->freed_key_data = NULL; 893bf215546Sopenharmony_ci return; 894bf215546Sopenharmony_ci } 895bf215546Sopenharmony_ci 896bf215546Sopenharmony_ci if (key == DELETED_KEY_VALUE) { 897bf215546Sopenharmony_ci ht->deleted_key_data = NULL; 898bf215546Sopenharmony_ci return; 899bf215546Sopenharmony_ci } 900bf215546Sopenharmony_ci 901bf215546Sopenharmony_ci entry = hash_table_u64_search(ht, key); 902bf215546Sopenharmony_ci if (!entry) 903bf215546Sopenharmony_ci return; 904bf215546Sopenharmony_ci 905bf215546Sopenharmony_ci if (sizeof(void *) == 8) { 906bf215546Sopenharmony_ci _mesa_hash_table_remove(ht->table, entry); 907bf215546Sopenharmony_ci } else { 908bf215546Sopenharmony_ci struct hash_key *_key = (struct hash_key *)entry->key; 909bf215546Sopenharmony_ci 910bf215546Sopenharmony_ci _mesa_hash_table_remove(ht->table, entry); 911bf215546Sopenharmony_ci free(_key); 912bf215546Sopenharmony_ci } 913bf215546Sopenharmony_ci} 914