Need those
This commit is contained in:
parent
c9bee1793c
commit
4ea9f5f2dd
2 changed files with 191 additions and 0 deletions
171
src/dict.c
Normal file
171
src/dict.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <patty/dict.h>
|
||||
#include <patty/hash.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;
|
||||
}
|
||||
|
||||
patty_dict_slot *patty_dict_slot_find(patty_dict *dict, uint32_t hash) {
|
||||
patty_dict_bucket *bucket = &dict->bucket;
|
||||
|
||||
int collisions;
|
||||
|
||||
for (collisions = 0; collisions < 7; collisions++) {
|
||||
uint32_t mask = 0x0f << (4 * collisions);
|
||||
uint8_t index = (hash & mask) >> (4 * collisions);
|
||||
|
||||
patty_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 = (patty_dict_bucket *)slot->next;
|
||||
|
||||
/*
|
||||
* If there is no next bucket available, then return null.
|
||||
*/
|
||||
if (bucket == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int bucket_each_slot(int level, patty_dict_bucket *bucket, patty_dict_callback callback, void *ctx) {
|
||||
int i;
|
||||
|
||||
if (level > 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<PATTY_DICT_BUCKET_SIZE; i++) {
|
||||
patty_dict_slot *slot = &bucket->slots[i];
|
||||
|
||||
if (slot->key != NULL && slot->keysz > 0) {
|
||||
if (callback(slot->key, slot->keysz, slot->value, ctx) < 0) {
|
||||
goto error_callback;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot->next) {
|
||||
return bucket_each_slot(level+1, (patty_dict_bucket *)slot->next, callback, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_callback:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int patty_dict_each(patty_dict *dict, patty_dict_callback callback, void *ctx) {
|
||||
return bucket_each_slot(0, &dict->bucket, callback, ctx);
|
||||
}
|
||||
|
||||
void *patty_dict_get(patty_dict *dict, void *key, size_t keysz) {
|
||||
patty_dict_slot *slot;
|
||||
|
||||
uint32_t hash = patty_hash(key, keysz);
|
||||
|
||||
if ((slot = patty_dict_slot_find(dict, hash)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return slot->value;
|
||||
}
|
||||
|
||||
void *patty_dict_set(patty_dict *dict, void *key, size_t keysz, void *value) {
|
||||
patty_dict_bucket *bucket = &dict->bucket;
|
||||
|
||||
uint32_t hash = patty_hash(key, keysz);
|
||||
|
||||
int collisions;
|
||||
|
||||
for (collisions = 0; collisions < 7; collisions++) {
|
||||
uint32_t mask = 0x0f << (4 * collisions);
|
||||
uint8_t index = (hash & mask) >> (4 * collisions);
|
||||
|
||||
patty_dict_slot *slot = &bucket->slots[index];
|
||||
|
||||
if (slot->hash == 0x00000000 && slot->key == NULL) {
|
||||
/*
|
||||
* We have found an empty hash slot, so let's store the value.
|
||||
*/
|
||||
slot->hash = hash;
|
||||
slot->key = key;
|
||||
slot->keysz = keysz;
|
||||
slot->value = value;
|
||||
|
||||
return value;
|
||||
} else if (slot->hash == hash) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
static int dict_item_release(void *key, size_t keysz, void *value, void *ctx) {
|
||||
free(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void patty_dict_destroy(patty_dict *dict) {
|
||||
(void)patty_dict_each(dict, dict_item_release, NULL);
|
||||
|
||||
free(dict);
|
||||
}
|
20
src/hash.c
Normal file
20
src/hash.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <patty/hash.h>
|
||||
|
||||
uint32_t patty_hash(void *key, size_t size) {
|
||||
uint32_t hash = 0, i;
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
hash += ((uint8_t *)key)[i];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
|
||||
return hash;
|
||||
}
|
Loading…
Add table
Reference in a new issue