How's about a hash table dangit
This commit is contained in:
parent
9fbd247dd4
commit
318704622c
5 changed files with 363 additions and 2 deletions
56
include/hexagram/dict.h
Normal file
56
include/hexagram/dict.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef _HEXAGRAM_DICT_H
|
||||
#define _HEXAGRAM_DICT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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 */
|
11
include/hexagram/hash.h
Normal file
11
include/hexagram/hash.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef _HEXAGRAM_HASH_H
|
||||
#define _HEXAGRAM_HASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define HEXAGRAM_DICT_BUCKET_SIZE 16
|
||||
|
||||
int hexagram_hash(void *key, size_t keysz, uint32_t *hash);
|
||||
|
||||
#endif /* _HEXAGRAM_HASH_H */
|
|
@ -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
|
||||
|
|
264
src/dict.c
Normal file
264
src/dict.c
Normal file
|
@ -0,0 +1,264 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
30
src/hash.c
Normal file
30
src/hash.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hexagram/hash.h>
|
||||
|
||||
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<size; i++) {
|
||||
value += ((uint8_t *)data)[i];
|
||||
value += (value << 10);
|
||||
value ^= (value >> 6);
|
||||
}
|
||||
|
||||
value += (value << 3);
|
||||
value ^= (value >> 11);
|
||||
value += (value << 15);
|
||||
|
||||
*hash = value;
|
||||
|
||||
return 0;
|
||||
|
||||
error_null_data:
|
||||
return -1;
|
||||
}
|
Loading…
Add table
Reference in a new issue