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操作初始化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); \
}