How's about a hash table dangit

This commit is contained in:
XANTRONIX Development 2019-05-18 19:48:28 -05:00
parent 9fbd247dd4
commit 318704622c
5 changed files with 363 additions and 2 deletions

56
include/hexagram/dict.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef _HEXAGRAM_DICT_H
#define _HEXAGRAM_DICT_H
#include <stdint.h>
#include <sys/types.h>
#define HEXAGRAM_DICT_BUCKET_SLOTS 16
#define HEXAGRAM_DICT_BUCKET_DEPTH 7
typedef struct _hexagram_dict_slot {
uint32_t hash;
void *key;
void *value;
struct _hexagram_dict_slot *next_bucket;
} hexagram_dict_slot;
typedef struct _hexagram_dict_bucket {
hexagram_dict_slot slots[16];
} hexagram_dict_bucket;
typedef void (hexagram_dict_retainer)(void *);
typedef void (hexagram_dict_releaser)(void *);
typedef struct _hexagram_dict {
hexagram_dict_bucket *bucket;
} hexagram_dict;
hexagram_dict *hexagram_dict_new();
void hexagram_dict_destroy(hexagram_dict *dict);
typedef int (hexagram_dict_callback)(hexagram_dict *dict,
hexagram_dict_slot *slot,
void *ctx);
int hexagram_dict_each(hexagram_dict *dict,
hexagram_dict_callback *callback,
void *ctx);
void *hexagram_dict_get(hexagram_dict *dict, void *key, size_t keysz);
int hexagram_dict_delete(hexagram_dict *dict, void *key, size_t keysz);
void *hexagram_dict_set_with_hash(hexagram_dict *dict,
void *key,
void *value,
uint32_t hash);
void *hexagram_dict_set(hexagram_dict *dict,
void *key,
size_t keysz,
void *value);
#endif /* _HEXAGRAM_DICT_H */

11
include/hexagram/hash.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef _HEXAGRAM_HASH_H
#define _HEXAGRAM_HASH_H
#include <stdint.h>
#include <sys/types.h>
#define HEXAGRAM_DICT_BUCKET_SIZE 16
int hexagram_hash(void *key, size_t keysz, uint32_t *hash);
#endif /* _HEXAGRAM_HASH_H */

View file

@ -7,10 +7,10 @@ CC = $(CROSS)cc
CFLAGS += -fPIC -I$(INCLUDE_PATH) CFLAGS += -fPIC -I$(INCLUDE_PATH)
LDFLAGS = LDFLAGS =
HEADERS = can.h capture.h pcapng.h HEADERS = dict.h hash.h can.h capture.h pcapng.h
HEADERS_LOCAL = util.h HEADERS_LOCAL = util.h
OBJS = can.o capture.o pcapng.o OBJS = dict.o hash.o can.o capture.o pcapng.o
VERSION_MAJOR = 0 VERSION_MAJOR = 0
VERSION_MINOR = 0.1 VERSION_MINOR = 0.1

264
src/dict.c Normal file
View file

@ -0,0 +1,264 @@
#include <stdlib.h>
#include <string.h>
#include <hexagram/dict.h>
#include <hexagram/hash.h>
hexagram_dict *hexagram_dict_new() {
hexagram_dict *dict;
if ((dict = malloc(sizeof(*dict))) == NULL) {
goto error_malloc_dict;
}
memset(dict, 0x00, sizeof(*dict));
if ((dict->bucket = malloc(sizeof(*dict->bucket))) == NULL) {
goto error_malloc_dict_bucket;
}
memset(dict->bucket, 0x00, sizeof(*dict->bucket));
return dict;
error_malloc_dict_bucket:
free(dict);
error_malloc_dict:
return NULL;
}
static void bucket_destroy(hexagram_dict *dict, hexagram_dict_bucket *bucket) {
int i;
for (i=0; i<HEXAGRAM_DICT_BUCKET_SLOTS; i++) {
hexagram_dict_slot *slot = &bucket->slots[i];
if (slot->next_bucket) {
bucket_destroy(dict, (hexagram_dict_bucket *)slot->next_bucket);
}
if (slot->key) {
slot->key = NULL;
}
if (slot->value) {
slot->value = NULL;
}
}
free(bucket);
}
void hexagram_dict_destroy(hexagram_dict *dict) {
bucket_destroy(dict, dict->bucket);
free(dict);
}
static hexagram_dict_slot *slot_find_readable(hexagram_dict *dict, uint32_t hash) {
hexagram_dict_bucket *bucket = dict->bucket;
int collisions;
for (collisions = 0; collisions < HEXAGRAM_DICT_BUCKET_DEPTH; collisions++) {
uint32_t mask = 0x0f << (4 * collisions);
uint8_t index = (hash & mask) >> (4 * collisions);
hexagram_dict_slot *slot = &bucket->slots[index];
if (slot->hash == 0x00000000) {
/*
* In this case, we have determined that there is no value in the
* dict for the given hash.
*/
return NULL;
} else if (slot->hash == hash) {
/*
* We have found the desired slot, so return that.
*/
return slot;
}
/*
* Otherwise, look for the next bucket, if present.
*/
bucket = (hexagram_dict_bucket *)slot->next_bucket;
/*
* If there is no next bucket available, then return null.
*/
if (bucket == NULL) {
return NULL;
}
}
return NULL;
}
static hexagram_dict_slot *slot_find_writable(hexagram_dict *dict, uint32_t hash) {
hexagram_dict_bucket *bucket = dict->bucket;
int collisions;
for (collisions = 0; collisions < HEXAGRAM_DICT_BUCKET_DEPTH; collisions++) {
uint32_t mask = 0x0f << (4 * collisions);
uint8_t index = (hash & mask) >> (4 * collisions);
hexagram_dict_slot *slot = &bucket->slots[index];
if ((slot->hash == 0x00 && slot->key == NULL) || slot->hash == hash) {
/*
* We have found a suitable slot, so let's return that.
*/
return slot;
}
/*
* Take a look to see if there is a next bucket in the chain.
*/
bucket = (hexagram_dict_bucket *)slot->next_bucket;
/*
* If there is no next bucket available, then create one.
*/
if (bucket == NULL) {
if ((bucket = malloc(sizeof(*bucket))) == NULL) {
goto error_malloc_bucket;
}
memset(bucket, 0x00, sizeof(*bucket));
slot->next_bucket = (hexagram_dict_slot *)bucket;
}
}
return NULL;
error_malloc_bucket:
return NULL;
}
static int bucket_each_slot(hexagram_dict *dict,
int level,
hexagram_dict_bucket *bucket,
hexagram_dict_callback *callback,
void *ctx) {
int i;
if (level > HEXAGRAM_DICT_BUCKET_DEPTH) {
return 0;
}
for (i=0; i<HEXAGRAM_DICT_BUCKET_SLOTS; i++) {
hexagram_dict_slot *slot = &bucket->slots[i];
if (slot->next_bucket) {
return bucket_each_slot(dict,
level+1,
(hexagram_dict_bucket *)slot->next_bucket,
callback,
ctx);
}
if (slot->key) {
if (callback(dict, slot, ctx) < 0) {
goto error_callback;
}
}
}
return 0;
error_callback:
return -1;
}
int hexagram_dict_each(hexagram_dict *dict,
hexagram_dict_callback *callback,
void *ctx) {
return bucket_each_slot(dict, 0, dict->bucket, callback, ctx);
}
void *hexagram_dict_get(hexagram_dict *dict,
void *key,
size_t keysz) {
hexagram_dict_slot *slot;
uint32_t hash;
if (hexagram_hash(key, keysz, &hash) < 0) {
goto error_hash;
}
if ((slot = slot_find_readable(dict, hash)) == NULL) {
goto error_slot_find_readable;
}
return slot->value;
error_slot_find_readable:
error_hash:
return NULL;
}
int hexagram_dict_delete(hexagram_dict *dict, void *key, size_t keysz) {
hexagram_dict_slot *slot;
uint32_t hash;
if (hexagram_hash(key, keysz, &hash) < 0) {
goto error_hash;
}
if ((slot = slot_find_readable(dict, hash)) == NULL) {
goto error_slot_find_readable;
}
if (slot->key) {
slot->key = NULL;
}
if (slot->value) {
slot->value = NULL;
}
return 0;
error_hash:
error_slot_find_readable:
return -1;
}
void *hexagram_dict_set_with_hash(hexagram_dict *dict,
void *key,
void *value,
uint32_t hash) {
hexagram_dict_slot *slot;
if ((slot = slot_find_writable(dict, hash)) == NULL) {
goto error_slot_find_writable;
}
slot->hash = hash;
slot->key = key;
return slot->value = value;
error_slot_find_writable:
return NULL;
}
void *hexagram_dict_set(hexagram_dict *dict,
void *key,
size_t keysz,
void *value) {
uint32_t hash;
if (hexagram_hash(key, keysz, &hash) < 0) {
goto error_hash;
}
return hexagram_dict_set_with_hash(dict, key, value, hash);
error_hash:
return NULL;
}

30
src/hash.c Normal file
View file

@ -0,0 +1,30 @@
#include <stdlib.h>
#include <string.h>
#include <hexagram/hash.h>
int hexagram_hash(void *data, size_t size, uint32_t *hash) {
uint32_t value = 0x00;
size_t i;
if (data == NULL) {
goto error_null_data;
}
for (i=0; i<size; i++) {
value += ((uint8_t *)data)[i];
value += (value << 10);
value ^= (value >> 6);
}
value += (value << 3);
value ^= (value >> 11);
value += (value << 15);
*hash = value;
return 0;
error_null_data:
return -1;
}