xref: /third_party/mesa3d/src/util/set.c (revision bf215546)
1/*
2 * Copyright © 2009-2012 Intel Corporation
3 * Copyright © 1988-2004 Keith Packard and Bart Massey.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * Except as contained in this notice, the names of the authors
25 * or their institutions shall not be used in advertising or
26 * otherwise to promote the sale, use or other dealings in this
27 * Software without prior written authorization from the
28 * authors.
29 *
30 * Authors:
31 *    Eric Anholt <eric@anholt.net>
32 *    Keith Packard <keithp@keithp.com>
33 */
34
35#include <stdlib.h>
36#include <assert.h>
37#include <string.h>
38
39#include "hash_table.h"
40#include "macros.h"
41#include "ralloc.h"
42#include "set.h"
43#include "fast_urem_by_const.h"
44
45/*
46 * From Knuth -- a good choice for hash/rehash values is p, p-2 where
47 * p and p-2 are both prime.  These tables are sized to have an extra 10%
48 * free to avoid exponential performance degradation as the hash table fills
49 */
50
51static const uint32_t deleted_key_value;
52static const void *deleted_key = &deleted_key_value;
53
54static const struct {
55   uint32_t max_entries, size, rehash;
56   uint64_t size_magic, rehash_magic;
57} hash_sizes[] = {
58#define ENTRY(max_entries, size, rehash) \
59   { max_entries, size, rehash, \
60      REMAINDER_MAGIC(size), REMAINDER_MAGIC(rehash) }
61
62   ENTRY(2,            5,            3            ),
63   ENTRY(4,            7,            5            ),
64   ENTRY(8,            13,           11           ),
65   ENTRY(16,           19,           17           ),
66   ENTRY(32,           43,           41           ),
67   ENTRY(64,           73,           71           ),
68   ENTRY(128,          151,          149          ),
69   ENTRY(256,          283,          281          ),
70   ENTRY(512,          571,          569          ),
71   ENTRY(1024,         1153,         1151         ),
72   ENTRY(2048,         2269,         2267         ),
73   ENTRY(4096,         4519,         4517         ),
74   ENTRY(8192,         9013,         9011         ),
75   ENTRY(16384,        18043,        18041        ),
76   ENTRY(32768,        36109,        36107        ),
77   ENTRY(65536,        72091,        72089        ),
78   ENTRY(131072,       144409,       144407       ),
79   ENTRY(262144,       288361,       288359       ),
80   ENTRY(524288,       576883,       576881       ),
81   ENTRY(1048576,      1153459,      1153457      ),
82   ENTRY(2097152,      2307163,      2307161      ),
83   ENTRY(4194304,      4613893,      4613891      ),
84   ENTRY(8388608,      9227641,      9227639      ),
85   ENTRY(16777216,     18455029,     18455027     ),
86   ENTRY(33554432,     36911011,     36911009     ),
87   ENTRY(67108864,     73819861,     73819859     ),
88   ENTRY(134217728,    147639589,    147639587    ),
89   ENTRY(268435456,    295279081,    295279079    ),
90   ENTRY(536870912,    590559793,    590559791    ),
91   ENTRY(1073741824,   1181116273,   1181116271   ),
92   ENTRY(2147483648ul, 2362232233ul, 2362232231ul )
93};
94
95ASSERTED static inline bool
96key_pointer_is_reserved(const void *key)
97{
98   return key == NULL || key == deleted_key;
99}
100
101static int
102entry_is_free(struct set_entry *entry)
103{
104   return entry->key == NULL;
105}
106
107static int
108entry_is_deleted(struct set_entry *entry)
109{
110   return entry->key == deleted_key;
111}
112
113static int
114entry_is_present(struct set_entry *entry)
115{
116   return entry->key != NULL && entry->key != deleted_key;
117}
118
119bool
120_mesa_set_init(struct set *ht, void *mem_ctx,
121                 uint32_t (*key_hash_function)(const void *key),
122                 bool (*key_equals_function)(const void *a,
123                                             const void *b))
124{
125   ht->size_index = 0;
126   ht->size = hash_sizes[ht->size_index].size;
127   ht->rehash = hash_sizes[ht->size_index].rehash;
128   ht->size_magic = hash_sizes[ht->size_index].size_magic;
129   ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic;
130   ht->max_entries = hash_sizes[ht->size_index].max_entries;
131   ht->key_hash_function = key_hash_function;
132   ht->key_equals_function = key_equals_function;
133   ht->table = rzalloc_array(mem_ctx, struct set_entry, ht->size);
134   ht->entries = 0;
135   ht->deleted_entries = 0;
136
137   return ht->table != NULL;
138}
139
140struct set *
141_mesa_set_create(void *mem_ctx,
142                 uint32_t (*key_hash_function)(const void *key),
143                 bool (*key_equals_function)(const void *a,
144                                             const void *b))
145{
146   struct set *ht;
147
148   ht = ralloc(mem_ctx, struct set);
149   if (ht == NULL)
150      return NULL;
151
152   if (!_mesa_set_init(ht, ht, key_hash_function, key_equals_function)) {
153      ralloc_free(ht);
154      return NULL;
155   }
156
157   return ht;
158}
159
160static uint32_t
161key_u32_hash(const void *key)
162{
163   uint32_t u = (uint32_t)(uintptr_t)key;
164   return _mesa_hash_uint(&u);
165}
166
167static bool
168key_u32_equals(const void *a, const void *b)
169{
170   return (uint32_t)(uintptr_t)a == (uint32_t)(uintptr_t)b;
171}
172
173/* key == 0 and key == deleted_key are not allowed */
174struct set *
175_mesa_set_create_u32_keys(void *mem_ctx)
176{
177   return _mesa_set_create(mem_ctx, key_u32_hash, key_u32_equals);
178}
179
180struct set *
181_mesa_set_clone(struct set *set, void *dst_mem_ctx)
182{
183   struct set *clone;
184
185   clone = ralloc(dst_mem_ctx, struct set);
186   if (clone == NULL)
187      return NULL;
188
189   memcpy(clone, set, sizeof(struct set));
190
191   clone->table = ralloc_array(clone, struct set_entry, clone->size);
192   if (clone->table == NULL) {
193      ralloc_free(clone);
194      return NULL;
195   }
196
197   memcpy(clone->table, set->table, clone->size * sizeof(struct set_entry));
198
199   return clone;
200}
201
202/**
203 * Frees the given set.
204 *
205 * If delete_function is passed, it gets called on each entry present before
206 * freeing.
207 */
208void
209_mesa_set_destroy(struct set *ht, void (*delete_function)(struct set_entry *entry))
210{
211   if (!ht)
212      return;
213
214   if (delete_function) {
215      set_foreach (ht, entry) {
216         delete_function(entry);
217      }
218   }
219   ralloc_free(ht->table);
220   ralloc_free(ht);
221}
222
223
224static void
225set_clear_fast(struct set *ht)
226{
227   memset(ht->table, 0, sizeof(struct set_entry) * hash_sizes[ht->size_index].size);
228   ht->entries = ht->deleted_entries = 0;
229}
230
231/**
232 * Clears all values from the given set.
233 *
234 * If delete_function is passed, it gets called on each entry present before
235 * the set is cleared.
236 */
237void
238_mesa_set_clear(struct set *set, void (*delete_function)(struct set_entry *entry))
239{
240   if (!set)
241      return;
242
243   struct set_entry *entry;
244
245   if (delete_function) {
246      for (entry = set->table; entry != set->table + set->size; entry++) {
247         if (entry_is_present(entry))
248            delete_function(entry);
249
250         entry->key = NULL;
251      }
252      set->entries = 0;
253      set->deleted_entries = 0;
254   } else
255      set_clear_fast(set);
256}
257
258/**
259 * Finds a set entry with the given key and hash of that key.
260 *
261 * Returns NULL if no entry is found.
262 */
263static struct set_entry *
264set_search(const struct set *ht, uint32_t hash, const void *key)
265{
266   assert(!key_pointer_is_reserved(key));
267
268   uint32_t size = ht->size;
269   uint32_t start_address = util_fast_urem32(hash, size, ht->size_magic);
270   uint32_t double_hash = util_fast_urem32(hash, ht->rehash,
271                                           ht->rehash_magic) + 1;
272   uint32_t hash_address = start_address;
273   do {
274      struct set_entry *entry = ht->table + hash_address;
275
276      if (entry_is_free(entry)) {
277         return NULL;
278      } else if (entry_is_present(entry) && entry->hash == hash) {
279         if (ht->key_equals_function(key, entry->key)) {
280            return entry;
281         }
282      }
283
284      hash_address += double_hash;
285      if (hash_address >= size)
286         hash_address -= size;
287   } while (hash_address != start_address);
288
289   return NULL;
290}
291
292struct set_entry *
293_mesa_set_search(const struct set *set, const void *key)
294{
295   assert(set->key_hash_function);
296   return set_search(set, set->key_hash_function(key), key);
297}
298
299struct set_entry *
300_mesa_set_search_pre_hashed(const struct set *set, uint32_t hash,
301                            const void *key)
302{
303   assert(set->key_hash_function == NULL ||
304          hash == set->key_hash_function(key));
305   return set_search(set, hash, key);
306}
307
308static void
309set_add_rehash(struct set *ht, uint32_t hash, const void *key)
310{
311   uint32_t size = ht->size;
312   uint32_t start_address = util_fast_urem32(hash, size, ht->size_magic);
313   uint32_t double_hash = util_fast_urem32(hash, ht->rehash,
314                                           ht->rehash_magic) + 1;
315   uint32_t hash_address = start_address;
316   do {
317      struct set_entry *entry = ht->table + hash_address;
318      if (likely(entry->key == NULL)) {
319         entry->hash = hash;
320         entry->key = key;
321         return;
322      }
323
324      hash_address = hash_address + double_hash;
325      if (hash_address >= size)
326         hash_address -= size;
327   } while (true);
328}
329
330static void
331set_rehash(struct set *ht, unsigned new_size_index)
332{
333   struct set old_ht;
334   struct set_entry *table;
335
336   if (ht->size_index == new_size_index && ht->deleted_entries == ht->max_entries) {
337      set_clear_fast(ht);
338      assert(!ht->entries);
339      return;
340   }
341
342   if (new_size_index >= ARRAY_SIZE(hash_sizes))
343      return;
344
345   table = rzalloc_array(ralloc_parent(ht->table), struct set_entry,
346                         hash_sizes[new_size_index].size);
347   if (table == NULL)
348      return;
349
350   old_ht = *ht;
351
352   ht->table = table;
353   ht->size_index = new_size_index;
354   ht->size = hash_sizes[ht->size_index].size;
355   ht->rehash = hash_sizes[ht->size_index].rehash;
356   ht->size_magic = hash_sizes[ht->size_index].size_magic;
357   ht->rehash_magic = hash_sizes[ht->size_index].rehash_magic;
358   ht->max_entries = hash_sizes[ht->size_index].max_entries;
359   ht->entries = 0;
360   ht->deleted_entries = 0;
361
362   set_foreach(&old_ht, entry) {
363      set_add_rehash(ht, entry->hash, entry->key);
364   }
365
366   ht->entries = old_ht.entries;
367
368   ralloc_free(old_ht.table);
369}
370
371void
372_mesa_set_resize(struct set *set, uint32_t entries)
373{
374   /* You can't shrink a set below its number of entries */
375   if (set->entries > entries)
376      entries = set->entries;
377
378   unsigned size_index = 0;
379   while (hash_sizes[size_index].max_entries < entries)
380      size_index++;
381
382   set_rehash(set, size_index);
383}
384
385/**
386 * Find a matching entry for the given key, or insert it if it doesn't already
387 * exist.
388 *
389 * Note that insertion may rearrange the table on a resize or rehash,
390 * so previously found hash_entries are no longer valid after this function.
391 */
392static struct set_entry *
393set_search_or_add(struct set *ht, uint32_t hash, const void *key, bool *found)
394{
395   struct set_entry *available_entry = NULL;
396
397   assert(!key_pointer_is_reserved(key));
398
399   if (ht->entries >= ht->max_entries) {
400      set_rehash(ht, ht->size_index + 1);
401   } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
402      set_rehash(ht, ht->size_index);
403   }
404
405   uint32_t size = ht->size;
406   uint32_t start_address = util_fast_urem32(hash, size, ht->size_magic);
407   uint32_t double_hash = util_fast_urem32(hash, ht->rehash,
408                                           ht->rehash_magic) + 1;
409   uint32_t hash_address = start_address;
410   do {
411      struct set_entry *entry = ht->table + hash_address;
412
413      if (!entry_is_present(entry)) {
414         /* Stash the first available entry we find */
415         if (available_entry == NULL)
416            available_entry = entry;
417         if (entry_is_free(entry))
418            break;
419      }
420
421      if (!entry_is_deleted(entry) &&
422          entry->hash == hash &&
423          ht->key_equals_function(key, entry->key)) {
424         if (found)
425            *found = true;
426         return entry;
427      }
428
429      hash_address = hash_address + double_hash;
430      if (hash_address >= size)
431         hash_address -= size;
432   } while (hash_address != start_address);
433
434   if (available_entry) {
435      /* There is no matching entry, create it. */
436      if (entry_is_deleted(available_entry))
437         ht->deleted_entries--;
438      available_entry->hash = hash;
439      available_entry->key = key;
440      ht->entries++;
441      if (found)
442         *found = false;
443      return available_entry;
444   }
445
446   /* We could hit here if a required resize failed. An unchecked-malloc
447    * application could ignore this result.
448    */
449   return NULL;
450}
451
452/**
453 * Inserts the key with the given hash into the table.
454 *
455 * Note that insertion may rearrange the table on a resize or rehash,
456 * so previously found hash_entries are no longer valid after this function.
457 */
458static struct set_entry *
459set_add(struct set *ht, uint32_t hash, const void *key)
460{
461   struct set_entry *entry = set_search_or_add(ht, hash, key, NULL);
462
463   if (unlikely(!entry))
464      return NULL;
465
466   /* Note: If a matching entry already exists, this will replace it.  This is
467    * a relatively common feature of hash tables, with the alternative
468    * generally being "insert the new value as well, and return it first when
469    * the key is searched for".
470    *
471    * Note that the hash table doesn't have a delete callback.  If freeing of
472    * old keys is required to avoid memory leaks, use the alternative
473    * _mesa_set_search_or_add function and implement the replacement yourself.
474    */
475   entry->key = key;
476   return entry;
477}
478
479struct set_entry *
480_mesa_set_add(struct set *set, const void *key)
481{
482   assert(set->key_hash_function);
483   return set_add(set, set->key_hash_function(key), key);
484}
485
486struct set_entry *
487_mesa_set_add_pre_hashed(struct set *set, uint32_t hash, const void *key)
488{
489   assert(set->key_hash_function == NULL ||
490          hash == set->key_hash_function(key));
491   return set_add(set, hash, key);
492}
493
494struct set_entry *
495_mesa_set_search_and_add(struct set *set, const void *key, bool *replaced)
496{
497   assert(set->key_hash_function);
498   return _mesa_set_search_and_add_pre_hashed(set,
499                                              set->key_hash_function(key),
500                                              key, replaced);
501}
502
503struct set_entry *
504_mesa_set_search_and_add_pre_hashed(struct set *set, uint32_t hash,
505                                    const void *key, bool *replaced)
506{
507   assert(set->key_hash_function == NULL ||
508          hash == set->key_hash_function(key));
509   struct set_entry *entry = set_search_or_add(set, hash, key, replaced);
510
511   if (unlikely(!entry))
512      return NULL;
513
514   /* This implements the replacement, same as _mesa_set_add(). The user will
515    * be notified if we're overwriting a found entry.
516    */
517   entry->key = key;
518   return entry;
519}
520
521struct set_entry *
522_mesa_set_search_or_add(struct set *set, const void *key, bool *found)
523{
524   assert(set->key_hash_function);
525   return set_search_or_add(set, set->key_hash_function(key), key, found);
526}
527
528struct set_entry *
529_mesa_set_search_or_add_pre_hashed(struct set *set, uint32_t hash,
530                                   const void *key, bool *found)
531{
532   assert(set->key_hash_function == NULL ||
533          hash == set->key_hash_function(key));
534   return set_search_or_add(set, hash, key, found);
535}
536
537/**
538 * This function deletes the given hash table entry.
539 *
540 * Note that deletion doesn't otherwise modify the table, so an iteration over
541 * the table deleting entries is safe.
542 */
543void
544_mesa_set_remove(struct set *ht, struct set_entry *entry)
545{
546   if (!entry)
547      return;
548
549   entry->key = deleted_key;
550   ht->entries--;
551   ht->deleted_entries++;
552}
553
554/**
555 * Removes the entry with the corresponding key, if exists.
556 */
557void
558_mesa_set_remove_key(struct set *set, const void *key)
559{
560   _mesa_set_remove(set, _mesa_set_search(set, key));
561}
562
563/**
564 * This function is an iterator over the set when no deleted entries are present.
565 *
566 * Pass in NULL for the first entry, as in the start of a for loop.
567 */
568struct set_entry *
569_mesa_set_next_entry_unsafe(const struct set *ht, struct set_entry *entry)
570{
571   assert(!ht->deleted_entries);
572   if (!ht->entries)
573      return NULL;
574   if (entry == NULL)
575      entry = ht->table;
576   else
577      entry = entry + 1;
578   if (entry != ht->table + ht->size)
579      return entry->key ? entry : _mesa_set_next_entry_unsafe(ht, entry);
580
581   return NULL;
582}
583
584/**
585 * This function is an iterator over the hash table.
586 *
587 * Pass in NULL for the first entry, as in the start of a for loop.  Note that
588 * an iteration over the table is O(table_size) not O(entries).
589 */
590struct set_entry *
591_mesa_set_next_entry(const struct set *ht, struct set_entry *entry)
592{
593   if (entry == NULL)
594      entry = ht->table;
595   else
596      entry = entry + 1;
597
598   for (; entry != ht->table + ht->size; entry++) {
599      if (entry_is_present(entry)) {
600         return entry;
601      }
602   }
603
604   return NULL;
605}
606
607struct set_entry *
608_mesa_set_random_entry(struct set *ht,
609                       int (*predicate)(struct set_entry *entry))
610{
611   struct set_entry *entry;
612   uint32_t i = rand() % ht->size;
613
614   if (ht->entries == 0)
615      return NULL;
616
617   for (entry = ht->table + i; entry != ht->table + ht->size; entry++) {
618      if (entry_is_present(entry) &&
619          (!predicate || predicate(entry))) {
620         return entry;
621      }
622   }
623
624   for (entry = ht->table; entry != ht->table + i; entry++) {
625      if (entry_is_present(entry) &&
626          (!predicate || predicate(entry))) {
627         return entry;
628      }
629   }
630
631   return NULL;
632}
633
634/**
635 * Helper to create a set with pointer keys.
636 */
637struct set *
638_mesa_pointer_set_create(void *mem_ctx)
639{
640   return _mesa_set_create(mem_ctx, _mesa_hash_pointer,
641                           _mesa_key_pointer_equal);
642}
643
644bool
645_mesa_set_intersects(struct set *a, struct set *b)
646{
647   assert(a->key_hash_function == b->key_hash_function);
648   assert(a->key_equals_function == b->key_equals_function);
649
650   /* iterate over the set with less entries */
651   if (b->entries < a->entries) {
652      struct set *tmp = a;
653      a = b;
654      b = tmp;
655   }
656
657   set_foreach(a, entry) {
658      if (_mesa_set_search_pre_hashed(b, entry->hash, entry->key))
659         return true;
660   }
661   return false;
662}
663