101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2009-2012 Intel Corporation 301e04c3fSmrg * Copyright © 1988-2004 Keith Packard and Bart Massey. 401e04c3fSmrg * 501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 601e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 701e04c3fSmrg * to deal in the Software without restriction, including without limitation 801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1101e04c3fSmrg * 1201e04c3fSmrg * The above copyright notice and this permission notice (including the next 1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1401e04c3fSmrg * Software. 1501e04c3fSmrg * 1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2201e04c3fSmrg * IN THE SOFTWARE. 2301e04c3fSmrg * 2401e04c3fSmrg * Except as contained in this notice, the names of the authors 2501e04c3fSmrg * or their institutions shall not be used in advertising or 2601e04c3fSmrg * otherwise to promote the sale, use or other dealings in this 2701e04c3fSmrg * Software without prior written authorization from the 2801e04c3fSmrg * authors. 2901e04c3fSmrg * 3001e04c3fSmrg * Authors: 3101e04c3fSmrg * Eric Anholt <eric@anholt.net> 3201e04c3fSmrg * Keith Packard <keithp@keithp.com> 3301e04c3fSmrg */ 3401e04c3fSmrg 3501e04c3fSmrg#include <stdlib.h> 3601e04c3fSmrg#include <assert.h> 3701e04c3fSmrg#include <string.h> 3801e04c3fSmrg 398a1362adSmaya#include "hash_table.h" 4001e04c3fSmrg#include "macros.h" 4101e04c3fSmrg#include "ralloc.h" 4201e04c3fSmrg#include "set.h" 437ec681f3Smrg#include "fast_urem_by_const.h" 4401e04c3fSmrg 4501e04c3fSmrg/* 4601e04c3fSmrg * From Knuth -- a good choice for hash/rehash values is p, p-2 where 4701e04c3fSmrg * p and p-2 are both prime. These tables are sized to have an extra 10% 4801e04c3fSmrg * free to avoid exponential performance degradation as the hash table fills 4901e04c3fSmrg */ 5001e04c3fSmrg 5101e04c3fSmrgstatic const uint32_t deleted_key_value; 5201e04c3fSmrgstatic const void *deleted_key = &deleted_key_value; 5301e04c3fSmrg 5401e04c3fSmrgstatic const struct { 5501e04c3fSmrg uint32_t max_entries, size, rehash; 567ec681f3Smrg uint64_t size_magic, rehash_magic; 5701e04c3fSmrg} hash_sizes[] = { 587ec681f3Smrg#define ENTRY(max_entries, size, rehash) \ 597ec681f3Smrg { max_entries, size, rehash, \ 607ec681f3Smrg REMAINDER_MAGIC(size), REMAINDER_MAGIC(rehash) } 617ec681f3Smrg 627ec681f3Smrg ENTRY(2, 5, 3 ), 637ec681f3Smrg ENTRY(4, 7, 5 ), 647ec681f3Smrg ENTRY(8, 13, 11 ), 657ec681f3Smrg ENTRY(16, 19, 17 ), 667ec681f3Smrg ENTRY(32, 43, 41 ), 677ec681f3Smrg ENTRY(64, 73, 71 ), 687ec681f3Smrg ENTRY(128, 151, 149 ), 697ec681f3Smrg ENTRY(256, 283, 281 ), 707ec681f3Smrg ENTRY(512, 571, 569 ), 717ec681f3Smrg ENTRY(1024, 1153, 1151 ), 727ec681f3Smrg ENTRY(2048, 2269, 2267 ), 737ec681f3Smrg ENTRY(4096, 4519, 4517 ), 747ec681f3Smrg ENTRY(8192, 9013, 9011 ), 757ec681f3Smrg ENTRY(16384, 18043, 18041 ), 767ec681f3Smrg ENTRY(32768, 36109, 36107 ), 777ec681f3Smrg ENTRY(65536, 72091, 72089 ), 787ec681f3Smrg ENTRY(131072, 144409, 144407 ), 797ec681f3Smrg ENTRY(262144, 288361, 288359 ), 807ec681f3Smrg ENTRY(524288, 576883, 576881 ), 817ec681f3Smrg ENTRY(1048576, 1153459, 1153457 ), 827ec681f3Smrg ENTRY(2097152, 2307163, 2307161 ), 837ec681f3Smrg ENTRY(4194304, 4613893, 4613891 ), 847ec681f3Smrg ENTRY(8388608, 9227641, 9227639 ), 857ec681f3Smrg ENTRY(16777216, 18455029, 18455027 ), 867ec681f3Smrg ENTRY(33554432, 36911011, 36911009 ), 877ec681f3Smrg ENTRY(67108864, 73819861, 73819859 ), 887ec681f3Smrg ENTRY(134217728, 147639589, 147639587 ), 897ec681f3Smrg ENTRY(268435456, 295279081, 295279079 ), 907ec681f3Smrg ENTRY(536870912, 590559793, 590559791 ), 917ec681f3Smrg ENTRY(1073741824, 1181116273, 1181116271 ), 927ec681f3Smrg ENTRY(2147483648ul, 2362232233ul, 2362232231ul ) 9301e04c3fSmrg}; 9401e04c3fSmrg 957ec681f3SmrgASSERTED static inline bool 967ec681f3Smrgkey_pointer_is_reserved(const void *key) 977ec681f3Smrg{ 987ec681f3Smrg return key == NULL || key == deleted_key; 997ec681f3Smrg} 1007ec681f3Smrg 10101e04c3fSmrgstatic int 10201e04c3fSmrgentry_is_free(struct set_entry *entry) 10301e04c3fSmrg{ 10401e04c3fSmrg return entry->key == NULL; 10501e04c3fSmrg} 10601e04c3fSmrg 10701e04c3fSmrgstatic int 10801e04c3fSmrgentry_is_deleted(struct set_entry *entry) 10901e04c3fSmrg{ 11001e04c3fSmrg return entry->key == deleted_key; 11101e04c3fSmrg} 11201e04c3fSmrg 11301e04c3fSmrgstatic int 11401e04c3fSmrgentry_is_present(struct set_entry *entry) 11501e04c3fSmrg{ 11601e04c3fSmrg return entry->key != NULL && entry->key != deleted_key; 11701e04c3fSmrg} 11801e04c3fSmrg 1197ec681f3Smrgbool 1207ec681f3Smrg_mesa_set_init(struct set *ht, void *mem_ctx, 12101e04c3fSmrg uint32_t (*key_hash_function)(const void *key), 12201e04c3fSmrg bool (*key_equals_function)(const void *a, 12301e04c3fSmrg const void *b)) 12401e04c3fSmrg{ 12501e04c3fSmrg ht->size_index = 0; 12601e04c3fSmrg ht->size = hash_sizes[ht->size_index].size; 12701e04c3fSmrg ht->rehash = hash_sizes[ht->size_index].rehash; 1287ec681f3Smrg ht->size_magic = hash_sizes[ht->size_index].size_magic; 1297ec681f3Smrg ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic; 13001e04c3fSmrg ht->max_entries = hash_sizes[ht->size_index].max_entries; 13101e04c3fSmrg ht->key_hash_function = key_hash_function; 13201e04c3fSmrg ht->key_equals_function = key_equals_function; 1337ec681f3Smrg ht->table = rzalloc_array(mem_ctx, struct set_entry, ht->size); 13401e04c3fSmrg ht->entries = 0; 13501e04c3fSmrg ht->deleted_entries = 0; 13601e04c3fSmrg 1377ec681f3Smrg return ht->table != NULL; 1387ec681f3Smrg} 1397ec681f3Smrg 1407ec681f3Smrgstruct set * 1417ec681f3Smrg_mesa_set_create(void *mem_ctx, 1427ec681f3Smrg uint32_t (*key_hash_function)(const void *key), 1437ec681f3Smrg bool (*key_equals_function)(const void *a, 1447ec681f3Smrg const void *b)) 1457ec681f3Smrg{ 1467ec681f3Smrg struct set *ht; 1477ec681f3Smrg 1487ec681f3Smrg ht = ralloc(mem_ctx, struct set); 1497ec681f3Smrg if (ht == NULL) 1507ec681f3Smrg return NULL; 1517ec681f3Smrg 1527ec681f3Smrg if (!_mesa_set_init(ht, ht, key_hash_function, key_equals_function)) { 15301e04c3fSmrg ralloc_free(ht); 15401e04c3fSmrg return NULL; 15501e04c3fSmrg } 15601e04c3fSmrg 15701e04c3fSmrg return ht; 15801e04c3fSmrg} 15901e04c3fSmrg 1607ec681f3Smrgstatic uint32_t 1617ec681f3Smrgkey_u32_hash(const void *key) 1627ec681f3Smrg{ 1637ec681f3Smrg uint32_t u = (uint32_t)(uintptr_t)key; 1647ec681f3Smrg return _mesa_hash_uint(&u); 1657ec681f3Smrg} 1667ec681f3Smrg 1677ec681f3Smrgstatic bool 1687ec681f3Smrgkey_u32_equals(const void *a, const void *b) 1697ec681f3Smrg{ 1707ec681f3Smrg return (uint32_t)(uintptr_t)a == (uint32_t)(uintptr_t)b; 1717ec681f3Smrg} 1727ec681f3Smrg 1737ec681f3Smrg/* key == 0 and key == deleted_key are not allowed */ 1747ec681f3Smrgstruct set * 1757ec681f3Smrg_mesa_set_create_u32_keys(void *mem_ctx) 1767ec681f3Smrg{ 1777ec681f3Smrg return _mesa_set_create(mem_ctx, key_u32_hash, key_u32_equals); 1787ec681f3Smrg} 1797ec681f3Smrg 18001e04c3fSmrgstruct set * 18101e04c3fSmrg_mesa_set_clone(struct set *set, void *dst_mem_ctx) 18201e04c3fSmrg{ 18301e04c3fSmrg struct set *clone; 18401e04c3fSmrg 18501e04c3fSmrg clone = ralloc(dst_mem_ctx, struct set); 18601e04c3fSmrg if (clone == NULL) 18701e04c3fSmrg return NULL; 18801e04c3fSmrg 18901e04c3fSmrg memcpy(clone, set, sizeof(struct set)); 19001e04c3fSmrg 19101e04c3fSmrg clone->table = ralloc_array(clone, struct set_entry, clone->size); 19201e04c3fSmrg if (clone->table == NULL) { 19301e04c3fSmrg ralloc_free(clone); 19401e04c3fSmrg return NULL; 19501e04c3fSmrg } 19601e04c3fSmrg 19701e04c3fSmrg memcpy(clone->table, set->table, clone->size * sizeof(struct set_entry)); 19801e04c3fSmrg 19901e04c3fSmrg return clone; 20001e04c3fSmrg} 20101e04c3fSmrg 20201e04c3fSmrg/** 20301e04c3fSmrg * Frees the given set. 20401e04c3fSmrg * 20501e04c3fSmrg * If delete_function is passed, it gets called on each entry present before 20601e04c3fSmrg * freeing. 20701e04c3fSmrg */ 20801e04c3fSmrgvoid 20901e04c3fSmrg_mesa_set_destroy(struct set *ht, void (*delete_function)(struct set_entry *entry)) 21001e04c3fSmrg{ 21101e04c3fSmrg if (!ht) 21201e04c3fSmrg return; 21301e04c3fSmrg 21401e04c3fSmrg if (delete_function) { 21501e04c3fSmrg set_foreach (ht, entry) { 21601e04c3fSmrg delete_function(entry); 21701e04c3fSmrg } 21801e04c3fSmrg } 21901e04c3fSmrg ralloc_free(ht->table); 22001e04c3fSmrg ralloc_free(ht); 22101e04c3fSmrg} 22201e04c3fSmrg 2237ec681f3Smrg 2247ec681f3Smrgstatic void 2257ec681f3Smrgset_clear_fast(struct set *ht) 2267ec681f3Smrg{ 2277ec681f3Smrg memset(ht->table, 0, sizeof(struct set_entry) * hash_sizes[ht->size_index].size); 2287ec681f3Smrg ht->entries = ht->deleted_entries = 0; 2297ec681f3Smrg} 2307ec681f3Smrg 23101e04c3fSmrg/** 23201e04c3fSmrg * Clears all values from the given set. 23301e04c3fSmrg * 23401e04c3fSmrg * If delete_function is passed, it gets called on each entry present before 23501e04c3fSmrg * the set is cleared. 23601e04c3fSmrg */ 23701e04c3fSmrgvoid 23801e04c3fSmrg_mesa_set_clear(struct set *set, void (*delete_function)(struct set_entry *entry)) 23901e04c3fSmrg{ 24001e04c3fSmrg if (!set) 24101e04c3fSmrg return; 24201e04c3fSmrg 2437ec681f3Smrg struct set_entry *entry; 24401e04c3fSmrg 2457ec681f3Smrg if (delete_function) { 2467ec681f3Smrg for (entry = set->table; entry != set->table + set->size; entry++) { 2477ec681f3Smrg if (entry_is_present(entry)) 2487ec681f3Smrg delete_function(entry); 2497ec681f3Smrg 2507ec681f3Smrg entry->key = NULL; 2517ec681f3Smrg } 2527ec681f3Smrg set->entries = 0; 2537ec681f3Smrg set->deleted_entries = 0; 2547ec681f3Smrg } else 2557ec681f3Smrg set_clear_fast(set); 25601e04c3fSmrg} 25701e04c3fSmrg 25801e04c3fSmrg/** 25901e04c3fSmrg * Finds a set entry with the given key and hash of that key. 26001e04c3fSmrg * 26101e04c3fSmrg * Returns NULL if no entry is found. 26201e04c3fSmrg */ 26301e04c3fSmrgstatic struct set_entry * 26401e04c3fSmrgset_search(const struct set *ht, uint32_t hash, const void *key) 26501e04c3fSmrg{ 2667ec681f3Smrg assert(!key_pointer_is_reserved(key)); 26701e04c3fSmrg 2687ec681f3Smrg uint32_t size = ht->size; 2697ec681f3Smrg uint32_t start_address = util_fast_urem32(hash, size, ht->size_magic); 2707ec681f3Smrg uint32_t double_hash = util_fast_urem32(hash, ht->rehash, 2717ec681f3Smrg ht->rehash_magic) + 1; 2727ec681f3Smrg uint32_t hash_address = start_address; 27301e04c3fSmrg do { 27401e04c3fSmrg struct set_entry *entry = ht->table + hash_address; 27501e04c3fSmrg 27601e04c3fSmrg if (entry_is_free(entry)) { 27701e04c3fSmrg return NULL; 27801e04c3fSmrg } else if (entry_is_present(entry) && entry->hash == hash) { 27901e04c3fSmrg if (ht->key_equals_function(key, entry->key)) { 28001e04c3fSmrg return entry; 28101e04c3fSmrg } 28201e04c3fSmrg } 28301e04c3fSmrg 2847ec681f3Smrg hash_address += double_hash; 2857ec681f3Smrg if (hash_address >= size) 2867ec681f3Smrg hash_address -= size; 2877ec681f3Smrg } while (hash_address != start_address); 28801e04c3fSmrg 28901e04c3fSmrg return NULL; 29001e04c3fSmrg} 29101e04c3fSmrg 29201e04c3fSmrgstruct set_entry * 29301e04c3fSmrg_mesa_set_search(const struct set *set, const void *key) 29401e04c3fSmrg{ 29501e04c3fSmrg assert(set->key_hash_function); 29601e04c3fSmrg return set_search(set, set->key_hash_function(key), key); 29701e04c3fSmrg} 29801e04c3fSmrg 29901e04c3fSmrgstruct set_entry * 30001e04c3fSmrg_mesa_set_search_pre_hashed(const struct set *set, uint32_t hash, 30101e04c3fSmrg const void *key) 30201e04c3fSmrg{ 30301e04c3fSmrg assert(set->key_hash_function == NULL || 30401e04c3fSmrg hash == set->key_hash_function(key)); 30501e04c3fSmrg return set_search(set, hash, key); 30601e04c3fSmrg} 30701e04c3fSmrg 3087ec681f3Smrgstatic void 3097ec681f3Smrgset_add_rehash(struct set *ht, uint32_t hash, const void *key) 3107ec681f3Smrg{ 3117ec681f3Smrg uint32_t size = ht->size; 3127ec681f3Smrg uint32_t start_address = util_fast_urem32(hash, size, ht->size_magic); 3137ec681f3Smrg uint32_t double_hash = util_fast_urem32(hash, ht->rehash, 3147ec681f3Smrg ht->rehash_magic) + 1; 3157ec681f3Smrg uint32_t hash_address = start_address; 3167ec681f3Smrg do { 3177ec681f3Smrg struct set_entry *entry = ht->table + hash_address; 3187ec681f3Smrg if (likely(entry->key == NULL)) { 3197ec681f3Smrg entry->hash = hash; 3207ec681f3Smrg entry->key = key; 3217ec681f3Smrg return; 3227ec681f3Smrg } 3237ec681f3Smrg 3247ec681f3Smrg hash_address = hash_address + double_hash; 3257ec681f3Smrg if (hash_address >= size) 3267ec681f3Smrg hash_address -= size; 3277ec681f3Smrg } while (true); 3287ec681f3Smrg} 32901e04c3fSmrg 33001e04c3fSmrgstatic void 33101e04c3fSmrgset_rehash(struct set *ht, unsigned new_size_index) 33201e04c3fSmrg{ 33301e04c3fSmrg struct set old_ht; 33401e04c3fSmrg struct set_entry *table; 33501e04c3fSmrg 3367ec681f3Smrg if (ht->size_index == new_size_index && ht->deleted_entries == ht->max_entries) { 3377ec681f3Smrg set_clear_fast(ht); 3387ec681f3Smrg assert(!ht->entries); 3397ec681f3Smrg return; 3407ec681f3Smrg } 3417ec681f3Smrg 34201e04c3fSmrg if (new_size_index >= ARRAY_SIZE(hash_sizes)) 34301e04c3fSmrg return; 34401e04c3fSmrg 3457ec681f3Smrg table = rzalloc_array(ralloc_parent(ht->table), struct set_entry, 34601e04c3fSmrg hash_sizes[new_size_index].size); 34701e04c3fSmrg if (table == NULL) 34801e04c3fSmrg return; 34901e04c3fSmrg 35001e04c3fSmrg old_ht = *ht; 35101e04c3fSmrg 35201e04c3fSmrg ht->table = table; 35301e04c3fSmrg ht->size_index = new_size_index; 35401e04c3fSmrg ht->size = hash_sizes[ht->size_index].size; 35501e04c3fSmrg ht->rehash = hash_sizes[ht->size_index].rehash; 3567ec681f3Smrg ht->size_magic = hash_sizes[ht->size_index].size_magic; 3577ec681f3Smrg ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic; 35801e04c3fSmrg ht->max_entries = hash_sizes[ht->size_index].max_entries; 35901e04c3fSmrg ht->entries = 0; 36001e04c3fSmrg ht->deleted_entries = 0; 36101e04c3fSmrg 36201e04c3fSmrg set_foreach(&old_ht, entry) { 3637ec681f3Smrg set_add_rehash(ht, entry->hash, entry->key); 36401e04c3fSmrg } 36501e04c3fSmrg 3667ec681f3Smrg ht->entries = old_ht.entries; 3677ec681f3Smrg 36801e04c3fSmrg ralloc_free(old_ht.table); 36901e04c3fSmrg} 37001e04c3fSmrg 3717ec681f3Smrgvoid 3727ec681f3Smrg_mesa_set_resize(struct set *set, uint32_t entries) 3737ec681f3Smrg{ 3747ec681f3Smrg /* You can't shrink a set below its number of entries */ 3757ec681f3Smrg if (set->entries > entries) 3767ec681f3Smrg entries = set->entries; 3777ec681f3Smrg 3787ec681f3Smrg unsigned size_index = 0; 3797ec681f3Smrg while (hash_sizes[size_index].max_entries < entries) 3807ec681f3Smrg size_index++; 3817ec681f3Smrg 3827ec681f3Smrg set_rehash(set, size_index); 3837ec681f3Smrg} 3847ec681f3Smrg 38501e04c3fSmrg/** 3867ec681f3Smrg * Find a matching entry for the given key, or insert it if it doesn't already 3877ec681f3Smrg * exist. 38801e04c3fSmrg * 38901e04c3fSmrg * Note that insertion may rearrange the table on a resize or rehash, 39001e04c3fSmrg * so previously found hash_entries are no longer valid after this function. 39101e04c3fSmrg */ 39201e04c3fSmrgstatic struct set_entry * 3937ec681f3Smrgset_search_or_add(struct set *ht, uint32_t hash, const void *key, bool *found) 39401e04c3fSmrg{ 39501e04c3fSmrg struct set_entry *available_entry = NULL; 39601e04c3fSmrg 3977ec681f3Smrg assert(!key_pointer_is_reserved(key)); 3987ec681f3Smrg 39901e04c3fSmrg if (ht->entries >= ht->max_entries) { 40001e04c3fSmrg set_rehash(ht, ht->size_index + 1); 40101e04c3fSmrg } else if (ht->deleted_entries + ht->entries >= ht->max_entries) { 40201e04c3fSmrg set_rehash(ht, ht->size_index); 40301e04c3fSmrg } 40401e04c3fSmrg 4057ec681f3Smrg uint32_t size = ht->size; 4067ec681f3Smrg uint32_t start_address = util_fast_urem32(hash, size, ht->size_magic); 4077ec681f3Smrg uint32_t double_hash = util_fast_urem32(hash, ht->rehash, 4087ec681f3Smrg ht->rehash_magic) + 1; 4097ec681f3Smrg uint32_t hash_address = start_address; 41001e04c3fSmrg do { 41101e04c3fSmrg struct set_entry *entry = ht->table + hash_address; 41201e04c3fSmrg 41301e04c3fSmrg if (!entry_is_present(entry)) { 41401e04c3fSmrg /* Stash the first available entry we find */ 41501e04c3fSmrg if (available_entry == NULL) 41601e04c3fSmrg available_entry = entry; 41701e04c3fSmrg if (entry_is_free(entry)) 41801e04c3fSmrg break; 41901e04c3fSmrg } 42001e04c3fSmrg 42101e04c3fSmrg if (!entry_is_deleted(entry) && 42201e04c3fSmrg entry->hash == hash && 42301e04c3fSmrg ht->key_equals_function(key, entry->key)) { 4247ec681f3Smrg if (found) 4257ec681f3Smrg *found = true; 42601e04c3fSmrg return entry; 42701e04c3fSmrg } 42801e04c3fSmrg 4297ec681f3Smrg hash_address = hash_address + double_hash; 4307ec681f3Smrg if (hash_address >= size) 4317ec681f3Smrg hash_address -= size; 4327ec681f3Smrg } while (hash_address != start_address); 43301e04c3fSmrg 43401e04c3fSmrg if (available_entry) { 4357ec681f3Smrg /* There is no matching entry, create it. */ 43601e04c3fSmrg if (entry_is_deleted(available_entry)) 43701e04c3fSmrg ht->deleted_entries--; 43801e04c3fSmrg available_entry->hash = hash; 43901e04c3fSmrg available_entry->key = key; 44001e04c3fSmrg ht->entries++; 4417ec681f3Smrg if (found) 4427ec681f3Smrg *found = false; 44301e04c3fSmrg return available_entry; 44401e04c3fSmrg } 44501e04c3fSmrg 44601e04c3fSmrg /* We could hit here if a required resize failed. An unchecked-malloc 44701e04c3fSmrg * application could ignore this result. 44801e04c3fSmrg */ 44901e04c3fSmrg return NULL; 45001e04c3fSmrg} 45101e04c3fSmrg 4527ec681f3Smrg/** 4537ec681f3Smrg * Inserts the key with the given hash into the table. 4547ec681f3Smrg * 4557ec681f3Smrg * Note that insertion may rearrange the table on a resize or rehash, 4567ec681f3Smrg * so previously found hash_entries are no longer valid after this function. 4577ec681f3Smrg */ 4587ec681f3Smrgstatic struct set_entry * 4597ec681f3Smrgset_add(struct set *ht, uint32_t hash, const void *key) 4607ec681f3Smrg{ 4617ec681f3Smrg struct set_entry *entry = set_search_or_add(ht, hash, key, NULL); 4627ec681f3Smrg 4637ec681f3Smrg if (unlikely(!entry)) 4647ec681f3Smrg return NULL; 4657ec681f3Smrg 4667ec681f3Smrg /* Note: If a matching entry already exists, this will replace it. This is 4677ec681f3Smrg * a relatively common feature of hash tables, with the alternative 4687ec681f3Smrg * generally being "insert the new value as well, and return it first when 4697ec681f3Smrg * the key is searched for". 4707ec681f3Smrg * 4717ec681f3Smrg * Note that the hash table doesn't have a delete callback. If freeing of 4727ec681f3Smrg * old keys is required to avoid memory leaks, use the alternative 4737ec681f3Smrg * _mesa_set_search_or_add function and implement the replacement yourself. 4747ec681f3Smrg */ 4757ec681f3Smrg entry->key = key; 4767ec681f3Smrg return entry; 4777ec681f3Smrg} 4787ec681f3Smrg 47901e04c3fSmrgstruct set_entry * 48001e04c3fSmrg_mesa_set_add(struct set *set, const void *key) 48101e04c3fSmrg{ 48201e04c3fSmrg assert(set->key_hash_function); 48301e04c3fSmrg return set_add(set, set->key_hash_function(key), key); 48401e04c3fSmrg} 48501e04c3fSmrg 48601e04c3fSmrgstruct set_entry * 48701e04c3fSmrg_mesa_set_add_pre_hashed(struct set *set, uint32_t hash, const void *key) 48801e04c3fSmrg{ 48901e04c3fSmrg assert(set->key_hash_function == NULL || 49001e04c3fSmrg hash == set->key_hash_function(key)); 49101e04c3fSmrg return set_add(set, hash, key); 49201e04c3fSmrg} 49301e04c3fSmrg 4947ec681f3Smrgstruct set_entry * 4957ec681f3Smrg_mesa_set_search_and_add(struct set *set, const void *key, bool *replaced) 4967ec681f3Smrg{ 4977ec681f3Smrg assert(set->key_hash_function); 4987ec681f3Smrg return _mesa_set_search_and_add_pre_hashed(set, 4997ec681f3Smrg set->key_hash_function(key), 5007ec681f3Smrg key, replaced); 5017ec681f3Smrg} 5027ec681f3Smrg 5037ec681f3Smrgstruct set_entry * 5047ec681f3Smrg_mesa_set_search_and_add_pre_hashed(struct set *set, uint32_t hash, 5057ec681f3Smrg const void *key, bool *replaced) 5067ec681f3Smrg{ 5077ec681f3Smrg assert(set->key_hash_function == NULL || 5087ec681f3Smrg hash == set->key_hash_function(key)); 5097ec681f3Smrg struct set_entry *entry = set_search_or_add(set, hash, key, replaced); 5107ec681f3Smrg 5117ec681f3Smrg if (unlikely(!entry)) 5127ec681f3Smrg return NULL; 5137ec681f3Smrg 5147ec681f3Smrg /* This implements the replacement, same as _mesa_set_add(). The user will 5157ec681f3Smrg * be notified if we're overwriting a found entry. 5167ec681f3Smrg */ 5177ec681f3Smrg entry->key = key; 5187ec681f3Smrg return entry; 5197ec681f3Smrg} 5207ec681f3Smrg 5217ec681f3Smrgstruct set_entry * 5227ec681f3Smrg_mesa_set_search_or_add(struct set *set, const void *key, bool *found) 5237ec681f3Smrg{ 5247ec681f3Smrg assert(set->key_hash_function); 5257ec681f3Smrg return set_search_or_add(set, set->key_hash_function(key), key, found); 5267ec681f3Smrg} 5277ec681f3Smrg 5287ec681f3Smrgstruct set_entry * 5297ec681f3Smrg_mesa_set_search_or_add_pre_hashed(struct set *set, uint32_t hash, 5307ec681f3Smrg const void *key, bool *found) 5317ec681f3Smrg{ 5327ec681f3Smrg assert(set->key_hash_function == NULL || 5337ec681f3Smrg hash == set->key_hash_function(key)); 5347ec681f3Smrg return set_search_or_add(set, hash, key, NULL); 5357ec681f3Smrg} 5367ec681f3Smrg 53701e04c3fSmrg/** 53801e04c3fSmrg * This function deletes the given hash table entry. 53901e04c3fSmrg * 54001e04c3fSmrg * Note that deletion doesn't otherwise modify the table, so an iteration over 54101e04c3fSmrg * the table deleting entries is safe. 54201e04c3fSmrg */ 54301e04c3fSmrgvoid 54401e04c3fSmrg_mesa_set_remove(struct set *ht, struct set_entry *entry) 54501e04c3fSmrg{ 54601e04c3fSmrg if (!entry) 54701e04c3fSmrg return; 54801e04c3fSmrg 54901e04c3fSmrg entry->key = deleted_key; 55001e04c3fSmrg ht->entries--; 55101e04c3fSmrg ht->deleted_entries++; 55201e04c3fSmrg} 55301e04c3fSmrg 55401e04c3fSmrg/** 55501e04c3fSmrg * Removes the entry with the corresponding key, if exists. 55601e04c3fSmrg */ 55701e04c3fSmrgvoid 55801e04c3fSmrg_mesa_set_remove_key(struct set *set, const void *key) 55901e04c3fSmrg{ 56001e04c3fSmrg _mesa_set_remove(set, _mesa_set_search(set, key)); 56101e04c3fSmrg} 56201e04c3fSmrg 5637ec681f3Smrg/** 5647ec681f3Smrg * This function is an iterator over the set when no deleted entries are present. 5657ec681f3Smrg * 5667ec681f3Smrg * Pass in NULL for the first entry, as in the start of a for loop. 5677ec681f3Smrg */ 5687ec681f3Smrgstruct set_entry * 5697ec681f3Smrg_mesa_set_next_entry_unsafe(const struct set *ht, struct set_entry *entry) 5707ec681f3Smrg{ 5717ec681f3Smrg assert(!ht->deleted_entries); 5727ec681f3Smrg if (!ht->entries) 5737ec681f3Smrg return NULL; 5747ec681f3Smrg if (entry == NULL) 5757ec681f3Smrg entry = ht->table; 5767ec681f3Smrg else 5777ec681f3Smrg entry = entry + 1; 5787ec681f3Smrg if (entry != ht->table + ht->size) 5797ec681f3Smrg return entry->key ? entry : _mesa_set_next_entry_unsafe(ht, entry); 5807ec681f3Smrg 5817ec681f3Smrg return NULL; 5827ec681f3Smrg} 5837ec681f3Smrg 58401e04c3fSmrg/** 58501e04c3fSmrg * This function is an iterator over the hash table. 58601e04c3fSmrg * 58701e04c3fSmrg * Pass in NULL for the first entry, as in the start of a for loop. Note that 58801e04c3fSmrg * an iteration over the table is O(table_size) not O(entries). 58901e04c3fSmrg */ 59001e04c3fSmrgstruct set_entry * 59101e04c3fSmrg_mesa_set_next_entry(const struct set *ht, struct set_entry *entry) 59201e04c3fSmrg{ 59301e04c3fSmrg if (entry == NULL) 59401e04c3fSmrg entry = ht->table; 59501e04c3fSmrg else 59601e04c3fSmrg entry = entry + 1; 59701e04c3fSmrg 59801e04c3fSmrg for (; entry != ht->table + ht->size; entry++) { 59901e04c3fSmrg if (entry_is_present(entry)) { 60001e04c3fSmrg return entry; 60101e04c3fSmrg } 60201e04c3fSmrg } 60301e04c3fSmrg 60401e04c3fSmrg return NULL; 60501e04c3fSmrg} 60601e04c3fSmrg 60701e04c3fSmrgstruct set_entry * 60801e04c3fSmrg_mesa_set_random_entry(struct set *ht, 60901e04c3fSmrg int (*predicate)(struct set_entry *entry)) 61001e04c3fSmrg{ 61101e04c3fSmrg struct set_entry *entry; 61201e04c3fSmrg uint32_t i = rand() % ht->size; 61301e04c3fSmrg 61401e04c3fSmrg if (ht->entries == 0) 61501e04c3fSmrg return NULL; 61601e04c3fSmrg 61701e04c3fSmrg for (entry = ht->table + i; entry != ht->table + ht->size; entry++) { 61801e04c3fSmrg if (entry_is_present(entry) && 61901e04c3fSmrg (!predicate || predicate(entry))) { 62001e04c3fSmrg return entry; 62101e04c3fSmrg } 62201e04c3fSmrg } 62301e04c3fSmrg 62401e04c3fSmrg for (entry = ht->table; entry != ht->table + i; entry++) { 62501e04c3fSmrg if (entry_is_present(entry) && 62601e04c3fSmrg (!predicate || predicate(entry))) { 62701e04c3fSmrg return entry; 62801e04c3fSmrg } 62901e04c3fSmrg } 63001e04c3fSmrg 63101e04c3fSmrg return NULL; 63201e04c3fSmrg} 6338a1362adSmaya 6348a1362adSmaya/** 6358a1362adSmaya * Helper to create a set with pointer keys. 6368a1362adSmaya */ 6378a1362adSmayastruct set * 6388a1362adSmaya_mesa_pointer_set_create(void *mem_ctx) 6398a1362adSmaya{ 6408a1362adSmaya return _mesa_set_create(mem_ctx, _mesa_hash_pointer, 6418a1362adSmaya _mesa_key_pointer_equal); 6428a1362adSmaya} 6437ec681f3Smrg 6447ec681f3Smrgbool 6457ec681f3Smrg_mesa_set_intersects(struct set *a, struct set *b) 6467ec681f3Smrg{ 6477ec681f3Smrg assert(a->key_hash_function == b->key_hash_function); 6487ec681f3Smrg assert(a->key_equals_function == b->key_equals_function); 6497ec681f3Smrg 6507ec681f3Smrg /* iterate over the set with less entries */ 6517ec681f3Smrg if (b->entries < a->entries) { 6527ec681f3Smrg struct set *tmp = a; 6537ec681f3Smrg a = b; 6547ec681f3Smrg b = tmp; 6557ec681f3Smrg } 6567ec681f3Smrg 6577ec681f3Smrg set_foreach(a, entry) { 6587ec681f3Smrg if (_mesa_set_search_pre_hashed(b, entry->hash, entry->key)) 6597ec681f3Smrg return true; 6607ec681f3Smrg } 6617ec681f3Smrg return false; 6627ec681f3Smrg} 663