#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; } 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); }