hexagram/src/dict.c
2019-05-21 09:24:19 -05:00

277 lines
6.6 KiB
C

#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;
}
void *hexagram_dict_get_s(hexagram_dict *dict, const char *key) {
return hexagram_dict_get(dict, (void *)key, strlen(key));
}
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;
}
int hexagram_dict_delete_s(hexagram_dict *dict, const char *key) {
return hexagram_dict_delete(dict, (void*)key, strlen(key));
}
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;
}
void *hexagram_dict_set_s(hexagram_dict *dict, const char *key, void *value) {
return hexagram_dict_set(dict, (void *)key, strlen(key), value);
}