Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.  
  37. #include "macros.h"
  38. #include "set.h"
  39. #include "ralloc.h"
  40.  
  41. /*
  42.  * From Knuth -- a good choice for hash/rehash values is p, p-2 where
  43.  * p and p-2 are both prime.  These tables are sized to have an extra 10%
  44.  * free to avoid exponential performance degradation as the hash table fills
  45.  */
  46.  
  47. uint32_t deleted_key_value;
  48. const void *deleted_key = &deleted_key_value;
  49.  
  50. static const struct {
  51.    uint32_t max_entries, size, rehash;
  52. } hash_sizes[] = {
  53.    { 2,            5,            3            },
  54.    { 4,            7,            5            },
  55.    { 8,            13,           11           },
  56.    { 16,           19,           17           },
  57.    { 32,           43,           41           },
  58.    { 64,           73,           71           },
  59.    { 128,          151,          149          },
  60.    { 256,          283,          281          },
  61.    { 512,          571,          569          },
  62.    { 1024,         1153,         1151         },
  63.    { 2048,         2269,         2267         },
  64.    { 4096,         4519,         4517         },
  65.    { 8192,         9013,         9011         },
  66.    { 16384,        18043,        18041        },
  67.    { 32768,        36109,        36107        },
  68.    { 65536,        72091,        72089        },
  69.    { 131072,       144409,       144407       },
  70.    { 262144,       288361,       288359       },
  71.    { 524288,       576883,       576881       },
  72.    { 1048576,      1153459,      1153457      },
  73.    { 2097152,      2307163,      2307161      },
  74.    { 4194304,      4613893,      4613891      },
  75.    { 8388608,      9227641,      9227639      },
  76.    { 16777216,     18455029,     18455027     },
  77.    { 33554432,     36911011,     36911009     },
  78.    { 67108864,     73819861,     73819859     },
  79.    { 134217728,    147639589,    147639587    },
  80.    { 268435456,    295279081,    295279079    },
  81.    { 536870912,    590559793,    590559791    },
  82.    { 1073741824,   1181116273,   1181116271   },
  83.    { 2147483648ul, 2362232233ul, 2362232231ul }
  84. };
  85.  
  86. static int
  87. entry_is_free(struct set_entry *entry)
  88. {
  89.    return entry->key == NULL;
  90. }
  91.  
  92. static int
  93. entry_is_deleted(struct set_entry *entry)
  94. {
  95.    return entry->key == deleted_key;
  96. }
  97.  
  98. static int
  99. entry_is_present(struct set_entry *entry)
  100. {
  101.    return entry->key != NULL && entry->key != deleted_key;
  102. }
  103.  
  104. struct set *
  105. _mesa_set_create(void *mem_ctx,
  106.                  bool (*key_equals_function)(const void *a,
  107.                                              const void *b))
  108. {
  109.    struct set *ht;
  110.  
  111.    ht = ralloc(mem_ctx, struct set);
  112.    if (ht == NULL)
  113.       return NULL;
  114.  
  115.    ht->mem_ctx = mem_ctx;
  116.    ht->size_index = 0;
  117.    ht->size = hash_sizes[ht->size_index].size;
  118.    ht->rehash = hash_sizes[ht->size_index].rehash;
  119.    ht->max_entries = hash_sizes[ht->size_index].max_entries;
  120.    ht->key_equals_function = key_equals_function;
  121.    ht->table = rzalloc_array(ht, struct set_entry, ht->size);
  122.    ht->entries = 0;
  123.    ht->deleted_entries = 0;
  124.  
  125.    if (ht->table == NULL) {
  126.       ralloc_free(ht);
  127.       return NULL;
  128.    }
  129.  
  130.    return ht;
  131. }
  132.  
  133. /**
  134.  * Frees the given set.
  135.  *
  136.  * If delete_function is passed, it gets called on each entry present before
  137.  * freeing.
  138.  */
  139. void
  140. _mesa_set_destroy(struct set *ht, void (*delete_function)(struct set_entry *entry))
  141. {
  142.    if (!ht)
  143.       return;
  144.  
  145.    if (delete_function) {
  146.       struct set_entry *entry;
  147.  
  148.       set_foreach (ht, entry) {
  149.          delete_function(entry);
  150.       }
  151.    }
  152.    ralloc_free(ht->table);
  153.    ralloc_free(ht);
  154. }
  155.  
  156. /**
  157.  * Finds a set entry with the given key and hash of that key.
  158.  *
  159.  * Returns NULL if no entry is found.
  160.  */
  161. struct set_entry *
  162. _mesa_set_search(const struct set *ht, uint32_t hash, const void *key)
  163. {
  164.    uint32_t hash_address;
  165.  
  166.    hash_address = hash % ht->size;
  167.    do {
  168.       uint32_t double_hash;
  169.  
  170.       struct set_entry *entry = ht->table + hash_address;
  171.  
  172.       if (entry_is_free(entry)) {
  173.          return NULL;
  174.       } else if (entry_is_present(entry) && entry->hash == hash) {
  175.          if (ht->key_equals_function(key, entry->key)) {
  176.             return entry;
  177.          }
  178.       }
  179.  
  180.       double_hash = 1 + hash % ht->rehash;
  181.  
  182.       hash_address = (hash_address + double_hash) % ht->size;
  183.    } while (hash_address != hash % ht->size);
  184.  
  185.    return NULL;
  186. }
  187.  
  188. static void
  189. set_rehash(struct set *ht, int new_size_index)
  190. {
  191.    struct set old_ht;
  192.    struct set_entry *table, *entry;
  193.  
  194.    if (new_size_index >= ARRAY_SIZE(hash_sizes))
  195.       return;
  196.  
  197.    table = rzalloc_array(ht, struct set_entry,
  198.                          hash_sizes[new_size_index].size);
  199.    if (table == NULL)
  200.       return;
  201.  
  202.    old_ht = *ht;
  203.  
  204.    ht->table = table;
  205.    ht->size_index = new_size_index;
  206.    ht->size = hash_sizes[ht->size_index].size;
  207.    ht->rehash = hash_sizes[ht->size_index].rehash;
  208.    ht->max_entries = hash_sizes[ht->size_index].max_entries;
  209.    ht->entries = 0;
  210.    ht->deleted_entries = 0;
  211.  
  212.    for (entry = old_ht.table;
  213.         entry != old_ht.table + old_ht.size;
  214.         entry++) {
  215.       if (entry_is_present(entry)) {
  216.          _mesa_set_add(ht, entry->hash, entry->key);
  217.       }
  218.    }
  219.  
  220.    ralloc_free(old_ht.table);
  221. }
  222.  
  223. /**
  224.  * Inserts the key with the given hash into the table.
  225.  *
  226.  * Note that insertion may rearrange the table on a resize or rehash,
  227.  * so previously found hash_entries are no longer valid after this function.
  228.  */
  229. struct set_entry *
  230. _mesa_set_add(struct set *ht, uint32_t hash, const void *key)
  231. {
  232.    uint32_t hash_address;
  233.  
  234.    if (ht->entries >= ht->max_entries) {
  235.       set_rehash(ht, ht->size_index + 1);
  236.    } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
  237.       set_rehash(ht, ht->size_index);
  238.    }
  239.  
  240.    hash_address = hash % ht->size;
  241.    do {
  242.       struct set_entry *entry = ht->table + hash_address;
  243.       uint32_t double_hash;
  244.  
  245.       if (!entry_is_present(entry)) {
  246.          if (entry_is_deleted(entry))
  247.             ht->deleted_entries--;
  248.          entry->hash = hash;
  249.          entry->key = key;
  250.          ht->entries++;
  251.          return entry;
  252.       }
  253.  
  254.       /* Implement replacement when another insert happens
  255.        * with a matching key.  This is a relatively common
  256.        * feature of hash tables, with the alternative
  257.        * generally being "insert the new value as well, and
  258.        * return it first when the key is searched for".
  259.        *
  260.        * Note that the hash table doesn't have a delete callback.
  261.        * If freeing of old keys is required to avoid memory leaks,
  262.        * perform a search before inserting.
  263.        */
  264.       if (entry->hash == hash &&
  265.           ht->key_equals_function(key, entry->key)) {
  266.          entry->key = key;
  267.          return entry;
  268.       }
  269.  
  270.       double_hash = 1 + hash % ht->rehash;
  271.  
  272.       hash_address = (hash_address + double_hash) % ht->size;
  273.    } while (hash_address != hash % ht->size);
  274.  
  275.    /* We could hit here if a required resize failed. An unchecked-malloc
  276.     * application could ignore this result.
  277.     */
  278.    return NULL;
  279. }
  280.  
  281. /**
  282.  * This function deletes the given hash table entry.
  283.  *
  284.  * Note that deletion doesn't otherwise modify the table, so an iteration over
  285.  * the table deleting entries is safe.
  286.  */
  287. void
  288. _mesa_set_remove(struct set *ht, struct set_entry *entry)
  289. {
  290.    if (!entry)
  291.       return;
  292.  
  293.    entry->key = deleted_key;
  294.    ht->entries--;
  295.    ht->deleted_entries++;
  296. }
  297.  
  298. /**
  299.  * This function is an iterator over the hash table.
  300.  *
  301.  * Pass in NULL for the first entry, as in the start of a for loop.  Note that
  302.  * an iteration over the table is O(table_size) not O(entries).
  303.  */
  304. struct set_entry *
  305. _mesa_set_next_entry(const struct set *ht, struct set_entry *entry)
  306. {
  307.    if (entry == NULL)
  308.       entry = ht->table;
  309.    else
  310.       entry = entry + 1;
  311.  
  312.    for (; entry != ht->table + ht->size; entry++) {
  313.       if (entry_is_present(entry)) {
  314.          return entry;
  315.       }
  316.    }
  317.  
  318.    return NULL;
  319. }
  320.  
  321. struct set_entry *
  322. _mesa_set_random_entry(struct set *ht,
  323.                        int (*predicate)(struct set_entry *entry))
  324. {
  325.    struct set_entry *entry;
  326.    uint32_t i = rand() % ht->size;
  327.  
  328.    if (ht->entries == 0)
  329.       return NULL;
  330.  
  331.    for (entry = ht->table + i; entry != ht->table + ht->size; entry++) {
  332.       if (entry_is_present(entry) &&
  333.           (!predicate || predicate(entry))) {
  334.          return entry;
  335.       }
  336.    }
  337.  
  338.    for (entry = ht->table; entry != ht->table + i; entry++) {
  339.       if (entry_is_present(entry) &&
  340.           (!predicate || predicate(entry))) {
  341.          return entry;
  342.       }
  343.    }
  344.  
  345.    return NULL;
  346. }
  347.  
  348.