Source

randomc / hash.c

Full commit
#include <stdlib.h>
#include <string.h>

#include "hash.h"

struct hash* hash_init() {
    struct hash *h;
    int i;

    h = malloc(sizeof(struct hash));
    if (h == NULL)
        return NULL;

    h->size = 5;
    h->table = malloc(sizeof(struct hash*) * h->size);
    if (h->table == NULL) {
        free(h);
        return NULL;
    }

    for (i = 0; i < h->size; i += 1) {
        h->table[i] = NULL;
    }

    return h;
}

unsigned int hash(struct hash *h, const char *str) {
    unsigned int val = 0;

    for (; *str != '\0'; str += 1) {
        val = *str + (val << 5) - val;
    }

    return val % h->size;
}

static struct hash_list* _hash_find(struct hash *h, const char *key) {
    unsigned int val = hash(h, key);
    struct hash_list *l;

    for (l = h->table[val]; l != NULL; l = l->next) {
        if (strcmp(key, l->key) == 0) {
            return l;
        }
    }

    return NULL;
}

void* hash_get(struct hash *h, const char *key, void *default_) {
    struct hash_list *l;

    l = _hash_find(h, key);
    if (l == NULL) {
        return default_;
    }
    else {
        return l->value;
    }
}

int hash_set(struct hash *h, const char *key, void *value) {
    unsigned int val;
    struct hash_list *l, *next;

    l = _hash_find(h, key);
    if (l == NULL) {
        next = malloc(sizeof(struct hash_list));
        if (next == NULL)
            return 1;

        next->key = strdup(key);
        next->value = value;

        val = hash(h, key);
        next->next = h->table[val];
        h->table[val] = next;
    }
    else {
        l->value = value;
    }

    return 0;
}

void hash_free(struct hash *h) {
    struct hash_list *l, *next;
    size_t i;

    for (i = 0; i < h->size; i += 1) {
        next = h->table[i];

        while (next != NULL) {
            l = next;
            next = next->next;
            free(l->key);
            free(l);
        }
    }

    free(h->table);
    free(h);
}