add hash iterator

This commit is contained in:
hjxilinx 2020-03-14 17:10:48 +08:00
parent d1b298bca6
commit af315a9cc7
2 changed files with 197 additions and 50 deletions

View File

@ -23,12 +23,13 @@ extern "C" {
#include "hashfunc.h" #include "hashfunc.h"
#define HASH_MAX_CAPACITY (1024 * 1024 * 16) #define HASH_MAX_CAPACITY (1024 * 1024 * 16)
#define HASH_VALUE_IN_TRASH (-1)
#define HASH_DEFAULT_LOAD_FACTOR (0.75) #define HASH_DEFAULT_LOAD_FACTOR (0.75)
#define HASH_INDEX(v, c) ((v) & ((c)-1)) #define HASH_INDEX(v, c) ((v) & ((c)-1))
typedef void (*_hash_free_fn_t)(void *param);
typedef struct SHashNode { typedef struct SHashNode {
char *key; // null-terminated string char *key;
union { union {
struct SHashNode * prev; struct SHashNode * prev;
struct SHashEntry *prev1; struct SHashEntry *prev1;
@ -50,6 +51,7 @@ typedef struct SHashObj {
size_t capacity; // number of slots size_t capacity; // number of slots
size_t size; // number of elements in hash table size_t size; // number of elements in hash table
_hash_fn_t hashFp; // hash function _hash_fn_t hashFp; // hash function
_hash_free_fn_t freeFp; // hash node free callback function
#if defined(LINUX) #if defined(LINUX)
pthread_rwlock_t *lock; pthread_rwlock_t *lock;
@ -58,6 +60,14 @@ typedef struct SHashObj {
#endif #endif
} SHashObj; } SHashObj;
typedef struct SHashMutableIterator {
SHashObj * pHashObj;
int32_t entryIndex;
SHashNode *pCur;
SHashNode *pNext; // current node can be deleted for mutable iterator, so keep the next one before return current
int32_t num; // already check number of elements in hash table
} SHashMutableIterator;
/** /**
* init the hash table * init the hash table
* *
@ -110,6 +120,41 @@ void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen);
*/ */
void taosHashCleanup(SHashObj *pHashObj); void taosHashCleanup(SHashObj *pHashObj);
/**
* Set the free callback function
* This function if set will be invoked right before freeing each hash node
* @param pHashObj
*/
void taosHashSetFreecb(SHashObj *pHashObj, _hash_free_fn_t freeFp);
/**
*
* @param pHashObj
* @return
*/
SHashMutableIterator* taosHashCreateIter(SHashObj *pHashObj);
/**
*
* @param iter
* @return
*/
bool taosHashIterNext(SHashMutableIterator *iter);
/**
*
* @param iter
* @return
*/
void *taosHashIterGet(SHashMutableIterator *iter);
/**
*
* @param iter
* @return
*/
void* taosHashDestroyIter(SHashMutableIterator* iter);
/** /**
* *
* @param pHashObj * @param pHashObj

View File

@ -155,8 +155,8 @@ static void taosHashTableResize(SHashObj *pHashObj) {
int32_t newSize = pHashObj->capacity << 1U; int32_t newSize = pHashObj->capacity << 1U;
if (newSize > HASH_MAX_CAPACITY) { if (newSize > HASH_MAX_CAPACITY) {
pTrace("current capacity:%d, maximum capacity:%d, no resize applied due to limitation is reached", pHashObj->capacity, pTrace("current capacity:%d, maximum capacity:%d, no resize applied due to limitation is reached",
HASH_MAX_CAPACITY); pHashObj->capacity, HASH_MAX_CAPACITY);
return; return;
} }
@ -483,6 +483,10 @@ void taosHashCleanup(SHashObj *pHashObj) {
while (pNode) { while (pNode) {
pNext = pNode->next; pNext = pNode->next;
if (pHashObj->freeFp) {
pHashObj->freeFp(pNode->data);
}
free(pNode); free(pNode);
pNode = pNext; pNode = pNext;
} }
@ -496,10 +500,108 @@ void taosHashCleanup(SHashObj *pHashObj) {
__unlock(pHashObj->lock); __unlock(pHashObj->lock);
__lock_destroy(pHashObj->lock); __lock_destroy(pHashObj->lock);
tfree(pHashObj->lock);
memset(pHashObj, 0, sizeof(SHashObj)); memset(pHashObj, 0, sizeof(SHashObj));
free(pHashObj); free(pHashObj);
} }
void taosHashSetFreecb(SHashObj *pHashObj, _hash_free_fn_t freeFp) {
if (pHashObj == NULL || freeFp == NULL) {
return;
}
pHashObj->freeFp = freeFp;
}
SHashMutableIterator *taosHashCreateIter(SHashObj *pHashObj) {
SHashMutableIterator *pIter = calloc(1, sizeof(SHashMutableIterator));
if (pIter == NULL) {
return NULL;
}
pIter->pHashObj = pHashObj;
}
static SHashNode *getNextHashNode(SHashMutableIterator *pIter) {
assert(pIter != NULL);
while (pIter->entryIndex < pIter->pHashObj->capacity) {
SHashEntry *pEntry = pIter->pHashObj->hashList[pIter->entryIndex];
if (pEntry->next == NULL) {
pIter->entryIndex++;
continue;
}
return pEntry->next;
}
return NULL;
}
bool taosHashIterNext(SHashMutableIterator *pIter) {
if (pIter == NULL) {
return false;
}
size_t size = taosHashGetSize(pIter->pHashObj);
if (size == 0 || pIter->num >= size) {
return false;
}
// check the first one
if (pIter->num == 0) {
assert(pIter->pCur == NULL && pIter->pNext == NULL);
while (1) {
SHashEntry *pEntry = pIter->pHashObj->hashList[pIter->entryIndex];
if (pEntry->next == NULL) {
pIter->entryIndex++;
continue;
}
pIter->pCur = pEntry->next;
if (pIter->pCur->next) {
pIter->pNext = pIter->pCur->next;
} else {
pIter->pNext = getNextHashNode(pIter);
}
break;
}
pIter->num++;
return true;
} else {
assert(pIter->pCur != NULL);
if (pIter->pNext) {
pIter->pCur = pIter->pNext;
} else { // no more data in the hash list
return false;
}
pIter->num++;
if (pIter->pCur->next) {
pIter->pNext = pIter->pCur->next;
} else {
pIter->pNext = getNextHashNode(pIter);
}
return true;
}
}
void *taosHashIterGet(SHashMutableIterator *iter) { return (iter == NULL) ? NULL : iter->pCur->data; }
void *taosHashDestroyIter(SHashMutableIterator *iter) {
if (iter == NULL) {
return NULL;
}
free(iter);
}
// for profile only // for profile only
int32_t taosHashGetMaxOverflowLinkLength(const SHashObj *pHashObj) { int32_t taosHashGetMaxOverflowLinkLength(const SHashObj *pHashObj) {
if (pHashObj == NULL || pHashObj->size == 0) { if (pHashObj == NULL || pHashObj->size == 0) {