1.uthash是c语言实现的hash库,使用方便简单,只要在自己的代码里引用uthash.h头文件,就可以使用.
源码下载:https://github.com/troydhanson/uthash
使用文档:http://troydhanson.github.io/uthash/userguide.html
2.使用uthash时,会有几个小问题
1)不做内存释放,2)非线程安全,3)使用不同类型的<key,value>建hash table时,要单独编写不同的操作接口,比较麻烦.
3.针对2中的问题,可以设计一个GNU/linux下简单的hash table的模板类,添加内存释放、线程锁,提练出主要的hash table操作接口,方便使用.
4.新建hash文件夹,将上面代码文件命名为hash.cpp,放入hash文件夹,并将uthash相关的头文件放在/hash/include文件夹下,进入hash文件夹,在GNU/linux下编译
g++ hash.cpp
源码下载:https://github.com/troydhanson/uthash
使用文档:http://troydhanson.github.io/uthash/userguide.html
2.使用uthash时,会有几个小问题
1)不做内存释放,2)非线程安全,3)使用不同类型的<key,value>建hash table时,要单独编写不同的操作接口,比较麻烦.
3.针对2中的问题,可以设计一个GNU/linux下简单的hash table的模板类,添加内存释放、线程锁,提练出主要的hash table操作接口,方便使用.
#include <stdlib.h>
#include <pthread.h>
#include "include/uthash.h"
template <class K, class V, class E>
class hash_table
{
public:
hash_table(bool with_lock);
~hash_table();
void add(E *entry);
void del(K key);
void replace(E *entry);
E* get(K key);
V* get_value(K key);
void destroy();
void print();
int count();
private:
bool _with_lock;
pthread_mutex_t _lock;
int _count;
E * _htab;
};
template <class K, class V, class E>
hash_table<K, V, E>::hash_table(bool with_lock):_with_lock(false)
{
if(_with_lock)
{
_with_lock = true;
pthread_mutex_init(&_lock,NULL);
}
_htab = NULL;
_count = 0;
}
template <class K, class V, class E>
hash_table<K, V, E>::~hash_table()
{
destroy();
_htab = NULL;
if(_with_lock)
{
pthread_mutex_unlock(&_lock);
pthread_mutex_destroy(&_lock);
}
}
template <class K, class V, class E>
void hash_table<K, V, E>::add(E *entry)
{
E * _entry = NULL;
K * _key = &entry->key;
if(_with_lock)
pthread_mutex_lock(&_lock);
HASH_FIND(hh, _htab, _key, sizeof(K), _entry);
if(_entry)
{
HASH_DEL(_htab, _entry);
free(_entry);
_count--;
}
HASH_ADD(hh, _htab, key, sizeof(K), entry);
_count++;
if(_with_lock)
pthread_mutex_unlock(&_lock);
}
template <class K, class V, class E>
void hash_table<K, V, E>::replace(E *entry)
{
E * _entry = NULL;
K * _key = &entry->key;
if(_with_lock)
pthread_mutex_lock(&_lock);
HASH_FIND(hh, _htab, _key, sizeof(K), _entry);
if(_entry)
{
HASH_DEL(_htab, _entry);
free(_entry);
}
HASH_ADD(hh, _htab, key, sizeof(K), entry);
if(_with_lock)
pthread_mutex_unlock(&_lock);
}
template <class K, class V, class E>
void hash_table<K, V, E>::del(K key)
{
E *entry = NULL;
if(_with_lock)
pthread_mutex_lock(&_lock);
HASH_FIND(hh, _htab, &key, sizeof(K), entry);
if(entry)
{
HASH_DEL(_htab, entry);
free(entry);
_count-- ;
}
if(_with_lock)
pthread_mutex_unlock(&_lock);
}
template <class K, class V, class E>
E *hash_table<K, V, E>::get(K key)
{
E* entry = NULL;
if(_with_lock)
pthread_mutex_lock(&_lock);
HASH_FIND(hh, _htab, &key, sizeof(K), entry);
if(_with_lock)
pthread_mutex_unlock(&_lock);
return entry;
}
template <class K, class V, class E>
V *hash_table<K, V, E>::get_value(K key)
{
E* entry = NULL;
if(_with_lock)
pthread_mutex_lock(&_lock);
HASH_FIND(hh, _htab, &key, sizeof(K), entry);
if(_with_lock)
pthread_mutex_unlock(&_lock);
if(entry != NULL)
return (V*)&(entry->val);
else
return NULL;
}
template <class K, class V, class E>
void hash_table<K, V, E>::destroy()
{
if(_with_lock)
pthread_mutex_lock(&_lock);
E *entry, *tmp;
HASH_ITER(hh, _htab, entry, tmp)
{
HASH_DEL(_htab,entry);
free(entry);
entry = NULL;
_count--;
}
if(_with_lock)
pthread_mutex_unlock(&_lock);
}
template <class K, class V, class E>
void hash_table<K, V, E>::print()
{
E *entry, *tmp;
if(_with_lock)
pthread_mutex_lock(&_lock);
printf("_htab count=%d\n",_count);
HASH_ITER(hh, _htab, entry, tmp)
{
entry->print();
}
if(_with_lock)
pthread_mutex_unlock(&_lock);
}
template <class K, class V, class E>
int hash_table<K, V, E>::count()
{
return _count;
}
//####################################//
// TEST //
//####################################//
#define LEN 16
struct E1
{
int key;
int val;
UT_hash_handle hh;
void print()
{
printf("\tE1: key=%d,val=%d.\n",key,val);
};
};
struct K2
{
char name[LEN];
int id;
};
struct E2
{
struct K2 key;
int val;
UT_hash_handle hh;
void print()
{
printf("\tE2: key.name=%s,key.id=%d,val=%d.\n",key.name,key.id,val);
};
};
struct K3
{
int id_1;
int id_2;
};
struct V3
{
int val_1;
int val_2;
};
struct E3
{
struct K3 key;
struct V3 val;
UT_hash_handle hh;
void print()
{
printf("\tE3: key.id_1=%d,key.id_2=%d,val.val_1=%d,val.val_2=%d.\n",
key.id_1,key.id_2,val.val_1,val.val_2);
};
};
int main()
{
// test E1
printf("\ntest E1:\n");
struct E1 *e11 = (struct E1 *) malloc(sizeof(struct E1));
e11->key = 1;
e11->val = 1;
struct E1 *e12 = (struct E1 *) malloc(sizeof(struct E1));
e12->key = 2;
e12->val = 2;
hash_table <int, int, struct E1> htab_1(false);
htab_1.add(e11);
htab_1.print();
htab_1.add(e12);
htab_1.print();
printf("\n");
int k11 = 2;
e11 = htab_1.get(k11);
e11->print();
int k12 = 1;
int *v12 = htab_1.get_value(k12);
printf("\tE1: get_value(key=1) = %d\n",*v12);
htab_1.del(k12);
htab_1.print();
int k13 = 3;
e11 = htab_1.get(k13);
if(!e11)
printf("\tE1: Error key:3\n");
htab_1.destroy();
htab_1.print();
// test E2
printf("\ntest E2:\n");
struct E2 *e21 = (struct E2 *) malloc(sizeof(struct E2));
memset(e21,0x0,sizeof(struct E2));
strncpy(e21->key.name,"10.0.0.1",LEN);
e21->key.id = 1024;
e21->val = 1;
struct E2 *e22 = (struct E2 *) malloc(sizeof(struct E2));
memset(e22,0x0,sizeof(struct E2));
strncpy(e22->key.name,"127.0.0.1",LEN);
e22->key.id = 2048;
e22->val = 2;
hash_table <struct K2, int, struct E2> htab_2(false);
htab_2.add(e21);
htab_2.print();
htab_2.add(e22);
htab_2.print();
printf("\n");
struct K2 k21 = {"127.0.0.1",2048};
e21 = htab_2.get(k21);
e21->print();
struct K2 k22 = {"10.0.0.1",1024};
int *v22 = htab_2.get_value(k22);
printf("\tE2: get_value(key={\"10.0.0.1\",1024}) = %d\n",*v22);
struct K2 k23 = {"0.0.0.1",1024};
e21 = htab_2.get(k23);
if(!e21)
printf("\tE2: Error key:{\"0.0.0.1\",1024}\n");
htab_2.destroy();
htab_2.print();
// test E3
printf("\ntest E3:\n");
struct E3 *e31 = (struct E3 *) malloc(sizeof(struct E3));
memset(e31,0x0,sizeof(struct E3));
e31->key.id_1 = 1;
e31->key.id_2 = 1;
e31->val.val_1 = 1;
e31->val.val_2 = 1;
struct E3 *e32 = (struct E3 *) malloc(sizeof(struct E3));
memset(e32,0x0,sizeof(struct E3));
e32->key.id_1 = 2;
e32->key.id_2 = 2;
e32->val.val_1 = 2;
e32->val.val_2 = 2;
hash_table <struct K3, struct V3, struct E3> htab_3(true);
htab_3.add(e31);
htab_3.print();
htab_3.add(e32);
htab_3.print();
struct E3 *e33 = (struct E3 *) malloc(sizeof(struct E3));
memset(e33,0x0,sizeof(struct E3));
e33->key.id_1 = 2;
e33->key.id_2 = 2;
e33->val.val_1 = 2;
e33->val.val_2 = 2;
htab_3.add(e33);
htab_3.print();
struct E3 *e34 = (struct E3 *) malloc(sizeof(struct E3));
memset(e34,0x0,sizeof(struct E3));
e34->key.id_1 = 2;
e34->key.id_2 = 2;
e34->val.val_1 = 3;
e34->val.val_2 = 3;
htab_3.replace(e34);
htab_3.print();
printf("\n");
struct K3 k31 = {2,2};
e32 = htab_3.get(k31);
e32->print();
struct K3 k32 = {1,1};
struct V3 *v32 = htab_3.get_value(k32);
printf("\tE3: get_value(key={1,1}) = val_1=%d,val_2=%d\n", v32->val_1, v32->val_2);
struct K3 k33 = {3,3};
e31 = htab_3.get(k33);
if(!e31)
printf("\tE3: Error key:{3,3}\n");
htab_3.destroy();
htab_3.print();
printf("\n");
return 0;
}
4.新建hash文件夹,将上面代码文件命名为hash.cpp,放入hash文件夹,并将uthash相关的头文件放在/hash/include文件夹下,进入hash文件夹,在GNU/linux下编译
g++ hash.cpp