hash_table.c revision 01e04c3f
1af69d88dSmrg/* 2af69d88dSmrg * Copyright © 2009,2012 Intel Corporation 3af69d88dSmrg * Copyright © 1988-2004 Keith Packard and Bart Massey. 4af69d88dSmrg * 5af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 6af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 7af69d88dSmrg * to deal in the Software without restriction, including without limitation 8af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 10af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 11af69d88dSmrg * 12af69d88dSmrg * The above copyright notice and this permission notice (including the next 13af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the 14af69d88dSmrg * Software. 15af69d88dSmrg * 16af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21af69d88dSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22af69d88dSmrg * IN THE SOFTWARE. 23af69d88dSmrg * 24af69d88dSmrg * Except as contained in this notice, the names of the authors 25af69d88dSmrg * or their institutions shall not be used in advertising or 26af69d88dSmrg * otherwise to promote the sale, use or other dealings in this 27af69d88dSmrg * Software without prior written authorization from the 28af69d88dSmrg * authors. 29af69d88dSmrg * 30af69d88dSmrg * Authors: 31af69d88dSmrg * Eric Anholt <eric@anholt.net> 32af69d88dSmrg * Keith Packard <keithp@keithp.com> 33af69d88dSmrg */ 34af69d88dSmrg 35af69d88dSmrg/** 36af69d88dSmrg * Implements an open-addressing, linear-reprobing hash table. 37af69d88dSmrg * 38af69d88dSmrg * For more information, see: 39af69d88dSmrg * 40af69d88dSmrg * http://cgit.freedesktop.org/~anholt/hash_table/tree/README 41af69d88dSmrg */ 42af69d88dSmrg 43af69d88dSmrg#include <stdlib.h> 44af69d88dSmrg#include <string.h> 4501e04c3fSmrg#include <assert.h> 46af69d88dSmrg 47af69d88dSmrg#include "hash_table.h" 48af69d88dSmrg#include "ralloc.h" 49af69d88dSmrg#include "macros.h" 5001e04c3fSmrg#include "main/hash.h" 51af69d88dSmrg 52af69d88dSmrgstatic const uint32_t deleted_key_value; 53af69d88dSmrg 54af69d88dSmrg/** 55af69d88dSmrg * From Knuth -- a good choice for hash/rehash values is p, p-2 where 56af69d88dSmrg * p and p-2 are both prime. These tables are sized to have an extra 10% 57af69d88dSmrg * free to avoid exponential performance degradation as the hash table fills 58af69d88dSmrg */ 59af69d88dSmrgstatic const struct { 60af69d88dSmrg uint32_t max_entries, size, rehash; 61af69d88dSmrg} hash_sizes[] = { 62af69d88dSmrg { 2, 5, 3 }, 63af69d88dSmrg { 4, 7, 5 }, 64af69d88dSmrg { 8, 13, 11 }, 65af69d88dSmrg { 16, 19, 17 }, 66af69d88dSmrg { 32, 43, 41 }, 67af69d88dSmrg { 64, 73, 71 }, 68af69d88dSmrg { 128, 151, 149 }, 69af69d88dSmrg { 256, 283, 281 }, 70af69d88dSmrg { 512, 571, 569 }, 71af69d88dSmrg { 1024, 1153, 1151 }, 72af69d88dSmrg { 2048, 2269, 2267 }, 73af69d88dSmrg { 4096, 4519, 4517 }, 74af69d88dSmrg { 8192, 9013, 9011 }, 75af69d88dSmrg { 16384, 18043, 18041 }, 76af69d88dSmrg { 32768, 36109, 36107 }, 77af69d88dSmrg { 65536, 72091, 72089 }, 78af69d88dSmrg { 131072, 144409, 144407 }, 79af69d88dSmrg { 262144, 288361, 288359 }, 80af69d88dSmrg { 524288, 576883, 576881 }, 81af69d88dSmrg { 1048576, 1153459, 1153457 }, 82af69d88dSmrg { 2097152, 2307163, 2307161 }, 83af69d88dSmrg { 4194304, 4613893, 4613891 }, 84af69d88dSmrg { 8388608, 9227641, 9227639 }, 85af69d88dSmrg { 16777216, 18455029, 18455027 }, 86af69d88dSmrg { 33554432, 36911011, 36911009 }, 87af69d88dSmrg { 67108864, 73819861, 73819859 }, 88af69d88dSmrg { 134217728, 147639589, 147639587 }, 89af69d88dSmrg { 268435456, 295279081, 295279079 }, 90af69d88dSmrg { 536870912, 590559793, 590559791 }, 91af69d88dSmrg { 1073741824, 1181116273, 1181116271}, 92af69d88dSmrg { 2147483648ul, 2362232233ul, 2362232231ul} 93af69d88dSmrg}; 94af69d88dSmrg 95af69d88dSmrgstatic int 96af69d88dSmrgentry_is_free(const struct hash_entry *entry) 97af69d88dSmrg{ 98af69d88dSmrg return entry->key == NULL; 99af69d88dSmrg} 100af69d88dSmrg 101af69d88dSmrgstatic int 102af69d88dSmrgentry_is_deleted(const struct hash_table *ht, struct hash_entry *entry) 103af69d88dSmrg{ 104af69d88dSmrg return entry->key == ht->deleted_key; 105af69d88dSmrg} 106af69d88dSmrg 107af69d88dSmrgstatic int 108af69d88dSmrgentry_is_present(const struct hash_table *ht, struct hash_entry *entry) 109af69d88dSmrg{ 110af69d88dSmrg return entry->key != NULL && entry->key != ht->deleted_key; 111af69d88dSmrg} 112af69d88dSmrg 113af69d88dSmrgstruct hash_table * 114af69d88dSmrg_mesa_hash_table_create(void *mem_ctx, 11501e04c3fSmrg uint32_t (*key_hash_function)(const void *key), 116af69d88dSmrg bool (*key_equals_function)(const void *a, 117af69d88dSmrg const void *b)) 118af69d88dSmrg{ 119af69d88dSmrg struct hash_table *ht; 120af69d88dSmrg 121af69d88dSmrg ht = ralloc(mem_ctx, struct hash_table); 122af69d88dSmrg if (ht == NULL) 123af69d88dSmrg return NULL; 124af69d88dSmrg 125af69d88dSmrg ht->size_index = 0; 126af69d88dSmrg ht->size = hash_sizes[ht->size_index].size; 127af69d88dSmrg ht->rehash = hash_sizes[ht->size_index].rehash; 128af69d88dSmrg ht->max_entries = hash_sizes[ht->size_index].max_entries; 12901e04c3fSmrg ht->key_hash_function = key_hash_function; 130af69d88dSmrg ht->key_equals_function = key_equals_function; 131af69d88dSmrg ht->table = rzalloc_array(ht, struct hash_entry, ht->size); 132af69d88dSmrg ht->entries = 0; 133af69d88dSmrg ht->deleted_entries = 0; 134af69d88dSmrg ht->deleted_key = &deleted_key_value; 135af69d88dSmrg 136af69d88dSmrg if (ht->table == NULL) { 137af69d88dSmrg ralloc_free(ht); 138af69d88dSmrg return NULL; 139af69d88dSmrg } 140af69d88dSmrg 141af69d88dSmrg return ht; 142af69d88dSmrg} 143af69d88dSmrg 14401e04c3fSmrgstruct hash_table * 14501e04c3fSmrg_mesa_hash_table_clone(struct hash_table *src, void *dst_mem_ctx) 14601e04c3fSmrg{ 14701e04c3fSmrg struct hash_table *ht; 14801e04c3fSmrg 14901e04c3fSmrg ht = ralloc(dst_mem_ctx, struct hash_table); 15001e04c3fSmrg if (ht == NULL) 15101e04c3fSmrg return NULL; 15201e04c3fSmrg 15301e04c3fSmrg memcpy(ht, src, sizeof(struct hash_table)); 15401e04c3fSmrg 15501e04c3fSmrg ht->table = ralloc_array(ht, struct hash_entry, ht->size); 15601e04c3fSmrg if (ht->table == NULL) { 15701e04c3fSmrg ralloc_free(ht); 15801e04c3fSmrg return NULL; 15901e04c3fSmrg } 16001e04c3fSmrg 16101e04c3fSmrg memcpy(ht->table, src->table, ht->size * sizeof(struct hash_entry)); 16201e04c3fSmrg 16301e04c3fSmrg return ht; 16401e04c3fSmrg} 16501e04c3fSmrg 166af69d88dSmrg/** 167af69d88dSmrg * Frees the given hash table. 168af69d88dSmrg * 169af69d88dSmrg * If delete_function is passed, it gets called on each entry present before 170af69d88dSmrg * freeing. 171af69d88dSmrg */ 172af69d88dSmrgvoid 173af69d88dSmrg_mesa_hash_table_destroy(struct hash_table *ht, 174af69d88dSmrg void (*delete_function)(struct hash_entry *entry)) 175af69d88dSmrg{ 176af69d88dSmrg if (!ht) 177af69d88dSmrg return; 178af69d88dSmrg 179af69d88dSmrg if (delete_function) { 180af69d88dSmrg hash_table_foreach(ht, entry) { 181af69d88dSmrg delete_function(entry); 182af69d88dSmrg } 183af69d88dSmrg } 184af69d88dSmrg ralloc_free(ht); 185af69d88dSmrg} 186af69d88dSmrg 18701e04c3fSmrg/** 18801e04c3fSmrg * Deletes all entries of the given hash table without deleting the table 18901e04c3fSmrg * itself or changing its structure. 19001e04c3fSmrg * 19101e04c3fSmrg * If delete_function is passed, it gets called on each entry present. 19201e04c3fSmrg */ 19301e04c3fSmrgvoid 19401e04c3fSmrg_mesa_hash_table_clear(struct hash_table *ht, 19501e04c3fSmrg void (*delete_function)(struct hash_entry *entry)) 19601e04c3fSmrg{ 19701e04c3fSmrg struct hash_entry *entry; 19801e04c3fSmrg 19901e04c3fSmrg for (entry = ht->table; entry != ht->table + ht->size; entry++) { 20001e04c3fSmrg if (entry->key == NULL) 20101e04c3fSmrg continue; 20201e04c3fSmrg 20301e04c3fSmrg if (delete_function != NULL && entry->key != ht->deleted_key) 20401e04c3fSmrg delete_function(entry); 20501e04c3fSmrg 20601e04c3fSmrg entry->key = NULL; 20701e04c3fSmrg } 20801e04c3fSmrg 20901e04c3fSmrg ht->entries = 0; 21001e04c3fSmrg ht->deleted_entries = 0; 21101e04c3fSmrg} 21201e04c3fSmrg 213af69d88dSmrg/** Sets the value of the key pointer used for deleted entries in the table. 214af69d88dSmrg * 215af69d88dSmrg * The assumption is that usually keys are actual pointers, so we use a 216af69d88dSmrg * default value of a pointer to an arbitrary piece of storage in the library. 217af69d88dSmrg * But in some cases a consumer wants to store some other sort of value in the 218af69d88dSmrg * table, like a uint32_t, in which case that pointer may conflict with one of 219af69d88dSmrg * their valid keys. This lets that user select a safe value. 220af69d88dSmrg * 221af69d88dSmrg * This must be called before any keys are actually deleted from the table. 222af69d88dSmrg */ 223af69d88dSmrgvoid 224af69d88dSmrg_mesa_hash_table_set_deleted_key(struct hash_table *ht, const void *deleted_key) 225af69d88dSmrg{ 226af69d88dSmrg ht->deleted_key = deleted_key; 227af69d88dSmrg} 228af69d88dSmrg 22901e04c3fSmrgstatic struct hash_entry * 23001e04c3fSmrghash_table_search(struct hash_table *ht, uint32_t hash, const void *key) 231af69d88dSmrg{ 232af69d88dSmrg uint32_t start_hash_address = hash % ht->size; 233af69d88dSmrg uint32_t hash_address = start_hash_address; 234af69d88dSmrg 235af69d88dSmrg do { 236af69d88dSmrg uint32_t double_hash; 237af69d88dSmrg 238af69d88dSmrg struct hash_entry *entry = ht->table + hash_address; 239af69d88dSmrg 240af69d88dSmrg if (entry_is_free(entry)) { 241af69d88dSmrg return NULL; 242af69d88dSmrg } else if (entry_is_present(ht, entry) && entry->hash == hash) { 243af69d88dSmrg if (ht->key_equals_function(key, entry->key)) { 244af69d88dSmrg return entry; 245af69d88dSmrg } 246af69d88dSmrg } 247af69d88dSmrg 248af69d88dSmrg double_hash = 1 + hash % ht->rehash; 249af69d88dSmrg 250af69d88dSmrg hash_address = (hash_address + double_hash) % ht->size; 251af69d88dSmrg } while (hash_address != start_hash_address); 252af69d88dSmrg 253af69d88dSmrg return NULL; 254af69d88dSmrg} 255af69d88dSmrg 25601e04c3fSmrg/** 25701e04c3fSmrg * Finds a hash table entry with the given key and hash of that key. 25801e04c3fSmrg * 25901e04c3fSmrg * Returns NULL if no entry is found. Note that the data pointer may be 26001e04c3fSmrg * modified by the user. 26101e04c3fSmrg */ 26201e04c3fSmrgstruct hash_entry * 26301e04c3fSmrg_mesa_hash_table_search(struct hash_table *ht, const void *key) 26401e04c3fSmrg{ 26501e04c3fSmrg assert(ht->key_hash_function); 26601e04c3fSmrg return hash_table_search(ht, ht->key_hash_function(key), key); 26701e04c3fSmrg} 26801e04c3fSmrg 26901e04c3fSmrgstruct hash_entry * 27001e04c3fSmrg_mesa_hash_table_search_pre_hashed(struct hash_table *ht, uint32_t hash, 27101e04c3fSmrg const void *key) 27201e04c3fSmrg{ 27301e04c3fSmrg assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key)); 27401e04c3fSmrg return hash_table_search(ht, hash, key); 27501e04c3fSmrg} 27601e04c3fSmrg 27701e04c3fSmrgstatic struct hash_entry * 27801e04c3fSmrghash_table_insert(struct hash_table *ht, uint32_t hash, 27901e04c3fSmrg const void *key, void *data); 28001e04c3fSmrg 281af69d88dSmrgstatic void 28201e04c3fSmrg_mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index) 283af69d88dSmrg{ 284af69d88dSmrg struct hash_table old_ht; 28501e04c3fSmrg struct hash_entry *table; 286af69d88dSmrg 287af69d88dSmrg if (new_size_index >= ARRAY_SIZE(hash_sizes)) 288af69d88dSmrg return; 289af69d88dSmrg 290af69d88dSmrg table = rzalloc_array(ht, struct hash_entry, 291af69d88dSmrg hash_sizes[new_size_index].size); 292af69d88dSmrg if (table == NULL) 293af69d88dSmrg return; 294af69d88dSmrg 295af69d88dSmrg old_ht = *ht; 296af69d88dSmrg 297af69d88dSmrg ht->table = table; 298af69d88dSmrg ht->size_index = new_size_index; 299af69d88dSmrg ht->size = hash_sizes[ht->size_index].size; 300af69d88dSmrg ht->rehash = hash_sizes[ht->size_index].rehash; 301af69d88dSmrg ht->max_entries = hash_sizes[ht->size_index].max_entries; 302af69d88dSmrg ht->entries = 0; 303af69d88dSmrg ht->deleted_entries = 0; 304af69d88dSmrg 305af69d88dSmrg hash_table_foreach(&old_ht, entry) { 30601e04c3fSmrg hash_table_insert(ht, entry->hash, entry->key, entry->data); 307af69d88dSmrg } 308af69d88dSmrg 309af69d88dSmrg ralloc_free(old_ht.table); 310af69d88dSmrg} 311af69d88dSmrg 31201e04c3fSmrgstatic struct hash_entry * 31301e04c3fSmrghash_table_insert(struct hash_table *ht, uint32_t hash, 31401e04c3fSmrg const void *key, void *data) 315af69d88dSmrg{ 316af69d88dSmrg uint32_t start_hash_address, hash_address; 31701e04c3fSmrg struct hash_entry *available_entry = NULL; 31801e04c3fSmrg 31901e04c3fSmrg assert(key != NULL); 320af69d88dSmrg 321af69d88dSmrg if (ht->entries >= ht->max_entries) { 322af69d88dSmrg _mesa_hash_table_rehash(ht, ht->size_index + 1); 323af69d88dSmrg } else if (ht->deleted_entries + ht->entries >= ht->max_entries) { 324af69d88dSmrg _mesa_hash_table_rehash(ht, ht->size_index); 325af69d88dSmrg } 326af69d88dSmrg 327af69d88dSmrg start_hash_address = hash % ht->size; 328af69d88dSmrg hash_address = start_hash_address; 329af69d88dSmrg do { 330af69d88dSmrg struct hash_entry *entry = ht->table + hash_address; 331af69d88dSmrg uint32_t double_hash; 332af69d88dSmrg 333af69d88dSmrg if (!entry_is_present(ht, entry)) { 33401e04c3fSmrg /* Stash the first available entry we find */ 33501e04c3fSmrg if (available_entry == NULL) 33601e04c3fSmrg available_entry = entry; 33701e04c3fSmrg if (entry_is_free(entry)) 33801e04c3fSmrg break; 339af69d88dSmrg } 340af69d88dSmrg 341af69d88dSmrg /* Implement replacement when another insert happens 342af69d88dSmrg * with a matching key. This is a relatively common 343af69d88dSmrg * feature of hash tables, with the alternative 344af69d88dSmrg * generally being "insert the new value as well, and 345af69d88dSmrg * return it first when the key is searched for". 346af69d88dSmrg * 347af69d88dSmrg * Note that the hash table doesn't have a delete 348af69d88dSmrg * callback. If freeing of old data pointers is 349af69d88dSmrg * required to avoid memory leaks, perform a search 350af69d88dSmrg * before inserting. 351af69d88dSmrg */ 35201e04c3fSmrg if (!entry_is_deleted(ht, entry) && 35301e04c3fSmrg entry->hash == hash && 354af69d88dSmrg ht->key_equals_function(key, entry->key)) { 355af69d88dSmrg entry->key = key; 356af69d88dSmrg entry->data = data; 357af69d88dSmrg return entry; 358af69d88dSmrg } 359af69d88dSmrg 360af69d88dSmrg 361af69d88dSmrg double_hash = 1 + hash % ht->rehash; 362af69d88dSmrg 363af69d88dSmrg hash_address = (hash_address + double_hash) % ht->size; 364af69d88dSmrg } while (hash_address != start_hash_address); 365af69d88dSmrg 36601e04c3fSmrg if (available_entry) { 36701e04c3fSmrg if (entry_is_deleted(ht, available_entry)) 36801e04c3fSmrg ht->deleted_entries--; 36901e04c3fSmrg available_entry->hash = hash; 37001e04c3fSmrg available_entry->key = key; 37101e04c3fSmrg available_entry->data = data; 37201e04c3fSmrg ht->entries++; 37301e04c3fSmrg return available_entry; 37401e04c3fSmrg } 37501e04c3fSmrg 376af69d88dSmrg /* We could hit here if a required resize failed. An unchecked-malloc 377af69d88dSmrg * application could ignore this result. 378af69d88dSmrg */ 379af69d88dSmrg return NULL; 380af69d88dSmrg} 381af69d88dSmrg 38201e04c3fSmrg/** 38301e04c3fSmrg * Inserts the key with the given hash into the table. 38401e04c3fSmrg * 38501e04c3fSmrg * Note that insertion may rearrange the table on a resize or rehash, 38601e04c3fSmrg * so previously found hash_entries are no longer valid after this function. 38701e04c3fSmrg */ 38801e04c3fSmrgstruct hash_entry * 38901e04c3fSmrg_mesa_hash_table_insert(struct hash_table *ht, const void *key, void *data) 39001e04c3fSmrg{ 39101e04c3fSmrg assert(ht->key_hash_function); 39201e04c3fSmrg return hash_table_insert(ht, ht->key_hash_function(key), key, data); 39301e04c3fSmrg} 39401e04c3fSmrg 39501e04c3fSmrgstruct hash_entry * 39601e04c3fSmrg_mesa_hash_table_insert_pre_hashed(struct hash_table *ht, uint32_t hash, 39701e04c3fSmrg const void *key, void *data) 39801e04c3fSmrg{ 39901e04c3fSmrg assert(ht->key_hash_function == NULL || hash == ht->key_hash_function(key)); 40001e04c3fSmrg return hash_table_insert(ht, hash, key, data); 40101e04c3fSmrg} 40201e04c3fSmrg 403af69d88dSmrg/** 404af69d88dSmrg * This function deletes the given hash table entry. 405af69d88dSmrg * 406af69d88dSmrg * Note that deletion doesn't otherwise modify the table, so an iteration over 407af69d88dSmrg * the table deleting entries is safe. 408af69d88dSmrg */ 409af69d88dSmrgvoid 410af69d88dSmrg_mesa_hash_table_remove(struct hash_table *ht, 411af69d88dSmrg struct hash_entry *entry) 412af69d88dSmrg{ 413af69d88dSmrg if (!entry) 414af69d88dSmrg return; 415af69d88dSmrg 416af69d88dSmrg entry->key = ht->deleted_key; 417af69d88dSmrg ht->entries--; 418af69d88dSmrg ht->deleted_entries++; 419af69d88dSmrg} 420af69d88dSmrg 42101e04c3fSmrg/** 42201e04c3fSmrg * Removes the entry with the corresponding key, if exists. 42301e04c3fSmrg */ 42401e04c3fSmrgvoid _mesa_hash_table_remove_key(struct hash_table *ht, 42501e04c3fSmrg const void *key) 42601e04c3fSmrg{ 42701e04c3fSmrg _mesa_hash_table_remove(ht, _mesa_hash_table_search(ht, key)); 42801e04c3fSmrg} 42901e04c3fSmrg 430af69d88dSmrg/** 431af69d88dSmrg * This function is an iterator over the hash table. 432af69d88dSmrg * 433af69d88dSmrg * Pass in NULL for the first entry, as in the start of a for loop. Note that 434af69d88dSmrg * an iteration over the table is O(table_size) not O(entries). 435af69d88dSmrg */ 436af69d88dSmrgstruct hash_entry * 437af69d88dSmrg_mesa_hash_table_next_entry(struct hash_table *ht, 438af69d88dSmrg struct hash_entry *entry) 439af69d88dSmrg{ 440af69d88dSmrg if (entry == NULL) 441af69d88dSmrg entry = ht->table; 442af69d88dSmrg else 443af69d88dSmrg entry = entry + 1; 444af69d88dSmrg 445af69d88dSmrg for (; entry != ht->table + ht->size; entry++) { 446af69d88dSmrg if (entry_is_present(ht, entry)) { 447af69d88dSmrg return entry; 448af69d88dSmrg } 449af69d88dSmrg } 450af69d88dSmrg 451af69d88dSmrg return NULL; 452af69d88dSmrg} 453af69d88dSmrg 454af69d88dSmrg/** 455af69d88dSmrg * Returns a random entry from the hash table. 456af69d88dSmrg * 457af69d88dSmrg * This may be useful in implementing random replacement (as opposed 458af69d88dSmrg * to just removing everything) in caches based on this hash table 459af69d88dSmrg * implementation. @predicate may be used to filter entries, or may 460af69d88dSmrg * be set to NULL for no filtering. 461af69d88dSmrg */ 462af69d88dSmrgstruct hash_entry * 463af69d88dSmrg_mesa_hash_table_random_entry(struct hash_table *ht, 464af69d88dSmrg bool (*predicate)(struct hash_entry *entry)) 465af69d88dSmrg{ 466af69d88dSmrg struct hash_entry *entry; 467af69d88dSmrg uint32_t i = rand() % ht->size; 468af69d88dSmrg 469af69d88dSmrg if (ht->entries == 0) 470af69d88dSmrg return NULL; 471af69d88dSmrg 472af69d88dSmrg for (entry = ht->table + i; entry != ht->table + ht->size; entry++) { 473af69d88dSmrg if (entry_is_present(ht, entry) && 474af69d88dSmrg (!predicate || predicate(entry))) { 475af69d88dSmrg return entry; 476af69d88dSmrg } 477af69d88dSmrg } 478af69d88dSmrg 479af69d88dSmrg for (entry = ht->table; entry != ht->table + i; entry++) { 480af69d88dSmrg if (entry_is_present(ht, entry) && 481af69d88dSmrg (!predicate || predicate(entry))) { 482af69d88dSmrg return entry; 483af69d88dSmrg } 484af69d88dSmrg } 485af69d88dSmrg 486af69d88dSmrg return NULL; 487af69d88dSmrg} 488af69d88dSmrg 489af69d88dSmrg 490af69d88dSmrg/** 49101e04c3fSmrg * Quick FNV-1a hash implementation based on: 492af69d88dSmrg * http://www.isthe.com/chongo/tech/comp/fnv/ 493af69d88dSmrg * 49401e04c3fSmrg * FNV-1a is not be the best hash out there -- Jenkins's lookup3 is supposed 49501e04c3fSmrg * to be quite good, and it probably beats FNV. But FNV has the advantage 49601e04c3fSmrg * that it involves almost no code. For an improvement on both, see Paul 497af69d88dSmrg * Hsieh's http://www.azillionmonkeys.com/qed/hash.html 498af69d88dSmrg */ 499af69d88dSmrguint32_t 500af69d88dSmrg_mesa_hash_data(const void *data, size_t size) 501af69d88dSmrg{ 50201e04c3fSmrg return _mesa_fnv32_1a_accumulate_block(_mesa_fnv32_1a_offset_bias, 50301e04c3fSmrg data, size); 504af69d88dSmrg} 505af69d88dSmrg 50601e04c3fSmrg/** FNV-1a string hash implementation */ 507af69d88dSmrguint32_t 50801e04c3fSmrg_mesa_hash_string(const void *_key) 509af69d88dSmrg{ 51001e04c3fSmrg uint32_t hash = _mesa_fnv32_1a_offset_bias; 51101e04c3fSmrg const char *key = _key; 512af69d88dSmrg 513af69d88dSmrg while (*key != 0) { 51401e04c3fSmrg hash = _mesa_fnv32_1a_accumulate(hash, *key); 515af69d88dSmrg key++; 516af69d88dSmrg } 517af69d88dSmrg 518af69d88dSmrg return hash; 519af69d88dSmrg} 520af69d88dSmrg 521af69d88dSmrg/** 522af69d88dSmrg * String compare function for use as the comparison callback in 523af69d88dSmrg * _mesa_hash_table_create(). 524af69d88dSmrg */ 525af69d88dSmrgbool 526af69d88dSmrg_mesa_key_string_equal(const void *a, const void *b) 527af69d88dSmrg{ 528af69d88dSmrg return strcmp(a, b) == 0; 529af69d88dSmrg} 530af69d88dSmrg 531af69d88dSmrgbool 532af69d88dSmrg_mesa_key_pointer_equal(const void *a, const void *b) 533af69d88dSmrg{ 534af69d88dSmrg return a == b; 535af69d88dSmrg} 53601e04c3fSmrg 53701e04c3fSmrg/** 53801e04c3fSmrg * Hash table wrapper which supports 64-bit keys. 53901e04c3fSmrg * 54001e04c3fSmrg * TODO: unify all hash table implementations. 54101e04c3fSmrg */ 54201e04c3fSmrg 54301e04c3fSmrgstruct hash_key_u64 { 54401e04c3fSmrg uint64_t value; 54501e04c3fSmrg}; 54601e04c3fSmrg 54701e04c3fSmrgstatic uint32_t 54801e04c3fSmrgkey_u64_hash(const void *key) 54901e04c3fSmrg{ 55001e04c3fSmrg return _mesa_hash_data(key, sizeof(struct hash_key_u64)); 55101e04c3fSmrg} 55201e04c3fSmrg 55301e04c3fSmrgstatic bool 55401e04c3fSmrgkey_u64_equals(const void *a, const void *b) 55501e04c3fSmrg{ 55601e04c3fSmrg const struct hash_key_u64 *aa = a; 55701e04c3fSmrg const struct hash_key_u64 *bb = b; 55801e04c3fSmrg 55901e04c3fSmrg return aa->value == bb->value; 56001e04c3fSmrg} 56101e04c3fSmrg 56201e04c3fSmrgstruct hash_table_u64 * 56301e04c3fSmrg_mesa_hash_table_u64_create(void *mem_ctx) 56401e04c3fSmrg{ 56501e04c3fSmrg struct hash_table_u64 *ht; 56601e04c3fSmrg 56701e04c3fSmrg ht = CALLOC_STRUCT(hash_table_u64); 56801e04c3fSmrg if (!ht) 56901e04c3fSmrg return NULL; 57001e04c3fSmrg 57101e04c3fSmrg if (sizeof(void *) == 8) { 57201e04c3fSmrg ht->table = _mesa_hash_table_create(mem_ctx, _mesa_hash_pointer, 57301e04c3fSmrg _mesa_key_pointer_equal); 57401e04c3fSmrg } else { 57501e04c3fSmrg ht->table = _mesa_hash_table_create(mem_ctx, key_u64_hash, 57601e04c3fSmrg key_u64_equals); 57701e04c3fSmrg } 57801e04c3fSmrg 57901e04c3fSmrg if (ht->table) 58001e04c3fSmrg _mesa_hash_table_set_deleted_key(ht->table, uint_key(DELETED_KEY_VALUE)); 58101e04c3fSmrg 58201e04c3fSmrg return ht; 58301e04c3fSmrg} 58401e04c3fSmrg 58501e04c3fSmrgvoid 58601e04c3fSmrg_mesa_hash_table_u64_destroy(struct hash_table_u64 *ht, 58701e04c3fSmrg void (*delete_function)(struct hash_entry *entry)) 58801e04c3fSmrg{ 58901e04c3fSmrg if (!ht) 59001e04c3fSmrg return; 59101e04c3fSmrg 59201e04c3fSmrg if (ht->deleted_key_data) { 59301e04c3fSmrg if (delete_function) { 59401e04c3fSmrg struct hash_table *table = ht->table; 59501e04c3fSmrg struct hash_entry deleted_entry; 59601e04c3fSmrg 59701e04c3fSmrg /* Create a fake entry for the delete function. */ 59801e04c3fSmrg deleted_entry.hash = table->key_hash_function(table->deleted_key); 59901e04c3fSmrg deleted_entry.key = table->deleted_key; 60001e04c3fSmrg deleted_entry.data = ht->deleted_key_data; 60101e04c3fSmrg 60201e04c3fSmrg delete_function(&deleted_entry); 60301e04c3fSmrg } 60401e04c3fSmrg ht->deleted_key_data = NULL; 60501e04c3fSmrg } 60601e04c3fSmrg 60701e04c3fSmrg _mesa_hash_table_destroy(ht->table, delete_function); 60801e04c3fSmrg free(ht); 60901e04c3fSmrg} 61001e04c3fSmrg 61101e04c3fSmrgvoid 61201e04c3fSmrg_mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key, 61301e04c3fSmrg void *data) 61401e04c3fSmrg{ 61501e04c3fSmrg if (key == DELETED_KEY_VALUE) { 61601e04c3fSmrg ht->deleted_key_data = data; 61701e04c3fSmrg return; 61801e04c3fSmrg } 61901e04c3fSmrg 62001e04c3fSmrg if (sizeof(void *) == 8) { 62101e04c3fSmrg _mesa_hash_table_insert(ht->table, (void *)(uintptr_t)key, data); 62201e04c3fSmrg } else { 62301e04c3fSmrg struct hash_key_u64 *_key = CALLOC_STRUCT(hash_key_u64); 62401e04c3fSmrg 62501e04c3fSmrg if (!_key) 62601e04c3fSmrg return; 62701e04c3fSmrg _key->value = key; 62801e04c3fSmrg 62901e04c3fSmrg _mesa_hash_table_insert(ht->table, _key, data); 63001e04c3fSmrg } 63101e04c3fSmrg} 63201e04c3fSmrg 63301e04c3fSmrgstatic struct hash_entry * 63401e04c3fSmrghash_table_u64_search(struct hash_table_u64 *ht, uint64_t key) 63501e04c3fSmrg{ 63601e04c3fSmrg if (sizeof(void *) == 8) { 63701e04c3fSmrg return _mesa_hash_table_search(ht->table, (void *)(uintptr_t)key); 63801e04c3fSmrg } else { 63901e04c3fSmrg struct hash_key_u64 _key = { .value = key }; 64001e04c3fSmrg return _mesa_hash_table_search(ht->table, &_key); 64101e04c3fSmrg } 64201e04c3fSmrg} 64301e04c3fSmrg 64401e04c3fSmrgvoid * 64501e04c3fSmrg_mesa_hash_table_u64_search(struct hash_table_u64 *ht, uint64_t key) 64601e04c3fSmrg{ 64701e04c3fSmrg struct hash_entry *entry; 64801e04c3fSmrg 64901e04c3fSmrg if (key == DELETED_KEY_VALUE) 65001e04c3fSmrg return ht->deleted_key_data; 65101e04c3fSmrg 65201e04c3fSmrg entry = hash_table_u64_search(ht, key); 65301e04c3fSmrg if (!entry) 65401e04c3fSmrg return NULL; 65501e04c3fSmrg 65601e04c3fSmrg return entry->data; 65701e04c3fSmrg} 65801e04c3fSmrg 65901e04c3fSmrgvoid 66001e04c3fSmrg_mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key) 66101e04c3fSmrg{ 66201e04c3fSmrg struct hash_entry *entry; 66301e04c3fSmrg 66401e04c3fSmrg if (key == DELETED_KEY_VALUE) { 66501e04c3fSmrg ht->deleted_key_data = NULL; 66601e04c3fSmrg return; 66701e04c3fSmrg } 66801e04c3fSmrg 66901e04c3fSmrg entry = hash_table_u64_search(ht, key); 67001e04c3fSmrg if (!entry) 67101e04c3fSmrg return; 67201e04c3fSmrg 67301e04c3fSmrg if (sizeof(void *) == 8) { 67401e04c3fSmrg _mesa_hash_table_remove(ht->table, entry); 67501e04c3fSmrg } else { 67601e04c3fSmrg struct hash_key *_key = (struct hash_key *)entry->key; 67701e04c3fSmrg 67801e04c3fSmrg _mesa_hash_table_remove(ht->table, entry); 67901e04c3fSmrg free(_key); 68001e04c3fSmrg } 68101e04c3fSmrg} 682