add hash iterator
This commit is contained in:
parent
d1b298bca6
commit
af315a9cc7
|
@ -23,12 +23,13 @@ extern "C" {
|
|||
#include "hashfunc.h"
|
||||
|
||||
#define HASH_MAX_CAPACITY (1024 * 1024 * 16)
|
||||
#define HASH_VALUE_IN_TRASH (-1)
|
||||
#define HASH_DEFAULT_LOAD_FACTOR (0.75)
|
||||
#define HASH_INDEX(v, c) ((v) & ((c)-1))
|
||||
|
||||
typedef void (*_hash_free_fn_t)(void *param);
|
||||
|
||||
typedef struct SHashNode {
|
||||
char *key; // null-terminated string
|
||||
char *key;
|
||||
union {
|
||||
struct SHashNode * prev;
|
||||
struct SHashEntry *prev1;
|
||||
|
@ -50,6 +51,7 @@ typedef struct SHashObj {
|
|||
size_t capacity; // number of slots
|
||||
size_t size; // number of elements in hash table
|
||||
_hash_fn_t hashFp; // hash function
|
||||
_hash_free_fn_t freeFp; // hash node free callback function
|
||||
|
||||
#if defined(LINUX)
|
||||
pthread_rwlock_t *lock;
|
||||
|
@ -58,6 +60,14 @@ typedef struct SHashObj {
|
|||
#endif
|
||||
} 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
|
||||
*
|
||||
|
@ -110,6 +120,41 @@ void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen);
|
|||
*/
|
||||
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
|
||||
|
|
|
@ -155,8 +155,8 @@ static void taosHashTableResize(SHashObj *pHashObj) {
|
|||
|
||||
int32_t newSize = pHashObj->capacity << 1U;
|
||||
if (newSize > HASH_MAX_CAPACITY) {
|
||||
pTrace("current capacity:%d, maximum capacity:%d, no resize applied due to limitation is reached", pHashObj->capacity,
|
||||
HASH_MAX_CAPACITY);
|
||||
pTrace("current capacity:%d, maximum capacity:%d, no resize applied due to limitation is reached",
|
||||
pHashObj->capacity, HASH_MAX_CAPACITY);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -483,6 +483,10 @@ void taosHashCleanup(SHashObj *pHashObj) {
|
|||
|
||||
while (pNode) {
|
||||
pNext = pNode->next;
|
||||
if (pHashObj->freeFp) {
|
||||
pHashObj->freeFp(pNode->data);
|
||||
}
|
||||
|
||||
free(pNode);
|
||||
pNode = pNext;
|
||||
}
|
||||
|
@ -496,10 +500,108 @@ void taosHashCleanup(SHashObj *pHashObj) {
|
|||
__unlock(pHashObj->lock);
|
||||
__lock_destroy(pHashObj->lock);
|
||||
|
||||
tfree(pHashObj->lock);
|
||||
memset(pHashObj, 0, sizeof(SHashObj));
|
||||
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
|
||||
int32_t taosHashGetMaxOverflowLinkLength(const SHashObj *pHashObj) {
|
||||
if (pHashObj == NULL || pHashObj->size == 0) {
|
||||
|
|
Loading…
Reference in New Issue