#ifndef ACL_HTABLE_INCLUDE_H #define ACL_HTABLE_INCLUDE_H #ifdef __cplusplus extern "C" { #endif #include "acl_define.h" #include "thread/acl_thread.h" #include "acl_hash.h" /* just for ACL_HASH_FN */ #include "acl_slice.h" #include "acl_iterator.h" /*--------------------------------------------------------------------------*/ typedef struct ACL_HTABLE ACL_HTABLE; typedef struct ACL_HTABLE_INFO ACL_HTABLE_INFO; /** * 哈希表对象结构句柄 */ struct ACL_HTABLE { int size; /* length of entries array */ int init_size; /* length of initial entryies array */ int used; /* number of entries in table */ ACL_HTABLE_INFO **data; /* entries array, auto-resized */ unsigned int flag; /* properties flag */ int status; /* the operator's status on the htable */ ACL_HASH_FN hash_fn; /* hash function */ ACL_SLICE_POOL *slice; acl_pthread_mutex_t *rwlock; /* for acl_iterator */ /* 取迭代器头函数 */ void *(*iter_head)(ACL_ITER*, struct ACL_HTABLE*); /* 取迭代器下一个函数 */ void *(*iter_next)(ACL_ITER*, struct ACL_HTABLE*); /* 取迭代器尾函数 */ void *(*iter_tail)(ACL_ITER*, struct ACL_HTABLE*); /* 取迭代器上一个函数 */ void *(*iter_prev)(ACL_ITER*, struct ACL_HTABLE*); /* 取迭代器关联的当前容器成员结构对象 */ ACL_HTABLE_INFO *(*iter_info)(ACL_ITER*, struct ACL_HTABLE*); }; /** * 哈希表中每一个哈希项的存储信息类型 */ struct ACL_HTABLE_INFO { union { char *key; const char *c_key; } key; /** * 哈希键, 只所以如此声明,是因为当创建哈希表的标志位为 * ACL_BINHASH_FLAG_KEY_REUSE 时需要复用输入的键空间 */ void *value; /**< associated value */ struct ACL_HTABLE_INFO *next; /**< colliding entry */ struct ACL_HTABLE_INFO *prev; /**< colliding entry */ }; /** * ACL_HTABLE 遍历用类型 */ typedef struct ACL_HTABLE_ITER { /* public */ ACL_HTABLE_INFO *ptr; /* private */ int i; int size; ACL_HTABLE_INFO **h; } ACL_HTABLE_ITER; /** * 建立哈希表 * @param size 哈希表长度 * @param flag {unsigned int} 哈希表属性标志位, ACL_BINHASH_FLAG_xxx * @return 所建哈希表的头指针或为空(这时表示出了严重的错误, 主要是内存分配问题) */ ACL_API ACL_HTABLE *acl_htable_create(int size, unsigned int flag); #define ACL_HTABLE_FLAG_KEY_REUSE (1 << 0) /* 添加新的对象时是否直接复用键地址 */ #define ACL_HTABLE_FLAG_USE_LOCK (1 << 1) /* 是否针对启用多线程互斥方式 */ #define ACL_HTABLE_FLAG_MSLOOK (1 << 2) /* 每次查询时是否将查询结果对象放在链头 */ #define ACL_HTABLE_FLAG_KEY_LOWER (1 << 3) /* 统一将键转换为小写,从而实现键查询不区分大小写的功能 */ ACL_API ACL_HTABLE *acl_htable_create3(int size, unsigned int flag, ACL_SLICE_POOL *slice); /** * 设置哈希表的控制参数 * @param table 哈希表对象句柄 * @param name 控制参数的变参初始值, name 及以后的控制参数如下定义 * ACL_HTABLE_CTL_END: 变参表结束标志 * ACL_HTABLE_CTL_RWLOCK: 是否启用读写锁机制 * ACL_HTABLE_CTL_HASH_FN: 用户自定义的哈希值计算函数 */ ACL_API void acl_htable_ctl(ACL_HTABLE *table, int name, ...); #define ACL_HTABLE_CTL_END 0 /**< 控制结束标志 */ #define ACL_HTABLE_CTL_RWLOCK 1 /**< 是否加锁 */ #define ACL_HTABLE_CTL_HASH_FN 2 /**< 设置私有哈希函数 */ /** * 检查上一次哈希表操作后哈希表的状态 * @param table 哈希表指针 * @return {int} 操作哈希表后的状态, 参见如下的 ACL_HTABLE_STAT_XXX */ ACL_API int acl_htable_errno(ACL_HTABLE *table); #define ACL_HTABLE_STAT_OK 0 /**< 状态正常 */ #define ACL_HTABLE_STAT_INVAL 1 /**< 无效参数 */ #define ACL_HTABLE_STAT_DUPLEX_KEY 2 /**< 重复键 */ /** * 设置哈希表的当前状态, error 取值 ACL_HTABLE_STAT_XXX * @param table 哈希表指针 * @param error 设置哈希表的错误状态 */ ACL_API void acl_htable_set_errno(ACL_HTABLE *table, int error); /** * 往哈希表里添加新的项 * @param table 哈希表指针 * @param key 键, 在函数内部会复制此 key 键 * @param value 用户自己的特定数据项(可以由类型硬转化而来, 但是此数据项必须不能堆栈变量) * @return 所分配的哈希表项的指针, == NULL: 表示内部分分配内存出错, 为严重的错误 * 注:如果在添加时该哈希争键存在,则返回已经存在的哈希项,使用者应该通过调用 * acl_htable_last_errno() 来查看是否重复添加同一个键值(ACL_HTABLE_STAT_DUPLEX_KEY) */ ACL_API ACL_HTABLE_INFO *acl_htable_enter(ACL_HTABLE *table, const char *key, void *value); /** * 往哈希表里添加新的项,当多个线程同时进行此操作时,函数内部会自动保证互斥操作 * @param table 哈希表指针 * @param key 键, 在函数内部会复制此 key 键 * @param value 用户自己的特定数据项(可以由类型硬转化而来, 但是此数据项必须不能堆栈变量) * @param callback 如果该函数指针不为空,则当添加成功后便调用该函数 * @param arg callback 的参数之一 * @return {int} 0 表示 添加成功,-1 表示添加失败 * 注:如果在添加时该哈希争键存在,则返回已经存在的哈希项,使用者应该通过调用 * acl_htable_last_errno() 来查看是否重复添加同一个键值(ACL_HTABLE_STAT_DUPLEX_KEY) */ ACL_API int acl_htable_enter_r(ACL_HTABLE *table, const char *key, void *value, void (*callback)(ACL_HTABLE_INFO *ht, void *arg), void *arg); /** * 由所给的 key 键查寻某一特定哈希项 * @param table 哈希表指针 * @param key 键 * @return 不为空指针: 表示查到了对应于 key 键的哈希项 * 为空: 表示未查到对应于 key 键的哈希项 */ ACL_API ACL_HTABLE_INFO *acl_htable_locate(ACL_HTABLE *table, const char *key); /** * 由所给的 key 键查寻某一特定哈希项,当多个线程同时进行此操作时, * 函数内部会自动保证互斥操作 * @param table 哈希表指针 * @param key 键 * @param callback 查到所要求的键值后如果该指针非空则调用之 * @param arg callback 参数之一 * @return 不为空指针: 表示查到了对应于 key 键的哈希项 * 为空: 表示未查到对应于 key 键的哈希项 */ ACL_API int acl_htable_locate_r(ACL_HTABLE *table, const char *key, void (*callback)(ACL_HTABLE_INFO *ht, void *arg), void *arg); /** * 由所给的 key 键查寻用户的数据项 * @param table 哈希表指针 * @param key 键 * @return 不为空: 表示查到了对应于 key 键的数据项, 用户可以根据用户自己的 * 数据类型进行转换; 为空: 表示未查到对应于 key 键的数据项 */ ACL_API void *acl_htable_find(ACL_HTABLE *table, const char *key); /** * 由所给的 key 键查寻用户的数据项, 当多个线程同时进行此操作时, * 函数内部会自动保证互斥操作 * @param table 哈希表指针 * @param key 键 * @param callback 当查到所要求的键值后,如果该函数指针不为空则调用之 * @param arg callback 的参数之一 * @return 不为空: 表示查到了对应于 key 键的数据项, 用户可以根据用户自己的 * 数据类型进行转换; 为空: 表示未查到对应于 key 键的数据项 */ ACL_API int acl_htable_find_r(ACL_HTABLE *table, const char *key, void (*callback)(void *value, void *arg), void *arg); /** * 根据所给的 key 键删除某一哈希项 * @param table 哈希表指针 * @param key 键 * @param free_fn 如果该函数指针不为空并且找到了对应于 key 键的数据项, 则先调用用户 * 所提供的析构函数做一些清尾工作, 然后再释放该哈希项 * @return 0: 成功; -1: 未找到该 key 键 */ ACL_API int acl_htable_delete(ACL_HTABLE *table, const char *key, void (*free_fn) (void *)); #define acl_htable_delete_r acl_htable_delete /** * 释放整个哈希表 * @param table 哈希表指针 * @param free_fn 如果该指针不为空则对哈希表中的每一项哈希项先用该函数做清尾工作, 然后再释放 */ ACL_API void acl_htable_free(ACL_HTABLE *table, void (*free_fn) (void *)); /** * 重置哈希表, 该函数会释放哈希表中的所有内容项, 并重新初始化 * @param table 哈希表指针 * @param free_fn 如果该指针不为空则对哈希表中的每一项哈希项先用该函数做清尾工作, 然后再释放 * @return 是否重置成功. 0: OK; < 0: error. */ ACL_API int acl_htable_reset(ACL_HTABLE *table, void (*free_fn) (void *)); #define acl_htable_reset_r acl_htable_reset /** * 对哈希表中的每一项哈希项进行处理 * @param table 哈希表指针 * @param walk_fn 处理每一项哈希项的函数指针, 不能为空 * @param arg 用户自己类型的数据 */ ACL_API void acl_htable_walk(ACL_HTABLE *table, void (*walk_fn) (ACL_HTABLE_INFO *, void *), void *arg); #define acl_htable_walk_r acl_htable_walk /** * 返回哈希表当前的容器空间大小 * @param table 哈希表指针 * @return 哈希表的容器空间大小 */ ACL_API int acl_htable_size(const ACL_HTABLE *table); /** * 返回哈希表当前的窗口中所含元素个数 * @param table 哈希表指针 * @return 哈希表中元素个数 */ ACL_API int acl_htable_used(const ACL_HTABLE *table); /** * 将哈希表里的所有项组合成一个链表 * @param table 哈希表 * @return 不为空: 链表指针; 为空: 表示该哈希表里没有哈希项 */ ACL_API ACL_HTABLE_INFO **acl_htable_list(const ACL_HTABLE *table); /** * 显示哈希表中 key 键的分布状态 * @param table 哈希表指针 */ ACL_API void acl_htable_stat(const ACL_HTABLE *table); #define acl_htable_stat_r acl_htable_stat ACL_API ACL_HTABLE_INFO **acl_htable_data(ACL_HTABLE *table); ACL_API const ACL_HTABLE_INFO *acl_htable_iter_head(ACL_HTABLE *table, ACL_HTABLE_ITER *iter); ACL_API const ACL_HTABLE_INFO *acl_htable_iter_next(ACL_HTABLE_ITER *iter); ACL_API const ACL_HTABLE_INFO *acl_htable_iter_tail(ACL_HTABLE *table, ACL_HTABLE_ITER *iter); ACL_API const ACL_HTABLE_INFO *acl_htable_iter_prev(ACL_HTABLE_ITER *iter); /*-------------------- 一些方便快捷的宏操作 --------------------------------*/ #define ACL_HTABLE_ITER_KEY(iter) ((iter).ptr->key.c_key) #define acl_htable_iter_key ACL_HTABLE_ITER_KEY #define ACL_HTABLE_ITER_VALUE(iter) ((iter).ptr->value) #define acl_htable_iter_value ACL_HTABLE_ITER_VALUE /** * 遍历 ACL_HTABLE * @param iter {ACL_HTABLE_ITER} * @param table_ptr {ACL_HTABLE *} * @example: void test() { ACL_HTABLE *table = acl_htable_create(10, 0); ACL_HTABLE_ITER iter; char *value, key[32]; int i; for (i = 0; i < 100; i++) { value = (char*) acl_mystrdup("value"); snprintf(key, sizeof(key), "key:%d", i); (void) acl_htable_enter(table, key, value); } acl_htable_foreach(iter, table) { printf("%s=%s\n", acl_htable_iter_key(iter), acl_htable_iter_value(iter)); if (i == 50) break; } acl_htable_free(table, acl_myfree_fn); } */ #if 0 #define ACL_HTABLE_FOREACH(iter, table_ptr) \ if (table_ptr) \ for((iter).size = acl_htable_size((table_ptr)), (iter).i = 0, \ (iter).h = acl_htable_data((table_ptr)); (iter).i < (iter).size; (iter).i++) \ for ((iter).ptr = *(iter).h++; (iter).ptr; (iter).ptr = (iter).ptr->next) #define ACL_HTABLE_FOREACH_REVERSE(iter, table_ptr) \ if (table_ptr) \ for((iter).size = acl_htable_size((table_ptr)), (iter).i = (iter).size - 1, \ (iter).h = acl_htable_data((table_ptr)) + (iter).i; (iter).i >= 0; (iter).i--) \ for ((iter).ptr = *(iter).h--; (iter).ptr; (iter).ptr = (iter).ptr->next) #else #define ACL_HTABLE_FOREACH(iter, table_ptr) \ if (table_ptr) \ for((void) acl_htable_iter_head((table_ptr), &iter); \ (iter).ptr; \ (void) acl_htable_iter_next(&iter)) #define ACL_HTABLE_FOREACH_REVERSE(iter, table_ptr) \ if (table_ptr) \ for((void) acl_htable_iter_tail((table_ptr), &iter); \ (iter).ptr; \ (void) acl_htable_iter_prev(&iter)) #endif #define acl_htable_foreach ACL_HTABLE_FOREACH #define acl_htable_foreach_reverse ACL_HTABLE_FOREACH_REVERSE #ifdef __cplusplus } #endif #endif