|
|
@ -8,26 +8,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
#include <hashtable.h>
|
|
|
|
#include <hashtable.h>
|
|
|
|
|
|
|
|
|
|
|
|
int32_t _h_getid(void* key, unsigned long* sum, size_t keysize, size_t blocksize)
|
|
|
|
#define h_page struct h_page
|
|
|
|
|
|
|
|
#define FILLBIT 0xAB
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int32_t _h_getid(const void* key, unsigned long* sum, size_t keysize, size_t blocksize)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return (int32_t)((*sum = _h_crc32(0xffffffffu, key, keysize)) % blocksize);
|
|
|
|
return (int32_t)((*sum = _h_crc32(0xffffffffu, key, keysize)) % blocksize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hashtable_t* h_create(size_t keytype, size_t valuetype, size_t blocksize)
|
|
|
|
static h_page* _h_create_page(size_t keytype, size_t valuetype, size_t blocksize)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
h_page* page = (h_page*)malloc(sizeof(h_page) + (blocksize*(sizeof(h_kvpair)+keytype+valuetype)));
|
|
|
|
|
|
|
|
memset(page, 0, sizeof(h_page) +(blocksize*(sizeof(h_kvpair)+keytype+valuetype)));
|
|
|
|
|
|
|
|
return page;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int _h_contains(const h_page* p, int32_t id)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return p->pairs[id].fillbit == FILLBIT;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void _h_create_pair(h_kvpair* pair, int32_t crc32,const void * key, size_t keysize, const void* value, size_t valuesize)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
pair->fillbit = FILLBIT;
|
|
|
|
|
|
|
|
pair->crc32 = crc32;
|
|
|
|
|
|
|
|
memcpy(pair->data, key, keysize);
|
|
|
|
|
|
|
|
memcpy(pair->data+keysize, value, valuesize);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int _h_check_key(const h_kvpair *pair, int32_t crc32, void* key, int ks)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(key) return memcmp(pair->data, key, ks)==0;
|
|
|
|
|
|
|
|
else return pair->crc32 == crc32;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hashtable_t* h_create(size_t keytype, size_t valuetype, size_t blocksize, unsigned int flags)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
hashtable_t* proto = (hashtable_t*)malloc(sizeof(hashtable_t));
|
|
|
|
hashtable_t* proto = (hashtable_t*)malloc(sizeof(hashtable_t));
|
|
|
|
|
|
|
|
|
|
|
|
proto->back = l_create(sizeof(struct _h_kvpair_t)+keytype+valuetype, blocksize);
|
|
|
|
proto->page0 = _h_create_page(keytype, valuetype, blocksize); //back = l_create(sizeof(struct _h_kvpair_t)+keytype+valuetype, blocksize);
|
|
|
|
proto->keysize = keytype;
|
|
|
|
proto->keysize = keytype;
|
|
|
|
|
|
|
|
proto->valuesize = valuetype; //we don't need to save this but we will to make it easier.
|
|
|
|
|
|
|
|
proto->blocksize = blocksize;
|
|
|
|
|
|
|
|
proto->flags = flags;
|
|
|
|
|
|
|
|
|
|
|
|
return proto;
|
|
|
|
return proto;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void h_add(hashtable_t* hash, void* key, void* value)
|
|
|
|
void h_add(hashtable_t* hash, const void* key, const void* value)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
unsigned long crc32;
|
|
|
|
unsigned long crc32;
|
|
|
|
int32_t id = _h_getid(key, &crc32, hash->keysize, hash->back->blocksize);
|
|
|
|
int32_t id = _h_getid(key, &crc32, hash->keysize, hash->blocksize);
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: search through blocks as pages for empty id match
|
|
|
|
//TODO: search through pages for empty id match
|
|
|
|
|
|
|
|
h_page* page = hash->page0;
|
|
|
|
|
|
|
|
while(_h_contains(page, id))
|
|
|
|
|
|
|
|
if(page->next==NULL)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
page->next = _h_create_page(hash->keysize, hash->valuesize, hash->blocksize);
|
|
|
|
|
|
|
|
page = page->next;
|
|
|
|
|
|
|
|
break; // we know this new one is empty
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
page = page->next; //at the moment we allow the same key to be added twice.
|
|
|
|
|
|
|
|
_h_create_pair(&page->pairs[id], (int32_t)crc32, key, hash->keysize, value, hash->valuesize);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void* _h_find(const hashtable_t* hash, int32_t* _crc32, h_page** _page, int32_t* _id, const void* key)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
unsigned long crc32;
|
|
|
|
|
|
|
|
int32_t id = _h_getid(key, &crc32, hash->keysize, hash->blocksize);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
h_page* page = hash->page0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
if(_h_contains(page, id))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
h_kvpair* pair = &page->pairs[id];
|
|
|
|
|
|
|
|
if(_h_check_key(pair, (int32_t)crc32, (hash->flags&H_FLAG_EXCHECK?key:NULL), hash->keysize)) {
|
|
|
|
|
|
|
|
if(_crc32!=NULL) *_crc32 = (int32_t)crc32;
|
|
|
|
|
|
|
|
if(_page!=NULL) *_page = page;
|
|
|
|
|
|
|
|
if(_id!=NULL) *_id = id;
|
|
|
|
|
|
|
|
return pair->data+hash->keysize;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
page = page->next;
|
|
|
|
|
|
|
|
} while(page!=NULL);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void* h_get(const hashtable_t* hash, const void* key)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return _h_find(hash, NULL, NULL, NULL, key);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void h_set(hashtable_t* hash, const void* key, const void* value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int32_t crc32;
|
|
|
|
|
|
|
|
h_kvpair *pair = _h_find(hash, &crc32, NULL, NULL, key);
|
|
|
|
|
|
|
|
if(pair!=NULL)
|
|
|
|
|
|
|
|
_h_create_pair(pair, crc32, key, value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int h_contains(const hashtable_t* hash, const void* key)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return _h_find(hash, NULL,NULL,NULL,key)!=NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void h_remove(hashtable_t* hash, const void* key)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
h_kvpair *pair = _h_find(hash, NULL, NULL, NULL, key);
|
|
|
|
|
|
|
|
if(pair!=NULL)
|
|
|
|
|
|
|
|
memset(pair, 0, sizeof(h_kvpair)+hash->keysize+hash->valuesize); //we could just set the fillbit to 0, but...
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int h_count(const hashtable_t* hash)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
//TODO: Count all entries in all pages
|
|
|
|
|
|
|
|
}
|
|
|
|