From 1561566b043ca8f0a04b7fab12b0920e10f2e3c1 Mon Sep 17 00:00:00 2001 From: Ringo Watanabe Date: Tue, 29 Jan 2019 16:49:35 +0000 Subject: [PATCH] hash --- include/hashtable.h | 19 ++++++-- src/hash.c | 109 +++++++++++++++++++++++++++++++++++++++++--- src/list.c | 4 +- 3 files changed, 121 insertions(+), 11 deletions(-) diff --git a/include/hashtable.h b/include/hashtable.h index b9f5401..1e0e550 100644 --- a/include/hashtable.h +++ b/include/hashtable.h @@ -2,14 +2,27 @@ #define H_DEFAULT_BLOCKSIZE 255 -struct _h_kvpair_t { - unsigned int crc32; +#define H_FLAG_EXCHECK (1<<0) //don't check the hash, check the key itself + +struct h_kvpair { + unsigned char fillbit; + unsigned int32_t crc32; unsigned char data[]; }; +struct h_page { + struct h_page* next; + struct h_kvpair pairs[]; //blocksize +}; + typedef struct { - list_t* back; size_t keysize; + size_t valuesize; + size_t blocksize; + + unsigned int flags; + + h_page* page0; } hashtable_t; #endif /* _HASHTABLE_H */ diff --git a/src/hash.c b/src/hash.c index fd7dfa2..93d241e 100644 --- a/src/hash.c +++ b/src/hash.c @@ -8,26 +8,123 @@ #include -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); } -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)); - 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->valuesize = valuetype; //we don't need to save this but we will to make it easier. + proto->blocksize = blocksize; + proto->flags = flags; 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; - 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 +} diff --git a/src/list.c b/src/list.c index 0ef2f23..bcd8c61 100644 --- a/src/list.c +++ b/src/list.c @@ -21,7 +21,7 @@ static int _mem_isnull(unsigned char* data, size_t le) static l_block* _l_create_block(size_t type,int blocksize) { - l_block* block= (l_block*) malloc(sizeof(l_block*) + ( blocksize*type)); + l_block* block= (l_block*) malloc(sizeof(l_block) + ( blocksize*type)); memset(block, 0, sizeof(l_block*) + ( blocksize*type)); return block; } @@ -400,4 +400,4 @@ L_C_FUNCTION(int_a) return comp_res; } -#undef l_block \ No newline at end of file +#undef l_block