当table插入新值而没有空位的时候,会触发rehash
static TValue *newkey(gafq_State *L, Table *t, const TValue *key)
{
Node *mp = mainposition(t, key); // 获取主要位置
if (!ttisnil(gval(mp)) || mp == dummynode)
{
Node *othern;
Node *n = getfreepos(t); // 获取一个空位置
if (n == NULL)
{
rehash(L, t, key); // 没有找到空位置就重新算hash
return gafqH_set(L, t, key);
}
}
static void rehash(gafq_State *L, Table *t, const TValue *ek)
{
int nasize, na;
int nums[MAXBITS + 1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */
int i;
int totaluse;
for (i = 0; i <= MAXBITS; i++)
nums[i] = 0; // 重置数组数量?
nasize = numusearray(t, nums); // 计算数组部分的key的数量
totaluse = nasize; // 所有整数的key的数量
totaluse += numusehash(t, nums, &nasize); // 哈希表部分的key数量
nasize += countint(ek, nums); // 新加的key 会不会加到整数部分
totaluse++;
na = computesizes(nums, &nasize); // 重新计算数组部分
/* resize the table to new computed sizes */
resize(L, t, nasize, totaluse - na);
}
1. 在rehash中首先计算数组部分使用的数量
// 统计array部分数量
static int numusearray(const Table *t, int *nums)
{
int lg;
int cur_max_lg; /* 2^lg */
int all_use_count = 0; // 计算使用的数字类型的key数量
int check_array_index = 1; // 遍历所有数字key
for (lg = 0, cur_max_lg = 1; lg <= MAXBITS; lg++, cur_max_lg *= 2)
{ /* for each slice */
int lc = 0; // 每一小部分的使用的数字的数量
int cur_limit = cur_max_lg;
if (cur_limit > t->sizearray)
{
cur_limit = t->sizearray; // 最多直到当前数组的大小
if (check_array_index > cur_limit)//检查超过了
break;
}
/* count elements in range (2^(lg-1), 2^lg] */
for (; check_array_index <= cur_limit; check_array_index++)
{
if (!ttisnil(&t->array[check_array_index - 1]))
lc++;
}
nums[lg] += lc;
all_use_count += lc;
}
return all_use_count;
}
1. 接着计算hash部分使用的数量
// 统计哈希部分的数量
static int numusehash(const Table *t, int *nums, int *pnasize)
{
int totaluse = 0; // 哈希部分使用的总量
int all_use_count = 0; // 使用的数量
int i = sizenode(t);
while (i--)
{
Node *n = &t->node[i];
if (!ttisnil(gval(n)))
{
all_use_count += countint(key2tval(n), nums);
totaluse++;
}
}
*pnasize += all_use_count;
return totaluse;
}
1. 计算数组部分的大小
static int computesizes(int nums[], int *narray)
{
int i;
int twotoi; /* 2^i */
int a = 0; /* number of elements smaller than 2^i */
int na = 0; /* number of elements to go to array part */
int n = 0; /* optimal size for array part */
for (i = 0, twotoi = 1; twotoi / 2 < *narray; i++, twotoi *= 2)
{
if (nums[i] > 0)
{
a += nums[i];
if (a > twotoi / 2)
{ /* more than half elements present? */
n = twotoi; /* optimal size (till now) */
na = a; /* all elements smaller than n will go to array part */
}
}
if (a == *narray)
break; /* all elements already counted */
}
*narray = n;
gafq_assert(*narray / 2 <= na && na <= *narray);
return na;
}
1. 重新计算resize
// 重新计算 根据 当前数组使用数量nasize 和 hash使用数量nhsize
static void resize(gafq_State *L, Table *t, int nasize, int nhsize)
{
int i;
int oldasize = t->sizearray;
int oldhsize = t->lsizenode;
Node *nold = t->node; // 旧的hash数量
if (nasize > oldasize) // 需要增加数组部分
setarrayvector(L, t, nasize);
setnodevector(L, t, nhsize); // 创建哈希位置
if (nasize < oldasize) // 数组部分变少了
{
t->sizearray = nasize;
for (i = nasize; i < oldasize; i++)
{
if (!ttisnil(&t->array[i]))
setobjt2t(L, gafqH_setnum(L, t, i + 1), &t->array[i]);
}
// 减少array
gafqM_reallocvector(L, t->array, oldasize, nasize, TValue);
}
// 重新插入哈希部分
for (i = twoto(oldhsize) - 1; i >= 0; i--)
{
Node *old = nold + i;
if (!ttisnil(gval(old)))
setobjt2t(L, gafqH_set(L, t, key2tval(old)), gval(old));
}
if (nold != dummynode)
gafqM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */
}