libevent中的hash表

来源:互联网 发布:mac 程序 卸装 编辑:程序博客网 时间:2024/05/18 00:32
libevent中的hash表的代码在ht-internal文件中,在添加io事件,signal事件时,底层是在操作


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