/* * Copyright (c) 2020 YuQing <384681@qq.com> * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the Lesser GNU General Public License, version 3 * or later ("LGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the Lesser GNU General Public License * along with this program. If not, see . */ #ifndef _HASH_H_ #define _HASH_H_ #include #include #include "common_define.h" #ifdef __cplusplus extern "C" { #endif #define CRC32_XINIT 0xFFFFFFFF /* initial value */ #define CRC32_XOROT 0xFFFFFFFF /* final xor value */ typedef int (*HashFunc) (const void *key, const int key_len); #ifdef HASH_STORE_HASH_CODE #define HASH_CODE(pHash, hash_data) hash_data->hash_code #else #define HASH_CODE(pHash, hash_data) ((unsigned int)pHash->hash_func( \ hash_data->key, hash_data->key_len)) #endif #define CALC_NODE_MALLOC_BYTES(key_len, value_size) \ sizeof(HashData) + key_len + value_size #define FREE_HASH_DATA(pHash, hash_data) \ pHash->item_count--; \ pHash->bytes_used -= CALC_NODE_MALLOC_BYTES(hash_data->key_len, \ hash_data->malloc_value_size); \ free(hash_data); typedef struct tagHashData { int key_len; int value_len; int malloc_value_size; #ifdef HASH_STORE_HASH_CODE unsigned int hash_code; #endif char *value; struct tagHashData *next; char key[0]; } HashData; typedef int64_t (*ConvertValueFunc)(const HashData *old_data, const int inc, char *new_value, int *new_value_len, void *arg); typedef struct tagHashArray { HashData **buckets; HashFunc hash_func; int item_count; unsigned int *capacity; double load_factor; int64_t max_bytes; int64_t bytes_used; bool is_malloc_capacity; bool is_malloc_value; unsigned int lock_count; pthread_mutex_t *locks; } HashArray; typedef struct tagHashStat { unsigned int capacity; int item_count; int bucket_used; double bucket_avg_length; int bucket_max_length; } HashStat; /** * hash walk function * parameters: * index: item index based 0 * data: hash data, including key and value * args: passed by fc_hash_walk function * return 0 for success, != 0 for error */ typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args); #define fc_hash_init(pHash, hash_func, capacity, load_factor) \ fc_hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false) #define fc_hash_insert(pHash, key, key_len, value) \ fc_hash_insert_ex(pHash, key, key_len, value, 0, true) /** * hash init function * parameters: * pHash: the hash table * hash_func: hash function * capacity: init capacity * load_factor: hash load factor (or watermark), >= 0.10 for auto rehash. eg. 0.75 * max_bytes: max memory can be used (bytes) * bMallocValue: if need malloc value buffer * return 0 for success, != 0 for error */ int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \ const unsigned int capacity, const double load_factor, \ const int64_t max_bytes, const bool bMallocValue); /** * set hash locks function * parameters: * lock_count: the lock count * return 0 for success, != 0 for error */ int fc_hash_set_locks(HashArray *pHash, const int lock_count); /** * convert the value * parameters: * HashData: the old hash data * inc: the increasement value * new_value: return the new value * new_value_len: return the length of the new value * arg: the user data * return the number after increasement */ int64_t fc_hash_inc_value(const HashData *old_data, const int inc, char *new_value, int *new_value_len, void *arg); #define fc_hash_inc(pHash, key, key_len, inc, value, value_len) \ fc_hash_inc_ex(pHash, key, key_len, inc, value, value_len, \ fc_hash_inc_value, NULL) /** * atomic increase value * parameters: * pHash: the hash table * key: the key to insert * key_len: length of th key * inc: the increasement value * value: return the new value * value_len: return the length of the new value * convert_func: the convert function * arg: the arg to convert function * return 0 for success, != 0 for error (errno) * */ int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len, const int inc, char *value, int *value_len, ConvertValueFunc convert_func, void *arg); /** * hash destroy function * parameters: * pHash: the hash table * return none */ void fc_hash_destroy(HashArray *pHash); /** * hash insert key * parameters: * pHash: the hash table * key: the key to insert * key_len: length of th key * value: the value * value_len: length of the value * needLock: if need lock * return >= 0 for success, 0 for key already exist (update), * 1 for new key (insert), < 0 for error */ int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \ void *value, const int value_len, const bool needLock); /** * hash find key * parameters: * pHash: the hash table * key: the key to find * key_len: length of th key * return user data, return NULL when the key not exist */ void *fc_hash_find(HashArray *pHash, const void *key, const int key_len); /** * hash find key * parameters: * pHash: the hash table * key: the key to find * key_len: length of th key * return hash data, return NULL when the key not exist */ HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len); /** * hash find key * parameters: * pHash: the hash table * key: the key to find * return user data, return NULL when the key not exist */ static inline void *fc_hash_find1(HashArray *pHash, const string_t *key) { return fc_hash_find(pHash, key->str, key->len); } /** * hash get the value of the key * parameters: * pHash: the hash table * key: the key to find * value: store the value * return 0 for success, != 0 fail (errno) */ int fc_hash_find2(HashArray *pHash, const string_t *key, string_t *value); /** * hash find key * parameters: * pHash: the hash table * key: the key to find * return hash data, return NULL when the key not exist */ HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key); /** * hash get the value of the key * parameters: * pHash: the hash table * key: the key to find * key_len: length of th key * value: store the value * value_len: input for the max size of the value * output for the length fo the value * return 0 for success, != 0 fail (errno) */ int fc_hash_get(HashArray *pHash, const void *key, const int key_len, void *value, int *value_len); /** * hash partial set * parameters: * pHash: the hash table * key: the key to insert * key_len: length of th key * value: the value * offset: the offset of existed value * value_len: length of the value * return 0 for success, != 0 fail (errno) */ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len, const char *value, const int offset, const int value_len); /** * hash delete key * parameters: * pHash: the hash table * key: the key to delete * key_len: length of th key * return 0 for success, != 0 fail (errno) */ int fc_hash_delete(HashArray *pHash, const void *key, const int key_len); /** * hash walk (iterator) * parameters: * pHash: the hash table * walkFunc: walk (interator) function * args: extra args which will be passed to walkFunc * return 0 for success, != 0 fail (errno) */ int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args); /** * get hash item count * parameters: * pHash: the hash table * return item count */ int fc_hash_count(HashArray *pHash); /** * hash best optimize * parameters: * pHash: the hash table * suggest_capacity: suggest init capacity for speed * return >0 for success, < 0 fail (errno) */ int fc_hash_best_op(HashArray *pHash, const int suggest_capacity); /** * hash stat * parameters: * pHash: the hash table * pStat: return stat info * stat_by_lens: return stats array by bucket length * stat_by_lens[0] empty buckets count * stat_by_lens[1] contain 1 key buckets count * stat_by_lens[2] contain 2 key buckets count, etc * stat_size: stats array size (contain max elments) * return 0 for success, != 0 fail (errno) */ int fc_hash_stat(HashArray *pHash, HashStat *pStat, \ int *stat_by_lens, const int stat_size); /** * print hash stat info * parameters: * pHash: the hash table * return none */ void fc_hash_stat_print(HashArray *pHash); /** * lock the bucket of hash table * parameters: * pHash: the hash table * bucket_index: the index of bucket * return 0 for success, != 0 fail (errno) */ int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index); /** * unlock the bucket of hash table * parameters: * pHash: the hash table * bucket_index: the index of bucket * return 0 for success, != 0 fail (errno) */ int fc_hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index); int RSHash(const void *key, const int key_len); int JSHash(const void *key, const int key_len); int JSHash_ex(const void *key, const int key_len, \ const int init_value); int PJWHash(const void *key, const int key_len); int PJWHash_ex(const void *key, const int key_len, \ const int init_value); int ELFHash(const void *key, const int key_len); int ELFHash_ex(const void *key, const int key_len, \ const int init_value); int BKDRHash(const void *key, const int key_len); int BKDRHash_ex(const void *key, const int key_len, \ const int init_value); int SDBMHash(const void *key, const int key_len); int SDBMHash_ex(const void *key, const int key_len, \ const int init_value); int Time33Hash(const void *key, const int key_len); int Time33Hash_ex(const void *key, const int key_len, \ const int init_value); int DJBHash(const void *key, const int key_len); int DJBHash_ex(const void *key, const int key_len, \ const int init_value); int APHash(const void *key, const int key_len); int APHash_ex(const void *key, const int key_len, \ const int init_value); int calc_hashnr (const void* key, const int key_len); int calc_hashnr1(const void* key, const int key_len); int calc_hashnr1_ex(const void* key, const int key_len, \ const int init_value); int fc_simple_hash(const void* key, const int key_len); int fc_simple_hash_ex(const void* key, const int key_len, \ const int init_value); int CRC32(const void *key, const int key_len); int64_t CRC32_ex(const void *key, const int key_len, \ const int64_t init_value); #define CRC32_FINAL(crc) (crc ^ CRC32_XOROT) #define INIT_HASH_CODES4(hash_codes) \ hash_codes[0] = CRC32_XINIT; \ hash_codes[1] = 0; \ hash_codes[2] = 0; \ hash_codes[3] = 0; \ #define CALC_HASH_CODES4(buff, buff_len, hash_codes) \ hash_codes[0] = CRC32_ex(buff, buff_len, hash_codes[0]); \ hash_codes[1] = ELFHash_ex(buff, buff_len, hash_codes[1]); \ hash_codes[2] = fc_simple_hash_ex(buff, buff_len, hash_codes[2]); \ hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \ #define FINISH_HASH_CODES4(hash_codes) \ hash_codes[0] = CRC32_FINAL(hash_codes[0]); \ unsigned int *fc_hash_get_prime_capacity(const int capacity); #ifdef __cplusplus } #endif #endif