2015-07-20 16:27:17 -05:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <patty/dict.h>
|
|
|
|
|
|
|
|
patty_dict *patty_dict_new() {
|
|
|
|
patty_dict *dict;
|
|
|
|
|
|
|
|
if ((dict = malloc(sizeof(*dict))) == NULL) {
|
|
|
|
goto error_malloc_dict;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(dict, 0x00, sizeof(*dict));
|
|
|
|
|
|
|
|
return dict;
|
|
|
|
|
|
|
|
error_malloc_dict:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t key) {
|
2015-07-20 16:27:17 -05:00
|
|
|
patty_dict_bucket *bucket = &dict->bucket;
|
|
|
|
|
|
|
|
int collisions;
|
|
|
|
|
|
|
|
for (collisions = 0; collisions < 7; collisions++) {
|
|
|
|
uint32_t mask = 0x0f << (4 * collisions);
|
2020-07-08 17:12:40 -04:00
|
|
|
uint8_t index = (key & mask) >> (4 * collisions);
|
2015-07-20 16:27:17 -05:00
|
|
|
|
|
|
|
patty_dict_slot *slot = &bucket->slots[index];
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
if (!slot->set) {
|
2015-07-20 16:27:17 -05:00
|
|
|
/*
|
|
|
|
* In this case, we have determined that there is no value in the
|
2020-07-08 17:12:40 -04:00
|
|
|
* dict for the given key.
|
2015-07-20 16:27:17 -05:00
|
|
|
*/
|
|
|
|
return NULL;
|
2020-07-08 17:12:40 -04:00
|
|
|
} else if (slot->key == key) {
|
2015-07-20 16:27:17 -05:00
|
|
|
/*
|
|
|
|
* We have found the desired slot, so return that.
|
|
|
|
*/
|
|
|
|
return slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise, look for the next bucket, if present.
|
|
|
|
*/
|
|
|
|
bucket = (patty_dict_bucket *)slot->next;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is no next bucket available, then return null.
|
|
|
|
*/
|
|
|
|
if (bucket == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
static int bucket_each_slot(int level,
|
|
|
|
patty_dict_bucket *bucket,
|
|
|
|
patty_dict_callback callback,
|
|
|
|
void *ctx) {
|
2015-07-20 16:27:17 -05:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (level > 7) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<PATTY_DICT_BUCKET_SIZE; i++) {
|
|
|
|
patty_dict_slot *slot = &bucket->slots[i];
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
if (slot->set) {
|
|
|
|
if (callback(slot->key, slot->value, ctx) < 0) {
|
2015-07-20 16:27:17 -05:00
|
|
|
goto error_callback;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slot->next) {
|
2020-05-23 13:44:52 -04:00
|
|
|
if (bucket_each_slot(level+1,
|
|
|
|
(patty_dict_bucket *)slot->next,
|
|
|
|
callback,
|
|
|
|
ctx) < 0) {
|
|
|
|
goto error_next_slot;
|
|
|
|
}
|
2015-07-20 16:27:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_callback:
|
2020-05-23 13:44:52 -04:00
|
|
|
error_next_slot:
|
2015-07-20 16:27:17 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int patty_dict_each(patty_dict *dict, patty_dict_callback callback, void *ctx) {
|
|
|
|
return bucket_each_slot(0, &dict->bucket, callback, ctx);
|
|
|
|
}
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
void *patty_dict_get(patty_dict *dict, uint32_t key) {
|
2015-07-20 16:27:17 -05:00
|
|
|
patty_dict_slot *slot;
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
if ((slot = patty_dict_slot_find(dict, key)) == NULL) {
|
2015-07-20 16:27:17 -05:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return slot->value;
|
|
|
|
}
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
void *patty_dict_set(patty_dict *dict,
|
|
|
|
uint32_t key,
|
|
|
|
void *value) {
|
2015-07-20 16:27:17 -05:00
|
|
|
patty_dict_bucket *bucket = &dict->bucket;
|
|
|
|
|
|
|
|
int collisions;
|
|
|
|
|
|
|
|
for (collisions = 0; collisions < 7; collisions++) {
|
|
|
|
uint32_t mask = 0x0f << (4 * collisions);
|
2020-07-08 17:12:40 -04:00
|
|
|
uint8_t index = (key & mask) >> (4 * collisions);
|
2015-07-20 16:27:17 -05:00
|
|
|
|
|
|
|
patty_dict_slot *slot = &bucket->slots[index];
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
if (!slot->set) {
|
2015-07-20 16:27:17 -05:00
|
|
|
/*
|
2020-07-08 17:12:40 -04:00
|
|
|
* We have found an empty slot, so let's store the value.
|
2015-07-20 16:27:17 -05:00
|
|
|
*/
|
|
|
|
slot->key = key;
|
|
|
|
slot->value = value;
|
2020-07-08 17:12:40 -04:00
|
|
|
slot->set = 1;
|
2015-07-20 16:27:17 -05:00
|
|
|
|
|
|
|
return value;
|
2020-07-08 17:12:40 -04:00
|
|
|
} else if (slot->key == key) {
|
2015-07-20 16:27:17 -05:00
|
|
|
/*
|
|
|
|
* Otherwise, we've found an existing slot, so let's update that
|
|
|
|
* and bail.
|
|
|
|
*/
|
|
|
|
return slot->value = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Take a look to see if there is a next bucket in the chain.
|
|
|
|
*/
|
|
|
|
bucket = (patty_dict_bucket *)slot->next;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 = (patty_dict_slot *)bucket;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
error_malloc_bucket:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
int patty_dict_delete(patty_dict *dict, uint32_t key) {
|
2015-07-21 23:01:34 -05:00
|
|
|
patty_dict_slot *slot;
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
if ((slot = patty_dict_slot_find(dict, key)) == NULL) {
|
2020-06-18 19:59:26 -04:00
|
|
|
goto error_dict_slot_find;
|
2015-07-21 23:01:34 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(slot, '\0', sizeof(*slot));
|
|
|
|
|
2020-06-18 19:59:26 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_dict_slot_find:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-07-20 16:27:17 -05:00
|
|
|
void patty_dict_destroy(patty_dict *dict) {
|
|
|
|
free(dict);
|
|
|
|
}
|