Skip to content

Instantly share code, notes, and snippets.

@sug0
Last active August 12, 2017 18:38
Show Gist options
  • Save sug0/bd7dfa0bbdcb7f8772839c2431d3b1c3 to your computer and use it in GitHub Desktop.
Save sug0/bd7dfa0bbdcb7f8772839c2431d3b1c3 to your computer and use it in GitHub Desktop.
Fixed size hash table implementation, based on https://www.youtube.com/watch?v=qTZJLJ3Gm6Q
#include "hash.h"
struct _lst {
void *e;
uint64_t hash;
struct _lst *next;
};
/*
* Adapted sdbm hashing function
* */
static uint64_t hash(void *data, size_t size)
{
size_t sz = size;
uint64_t hash = 0;
uint8_t *ptr = (uint8_t *)data;
while (sz-- > 0) {
hash = *ptr + (hash << 6) + (hash << 16) - hash;
ptr++;
}
return hash;
}
static inline struct _lst *new_lst(void)
{
return (struct _lst *)calloc(sizeof(struct _lst), 1);
}
static int add(struct _lst *lst, void *e, uint64_t keyhash)
{
if (!lst || !e)
return -1;
struct _lst *ptr = lst, *new, *last;
while (ptr) {
if (!ptr->next)
last = ptr;
if (ptr->hash == keyhash) {
ptr->e = e;
goto done;
}
ptr = ptr->next;
}
new = new_lst();
if (!new)
return -2;
new->e = e;
new->hash = keyhash;
last->next = new;
done:
return 0;
}
static void *get(struct _lst *lst, uint64_t hash)
{
struct _lst *ptr = lst;
while (ptr) {
if (ptr->hash == hash)
return ptr->e;
else
ptr = ptr->next;
}
return NULL;
}
static void free_lst(struct _lst *lst)
{
struct _lst *ptr = lst, *next;
while (ptr) {
next = ptr->next;
free(ptr);
ptr = next;
}
}
int init_dict(dict_t *d, size_t size)
{
if (!d)
return -1;
struct _lst **es = calloc(sizeof(struct _lst), size);
if (!es)
return -2;
d->es = es;
d->size = size;
return 0;
}
int insert_dict(dict_t *d, size_t keysize, void *k, void *v)
{
if (!d || !k || !v)
return -1;
uint64_t keyhash = hash(k, keysize);
uint64_t index = keyhash % d->size;
if (!d->es[index]) {
struct _lst *new = new_lst();
if (!new)
return -2;
new->e = v;
new->hash = keyhash;
d->es[index] = new;
} else {
int rt = add(d->es[index], v, keyhash);
if (rt < 0)
return rt;
}
return 0;
}
void *at(dict_t *d, size_t keysize, void *k)
{
if (!d || !k)
return NULL;
uint64_t keyhash = hash(k, keysize);
uint64_t index = keyhash % d->size;
return get(d->es[index], keyhash);
}
void destroy_dict(dict_t *d)
{
if (!d)
return;
for (size_t i = 0; i < d->size; i++)
free_lst(d->es[i]);
free(d->es);
}
#ifndef _HASHTAB_H_
#define _HASHTAB_H_
/*
* Fixed size hash table implementation,
* with collision handled by a single linked list;
* based on https://www.youtube.com/watch?v=qTZJLJ3Gm6Q
* */
#include <stdlib.h>
#include <stdint.h>
struct _lst;
typedef struct hashtab dict_t;
struct hashtab {
struct _lst **es;
size_t size;
};
extern int init_dict(dict_t *d, size_t size);
extern int insert_dict(dict_t *d, size_t keysize, void *k, void *v);
extern void *at(dict_t *d, size_t keysize, void *k);
extern void destroy_dict(dict_t *d);
#endif
#include <stdio.h>
#include <string.h>
#include "hash.h"
int main(void)
{
dict_t d;
char *key1 = "wew", *key2 = "lad";
size_t len1 = strlen(key1) + 1, len2 = strlen(key2) + 1;
init_dict(&d, 10);
insert_dict(&d, len1, key1, (void *)123);
insert_dict(&d, len2, key2, (void *)321);
printf("%d, %d\n",
at(&d, len1, key1),
at(&d, len2, key2));
destroy_dict(&d);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "hash.h"
#define dict_entry(D, K, V) insert_dict(D, strlen(K) + 1, K, V)
#define entry(D, K) at(D, strlen(K) + 1, K)
#define call(D, T, K, ...) ((T)entry(D, K))(__VA_ARGS__)
static inline void hey(void)
{
puts("sup");
}
static inline void dude(char *a, char *b)
{
puts(a);
puts(b);
}
int main(void)
{
dict_t d;
init_dict(&d, 0x10);
dict_entry(&d, "upper", isupper);
dict_entry(&d, "lower", islower);
dict_entry(&d, "alpha", isalpha);
dict_entry(&d, "alnum", isalnum);
dict_entry(&d, "hey", hey);
dict_entry(&d, "dude", dude);
if (call(&d, int (*)(int), "upper", 'A'))
puts("ye");
call(&d, void (*)(void), "hey");
call(&d, void (*)(char *, char *), "dude", "wat up", "nigga");
destroy_dict(&d);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment