diff --git a/include/hexagram/dict.h b/include/hexagram/dict.h new file mode 100644 index 0000000..3f9b08c --- /dev/null +++ b/include/hexagram/dict.h @@ -0,0 +1,56 @@ +#ifndef _HEXAGRAM_DICT_H +#define _HEXAGRAM_DICT_H + +#include +#include + +#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 */ diff --git a/include/hexagram/hash.h b/include/hexagram/hash.h new file mode 100644 index 0000000..ae40e0d --- /dev/null +++ b/include/hexagram/hash.h @@ -0,0 +1,11 @@ +#ifndef _HEXAGRAM_HASH_H +#define _HEXAGRAM_HASH_H + +#include +#include + +#define HEXAGRAM_DICT_BUCKET_SIZE 16 + +int hexagram_hash(void *key, size_t keysz, uint32_t *hash); + +#endif /* _HEXAGRAM_HASH_H */ diff --git a/src/Makefile b/src/Makefile index a9bceec..ad4cc1b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,10 +7,10 @@ CC = $(CROSS)cc CFLAGS += -fPIC -I$(INCLUDE_PATH) LDFLAGS = -HEADERS = can.h capture.h pcapng.h +HEADERS = dict.h hash.h can.h capture.h pcapng.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_MINOR = 0.1 diff --git a/src/dict.c b/src/dict.c new file mode 100644 index 0000000..5a91b12 --- /dev/null +++ b/src/dict.c @@ -0,0 +1,264 @@ +#include +#include + +#include +#include + +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; islots[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; islots[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; +} diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..39e77c7 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,30 @@ +#include +#include + +#include + +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> 6); + } + + value += (value << 3); + value ^= (value >> 11); + value += (value << 15); + + *hash = value; + + return 0; + +error_null_data: + return -1; +}