结构
struct lhash_st {
OPENSSL_LH_NODE **b;
OPENSSL_LH_COMPFUNC comp; //比较函数
OPENSSL_LH_HASHFUNC hash;//哈希函数
unsigned int num_nodes; //用来判断是否需要扩容,比如目前是16,当时num_nodes为15时就需要扩容,目前实现扩容是之前容量的2倍
unsigned int num_alloc_nodes; //容量,b空间的大小
unsigned int p; //工具指针,从0到容量的一半
unsigned int pmax; //总是为容量的一半
unsigned long up_load; /* load times 256 */
unsigned long down_load; /* load times 256 */
unsigned long num_items; //数据总量
unsigned long num_expands;
unsigned long num_expand_reallocs;
unsigned long num_contracts;
unsigned long num_contract_reallocs;
TSAN_QUALIFIER unsigned long num_hash_calls;
TSAN_QUALIFIER unsigned long num_comp_calls;
unsigned long num_insert;
unsigned long num_replace;
unsigned long num_delete;
unsigned long num_no_delete;
TSAN_QUALIFIER unsigned long num_retrieve;
TSAN_QUALIFIER unsigned long num_retrieve_miss;
TSAN_QUALIFIER unsigned long num_hash_comps;
int error;
};
数组上挂链表
搬移和扩容
当使用数据达到容量的一半时开始进行搬移,
当达到全部容量时重新分配原来2倍的内存,进行扩容
static int expand(OPENSSL_LHASH *lh)
{
OPENSSL_LH_NODE **n, **n1, **n2, *np;
unsigned int p, pmax, nni, j;
unsigned long hash;
nni = lh->num_alloc_nodes;
p = lh->p;
pmax = lh->pmax;
if (p + 1 >= pmax) {
j = nni * 2;
n = OPENSSL_realloc(lh->b, sizeof(OPENSSL_LH_NODE *) * j);
if (n == NULL) {
lh->error++;
return 0;
}
lh->b = n;
memset(n + nni, 0, sizeof(*n) * (j - nni));
lh->pmax = nni;
lh->num_alloc_nodes = j;
lh->num_expand_reallocs++;
lh->p = 0;
} else {
lh->p++;
}
lh->num_nodes++;
lh->num_expands++;
n1 = &(lh->b[p]);
n2 = &(lh->b[p + pmax]);
*n2 = NULL;
for (np = *n1; np != NULL;) {
hash = np->hash;
if ((hash % nni) != p) { /* move it */
*n1 = (*n1)->next;
np->next = *n2;
*n2 = np;
} else
n1 = &((*n1)->next);
np = *n1;
}
return 1;
}
插入方法分析
- 看容量够不够,不够就扩容
- 通过hash函数计算哈希值,找到要插入的位置
- 如果此位置上有数据,说明插入了相同的值(通过传入的比较函数进行比较),更新一下
- 如果此位置没有数据,分配一个节点,并插入到此位置上。
void *OPENSSL_LH_insert(OPENSSL_LHASH *lh, void *data)
{
unsigned long hash;
OPENSSL_LH_NODE *nn, **rn;
void *ret;
lh->error = 0;
if ((lh->up_load <= (lh->num_items * LH_LOAD_MULT / lh->num_nodes)) && !expand(lh))
return NULL; /* 'lh->error++' already done in 'expand' */
rn = getrn(lh, data, &hash);
if (*rn == NULL) {
if ((nn = OPENSSL_malloc(sizeof(*nn))) == NULL) {
lh->error++;
return NULL;
}
nn->data = data;
nn->next = NULL;
nn->hash = hash;
*rn = nn;
ret = NULL;
lh->num_insert++;
lh->num_items++;
} else { /* replace same key */
ret = (*rn)->data;
(*rn)->data = data;
lh->num_replace++;
}
return ret;
}