set.c revision 8a1362ad
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"
4301e04c3fSmrg
4401e04c3fSmrg/*
4501e04c3fSmrg * From Knuth -- a good choice for hash/rehash values is p, p-2 where
4601e04c3fSmrg * p and p-2 are both prime.  These tables are sized to have an extra 10%
4701e04c3fSmrg * free to avoid exponential performance degradation as the hash table fills
4801e04c3fSmrg */
4901e04c3fSmrg
5001e04c3fSmrgstatic const uint32_t deleted_key_value;
5101e04c3fSmrgstatic const void *deleted_key = &deleted_key_value;
5201e04c3fSmrg
5301e04c3fSmrgstatic const struct {
5401e04c3fSmrg   uint32_t max_entries, size, rehash;
5501e04c3fSmrg} hash_sizes[] = {
5601e04c3fSmrg   { 2,            5,            3            },
5701e04c3fSmrg   { 4,            7,            5            },
5801e04c3fSmrg   { 8,            13,           11           },
5901e04c3fSmrg   { 16,           19,           17           },
6001e04c3fSmrg   { 32,           43,           41           },
6101e04c3fSmrg   { 64,           73,           71           },
6201e04c3fSmrg   { 128,          151,          149          },
6301e04c3fSmrg   { 256,          283,          281          },
6401e04c3fSmrg   { 512,          571,          569          },
6501e04c3fSmrg   { 1024,         1153,         1151         },
6601e04c3fSmrg   { 2048,         2269,         2267         },
6701e04c3fSmrg   { 4096,         4519,         4517         },
6801e04c3fSmrg   { 8192,         9013,         9011         },
6901e04c3fSmrg   { 16384,        18043,        18041        },
7001e04c3fSmrg   { 32768,        36109,        36107        },
7101e04c3fSmrg   { 65536,        72091,        72089        },
7201e04c3fSmrg   { 131072,       144409,       144407       },
7301e04c3fSmrg   { 262144,       288361,       288359       },
7401e04c3fSmrg   { 524288,       576883,       576881       },
7501e04c3fSmrg   { 1048576,      1153459,      1153457      },
7601e04c3fSmrg   { 2097152,      2307163,      2307161      },
7701e04c3fSmrg   { 4194304,      4613893,      4613891      },
7801e04c3fSmrg   { 8388608,      9227641,      9227639      },
7901e04c3fSmrg   { 16777216,     18455029,     18455027     },
8001e04c3fSmrg   { 33554432,     36911011,     36911009     },
8101e04c3fSmrg   { 67108864,     73819861,     73819859     },
8201e04c3fSmrg   { 134217728,    147639589,    147639587    },
8301e04c3fSmrg   { 268435456,    295279081,    295279079    },
8401e04c3fSmrg   { 536870912,    590559793,    590559791    },
8501e04c3fSmrg   { 1073741824,   1181116273,   1181116271   },
8601e04c3fSmrg   { 2147483648ul, 2362232233ul, 2362232231ul }
8701e04c3fSmrg};
8801e04c3fSmrg
8901e04c3fSmrgstatic int
9001e04c3fSmrgentry_is_free(struct set_entry *entry)
9101e04c3fSmrg{
9201e04c3fSmrg   return entry->key == NULL;
9301e04c3fSmrg}
9401e04c3fSmrg
9501e04c3fSmrgstatic int
9601e04c3fSmrgentry_is_deleted(struct set_entry *entry)
9701e04c3fSmrg{
9801e04c3fSmrg   return entry->key == deleted_key;
9901e04c3fSmrg}
10001e04c3fSmrg
10101e04c3fSmrgstatic int
10201e04c3fSmrgentry_is_present(struct set_entry *entry)
10301e04c3fSmrg{
10401e04c3fSmrg   return entry->key != NULL && entry->key != deleted_key;
10501e04c3fSmrg}
10601e04c3fSmrg
10701e04c3fSmrgstruct set *
10801e04c3fSmrg_mesa_set_create(void *mem_ctx,
10901e04c3fSmrg                 uint32_t (*key_hash_function)(const void *key),
11001e04c3fSmrg                 bool (*key_equals_function)(const void *a,
11101e04c3fSmrg                                             const void *b))
11201e04c3fSmrg{
11301e04c3fSmrg   struct set *ht;
11401e04c3fSmrg
11501e04c3fSmrg   ht = ralloc(mem_ctx, struct set);
11601e04c3fSmrg   if (ht == NULL)
11701e04c3fSmrg      return NULL;
11801e04c3fSmrg
11901e04c3fSmrg   ht->size_index = 0;
12001e04c3fSmrg   ht->size = hash_sizes[ht->size_index].size;
12101e04c3fSmrg   ht->rehash = hash_sizes[ht->size_index].rehash;
12201e04c3fSmrg   ht->max_entries = hash_sizes[ht->size_index].max_entries;
12301e04c3fSmrg   ht->key_hash_function = key_hash_function;
12401e04c3fSmrg   ht->key_equals_function = key_equals_function;
12501e04c3fSmrg   ht->table = rzalloc_array(ht, struct set_entry, ht->size);
12601e04c3fSmrg   ht->entries = 0;
12701e04c3fSmrg   ht->deleted_entries = 0;
12801e04c3fSmrg
12901e04c3fSmrg   if (ht->table == NULL) {
13001e04c3fSmrg      ralloc_free(ht);
13101e04c3fSmrg      return NULL;
13201e04c3fSmrg   }
13301e04c3fSmrg
13401e04c3fSmrg   return ht;
13501e04c3fSmrg}
13601e04c3fSmrg
13701e04c3fSmrgstruct set *
13801e04c3fSmrg_mesa_set_clone(struct set *set, void *dst_mem_ctx)
13901e04c3fSmrg{
14001e04c3fSmrg   struct set *clone;
14101e04c3fSmrg
14201e04c3fSmrg   clone = ralloc(dst_mem_ctx, struct set);
14301e04c3fSmrg   if (clone == NULL)
14401e04c3fSmrg      return NULL;
14501e04c3fSmrg
14601e04c3fSmrg   memcpy(clone, set, sizeof(struct set));
14701e04c3fSmrg
14801e04c3fSmrg   clone->table = ralloc_array(clone, struct set_entry, clone->size);
14901e04c3fSmrg   if (clone->table == NULL) {
15001e04c3fSmrg      ralloc_free(clone);
15101e04c3fSmrg      return NULL;
15201e04c3fSmrg   }
15301e04c3fSmrg
15401e04c3fSmrg   memcpy(clone->table, set->table, clone->size * sizeof(struct set_entry));
15501e04c3fSmrg
15601e04c3fSmrg   return clone;
15701e04c3fSmrg}
15801e04c3fSmrg
15901e04c3fSmrg/**
16001e04c3fSmrg * Frees the given set.
16101e04c3fSmrg *
16201e04c3fSmrg * If delete_function is passed, it gets called on each entry present before
16301e04c3fSmrg * freeing.
16401e04c3fSmrg */
16501e04c3fSmrgvoid
16601e04c3fSmrg_mesa_set_destroy(struct set *ht, void (*delete_function)(struct set_entry *entry))
16701e04c3fSmrg{
16801e04c3fSmrg   if (!ht)
16901e04c3fSmrg      return;
17001e04c3fSmrg
17101e04c3fSmrg   if (delete_function) {
17201e04c3fSmrg      set_foreach (ht, entry) {
17301e04c3fSmrg         delete_function(entry);
17401e04c3fSmrg      }
17501e04c3fSmrg   }
17601e04c3fSmrg   ralloc_free(ht->table);
17701e04c3fSmrg   ralloc_free(ht);
17801e04c3fSmrg}
17901e04c3fSmrg
18001e04c3fSmrg/**
18101e04c3fSmrg * Clears all values from the given set.
18201e04c3fSmrg *
18301e04c3fSmrg * If delete_function is passed, it gets called on each entry present before
18401e04c3fSmrg * the set is cleared.
18501e04c3fSmrg */
18601e04c3fSmrgvoid
18701e04c3fSmrg_mesa_set_clear(struct set *set, void (*delete_function)(struct set_entry *entry))
18801e04c3fSmrg{
18901e04c3fSmrg   if (!set)
19001e04c3fSmrg      return;
19101e04c3fSmrg
19201e04c3fSmrg   set_foreach (set, entry) {
19301e04c3fSmrg      if (delete_function)
19401e04c3fSmrg         delete_function(entry);
19501e04c3fSmrg      entry->key = deleted_key;
19601e04c3fSmrg   }
19701e04c3fSmrg
19801e04c3fSmrg   set->entries = set->deleted_entries = 0;
19901e04c3fSmrg}
20001e04c3fSmrg
20101e04c3fSmrg/**
20201e04c3fSmrg * Finds a set entry with the given key and hash of that key.
20301e04c3fSmrg *
20401e04c3fSmrg * Returns NULL if no entry is found.
20501e04c3fSmrg */
20601e04c3fSmrgstatic struct set_entry *
20701e04c3fSmrgset_search(const struct set *ht, uint32_t hash, const void *key)
20801e04c3fSmrg{
20901e04c3fSmrg   uint32_t hash_address;
21001e04c3fSmrg
21101e04c3fSmrg   hash_address = hash % ht->size;
21201e04c3fSmrg   do {
21301e04c3fSmrg      uint32_t double_hash;
21401e04c3fSmrg
21501e04c3fSmrg      struct set_entry *entry = ht->table + hash_address;
21601e04c3fSmrg
21701e04c3fSmrg      if (entry_is_free(entry)) {
21801e04c3fSmrg         return NULL;
21901e04c3fSmrg      } else if (entry_is_present(entry) && entry->hash == hash) {
22001e04c3fSmrg         if (ht->key_equals_function(key, entry->key)) {
22101e04c3fSmrg            return entry;
22201e04c3fSmrg         }
22301e04c3fSmrg      }
22401e04c3fSmrg
22501e04c3fSmrg      double_hash = 1 + hash % ht->rehash;
22601e04c3fSmrg
22701e04c3fSmrg      hash_address = (hash_address + double_hash) % ht->size;
22801e04c3fSmrg   } while (hash_address != hash % ht->size);
22901e04c3fSmrg
23001e04c3fSmrg   return NULL;
23101e04c3fSmrg}
23201e04c3fSmrg
23301e04c3fSmrgstruct set_entry *
23401e04c3fSmrg_mesa_set_search(const struct set *set, const void *key)
23501e04c3fSmrg{
23601e04c3fSmrg   assert(set->key_hash_function);
23701e04c3fSmrg   return set_search(set, set->key_hash_function(key), key);
23801e04c3fSmrg}
23901e04c3fSmrg
24001e04c3fSmrgstruct set_entry *
24101e04c3fSmrg_mesa_set_search_pre_hashed(const struct set *set, uint32_t hash,
24201e04c3fSmrg                            const void *key)
24301e04c3fSmrg{
24401e04c3fSmrg   assert(set->key_hash_function == NULL ||
24501e04c3fSmrg          hash == set->key_hash_function(key));
24601e04c3fSmrg   return set_search(set, hash, key);
24701e04c3fSmrg}
24801e04c3fSmrg
24901e04c3fSmrgstatic struct set_entry *
25001e04c3fSmrgset_add(struct set *ht, uint32_t hash, const void *key);
25101e04c3fSmrg
25201e04c3fSmrgstatic void
25301e04c3fSmrgset_rehash(struct set *ht, unsigned new_size_index)
25401e04c3fSmrg{
25501e04c3fSmrg   struct set old_ht;
25601e04c3fSmrg   struct set_entry *table;
25701e04c3fSmrg
25801e04c3fSmrg   if (new_size_index >= ARRAY_SIZE(hash_sizes))
25901e04c3fSmrg      return;
26001e04c3fSmrg
26101e04c3fSmrg   table = rzalloc_array(ht, struct set_entry,
26201e04c3fSmrg                         hash_sizes[new_size_index].size);
26301e04c3fSmrg   if (table == NULL)
26401e04c3fSmrg      return;
26501e04c3fSmrg
26601e04c3fSmrg   old_ht = *ht;
26701e04c3fSmrg
26801e04c3fSmrg   ht->table = table;
26901e04c3fSmrg   ht->size_index = new_size_index;
27001e04c3fSmrg   ht->size = hash_sizes[ht->size_index].size;
27101e04c3fSmrg   ht->rehash = hash_sizes[ht->size_index].rehash;
27201e04c3fSmrg   ht->max_entries = hash_sizes[ht->size_index].max_entries;
27301e04c3fSmrg   ht->entries = 0;
27401e04c3fSmrg   ht->deleted_entries = 0;
27501e04c3fSmrg
27601e04c3fSmrg   set_foreach(&old_ht, entry) {
27701e04c3fSmrg      set_add(ht, entry->hash, entry->key);
27801e04c3fSmrg   }
27901e04c3fSmrg
28001e04c3fSmrg   ralloc_free(old_ht.table);
28101e04c3fSmrg}
28201e04c3fSmrg
28301e04c3fSmrg/**
28401e04c3fSmrg * Inserts the key with the given hash into the table.
28501e04c3fSmrg *
28601e04c3fSmrg * Note that insertion may rearrange the table on a resize or rehash,
28701e04c3fSmrg * so previously found hash_entries are no longer valid after this function.
28801e04c3fSmrg */
28901e04c3fSmrgstatic struct set_entry *
29001e04c3fSmrgset_add(struct set *ht, uint32_t hash, const void *key)
29101e04c3fSmrg{
29201e04c3fSmrg   uint32_t hash_address;
29301e04c3fSmrg   struct set_entry *available_entry = NULL;
29401e04c3fSmrg
29501e04c3fSmrg   if (ht->entries >= ht->max_entries) {
29601e04c3fSmrg      set_rehash(ht, ht->size_index + 1);
29701e04c3fSmrg   } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
29801e04c3fSmrg      set_rehash(ht, ht->size_index);
29901e04c3fSmrg   }
30001e04c3fSmrg
30101e04c3fSmrg   hash_address = hash % ht->size;
30201e04c3fSmrg   do {
30301e04c3fSmrg      struct set_entry *entry = ht->table + hash_address;
30401e04c3fSmrg      uint32_t double_hash;
30501e04c3fSmrg
30601e04c3fSmrg      if (!entry_is_present(entry)) {
30701e04c3fSmrg         /* Stash the first available entry we find */
30801e04c3fSmrg         if (available_entry == NULL)
30901e04c3fSmrg            available_entry = entry;
31001e04c3fSmrg         if (entry_is_free(entry))
31101e04c3fSmrg            break;
31201e04c3fSmrg      }
31301e04c3fSmrg
31401e04c3fSmrg      /* Implement replacement when another insert happens
31501e04c3fSmrg       * with a matching key.  This is a relatively common
31601e04c3fSmrg       * feature of hash tables, with the alternative
31701e04c3fSmrg       * generally being "insert the new value as well, and
31801e04c3fSmrg       * return it first when the key is searched for".
31901e04c3fSmrg       *
32001e04c3fSmrg       * Note that the hash table doesn't have a delete callback.
32101e04c3fSmrg       * If freeing of old keys is required to avoid memory leaks,
32201e04c3fSmrg       * perform a search before inserting.
32301e04c3fSmrg       */
32401e04c3fSmrg      if (!entry_is_deleted(entry) &&
32501e04c3fSmrg          entry->hash == hash &&
32601e04c3fSmrg          ht->key_equals_function(key, entry->key)) {
32701e04c3fSmrg         entry->key = key;
32801e04c3fSmrg         return entry;
32901e04c3fSmrg      }
33001e04c3fSmrg
33101e04c3fSmrg      double_hash = 1 + hash % ht->rehash;
33201e04c3fSmrg
33301e04c3fSmrg      hash_address = (hash_address + double_hash) % ht->size;
33401e04c3fSmrg   } while (hash_address != hash % ht->size);
33501e04c3fSmrg
33601e04c3fSmrg   if (available_entry) {
33701e04c3fSmrg      if (entry_is_deleted(available_entry))
33801e04c3fSmrg         ht->deleted_entries--;
33901e04c3fSmrg      available_entry->hash = hash;
34001e04c3fSmrg      available_entry->key = key;
34101e04c3fSmrg      ht->entries++;
34201e04c3fSmrg      return available_entry;
34301e04c3fSmrg   }
34401e04c3fSmrg
34501e04c3fSmrg   /* We could hit here if a required resize failed. An unchecked-malloc
34601e04c3fSmrg    * application could ignore this result.
34701e04c3fSmrg    */
34801e04c3fSmrg   return NULL;
34901e04c3fSmrg}
35001e04c3fSmrg
35101e04c3fSmrgstruct set_entry *
35201e04c3fSmrg_mesa_set_add(struct set *set, const void *key)
35301e04c3fSmrg{
35401e04c3fSmrg   assert(set->key_hash_function);
35501e04c3fSmrg   return set_add(set, set->key_hash_function(key), key);
35601e04c3fSmrg}
35701e04c3fSmrg
35801e04c3fSmrgstruct set_entry *
35901e04c3fSmrg_mesa_set_add_pre_hashed(struct set *set, uint32_t hash, const void *key)
36001e04c3fSmrg{
36101e04c3fSmrg   assert(set->key_hash_function == NULL ||
36201e04c3fSmrg          hash == set->key_hash_function(key));
36301e04c3fSmrg   return set_add(set, hash, key);
36401e04c3fSmrg}
36501e04c3fSmrg
36601e04c3fSmrg/**
36701e04c3fSmrg * This function deletes the given hash table entry.
36801e04c3fSmrg *
36901e04c3fSmrg * Note that deletion doesn't otherwise modify the table, so an iteration over
37001e04c3fSmrg * the table deleting entries is safe.
37101e04c3fSmrg */
37201e04c3fSmrgvoid
37301e04c3fSmrg_mesa_set_remove(struct set *ht, struct set_entry *entry)
37401e04c3fSmrg{
37501e04c3fSmrg   if (!entry)
37601e04c3fSmrg      return;
37701e04c3fSmrg
37801e04c3fSmrg   entry->key = deleted_key;
37901e04c3fSmrg   ht->entries--;
38001e04c3fSmrg   ht->deleted_entries++;
38101e04c3fSmrg}
38201e04c3fSmrg
38301e04c3fSmrg/**
38401e04c3fSmrg * Removes the entry with the corresponding key, if exists.
38501e04c3fSmrg */
38601e04c3fSmrgvoid
38701e04c3fSmrg_mesa_set_remove_key(struct set *set, const void *key)
38801e04c3fSmrg{
38901e04c3fSmrg   _mesa_set_remove(set, _mesa_set_search(set, key));
39001e04c3fSmrg}
39101e04c3fSmrg
39201e04c3fSmrg/**
39301e04c3fSmrg * This function is an iterator over the hash table.
39401e04c3fSmrg *
39501e04c3fSmrg * Pass in NULL for the first entry, as in the start of a for loop.  Note that
39601e04c3fSmrg * an iteration over the table is O(table_size) not O(entries).
39701e04c3fSmrg */
39801e04c3fSmrgstruct set_entry *
39901e04c3fSmrg_mesa_set_next_entry(const struct set *ht, struct set_entry *entry)
40001e04c3fSmrg{
40101e04c3fSmrg   if (entry == NULL)
40201e04c3fSmrg      entry = ht->table;
40301e04c3fSmrg   else
40401e04c3fSmrg      entry = entry + 1;
40501e04c3fSmrg
40601e04c3fSmrg   for (; entry != ht->table + ht->size; entry++) {
40701e04c3fSmrg      if (entry_is_present(entry)) {
40801e04c3fSmrg         return entry;
40901e04c3fSmrg      }
41001e04c3fSmrg   }
41101e04c3fSmrg
41201e04c3fSmrg   return NULL;
41301e04c3fSmrg}
41401e04c3fSmrg
41501e04c3fSmrgstruct set_entry *
41601e04c3fSmrg_mesa_set_random_entry(struct set *ht,
41701e04c3fSmrg                       int (*predicate)(struct set_entry *entry))
41801e04c3fSmrg{
41901e04c3fSmrg   struct set_entry *entry;
42001e04c3fSmrg   uint32_t i = rand() % ht->size;
42101e04c3fSmrg
42201e04c3fSmrg   if (ht->entries == 0)
42301e04c3fSmrg      return NULL;
42401e04c3fSmrg
42501e04c3fSmrg   for (entry = ht->table + i; entry != ht->table + ht->size; entry++) {
42601e04c3fSmrg      if (entry_is_present(entry) &&
42701e04c3fSmrg          (!predicate || predicate(entry))) {
42801e04c3fSmrg         return entry;
42901e04c3fSmrg      }
43001e04c3fSmrg   }
43101e04c3fSmrg
43201e04c3fSmrg   for (entry = ht->table; entry != ht->table + i; entry++) {
43301e04c3fSmrg      if (entry_is_present(entry) &&
43401e04c3fSmrg          (!predicate || predicate(entry))) {
43501e04c3fSmrg         return entry;
43601e04c3fSmrg      }
43701e04c3fSmrg   }
43801e04c3fSmrg
43901e04c3fSmrg   return NULL;
44001e04c3fSmrg}
4418a1362adSmaya
4428a1362adSmaya/**
4438a1362adSmaya * Helper to create a set with pointer keys.
4448a1362adSmaya */
4458a1362adSmayastruct set *
4468a1362adSmaya_mesa_pointer_set_create(void *mem_ctx)
4478a1362adSmaya{
4488a1362adSmaya   return _mesa_set_create(mem_ctx, _mesa_hash_pointer,
4498a1362adSmaya                           _mesa_key_pointer_equal);
4508a1362adSmaya}
451