mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-06 05:49:34 +08:00
357 lines
12 KiB
C
357 lines
12 KiB
C
#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 {
|
|
/**
|
|
* 哈希键, 只所以如此声明,是因为当创建哈希表的标志位为
|
|
* ACL_BINHASH_FLAG_KEY_REUSE 时需要复用输入的键空间
|
|
*/
|
|
union {
|
|
char *key;
|
|
const char *c_key;
|
|
} key;
|
|
void *value; /**< associated value */
|
|
unsigned hash; /**< store the key's hash 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
|
|
|
|
/**
|
|
* 直接根据 acl_htable_locate 返回的非空对象从哈希表中删除该对象
|
|
* @param table 哈希表指针
|
|
* @param ht {ACL_HTABLE_INFO*} 存储于哈希表中的内部结构对象
|
|
* @param free_fn 如果该函数指针不为空并且找到了对应于 key 键的数据项, 则先
|
|
* 调用用户所提供的析构函数做一些清尾工作, 然后再释放该哈希项
|
|
*/
|
|
ACL_API void acl_htable_delete_entry(ACL_HTABLE *table, ACL_HTABLE_INFO *ht,
|
|
void (*free_fn) (void *));
|
|
|
|
/**
|
|
* 释放整个哈希表
|
|
* @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
|
|
|