基于uthash的GNU/linux下简单hash_table模板类

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操作接口,方便使用.

#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
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值