自己写的共享内存hash链表

CAlgHashList.h

#ifndef _C_ALG_HASH_LIST_H_
#define _C_ALG_HASH_LIST_H_
#include 
#include 
#include 
#include "CAlgShareList.h"

#ifdef	__cplusplus
extern "C" {
#endif


typedef struct{
	unsigned int  k_size;
	unsigned int  v_size;
	unsigned int  max_count;
	unsigned int  trunk_size;
	unsigned int  trunk_mask;
	CAlgShareList free_list;
#ifdef WIN32
#pragma warning(disable:4200)
#endif
	CAlgShareList hlist[0];
#ifdef WIN32
#pragma warning(default:4200)
#endif
}CAlgHashList;

typedef struct{
	int            pos;
	CAlgShareList  *list;
	CAlgShareNode  *node_base; //node base address
	unsigned char  *kv_base;   //kv base address
	unsigned char  *kv;
}HashListRC;

typedef unsigned int (*Alg_Hash_F)(const void* k, unsigned int size);

static inline unsigned int CAlgHashList_Pow2(unsigned int mask)
{
	int order = 31;
	while((mask &  (1<< order))== 0 && order > 0)
		order --;

	return 1 << order;
}

static inline unsigned int CAlgHashList_MemSize(unsigned int key_size, unsigned int val_size,
												 unsigned int trunk_size, unsigned int max_count)
{
	//make trunk_size is pow of 2
	trunk_size = CAlgHashList_Pow2(trunk_size);
	return sizeof(CAlgHashList) 
		+ sizeof(CAlgShareList) * trunk_size
		+ sizeof(CAlgShareNode) * max_count
		+ (key_size + val_size) * max_count;
}

static inline void CAlgHashList_Create(CAlgHashList* h, unsigned int key_size, unsigned int val_size,
									  unsigned int trunk_size, unsigned int max_count)
{
	unsigned int i;
	CAlgShareNode* n = (CAlgShareNode*)((unsigned char*)(h->hlist) + sizeof(CAlgShareList) * trunk_size);
	trunk_size = CAlgHashList_Pow2(trunk_size);
	h->k_size = key_size;
	h->v_size = val_size;
	h->trunk_size = trunk_size;
	h->max_count = max_count;
	h->trunk_mask = h->trunk_size - 1;
	CAlgShareList_ReSet(&h->free_list, key_size);

	//add ShareNode to free list
	n->curr_data = NULL;
	CAlgShareList_InsertPointer(&h->free_list, NULL, NULL, n, 0);
	for(i=1; i
		(n+1)->curr_data = NULL;
		CAlgShareList_InsertPointer(&h->free_list, 
			n, NULL, n+1, i);
	}

	for(i=0; i
		//NOTE: only set key_size, but the list node pointer store key_size + val_size
		CAlgShareList_ReSet(&h->hlist[i], key_size);
	}
}

static inline unsigned int CAlgHashList_DefaultHash(const void* k, unsigned int k_size)
{
	unsigned int i, hash = 0;
	const unsigned char *p = (const unsigned char *)k;

	for (i = 0; i< k_size; i++, p++) {
		hash = hash * 33 + *p;
	}
	return hash;
}

static inline int CAlgHashList_Find(CAlgHashList* h, const void* k, HashListRC* rc, 
									  Alg_Cmp_F cmp_f, Alg_Hash_F hash_f)
{
	CAlgShareList* list;
	CAlgShareNode* node_base = (CAlgShareNode*)(&h->hlist[h->trunk_size]);
	int pos;
	unsigned int hash_v ;
	unsigned char* kv_base = ((unsigned char*)node_base) + sizeof(CAlgShareNode)*h->max_count;
	unsigned int kv_size = h->k_size + h->v_size;

	if(hash_f == NULL ) hash_f = CAlgHashList_DefaultHash;
	if(cmp_f == NULL ) cmp_f = memcmp;
	hash_v = hash_f(k, h->k_size);

	list = &h->hlist[hash_v & h->trunk_mask];

	pos = list->head;
	rc->kv = NULL;
	rc->list = list;
	rc->node_base = node_base;
	rc->kv_base = kv_base;
	rc->pos = -1;
	while(pos >=0 && pos < (int)h->max_count)
	{
		if(cmp_f(k, kv_base+kv_size*pos, h->k_size) == 0)
		{
			rc->kv = &kv_base[kv_size*pos]; //return key-value pointer
			rc->pos = node_base[pos].curr;
			rc->list = list;
			return 0;
		}

		pos = node_base[pos].next;
	}
	return -1;
}

static inline int CAlgHashList_Set(CAlgHashList* h, void* k, void* v, 
									 Alg_Cmp_F cmp_f, Alg_Hash_F hash_f)
{
	HashListRC rc;
	CAlgShareNode *prev, *next, *n;
	CAlgHashList_Find(h, k, &rc, cmp_f, hash_f);
	prev = next = NULL;
	if(rc.kv)
	{
		if(v)
		{//update value
			memcpy(rc.kv + h->k_size, v, h->v_size);
			return 0;
			//return rc.kv + h->k_size; //return v pointer
		}
		else
		{//remove
			//remove from hash trunk list
			n= &rc.node_base[rc.pos];
			if(n->prev != ALG_SHARE_LIST_INVALID_POS)
				prev = &rc.node_base[n->prev];
			if(n->next != ALG_SHARE_LIST_INVALID_POS)
				next = &rc.node_base[n->next];
			CAlgShareList_RemoveNodePointer(rc.list, prev, next, n);

			//link this node to free list tail
			if(h->free_list.tail != ALG_SHARE_LIST_INVALID_POS)
				prev = &rc.node_base[h->free_list.tail];
			else
				prev = NULL;
			n->curr_data = NULL;
			CAlgShareList_InsertPointer(&h->free_list, prev, NULL, n, n->curr);

			return 0;
		}
	}
	else if(v && h->free_list.elem_count > 0)
	{// add
		n = &(rc.node_base[h->free_list.head]);

		//remove free list head
		if(n->next != ALG_SHARE_LIST_INVALID_POS)
			next = &(rc.node_base[n->next]);
		CAlgShareList_RemoveNodePointer(&h->free_list, NULL, next, n);

		//copy data
		memcpy(&rc.kv_base[(h->k_size+h->v_size)*n->curr], k, h->k_size);
		memcpy(&rc.kv_base[(h->k_size+h->v_size)*n->curr+h->k_size], v, h->v_size);

		//link the node to hash trunk list tail
		if(rc.list->tail != ALG_SHARE_LIST_INVALID_POS)
			prev = &(rc.node_base[rc.list->tail]);
		n->curr_data = (void*)rc.list; //node current data points to corresponding list
		CAlgShareList_InsertPointer(rc.list, prev, NULL, n, n->curr);

		return 0;

	}

	return -1;
}

static inline void* CAlgHashList_Get(CAlgHashList* h, const void* k, 
								   Alg_Cmp_F cmp_f, Alg_Hash_F hash_f)
{
	HashListRC rc;
	if(0 == CAlgHashList_Find(h, k, &rc, memcmp, NULL))
		return (rc.kv + h->k_size);
	return NULL;
}

#define FOR_EACH_HASH_NODE(h, k, v) \
{\
	CAlgShareNode* __node = (CAlgShareNode*)(&((h)->hlist[h->trunk_size]));\
	unsigned char* __kv_base = ((unsigned char*)__node) \
		+ sizeof(CAlgShareNode)*((h)->max_count);\
	unsigned int __kv_size = (h)->k_size + (h)->v_size; \
	unsigned int __ii; \
	for(__ii=0; __iimax_count; __ii++, __node++){ \
		if(__node->curr_data == NULL) continue; \
		if(k) memcpy(k, __kv_base+__kv_size*__node->curr, h->k_size); \
		if(v) memcpy(v, __kv_base+__kv_size*__node->curr + h->k_size, h->v_size); 

#define FOR_EACH_HASH_NODE_END() }}

#define FOR_EACH_HASH_LIST(h, k, v) \
{\
	CAlgShareNode* __node_base = (CAlgShareNode*)(&((h)->hlist[h->trunk_size]));\
	CAlgShareNode* __node;\
	unsigned char* __kv_base = ((unsigned char*)__node_base) \
		+ sizeof(CAlgShareNode)*((h)->max_count);\
	CAlgShareList* __thelist ; \
	unsigned int __kv_size = (h)->k_size + (h)->v_size; \
	unsigned int __ii;\
	int __pos;\
	for(__ii=0; __iitrunk_size; __ii++){\
		__thelist = &h->hlist[__ii];

#define FOR_EACH_HASH_LIST_NODE(h, k, v) \
		__pos = __thelist->head;\
		while(__pos != ALG_SHARE_LIST_INVALID_POS){\
			__node = &__node_base[__pos]; \
			if(k) memcpy(k, __kv_base+__kv_size*__node->curr, h->k_size); \
			if(v) memcpy(v, __kv_base+__kv_size*__node->curr + h->k_size, h->v_size);

#define FOR_EACH_HASH_LIST_NODE_END()	__pos = __node->next;}

#define FOR_EACH_HASH_LIST_END() }}

static inline int CAlgHashList_Count(CAlgHashList* hlist)
{
	return hlist->max_count - hlist->free_list.elem_count;
}

static inline void CAlgHashList_Print(CAlgHashList* hlist, int detail)
{
	CAlgShareNode* nb = (CAlgShareNode*)(&((hlist)->hlist[hlist->trunk_size]));
	int free_pos;

	free_pos = hlist->free_list.head;

	if(detail)
	{
		while(free_pos != ALG_SHARE_LIST_INVALID_POS)
		{
			printf("\t(%6d, %6d, %6d) \n", nb[free_pos].prev,
				nb[free_pos].curr, nb[free_pos].next);
			free_pos = nb[free_pos].next;
		}
	}
	printf("\n");

	FOR_EACH_HASH_LIST(hlist, NULL, NULL)
	printf("trunk_%04d size: %4d addr: 0X%p\n", __ii, __thelist->elem_count, __thelist);
	if(detail){
		FOR_EACH_HASH_LIST_NODE(hlist, NULL, NULL)
			printf("\t(%6d, %6d, %6d) list: 0X%p\n", 
			__node->prev, __node->curr, __node->next,
			__node->curr_data);
		assert(__node->curr_data == (void*)__thelist);
		FOR_EACH_HASH_LIST_NODE_END()
		printf("\n");
	}
	FOR_EACH_HASH_LIST_END()

	printf("hlist usage: %d out of %u (%.2f%%), free nodes left: %d\n",
		CAlgHashList_Count(hlist), hlist->max_count,
		(float)CAlgHashList_Count(hlist)/(float)hlist->max_count * 100,
		hlist->free_list.elem_count);
}

#ifdef	__cplusplus
}
#endif
#endif
//endif

单元测试:

#include 
#include 
#include 
#include 
#include "CAlgHashList.h"

typedef struct {
	int a;
	int b;
}HashKey;

typedef struct {
	int   v;
	int   f;
}HashValue;

void TestCAlgHashList_Print(CAlgHashList* hlist, int all_list, int detail)
{
	HashKey k;
	HashValue v;

	if(!all_list){
		FOR_EACH_HASH_NODE(hlist, &k, &v)
		printf("\t(%3d, %3d, %3d) k.a=%3d, k.b=%3d, v=%3d list: 0X%p\n", 
			__node->prev, __node->curr, __node->next,
			k.a, k.b, v.v, __node->curr_data);
		FOR_EACH_HASH_NODE_END()

		printf("\n\n");
		return ;
	}


	FOR_EACH_HASH_LIST(hlist, &k, &v)
	printf("trunk_%04d size: %4d addr: 0X%p\n", __ii, __thelist->elem_count, __thelist);
	if(detail){
		FOR_EACH_HASH_LIST_NODE(hlist, &k, &v)
			printf("\t(%3d, %3d, %3d) k.a=%3d, k.b=%3d, v=%3d list: 0X%p\n", 
			__node->prev, __node->curr, __node->next,
			k.a, k.b, v.v, __node->curr_data);
		assert(__node->curr_data == (void*)__thelist);
		FOR_EACH_HASH_LIST_NODE_END()
		printf("\n");
	}
	FOR_EACH_HASH_LIST_END()
}

void TestCAlgHashList_AddRemoveFind(unsigned int trunk_size, unsigned int node_size, 
									int print, int chkfind)
{
	HashKey k;
	HashValue v;
	unsigned int mem_size = CAlgHashList_MemSize(sizeof(HashKey), sizeof(HashValue), trunk_size, node_size);
	CAlgHashList* hlist;
	unsigned int i;
	HashListRC rc;

	hlist = (CAlgHashList*)malloc(mem_size);
	CAlgHashList_Create(hlist, sizeof(HashKey), sizeof(HashValue), trunk_size, node_size);

	if(print){
		CAlgHashList_Print(hlist, 0);

		printf("//////////////////////////////////////////////////////////////////////////\n");
		printf("//add full\n");
	}

	//hash table empty,  find fail
	for(i=0; i<2; i++)
	{
		k.a = 100 + i;
		k.b = 200 + i;
		v.v = i+1;
		v.f = 0xee;

		if(chkfind){
			assert(CAlgHashList_Find(hlist, &k, &rc, NULL, NULL) == -1);

			assert(rc.kv_base != NULL);
			assert(rc.node_base != NULL);
			assert(rc.kv == NULL);
			assert(rc.pos == -1);
			assert(rc.list != NULL);
		}
	}

	//add full
	for(i=0; i
	{
		k.a = 100 + i;
		k.b = 200 + i;
		v.v = i+1;
		v.f = 0xee;

		assert(CAlgHashList_Set(hlist, &k, &v, NULL, NULL) == 0);
	}

	//add full so add fail
	k.a = k.b = 0;
	assert(CAlgHashList_Set(hlist, &k, &v, NULL, NULL) == -1);

	if(print){
		TestCAlgHashList_Print(hlist, 1, 1);
	}

	if(chkfind){
		//find return ok
		for(i=0; i
		{
			k.a = 100 + i;
			k.b = 200 + i;
			v.v = i+1;
			v.f = 0xee;

			assert(CAlgHashList_Find(hlist, &k, &rc, NULL, NULL) == 0);
			assert(rc.kv_base != NULL);
			assert(rc.node_base != NULL);
			assert(rc.kv != NULL);
			assert(rc.pos > -1);
			assert(rc.list != NULL);
		}
	}

	if(print){
		printf("//////////////////////////////////////////////////////////////////////////\n");
		printf("//remove odd num\n");
	}
	//remove odd num
	for(i=0; i2; i++)
	{
		k.a = 100 + i*2 + 1;
		k.b = 200 + i*2 + 1;

		//remove
		assert(CAlgHashList_Set(hlist, &k, NULL, NULL, NULL) == 0);
		if(chkfind){
			//find fail
			assert(CAlgHashList_Find(hlist, &k, &rc, NULL, NULL) == -1);
			assert(rc.kv_base != NULL);
			assert(rc.node_base != NULL);
			assert(rc.kv == NULL);
			assert(rc.pos == -1);
			assert(rc.list != NULL);
		}
	}

	if(print){
		TestCAlgHashList_Print(hlist, 1, 1);
		CAlgHashList_Print(hlist, 1);

		printf("//////////////////////////////////////////////////////////////////////////\n");
		printf("//update event num\n");
	}
	//update
	for(i=0; i2; i++)
	{
		k.a = 100 + i*2;
		k.b = 200 + i*2;
		v.v = 300 + i;
		v.f = 0xdd;

		//update
		assert(CAlgHashList_Set(hlist, &k, &v, NULL, NULL) == 0);
	}

	if(print){
		TestCAlgHashList_Print(hlist, 1, 1);

		printf("//////////////////////////////////////////////////////////////////////////\n");
		printf("//remove even num\n");
	}
	//remove even num
	for(i=0; i2; i++)
	{
		k.a = 100 + i*2;
		k.b = 200 + i*2;

		//remove
		assert(CAlgHashList_Set(hlist, &k, NULL, NULL, NULL) == 0);
		if(chkfind){
			//find fail
			assert(CAlgHashList_Find(hlist, &k, &rc, NULL, NULL) == -1);
			assert(rc.kv_base != NULL);
			assert(rc.node_base != NULL);
			assert(rc.kv == NULL);
			assert(rc.pos == -1);
			assert(rc.list != NULL);
		}
	}

	if(print){
		CAlgHashList_Print(hlist, 1);
	}

	free(hlist);
}

#include 
void TestCAlgHashList_Run()
{
	SYSTEMTIME st1, st2;
	FILETIME ft1, ft2; //100ns

	printf("CAlgHashList_MemSize(4,8,8192,100000) = %u\n", 
		CAlgHashList_MemSize(4,8,8192,100000));
	printf("CAlgHashList_MemSize(4,8,32768,100000) = %u\n", 
		CAlgHashList_MemSize(4,8,32768,100000));
	printf("CAlgHashList_MemSize(4,8,32768,1000000) = %u\n", 
		CAlgHashList_MemSize(4,8,32768,1000000));
	printf("CAlgHashList_MemSize(40,40,32768,1000000) = %u\n", 
		CAlgHashList_MemSize(40,0,32768,1000000));


	TestCAlgHashList_AddRemoveFind(8, 100, 1, 1);

	GetLocalTime(&st1);
	TestCAlgHashList_AddRemoveFind(4096, 1000000, 0, 0);
	GetLocalTime(&st2);
	SystemTimeToFileTime(&st1, &ft1);
	SystemTimeToFileTime(&st2, &ft2);
	printf("%s using %u.%03ums to add/find/remove/update %d nodes trunk %d %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n", 
		__FILE__,
		(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
		((ft2.dwLowDateTime-ft1.dwLowDateTime)%10000)/10, 1000000, 4096,
		st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
		st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);

	GetLocalTime(&st1);
	TestCAlgHashList_AddRemoveFind(8192, 1000000, 0, 0);
	GetLocalTime(&st2);
	SystemTimeToFileTime(&st1, &ft1);
	SystemTimeToFileTime(&st2, &ft2);
	printf("%s using %u.%03ums to add/find/remove/update %d nodes trunk %d %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n", 
		__FILE__,
		(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
		((ft2.dwLowDateTime-ft1.dwLowDateTime)%10000)/10, 1000000, 8192,
		st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
		st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);

	GetLocalTime(&st1);
	TestCAlgHashList_AddRemoveFind(8192*2, 1000000, 0, 0);
	GetLocalTime(&st2);
	SystemTimeToFileTime(&st1, &ft1);
	SystemTimeToFileTime(&st2, &ft2);
	printf("%s using %u.%03ums to add/find/remove/update %d nodes trunk %d %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n", 
		__FILE__,
		(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
		((ft2.dwLowDateTime-ft1.dwLowDateTime)%10000)/10, 1000000, 8192*2,
		st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
		st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);

	GetLocalTime(&st1);
	TestCAlgHashList_AddRemoveFind(8192*4, 1000000, 0, 0);
	GetLocalTime(&st2);
	SystemTimeToFileTime(&st1, &ft1);
	SystemTimeToFileTime(&st2, &ft2);
	printf("%s using %u.%03ums to add/find/remove/update %d nodes trunk %d %02u:%02u:%02u.%03u - %02u:%02u:%02u.%03u\n", 
		__FILE__,
		(ft2.dwLowDateTime-ft1.dwLowDateTime)/10000,
		((ft2.dwLowDateTime-ft1.dwLowDateTime)%10000)/10, 1000000, 8192*4,
		st1.wHour,st1.wMinute,st1.wSecond,st1.wMilliseconds,
		st2.wHour,st2.wMinute,st2.wSecond,st2.wMilliseconds);
}

//end of file

你可能感兴趣的:(算法)