libevent中的hash表

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);                                               \
  }  




















你可能感兴趣的:(libevent)