mirror of
https://review.haiku-os.org/buildtools
synced 2024-11-23 07:18:49 +01:00
9897128cb9
Change-Id: I9d707083f0a9e71d3bcc02b3265bfb233bdbe46c Reviewed-on: https://review.haiku-os.org/c/buildtools/+/3019 Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
242 lines
5.0 KiB
C
242 lines
5.0 KiB
C
/*
|
|
* Copyright 2008-2009 Katholieke Universiteit Leuven
|
|
*
|
|
* Use of this software is governed by the MIT license
|
|
*
|
|
* Written by Sven Verdoolaege, K.U.Leuven, Departement
|
|
* Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <isl/hash.h>
|
|
#include <isl/ctx.h>
|
|
#include "isl_config.h"
|
|
|
|
uint32_t isl_hash_string(uint32_t hash, const char *s)
|
|
{
|
|
for (; *s; s++)
|
|
isl_hash_byte(hash, *s);
|
|
return hash;
|
|
}
|
|
|
|
uint32_t isl_hash_mem(uint32_t hash, const void *p, size_t len)
|
|
{
|
|
int i;
|
|
const char *s = p;
|
|
for (i = 0; i < len; ++i)
|
|
isl_hash_byte(hash, s[i]);
|
|
return hash;
|
|
}
|
|
|
|
static unsigned int round_up(unsigned int v)
|
|
{
|
|
int old_v = v;
|
|
|
|
while (v) {
|
|
old_v = v;
|
|
v ^= v & -v;
|
|
}
|
|
return old_v << 1;
|
|
}
|
|
|
|
int isl_hash_table_init(struct isl_ctx *ctx, struct isl_hash_table *table,
|
|
int min_size)
|
|
{
|
|
size_t size;
|
|
|
|
if (!table)
|
|
return -1;
|
|
|
|
if (min_size < 2)
|
|
min_size = 2;
|
|
table->bits = ffs(round_up(4 * (min_size + 1) / 3 - 1)) - 1;
|
|
table->n = 0;
|
|
|
|
size = 1 << table->bits;
|
|
table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
|
|
size);
|
|
if (!table->entries)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Dummy comparison function that always returns false.
|
|
*/
|
|
static isl_bool no(const void *entry, const void *val)
|
|
{
|
|
return isl_bool_false;
|
|
}
|
|
|
|
/* Extend "table" to twice its size.
|
|
* Return 0 on success and -1 on error.
|
|
*
|
|
* We reuse isl_hash_table_find to create entries in the extended table.
|
|
* Since all entries in the original table are assumed to be different,
|
|
* there is no need to compare them against each other.
|
|
*/
|
|
static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table)
|
|
{
|
|
int n;
|
|
size_t old_size, size;
|
|
struct isl_hash_table_entry *entries;
|
|
uint32_t h;
|
|
|
|
entries = table->entries;
|
|
old_size = 1 << table->bits;
|
|
size = 2 * old_size;
|
|
table->entries = isl_calloc_array(ctx, struct isl_hash_table_entry,
|
|
size);
|
|
if (!table->entries) {
|
|
table->entries = entries;
|
|
return -1;
|
|
}
|
|
|
|
n = table->n;
|
|
table->n = 0;
|
|
table->bits++;
|
|
|
|
for (h = 0; h < old_size; ++h) {
|
|
struct isl_hash_table_entry *entry;
|
|
|
|
if (!entries[h].data)
|
|
continue;
|
|
|
|
entry = isl_hash_table_find(ctx, table, entries[h].hash,
|
|
&no, NULL, 1);
|
|
if (!entry) {
|
|
table->bits--;
|
|
free(table->entries);
|
|
table->entries = entries;
|
|
table->n = n;
|
|
return -1;
|
|
}
|
|
|
|
*entry = entries[h];
|
|
}
|
|
|
|
free(entries);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct isl_hash_table *isl_hash_table_alloc(struct isl_ctx *ctx, int min_size)
|
|
{
|
|
struct isl_hash_table *table = NULL;
|
|
|
|
table = isl_alloc_type(ctx, struct isl_hash_table);
|
|
if (isl_hash_table_init(ctx, table, min_size))
|
|
goto error;
|
|
return table;
|
|
error:
|
|
isl_hash_table_free(ctx, table);
|
|
return NULL;
|
|
}
|
|
|
|
void isl_hash_table_clear(struct isl_hash_table *table)
|
|
{
|
|
if (!table)
|
|
return;
|
|
free(table->entries);
|
|
}
|
|
|
|
void isl_hash_table_free(struct isl_ctx *ctx, struct isl_hash_table *table)
|
|
{
|
|
if (!table)
|
|
return;
|
|
isl_hash_table_clear(table);
|
|
free(table);
|
|
}
|
|
|
|
/* A dummy entry that is used by isl_hash_table_find
|
|
* to make a distinction between a missing entry and an error condition.
|
|
*/
|
|
static struct isl_hash_table_entry none = { 0, NULL };
|
|
struct isl_hash_table_entry *isl_hash_table_entry_none = &none;
|
|
|
|
struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
|
|
struct isl_hash_table *table,
|
|
uint32_t key_hash,
|
|
isl_bool (*eq)(const void *entry, const void *val),
|
|
const void *val, int reserve)
|
|
{
|
|
size_t size;
|
|
uint32_t h, key_bits;
|
|
|
|
key_bits = isl_hash_bits(key_hash, table->bits);
|
|
size = 1 << table->bits;
|
|
for (h = key_bits; table->entries[h].data; h = (h+1) % size) {
|
|
isl_bool equal;
|
|
|
|
if (table->entries[h].hash != key_hash)
|
|
continue;
|
|
equal = eq(table->entries[h].data, val);
|
|
if (equal < 0)
|
|
return NULL;
|
|
if (equal)
|
|
return &table->entries[h];
|
|
}
|
|
|
|
if (!reserve)
|
|
return isl_hash_table_entry_none;
|
|
|
|
if (4 * table->n >= 3 * size) {
|
|
if (grow_table(ctx, table) < 0)
|
|
return NULL;
|
|
return isl_hash_table_find(ctx, table, key_hash, eq, val, 1);
|
|
}
|
|
|
|
table->n++;
|
|
table->entries[h].hash = key_hash;
|
|
|
|
return &table->entries[h];
|
|
}
|
|
|
|
isl_stat isl_hash_table_foreach(isl_ctx *ctx, struct isl_hash_table *table,
|
|
isl_stat (*fn)(void **entry, void *user), void *user)
|
|
{
|
|
size_t size;
|
|
uint32_t h;
|
|
|
|
if (!table->entries)
|
|
return isl_stat_error;
|
|
|
|
size = 1 << table->bits;
|
|
for (h = 0; h < size; ++ h)
|
|
if (table->entries[h].data &&
|
|
fn(&table->entries[h].data, user) < 0)
|
|
return isl_stat_error;
|
|
|
|
return isl_stat_ok;
|
|
}
|
|
|
|
void isl_hash_table_remove(struct isl_ctx *ctx,
|
|
struct isl_hash_table *table,
|
|
struct isl_hash_table_entry *entry)
|
|
{
|
|
int h, h2;
|
|
size_t size;
|
|
|
|
if (!table || !entry)
|
|
return;
|
|
|
|
size = 1 << table->bits;
|
|
h = entry - table->entries;
|
|
isl_assert(ctx, h >= 0 && h < size, return);
|
|
|
|
for (h2 = h+1; table->entries[h2 % size].data; h2++) {
|
|
uint32_t bits = isl_hash_bits(table->entries[h2 % size].hash,
|
|
table->bits);
|
|
uint32_t offset = (size + bits - (h+1)) % size;
|
|
if (offset <= h2 - (h+1))
|
|
continue;
|
|
*entry = table->entries[h2 % size];
|
|
h = h2;
|
|
entry = &table->entries[h % size];
|
|
}
|
|
|
|
entry->hash = 0;
|
|
entry->data = NULL;
|
|
table->n--;
|
|
}
|