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