// hash_table
// |------------|
// |____________| _hlist_node1__ _hlist_node2__ _hlist_node3__
// | hlist_head | | next |\--->| next |\--->| next |
// |___frist____|\-->|--------------| \ |--------------| \ |--------------|
// | | \ |_____pprev____| \|_____pprev____| \|_____pprev____|
// |____________|
//hash_table为散列表(数组),其中的元素类型为struct hlist_head。以hlist_head为链表头的链表,其中的节点hash值是相同的(也叫冲突)。
// first指针指向链表中的节点①,然后节点①的pprev指针指向hlist_head中的first,节点①的next指针指向节点②。以此类推。
//
//hash_table的列表头仅存放一个指针,也就是first指针,指向的是对应链表的头结点,没有tail指针也就是指向链表尾节点的指针,
// 这样的考虑是为了节省空间——尤其在hash bucket(数组size)很大的情况下可以节省一半的指针空间。
//
//为什么pprev是一个指向指针的指针呢?按照这个设计,我们如果想要得到尾节点,必须遍历整个链表,可如果是一个指向节点的指针,
//那么头结点现在的pprev便可以直接指向尾节点,也就是list_head的做法。
//
//对于散列表来说,一般发生冲突的情况并不多(除非hash设计出现了问题),所以一个链表中的元素数量比较有限,遍历的劣势基本可以忽略。
//在删除链表头结点的时候,pprev这个设计无需判断删除的节点是否为头结点。如果是普通双向链表的设计,那么删除头结点之后,hlist_head中的first指针需要指向新的头结点
/*(uint8_t *pstHashkey, u32 ulHashkeyLen,u32 ulHashbit)*/
typedef unsigned int (*HashFunc)(unsigned char *, unsigned int ,unsigned int );
typedef struct
{
uint32_t usSize; //元素个数
THListHead hlistfirst; //每个哈希值对应 链表头,hlist的结构
pthread_spinlock_t bucketlock; //桶节点的锁
}THashHead;
/* 哈希散列结构数据节点 */
typedef struct
{
uint32_t ulBitWidth; /* 表示hash计算值的位宽,比如16位宽,32位宽*/
uint32_t ulNumUsed; /*使用的节点个数*/
THashHead *pstHashHead; /*哈希表节点,类似指针数组,数组内每个模块存一个链*/
HashFunc pHashFunc; //哈希算法
}THashManager;
typedef struct
{
THListNode hlistnode; //当前哈希值对应的哈希链表
uint64_t ulData; //哈希节点的具体数值
uint32_t ulKeyLen; //哈希Key长度
uint8_t pucKey[0]; //key,因为key的长度未知,存储key都是动态申请内存,因此这里需要将key放在最后,否则数据就会乱。从这个地址往后keylen长度就可以存储可以
}THashElem;
//最多支持32位宽的hash
#define MAX_BIT_WIDTH 32
#define TINY_MASK(x) (((uint32_t)1<<(x))-1)
#define HASH_BUCKET_NUM(x) ((uint32_t)1<<(x))
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :HashFuncAdditive
* Description :加法哈希
* Input :
* uint8_t *ptHashKey //哈希key
* uint32_t ulHashkeyLen//key长度
* uint32_t prime//素数
* Output :
* Return :void
* Mark :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32_t HashFuncAdditive(uint8_t *ptHashKey, uint32_t ulHashkeyLen,uint32_t prime)
{
uint32_t hash, i;
for(hash = ulHashkeyLen, i = 0; i < ulHashkeyLen; ++i)
{
hash += (uint32_t)(ptHashKey[i]);
}
return (hash%prime);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :HashFuncMultiplication
* Description :乘法哈希
* Input :
* uint8_t *ptHashKey //哈希key
* uint32_t ulHashkeyLen//key长度
* Output :
* Return :void
* Mark :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32_t HashFuncMultiplication(uint8_t *ptHashKey, uint32_t ulHashkeyLen,uint32_t ulHashbit)
{
uint32_t hash, i;
for(hash = 0, i = 0; i < ulHashkeyLen; ++i)
{
hash = 33*hash + (uint32_t)(ptHashKey[i]);
}
return hash;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :HashFuncFowlerNollVo
* Description :FNV哈希算法
* Input :
* uint8_t *ptHashKey //哈希key
* uint32_t ulHashkeyLen//key长度
* uint32_t ulHashbit//位宽
* Output :
* Return :void
* Mark :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32_t HashFuncFowlerNollVo(uint8_t *ptHashKey, uint32_t ulHashkeyLen,uint32_t ulHashbit)
{
uint32_t i ;
uint32_t ulMask ;
uint32_t ulHashValue = 2166136261;
if(null_ptr == ptHashKey || 0 == ulHashkeyLen)
{
// LOG_RECORD(LOG_LEV_ERROR, "input params invalid, Hashkey = %d, KeyLen=%d", ptHashKey,ulHashkeyLen);
return null_byte_dword;
}
ulMask = TINY_MASK(ulHashbit);
for(i = 0; i < ulHashkeyLen; i++)
{
ulHashValue *= 16777619;
ulHashValue ^= (uint32_t)(ptHashKey[i]);
}
return (((ulHashValue>>ulHashbit)^ulHashValue) & ulMask);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :THListHead
* Description :初始化hash桶的头结点
* Input :
* THashManager *pstHash
* uint32_t ulBitWidth//key长度
* Output :
* Return :void
* Mark :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32_t HashManagerInit(THashManager *pstHash, uint32_t ulBitWidth,HashFunc pfHashFunc)
{
uint32_t index = 0;
uint32_t ulsize = 0;
THashHead *ptHashHead = null_ptr;
if (null_ptr == pstHash)
{
// LOG_RECORD(LOG_LEV_ERROR,"pstHash is null");
return proc_fail;
}
if (( 0 == ulBitWidth) || ( ulBitWidth > MAX_BIT_WIDTH))
{
// LOG_RECORD(LOG_LEV_ERROR,"ulBitWidth is invalid");
return proc_fail;
}
ulsize = HASH_BUCKET_NUM(ulBitWidth);
ptHashHead = (THashHead *)malloc(ulsize * sizeof(THashHead));
if(null_ptr == ptHashHead)
{
// LOG_RECORD(LOG_LEV_ERROR, "malloc the hashhead fail \r\n");
return proc_fail;
}
pstHash->ulBitWidth = ulBitWidth;
pstHash->pstHashHead = ptHashHead;
pstHash->ulNumUsed = 0;
pstHash->pHashFunc = pfHashFunc;
for (index=0; index<ulsize; index++)
{
HListInitHead(&ptHashHead->hlistfirst);
ptHashHead->usSize = 0;
ptHashHead ++;
}
return proc_succ;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :HashManagerGetBucketHead
* Description :根据hash 值找到对应的桶节点
* Input :
* THashManager *pstHash //哈希
* uint8_t *ptHashKey //哈希key
* uint32_t ulHashkeyLen//key长度
* Output :
* Return :void
* Mark :
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
THashHead* HashManagerGetBucketHead(THashManager *pstHash, uint8_t * pucKey, uint32_t ulKeyLen)
{
uint32_t ulHashValue = 0;
ulHashValue = pstHash->pHashFunc(pucKey, ulKeyLen,pstHash->ulBitWidth);
return (pstHash->pstHashHead) + ulHashValue; //获取对应Hash值对应的桶
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :HashManagerInsert
* Description :插入hash数据
* Input :
* THashManager *pstHash //哈希
* uint8_t *ptHashKey //哈希key
* uint32_t ulHashkeyLen//key长度
* uint64_t ulData //哈希表存储的数据,一般情况是一个表的索引
* Output :
* Return :void
* Mark :
* * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool_t HashManagerInsert(THashManager *ptHash, uint8_t *pcKey, uint32_t ulKeyLen, uint64_t ulData )
{
THashElem *ptHashElem ;
THashHead *ptHashHead ;
if ((null_ptr == ptHash) || (null_ptr == pcKey) )
{
// LOG_RECORD(LOG_LEV_ERROR, "input params invalid,pstHash = %d, pucKey = %d, ulData = %d", ptHash, pcKey, ulData);
return proc_fail;
}
//加keylen的长度,是因为这里要存储key的值。
ptHashElem = (THashElem * )malloc(sizeof(THashElem)+ulKeyLen);
if (null_ptr == ptHashElem)
{
// LOG_RECORD(LOG_LEV_ERROR, "malloc hashnode mem failed");
return proc_fail;
}
ptHashElem->ulData = ulData;
ptHashElem->ulKeyLen = ulKeyLen;
//存储key
memcpy_s(ptHashElem->pucKey,ulKeyLen,pcKey,ulKeyLen);
//找到桶节点的头
ptHashHead = HashManagerGetBucketHead(ptHash,pcKey,ulKeyLen);
//将新的节点插入到桶里面
HlistAddHead(&ptHashElem->hlistnode,&ptHashHead->hlistfirst);
ptHashHead->usSize ++;
ptHash->ulNumUsed ++;
return proc_succ;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :HashManagerLookup
* Description :查找hash,返回存储的data
* Input :
* THashManager *pstHash //哈希
* uint8_t *ptHashKey //哈希key
* uint32_t ulHashkeyLen//key长度
* Output :
* Return :void
* Mark :
* * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint64_t HashManagerLookup(THashManager *ptHash, uint8_t *pcKey, uint32_t ulKeyLen)
{
THashElem *ptHashElem;
THashHead *ptHashHead;
THListNode *pstListTemp;
uint64_t ulHashData = null_byte_dword;
ptHashHead = HashManagerGetBucketHead(ptHash,pcKey,ulKeyLen);
HListForEach(pstListTemp,&ptHashHead->hlistfirst)
{
ptHashElem = HListEntryGet(pstListTemp,THashElem,hlistnode);
if(0 == memcmp(ptHashElem->pucKey,pcKey,ulKeyLen))
{
ulHashData = ptHashElem->ulData;
break;
}
}
return ulHashData;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Function Name :HashManagerDelete
* Description : 删除hash节点
* Input :
* THashManager *pstHash //哈希
* uint8_t *ptHashKey //哈希key
* uint32_t ulHashkeyLen//key长度
* Output :
* Return :void
* Mark :
* * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint64_t HashManagerDelete(THashManager *ptHash, uint8_t *pcKey, uint32_t ulKeyLen)
{
THashElem* pstHashElem ;
THashHead* pstHashHead ;
THListNode *pstListTemp;
THListNode *pstListSafe;
bool_t bret = hash_false;
if ((null_ptr == ptHash) || (null_ptr == pcKey) || (0 == ulKeyLen))
{
// LOG_RECORD(LOG_LEV_ERROR, "input params invalid,pstHash = %d, pucKey = %d, ulKeyLen = %d", ptHash, pcKey, ulKeyLen);
return proc_fail;
}
pstHashHead = HashManagerGetBucketHead(ptHash,pcKey,ulKeyLen);
HListForEachSafe(pstListTemp,pstListSafe,&pstHashHead->hlistfirst)
{
pstHashElem = HListEntryGet(pstListTemp,THashElem,hlistnode);
if(0 == memcmp(pstHashElem->pucKey,pcKey,ulKeyLen))
{
pstHashHead->usSize --;
HListDelInit(&pstHashElem->hlistnode);
free(pstHashElem);
pstHashElem = null_ptr;
ptHash->ulNumUsed --;
bret = hash_true;
break;
}
}
return bret;
}