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