hash.c revision c04da04cc300ef1c143ff09b566e44f74f5626df
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith/* @UNSAFE: whole file */
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith unsigned int initial_size, nodes_count, removed_count;
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith unsigned int size;
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith unsigned int pos;
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic bool hash_table_resize(struct hash_table *table, bool grow);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithvoid hash_table_create(struct hash_table **table_r, pool_t node_pool,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith unsigned int initial_size, hash_callback_t *hash_cb,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith I_MAX(primes_closest(initial_size), HASH_TABLE_MIN_SIZE);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith table->nodes = i_new(struct hash_node, table->size);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic unsigned int direct_hash(const void *p)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith /* NOTE: may truncate the value, but that doesn't matter. */
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith return POINTER_CAST_TO(p, unsigned int);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic int direct_cmp(const void *p1, const void *p2)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithvoid hash_table_create_direct(struct hash_table **table_r, pool_t node_pool,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith hash_table_create(table_r, node_pool, initial_size,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic void free_node(struct hash_table *table, struct hash_node *node)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic void destroy_node_list(struct hash_table *table, struct hash_node *node)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic void hash_table_destroy_nodes(struct hash_table *table)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith unsigned int i;
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith destroy_node_list(table, table->nodes[i].next);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithvoid hash_table_destroy(struct hash_table **_table)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith destroy_node_list(table, table->free_nodes);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithvoid hash_table_clear(struct hash_table *table, bool free_nodes)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith destroy_node_list(table, table->free_nodes);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith memset(table->nodes, 0, sizeof(struct hash_node) * table->size);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic struct hash_node *
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithhash_table_lookup_node(const struct hash_table *table,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith if (table->key_compare_cb(node->key, key) == 0)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithvoid *hash_table_lookup(const struct hash_table *table, const void *key)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith node = hash_table_lookup_node(table, key, table->hash_cb(key));
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithbool hash_table_lookup_full(const struct hash_table *table,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith node = hash_table_lookup_node(table, lookup_key,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithstatic struct hash_node * ATTR_NOWARN_UNUSED_RESULT
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithhash_table_insert_node(struct hash_table *table, void *key, void *value,
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith unsigned int hash;
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith if (check_existing && table->removed_count > 0) {
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith /* there may be holes, have to check everything */
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith node = hash_table_lookup_node(table, key, hash);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith /* a) primary node */
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith if (table->key_compare_cb(node->key, key) == 0) {
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith /* b) collisions list */
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith if (table->key_compare_cb(node->key, key) == 0) {
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith if (table->frozen == 0 && hash_table_resize(table, TRUE)) {
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith /* resized table, try again */
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith return hash_table_insert_node(table, key, value, FALSE);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith node = p_new(table->node_pool, struct hash_node, 1);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithvoid hash_table_insert(struct hash_table *table, void *key, void *value)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith node = hash_table_insert_node(table, key, value, TRUE);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithvoid hash_table_update(struct hash_table *table, void *key, void *value)
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmith hash_table_insert_node(table, key, value, TRUE);
c1bef59b02d89a84c23d29663cc4e6d46148ebd2David Goldsmithhash_table_compress(struct hash_table *table, struct hash_node *root)
unsigned int hash;
return FALSE;
return TRUE;
return ctx;
static struct hash_node *
return NULL;
return node;
return FALSE;
return TRUE;
float nodes_per_list;
return FALSE;
return FALSE;
return FALSE;
for (i = 0; i < old_size; i++) {
return TRUE;
unsigned int str_hash(const char *p)
unsigned int strcase_hash(const char *p)
for (i = 0; i < size; i++) {