nexmon – Rev 1

Subversion Repositories:
Rev:
/*
 * Copyright 2008-2009 Katholieke Universiteit Leuven
 *
 * Use of this software is governed by the GNU LGPLv2.1 license
 *
 * Written by Sven Verdoolaege, K.U.Leuven, Departement
 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
 */

#include <stdlib.h>
#include <strings.h>
#include <isl/hash.h>
#include <isl/ctx.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;
}

static int grow_table(struct isl_ctx *ctx, struct isl_hash_table *table,
                        int (*eq)(const void *entry, const void *val))
{
        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;
        }

        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,
                                            eq, entries[h].data, 1);
                if (!entry) {
                        table->bits--;
                        free(table->entries);
                        table->entries = entries;
                        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);
}

struct isl_hash_table_entry *isl_hash_table_find(struct isl_ctx *ctx,
                                struct isl_hash_table *table,
                                uint32_t key_hash,
                                int (*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)
                if (table->entries[h].hash == key_hash &&
                    eq(table->entries[h].data, val))
                        return &table->entries[h];

        if (!reserve)
                return NULL;

        if (4 * table->n >= 3 * size) {
                if (grow_table(ctx, table, eq) < 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];
}

int isl_hash_table_foreach(struct isl_ctx *ctx,
                                struct isl_hash_table *table,
                                int (*fn)(void **entry, void *user), void *user)
{
        size_t size;
        uint32_t h;

        size = 1 << table->bits;
        for (h = 0; h < size; ++ h)
                if (table->entries[h].data &&
                    fn(&table->entries[h].data, user) < 0)
                        return -1;
        
        return 0;
}

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--;
}