Blame isl-0.14/isl_hash.c

Packit fb9d21
/*
Packit fb9d21
 * Copyright 2008-2009 Katholieke Universiteit Leuven
Packit fb9d21
 *
Packit fb9d21
 * Use of this software is governed by the MIT license
Packit fb9d21
 *
Packit fb9d21
 * Written by Sven Verdoolaege, K.U.Leuven, Departement
Packit fb9d21
 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
Packit fb9d21
 */
Packit fb9d21
Packit fb9d21
#include <stdlib.h>
Packit fb9d21
#include <strings.h>
Packit fb9d21
#include <isl/hash.h>
Packit fb9d21
#include <isl/ctx.h>
Packit fb9d21
#include "isl_config.h"
Packit fb9d21
Packit fb9d21
uint32_t isl_hash_string(uint32_t hash, const char *s)
Packit fb9d21
{
Packit fb9d21
	for (; *s; s++)
Packit fb9d21
		isl_hash_byte(hash, *s);
Packit fb9d21
	return hash;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
	const char *s = p;
Packit fb9d21
	for (i = 0; i < len; ++i)
Packit fb9d21
		isl_hash_byte(hash, s[i]);
Packit fb9d21
	return hash;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
static unsigned int round_up(unsigned int v)
Packit fb9d21
{
Packit fb9d21
	int old_v = v;
Packit fb9d21
Packit fb9d21
	while (v) {
Packit fb9d21
		old_v = v;
Packit fb9d21
		v ^= v & -v;
Packit fb9d21
	}
Packit fb9d21
	return old_v << 1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table,
Packit fb9d21
			int min_size)
Packit fb9d21
{
Packit fb9d21
	size_t size;
Packit fb9d21
Packit fb9d21
	if (!table)
Packit fb9d21
		return -1;
Packit fb9d21
Packit fb9d21
	if (min_size < 2)
Packit fb9d21
		min_size = 2;
Packit fb9d21
	table->bits = ffs(round_up(4 * (min_size + 1) / 3 - 1)) - 1;
Packit fb9d21
	table->n = 0;
Packit fb9d21
Packit fb9d21
	size = 1 << table->bits;
Packit fb9d21
	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
Packit fb9d21
					  size);
Packit fb9d21
	if (!table->entries)
Packit fb9d21
		return -1;
Packit fb9d21
Packit fb9d21
	return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Dummy comparison function that always returns false.
Packit fb9d21
 */
Packit fb9d21
static int no(const void *entry, const void *val)
Packit fb9d21
{
Packit fb9d21
	return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Extend "table" to twice its size.
Packit fb9d21
 * Return 0 on success and -1 on error.
Packit fb9d21
 *
Packit fb9d21
 * We reuse isl_hash_table_find to create entries in the extended table.
Packit fb9d21
 * Since all entries in the original table are assumed to be different,
Packit fb9d21
 * there is no need to compare them against each other.
Packit fb9d21
 */
Packit fb9d21
static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table)
Packit fb9d21
{
Packit fb9d21
	int n;
Packit fb9d21
	size_t old_size, size;
Packit fb9d21
	struct isl_hash_table_entry *entries;
Packit fb9d21
	uint32_t h;
Packit fb9d21
Packit fb9d21
	entries = table->entries;
Packit fb9d21
	old_size = 1 << table->bits;
Packit fb9d21
	size = 2 * old_size;
Packit fb9d21
	table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
Packit fb9d21
					  size);
Packit fb9d21
	if (!table->entries) {
Packit fb9d21
		table->entries = entries;
Packit fb9d21
		return -1;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	n = table->n;
Packit fb9d21
	table->n = 0;
Packit fb9d21
	table->bits++;
Packit fb9d21
Packit fb9d21
	for (h = 0; h < old_size; ++h) {
Packit fb9d21
		struct isl_hash_table_entry *entry;
Packit fb9d21
Packit fb9d21
		if (!entries[h].data)
Packit fb9d21
			continue;
Packit fb9d21
Packit fb9d21
		entry = isl_hash_table_find(ctx, table, entries[h].hash,
Packit fb9d21
					    &no, NULL, 1);
Packit fb9d21
		if (!entry) {
Packit fb9d21
			table->bits--;
Packit fb9d21
			free(table->entries);
Packit fb9d21
			table->entries = entries;
Packit fb9d21
			table->n = n;
Packit fb9d21
			return -1;
Packit fb9d21
		}
Packit fb9d21
Packit fb9d21
		*entry = entries[h];
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	free(entries);
Packit fb9d21
Packit fb9d21
	return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size)
Packit fb9d21
{
Packit fb9d21
	struct isl_hash_table *table = NULL;
Packit fb9d21
Packit fb9d21
	table = isl_alloc_type(ctx, struct isl_hash_table);
Packit fb9d21
	if (isl_hash_table_init(ctx, table, min_size))
Packit fb9d21
		goto error;
Packit fb9d21
	return table;
Packit fb9d21
error:
Packit fb9d21
	isl_hash_table_free(ctx, table);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
void isl_hash_table_clear(struct isl_hash_table *table)
Packit fb9d21
{
Packit fb9d21
	if (!table)
Packit fb9d21
		return;
Packit fb9d21
	free(table->entries);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table)
Packit fb9d21
{
Packit fb9d21
	if (!table)
Packit fb9d21
		return;
Packit fb9d21
	isl_hash_table_clear(table);
Packit fb9d21
	free(table);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
Packit fb9d21
				struct isl_hash_table *table,
Packit fb9d21
				uint32_t key_hash,
Packit fb9d21
				int (*eq)(const void *entry, const void *val),
Packit fb9d21
				const void *val, int reserve)
Packit fb9d21
{
Packit fb9d21
	size_t size;
Packit fb9d21
	uint32_t h, key_bits;
Packit fb9d21
Packit fb9d21
	key_bits = isl_hash_bits(key_hash, table->bits);
Packit fb9d21
	size = 1 << table->bits;
Packit fb9d21
	for (h = key_bits; table->entries[h].data; h = (h+1) % size)
Packit fb9d21
		if (table->entries[h].hash == key_hash &&
Packit fb9d21
		    eq(table->entries[h].data, val))
Packit fb9d21
			return &table->entries[h];
Packit fb9d21
Packit fb9d21
	if (!reserve)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	if (4 * table->n >= 3 * size) {
Packit fb9d21
		if (grow_table(ctx, table) < 0)
Packit fb9d21
			return NULL;
Packit fb9d21
		return isl_hash_table_find(ctx, table, key_hash, eq, val, 1);
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	table->n++;
Packit fb9d21
	table->entries[h].hash = key_hash;
Packit fb9d21
Packit fb9d21
	return &table->entries[h];
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
int isl_hash_table_foreach(struct isl_ctx *ctx,
Packit fb9d21
				struct isl_hash_table *table,
Packit fb9d21
				int (*fn)(void **entry, void *user), void *user)
Packit fb9d21
{
Packit fb9d21
	size_t size;
Packit fb9d21
	uint32_t h;
Packit fb9d21
Packit fb9d21
	if (!table->entries)
Packit fb9d21
		return -1;
Packit fb9d21
Packit fb9d21
	size = 1 << table->bits;
Packit fb9d21
	for (h = 0; h < size; ++ h)
Packit fb9d21
		if (table->entries[h].data &&
Packit fb9d21
		    fn(&table->entries[h].data, user) < 0)
Packit fb9d21
			return -1;
Packit fb9d21
	
Packit fb9d21
	return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
void isl_hash_table_remove(struct isl_ctx *ctx,
Packit fb9d21
				struct isl_hash_table *table,
Packit fb9d21
				struct isl_hash_table_entry *entry)
Packit fb9d21
{
Packit fb9d21
	int h, h2;
Packit fb9d21
	size_t size;
Packit fb9d21
Packit fb9d21
	if (!table || !entry)
Packit fb9d21
		return;
Packit fb9d21
Packit fb9d21
	size = 1 << table->bits;
Packit fb9d21
	h = entry - table->entries;
Packit fb9d21
	isl_assert(ctx, h >= 0 && h < size, return);
Packit fb9d21
Packit fb9d21
	for (h2 = h+1; table->entries[h2 % size].data; h2++) {
Packit fb9d21
		uint32_t bits = isl_hash_bits(table->entries[h2 % size].hash,
Packit fb9d21
						table->bits);
Packit fb9d21
		uint32_t offset = (size + bits - (h+1)) % size;
Packit fb9d21
		if (offset <= h2 - (h+1))
Packit fb9d21
			continue;
Packit fb9d21
		*entry = table->entries[h2 % size];
Packit fb9d21
		h = h2;
Packit fb9d21
		entry = &table->entries[h % size];
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	entry->hash = 0;
Packit fb9d21
	entry->data = NULL;
Packit fb9d21
	table->n--;
Packit fb9d21
}