libevent中的hash表
来源:互联网 发布:mac 程序 卸装 编辑:程序博客网 时间:2024/05/18 00:32
libevent中的hash表的代码在ht-internal文件中,在添加io事件,signal事件时,底层是在操作
2.1初始化
event_io_map和event_signal_map
1、 hash的结构(开链)
libevent中的hash表是用宏来定义的
#define HT_HEAD(name, type) \ struct name { \ /* The hash table itself. */ \ struct type **hth_table; \ //hash表的指针,可以理解为一个指针数组 /* How long is the hash table? */ \ unsigned hth_table_length; \//hash表的长度,即指针数据的大小 /* How many elements does the table contain? */ \ unsigned hth_n_entries; \//hash表中的元素个数,即插入了多少个元素 /* How many elements will we allow in the table before resizing it? */ \ unsigned hth_load_limit; \ //hash表的加载限制,比如当表中的元素大于这个限制时,会重新设置表的长度 /* Position of hth_table_length in the primes table. */ \ int hth_prime_idx; \ }
hash表中的结点也是用宏来定义的:
#define HT_ENTRY(type) \ struct { \ struct type *hte_next; \ //指向下一个结点,构成链表 unsigned hte_hash; \ //结点对应的hash值 }2、 hash操作
2.1初始化
初始化hash表结构,将表的桶数,元素个数,增长限制设置为0
static inline void \ name##_HT_INIT(struct name *head) { \ head->hth_table_length = 0; \ head->hth_table = NULL; \ head->hth_n_entries = 0; \ head->hth_load_limit = 0; \ head->hth_prime_idx = -1; \ }
2.2查找
_##name##_HT_FIND_P这个宏返回的是指向next的二级指针
static inline struct type ** \ _##name##_HT_FIND_P(struct name *head, struct type *elm) \ { \ struct type **p; \ if (!head->hth_table) \ return NULL; \ p = &_HT_BUCKET(head, field, elm, hashfn);\ //找到对应的桶 while (*p) { \ if (eqfn(*p, elm)) \ return p; \ p = &(*p)->field.hte_next; \ } \ return p; \ }
static inline struct type * \ name##_HT_FIND(const struct name *head, struct type *elm) \ { \ struct type **p; \ struct name *h = (struct name *) head; \ _HT_SET_HASH(elm, field, hashfn); \ p = _##name##_HT_FIND_P(h, elm); \ return p ? *p : NULL; \ }
通过调用_##name##_HT_FIND_P来得到存放next的指针,如果不为空,就返回其所指向的指针
2.3增长
int \ name##_HT_GROW(struct name *head, unsigned size) \ { \ unsigned new_len, new_load_limit; \ int prime_idx; \ struct type **new_table; \ if (head->hth_prime_idx == (int)name##_N_PRIMES - 1) \ //素数索引大于素数表大小返回 return 0; \ if (head->hth_load_limit > size) \ //希望的大小比增长限制还小,就不增长,直接返回 return 0; \ prime_idx = head->hth_prime_idx; \ do { \ //遍历素数表,找到与size匹配的素数 new_len = name##_PRIMES[++prime_idx]; \ new_load_limit = (unsigned)(load*new_len); \ } while (new_load_limit <= size && \ prime_idx < (int)name##_N_PRIMES); \ if ((new_table = mallocfn(new_len*sizeof(struct type*)))) { \ //将原来的hash表分配到新建的hash表中 unsigned b; \ memset(new_table, 0, new_len*sizeof(struct type*)); \ for (b = 0; b < head->hth_table_length; ++b) { \ struct type *elm, *next; \ unsigned b2; \ elm = head->hth_table[b]; \ while (elm) { \ next = elm->field.hte_next; \ b2 = _HT_ELT_HASH(elm, field, hashfn) % new_len; \ elm->field.hte_next = new_table[b2]; \ new_table[b2] = elm; \ elm = next; \ } \ } \ if (head->hth_table) \ //建完后,释放原来的hash表 freefn(head->hth_table); \ head->hth_table = new_table; \ } else { \ //保持原来存储空间,新增新空间时的处理 unsigned b, b2; \ new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \ if (!new_table) return -1; \ memset(new_table + head->hth_table_length, 0, \ (new_len - head->hth_table_length)*sizeof(struct type*)); \ for (b=0; b < head->hth_table_length; ++b) { \ struct type *e, **pE; \ for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) { \ b2 = _HT_ELT_HASH(e, field, hashfn) % new_len; \ if (b2 == b) { \//元素原来的hash值与新的hash值一样,就直接继续下一个 pE = &e->field.hte_next; \ } else { \//不一样,将该元素放在新首部,在原来桶中将其删除 *pE = e->field.hte_next; \ e->field.hte_next = new_table[b2]; \ new_table[b2] = e; \ } \ } \ } \ head->hth_table = new_table; \ } \ head->hth_table_length = new_len; \ head->hth_prime_idx = prime_idx; \ head->hth_load_limit = new_load_limit; \ return 0; \ }
2.4插入
static inline void \ name##_HT_INSERT(struct name *head, struct type *elm) \ { \ struct type **p; \ if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \ //如果满足增长条件,在插入前先增长hash表 name##_HT_GROW(head, head->hth_n_entries+1); \ ++head->hth_n_entries; \ _HT_SET_HASH(elm, field, hashfn); \ p = &_HT_BUCKET(head, field, elm, hashfn);\ //获取存放桶头的指针 elm->field.hte_next = *p; \ //将新加的元素插入桶头 *p = elm; \ }
2.5替换
static inline struct type * \ name##_HT_REPLACE(struct name *head, struct type *elm) \ { \ struct type **p, *r; \ if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \ name##_HT_GROW(head, head->hth_n_entries+1); \ _HT_SET_HASH(elm, field, hashfn); \ p = _##name##_HT_FIND_P(head, elm); \ r = *p; \ *p = elm; \ if (r && (r!=elm)) { \ //如果表中存在一样的替换 elm->field.hte_next = r->field.hte_next; \ r->field.hte_next = NULL; \ return r; \ } else { \ ++head->hth_n_entries; \//没有一样就将其插入桶尾,通过*p = elm来实现的 return NULL; \ } \ }
2.6删除
static inline struct type * \ name##_HT_REMOVE(struct name *head, struct type *elm) \ { \ struct type **p, *r; \ _HT_SET_HASH(elm, field, hashfn); \ p = _##name##_HT_FIND_P(head,elm); \ if (!p || !*p) \ //没有找到退出 return NULL; \ r = *p; \ *p = r->field.hte_next; \删除元素,将前驱指向后继 r->field.hte_next = NULL; \ --head->hth_n_entries; \ return r; \ }
2.7遍历条件删除
static inline void \ name##_HT_FOREACH_FN(struct name *head, \ int (*fn)(struct type *, void *), \ void *data) \ { \ unsigned idx; \ struct type **p, **nextp, *next; \ if (!head->hth_table) \ return; \ for (idx=0; idx < head->hth_table_length; ++idx) { \ p = &head->hth_table[idx]; \ while (*p) { \ nextp = &(*p)->field.hte_next; \ next = *nextp; \ if (fn(*p, data)) { \//如果fn为非0,删除该元素 --head->hth_n_entries; \ *p = next; \ } else { \ p = nextp; \ } \ } \ } \ }
2.8找到hash表中存在元素的第一个桶
static inline struct type ** \ name##_HT_START(struct name *head) \ { \ unsigned b = 0; \ while (b < head->hth_table_length) { \ if (head->hth_table[b]) \ return &head->hth_table[b]; \ ++b; \ } \ return NULL; \ }
2.9找到elem的下一个元素
static inline struct type ** \ name##_HT_NEXT(struct name *head, struct type **elm) \ { \ if ((*elm)->field.hte_next) { \ return &(*elm)->field.hte_next; \ } else { \ unsigned b = (_HT_ELT_HASH(*elm, field, hashfn) % head->hth_table_length)+1; \ while (b < head->hth_table_length) { \ if (head->hth_table[b]) \ return &head->hth_table[b]; \ ++b; \ } \ return NULL; \ } \ }
2.10删除elem的下一个元素
static inline struct type ** \ name##_HT_NEXT_RMV(struct name *head, struct type **elm) \ { \ unsigned h = _HT_ELT_HASH(*elm, field, hashfn); \ *elm = (*elm)->field.hte_next; \ //删除后继 --head->hth_n_entries; \ if (*elm) { \ return elm; \ } else { \//如果到桶尾,就返回下一个桶头 unsigned b = (h % head->hth_table_length)+1; \ while (b < head->hth_table_length) { \ if (head->hth_table[b]) \ return &head->hth_table[b]; \ ++b; \ } \ return NULL; \ } \ }
2.11表清空
void \ name##_HT_CLEAR(struct name *head) \ { \ if (head->hth_table) \ freefn(head->hth_table); \ //释放空间,然后初始化 head->hth_table_length = 0; \ name##_HT_INIT(head); \ }
0 0
- libevent中的hash表
- js中的hash表
- 关于ABAP中的HASH表
- libevent中的信号处理
- libevent中的基本数据结构
- libevent中的缓冲区(二)
- libevent中的bufferevent
- libevent中的时间管理
- libevent中的时间管理
- FileMon中的Hash表算法代码
- hash 表在Java中的应用
- Postgres内存中的Hash表结构
- libEvent在vs2005中的配置
- libevent中的缓冲区(一)
- libevent中的event结构体
- Hash 函数、Hash表
- hash表、hash算法
- hash-A-hash表
- 在屏幕显示信息
- C++类入门
- 百度地图开发
- 第32题
- STL学习记录(一):STL简介
- libevent中的hash表
- 2-09. 装箱问题模拟(20)
- 火焰圆形度计算
- 研究生记录(3)2015-4-27
- id、NSObject *、id<NSObject>、instancetype的区别
- 【cocos2d-x 3.5】Lua动画API
- 使用python3.4解析xml文件(sax、dom、etree)
- 登泰山
- Web前端开发工程师必读的15个设计博客