| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- #include "swapi.h"
- #include "swmem.h"
- #include "swhash.h"
- //////////////////////////////////////////////////////////////////////////////////////////
- // base struct
- /* hash表操作结构 */
- struct hash_ops
- {
- int32_t (*insert)(hash_t, const void *, int32_t, const void *); // 插入
- int32_t (*delete)(hash_t, const void *, int32_t, bool); // 删除
- int32_t (*replace)(hash_t, const void *, int32_t, const void *, void **); // 替换
- void *(*lookup)(hash_t, const void *, int32_t); // 查找
- void (*visit)(hash_t, hash_visit_cb); // 遍历hash表
- void (*destroy)(hash_t, bool); // 销毁
- };
- /* hash表结构 */
- struct shash_t
- {
- uint32_t tsize; // 表长
- uint32_t ksize; // key值长度,默认0为变长
- uint32_t nelems; // hash表中已存在元素的数目
- uint32_t nElemCollisionCnts; // hash表中元素发生碰撞的次数(mixed-value)
- struct hash_ops *h_ops; // hash操作结构
- hash_ex_func_hash hash_fn; // hash函数
- hash_ex_func_cmp cmp_fn; // hash比较key函数
- hash_data_free_cb free_cb; // hash释放data函数
- union
- {
- struct elem **chtable; // 链表类型
- } dm; // hash表数据管理者(无论哪种类型,都必须解决碰撞冲突的问题)
- };
- //////////////////////////////////////////////////////////////////////////////////////////
- // "chain hash" struct
- struct elem
- {
- void *key; // 关键字
- int32_t keylen; // 关键字长度
- void *data; // 数据指针
- struct elem *next; // 指向下一个元素
- };
- static int32_t ch_insert(hash_t, const void *, int32_t, const void *);
- static int32_t ch_delete(hash_t, const void *, int32_t, bool);
- static int32_t ch_replace(hash_t, const void *, int32_t, const void *, void **);
- static void *ch_lookup(hash_t, const void *, int32_t);
- static void ch_visit(hash_t, hash_visit_cb);
- static void ch_destroy(hash_t, bool);
- static struct hash_ops ch_ops = {
- ch_insert,
- ch_delete,
- ch_replace,
- ch_lookup,
- ch_visit,
- ch_destroy,
- };
- //////////////////////////////////////////////////////////////////////////////////////////
- // hash functions
- /* bob hash(http://burtleburtle.net/bob/index.html) */
- #define mix(a, b, c) \
- { \
- a -= b; a -= c; a ^= (c >> 13); \
- b -= c; b -= a; b ^= (a << 8); \
- c -= a; c -= b; c ^= (b >> 13); \
- a -= b; a -= c; a ^= (c >> 12); \
- b -= c; b -= a; b ^= (a << 16); \
- c -= a; c -= b; c ^= (b >> 5); \
- a -= b; a -= c; a ^= (c >> 3); \
- b -= c; b -= a; b ^= (a << 10); \
- c -= a; c -= b; c ^= (b >> 15); \
- }
- static uint32_t bob_hash(const unsigned char *k, uint32_t length)
- {
- uint32_t a, b, c, len;
- /* set up the internal state */
- len = length;
- a = b = c = 0x9e3779b9; // the golden ratio; an arbitrary data
- /* handle most of the key */
- while (len >= 12)
- {
- a += (k[0] +((uint32_t)k[1] << 8) +((uint32_t)k[2] << 16) +((uint32_t)k[3] << 24));
- b += (k[4] +((uint32_t)k[5] << 8) +((uint32_t)k[6] << 16) +((uint32_t)k[7] << 24));
- c += (k[8] +((uint32_t)k[9] << 8) +((uint32_t)k[10]<< 16)+((uint32_t)k[11] << 24));
- mix(a, b, c);
- k += 12; len -= 12;
- }
- /* handle the last 11 bytes */
- c += length;
- switch(len)
- { /* all the case statements fall through */
- case 11: c += ((uint32_t)k[10] << 24);
- case 10: c += ((uint32_t)k[9] << 16);
- case 9 : c += ((uint32_t)k[8] << 8);
- /* the first byte of c is reserved for the length */
- case 8 : b += ((uint32_t)k[7] << 24);
- case 7 : b += ((uint32_t)k[6] << 16);
- case 6 : b += ((uint32_t)k[5] << 8);
- case 5 : b += k[4];
- case 4 : a += ((uint32_t)k[3] << 24);
- case 3 : a += ((uint32_t)k[2] << 16);
- case 2 : a += ((uint32_t)k[1] << 8);
- case 1 : a += k[0];
- /* case 0: nothing left to add */
- }
- mix(a, b, c);
- return c;
- }
- /* one-at-a-time hash */
- static uint32_t oneatatime_hash(const unsigned char *k, uint32_t length)
- {
- uint32_t hash = 0;
- uint32_t i;
- for(i = 0; i < length; ++i)
- {
- hash += k[i];
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
- hash += (hash << 3);
- hash ^= (hash >> 11);
- hash += (hash << 15);
- return hash;
- }
- /* time33 hash */
- static uint32_t time33_hash(const unsigned char *k, uint32_t length)
- {
- uint32_t hash = 5381;
- uint32_t i = 0;
- for(i = 0; i < length; i++)
- {
- hash = (hash<<5) + hash + k[i]; // hash = hash*31 + k[i];
- }
- return hash;
- }
- /* mixed computing imaging to my hash table */
- static uint32_t getHash(hash_t htable, const void *key, int32_t keylen)
- {
- int32_t len;
- if(htable->ksize == 0) len = keylen;
- else len = htable->ksize;
- return ((htable->hash_fn(key, len)) & (htable->tsize-1)); // hash the key and get the meaningful bits for our table
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // default hash key compare functions
- static int32_t default_hash_key_cmp(const void *p1, int32_t len1,const void *p2, int32_t len2)
- {
- if(len1 != len2) return -1;
- else return memcmp(p1, p2, len1); // return strncmp((const char * )p1, (const char * )p2, len1);
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // main functions
- hash_t sw_hash_create(uint32_t sizehint, uint32_t keysize, enum hash_alg alg, hash_ex_func_hash hfunc, hash_ex_func_cmp cfunc, hash_data_free_cb fcb, uint32_t flag)
- {
- hash_t htable;
- uint32_t size = 0; // htable size
- uint32_t i = 1;
- /* 1, take the size hint and round it to the next higher power of two */
- while(size < sizehint)
- {
- size = 1<<i++;
- if(size == 0) { size = 1<<(i-2); break; }
- }
- /* 2, create hash htable */
- htable = (hash_t)sw_heap_malloc(sizeof(struct shash_t));
- if(!htable) { errno = ENOMEM; goto ErrorP; }
- /* 3, initialize hash htable common fields */
- htable->tsize = size;
- htable->ksize = keysize;
- htable->nelems = 0;
- htable->nElemCollisionCnts = 0;
- switch(alg)
- {
- case BOB_HASH:
- htable->hash_fn = bob_hash;
- break;
- case ONEATATIME_HASH:
- htable->hash_fn = oneatatime_hash;
- break;
- case TIME33_HASH:
- htable->hash_fn = time33_hash;
- break;
- default:
- if(hfunc) htable->hash_fn = hfunc;
- else {
- errno = EINVAL;
- goto ErrorP;
- }
- }
- if(cfunc) htable->cmp_fn = cfunc;
- else htable->cmp_fn = default_hash_key_cmp;
- htable->free_cb = fcb;
- /* 4, create elements for each hash htable type */
- switch(flag)
- {
- case CHAIN_H:
- htable->h_ops = &ch_ops;
- htable->dm.chtable = (struct elem **)sw_heap_malloc(size*sizeof(struct elem *));
- if(!htable->dm.chtable) { errno = ENOMEM; goto ErrorP; }
- else memset(htable->dm.chtable, 0, size*sizeof(struct elem *));
- break;
- default:
- errno = EINVAL;
- goto ErrorP;
- }
- return htable;
- ErrorP:
- if(htable && flag == CHAIN_H && htable->dm.chtable) sw_heap_free((void *)htable->dm.chtable);
- if(htable) sw_heap_free((void *)htable);
- return NULL;
- }
- int32_t sw_hash_insert(hash_t htable, const void *key, int32_t keylen, const void *data)
- {
- if(!htable || !key || keylen <= 0 || !data) return -1;
- else return htable->h_ops->insert(htable, key, keylen, data);
- }
- int32_t sw_hash_delete(hash_t htable, const void *key, int32_t keylen, bool bAutoFreeData)
- {
- if(!htable || !key || keylen <= 0) return -1;
- else return htable->h_ops->delete(htable, key, keylen, bAutoFreeData);
- }
- int32_t sw_hash_replace(hash_t htable, const void *key, int32_t keylen, const void *newdata, void **olddata)
- {
- if(!htable || !key || keylen <= 0 || !newdata || !olddata) return -1;
- else return htable->h_ops->replace(htable, key, keylen, newdata, olddata);
- }
- void *sw_hash_lookup(hash_t htable, const void *key, int32_t keylen)
- {
- if(!htable || !key || keylen <= 0) return NULL;
- else return htable->h_ops->lookup(htable, key, keylen);
- }
- uint32_t sw_hash_getTableSize(hash_t htable)
- {
- assert(htable);
- return htable->tsize;
- }
- uint32_t sw_hash_getElemsCnt(hash_t htable)
- {
- assert(htable);
- return htable->nelems;
- }
- uint32_t sw_hash_getElemCollisionCnts(hash_t htable)
- {
- assert(htable);
- return htable->nElemCollisionCnts;
- }
- void sw_hash_visit(hash_t htable, hash_visit_cb vcb)
- {
- if(!htable) return;
- htable->h_ops->visit(htable, vcb);
- }
- void sw_hash_destroy(hash_t htable, bool bAutoFreeData)
- {
- if(!htable) return;
- htable->h_ops->destroy(htable, bAutoFreeData);
- sw_heap_free((void *)htable);
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // "chain hash" functions
- static int32_t ch_insert(hash_t htable, const void *key, int32_t keylen, const void *data)
- {
- uint32_t idx;
- struct elem *cursor = NULL;
- struct elem *newelem = NULL;
- void *keycopy = NULL;
- newelem = (struct elem *)sw_heap_malloc(sizeof(struct elem));
- if(!newelem) { errno = ENOMEM; goto ErrorP; }
- keycopy = (struct elem *)sw_heap_malloc(keylen*sizeof(char));
- if(!keycopy) { errno = ENOMEM; goto ErrorP; }
- else memcpy(keycopy, key, keylen);
- newelem->key = keycopy;
- newelem->keylen = keylen;
- newelem->data = (void *)data;
- newelem->next = NULL;
- idx = getHash(htable, key, keylen);
- if(htable->dm.chtable[idx] == NULL)
- { // no collision, first element in this bucket
- htable->dm.chtable[idx] = newelem;
- }
- else
- { // collision, insert at the end of the chain
- cursor = htable->dm.chtable[idx];
- while(1)
- {
- if(htable->cmp_fn(cursor->key, cursor->keylen, newelem->key, keylen) == 0)
- { // key is already inserted in the table, insert fails
- errno = EINVAL;
- goto ErrorP;
- }
- if(cursor->next == NULL) break;
- else cursor = cursor->next;
- }
- cursor->next = newelem; // insert element at the end of the chain
- htable->nElemCollisionCnts++;
- }
- htable->nelems++;
- return 0;
- ErrorP:
- if(newelem && newelem->key) sw_heap_free((void *)newelem->key);
- if(newelem) sw_heap_free((void *)newelem);
- return -1;
- }
- static int32_t ch_delete(hash_t htable, const void *key, int32_t keylen, bool bAutoFreeData)
- {
- uint32_t idx;
- struct elem *cursor;
- struct elem *delelem;
- bool bElemCollisionDecrement;
- idx = getHash(htable, key, keylen);
- if(!htable->dm.chtable[idx]) return 0;
- delelem = NULL, bElemCollisionDecrement = false;
- if(htable->cmp_fn(htable->dm.chtable[idx]->key, htable->dm.chtable[idx]->keylen, key, keylen) == 0)
- { // element to delete is the first in the chain
- delelem = htable->dm.chtable[idx];
- htable->dm.chtable[idx] = delelem->next;
- if(htable->dm.chtable[idx]) bElemCollisionDecrement = true;
- }
- else
- { // search thru the chain for the element
- cursor = htable->dm.chtable[idx];
- while(cursor->next)
- {
- if(htable->cmp_fn(cursor->next->key, cursor->next->keylen, key, keylen) == 0)
- {
- delelem = cursor->next;
- cursor->next = delelem->next;
- bElemCollisionDecrement = true;
- break;
- }
- cursor = cursor->next;
- }
- }
- if(delelem)
- {
- sw_heap_free((void *)delelem->key);
- if(bAutoFreeData && htable->free_cb) htable->free_cb((void *)delelem->data);
- sw_heap_free((void *)delelem);
- htable->nelems--;
- if(bElemCollisionDecrement) htable->nElemCollisionCnts--;
- }
- return 0;
- }
- static int32_t ch_replace(hash_t htable, const void *key, int32_t keylen, const void *newdata, void **olddata)
- {
- uint32_t idx;
- struct elem *cursor;
- idx = getHash(htable, key, keylen);
- cursor = htable->dm.chtable[idx];
- while(cursor)
- {
- if(htable->cmp_fn(cursor->key, cursor->keylen, key, keylen) == 0)
- {
- *olddata = cursor->data;
- cursor->data = (void *)newdata;
- return 0;
- }
- cursor = cursor->next;
- }
- return -1;
- }
- static void *ch_lookup(hash_t htable, const void *key, int32_t keylen)
- {
- uint32_t idx;
- struct elem *cursor;
- idx = getHash(htable, key, keylen);
- cursor = htable->dm.chtable[idx];
- while(cursor)
- {
- if(htable->cmp_fn(cursor->key, cursor->keylen, key, keylen) == 0) return cursor->data;
- cursor = cursor->next;
- }
- return NULL;
- }
- static void ch_visit(hash_t htable, hash_visit_cb vcb)
- {
- uint32_t idx;
- struct elem *cursor;
- for(idx = 0; idx < htable->tsize; idx++)
- {
- cursor = htable->dm.chtable[idx];
- while(cursor)
- {
- if(vcb) vcb(cursor->key, cursor->keylen, cursor->data);
- cursor = cursor->next;
- }
- }
- }
- static void ch_destroy(hash_t htable, bool bAutoFreeData)
- {
- uint32_t idx;
- struct elem *cursor, *delelem;
- for(idx = 0; idx < htable->tsize; idx++)
- {
- cursor = htable->dm.chtable[idx];
- while(cursor)
- {
- delelem = cursor;
- cursor = cursor->next;
- sw_heap_free((void *)delelem->key);
- if(bAutoFreeData && htable->free_cb) htable->free_cb((void *)delelem->data);
- sw_heap_free((void *)delelem);
- }
- }
- sw_heap_free((void *)htable->dm.chtable);
- }
|