问题笔记
hash算法
源码里默认使用time33算法,在创建时可自定义算法。
array的结构
数组中每个元素都是一个指针,指向一个条目链表。以hash值和max与运算结果作为索引。当条目数量大于max时会对数组扩展,装填因子最大为1。
对源码主要的几个函数做注释笔记,其他略过了。
数据结构
struct apr_hash_t {
apr_pool_t *pool;//使用的内存池
apr_hash_entry_t **array;//条目数组
apr_hash_index_t iterator; //迭代器
unsigned int count, max, seed;//count条目数量,max最大条目数量,seed种子。
apr_hashfunc_t hash_func;//自定义的hash计算方法
apr_hash_entry_t *free;//废弃的条目链表,创建条目时先从这个链表获取一个条目。
};
struct apr_hash_entry_t {
apr_hash_entry_t *next;//下一个条目
unsigned int hash;//hash值
const void *key;//key首地址
apr_ssize_t klen;//key长度
const void *val;//value首地址
};
struct apr_hash_index_t {
apr_hash_t *ht;//遍历的hashtable
apr_hash_entry_t *this, *next;//this当前条目,next下一个条目。
unsigned int index;//当前的索引
};
find_entry
查找一个条目的实现
static apr_hash_entry_t **find_entry(apr_hash_t *ht,
const void *key,
apr_ssize_t klen,
const void *val)
{
apr_hash_entry_t **hep, *he;
unsigned int hash;
//计算hash值
if (ht->hash_func)
hash = ht->hash_func(key, &klen);
else
hash = hashfunc_default(key, &klen, ht->seed);
//遍历ht查找hash,key,klen三值相等的条目。
for (hep = &ht->array[hash & ht->max], he = *hep;
he; hep = &he->next, he = *hep) {
if (he->hash == hash
&& he->klen == klen
&& memcmp(he->key, key, klen) == 0)
break;
}
//he!=NULL时找到满足的条目,val==null时表示查找。
if (he || !val)
return hep;
//添加val!=null && he==null的条目。
//先从free中获取实例,没有就从pool中申请内存。
if ((he = ht->free) != NULL)
ht->free = he->next;
else
he = apr_palloc(ht->pool, sizeof(*he));
he->next = NULL;
he->hash = hash;
he->key = key;
he->klen = klen;
he->val = val;
*hep = he;
ht->count++;
return hep;
}
Get
APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht,
const void *key,
apr_ssize_t klen)
{
apr_hash_entry_t *he;
//val输入NULL表示查找
he = *find_entry(ht, key, klen, NULL);
if (he)
return (void *)he->val;
else
return NULL;
}
Set
APR_DECLARE(void) apr_hash_set(apr_hash_t *ht,
const void *key,
apr_ssize_t klen,
const void *val)
{
apr_hash_entry_t **hep;
//查找条目,如果不存在则会添加一个。
hep = find_entry(ht, key, klen, val);
if (*hep) {
//val为NULL删除条目
if (!val) {
apr_hash_entry_t *old = *hep;
*hep = (*hep)->next;
old->next = ht->free;
ht->free = old;
--ht->count;
}
else {
//替换value的值
(*hep)->val = val;
//条目数量大于max则扩展hashtable大小
if (ht->count > ht->max) {
expand_array(ht);
}
}
}
}