lua.5.2.3源码阅读(06):Table内存的申请

rehash是根据当前表格中的数据重新计算一个比较函数的:数组大小和hash表大小,重新申请空间,并重新插入原有数据:

 1 static void rehash (lua_State *L, Table *t, const TValue *ek) {
 2   int nasize, na;
 3   int nums[MAXBITS+1];  /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */
 4   int i;
 5   int totaluse;
 6   for (i=0; i<=MAXBITS; i++) nums[i] = 0;  /* reset counts */
 7   nasize = numusearray(t, nums);  /* count keys in array part */
 8   totaluse = nasize;  /* all those keys are integer keys */
 9   totaluse += numusehash(t, nums, &nasize);  /* count keys in hash part */
10   /* count extra key */
11   nasize += countint(ek, nums);
12   totaluse++;
13   /* compute new size for array part */
14   na = computesizes(nums, &nasize);
15   /* resize the table to new computed sizes */
16   luaH_resize(L, t, nasize, totaluse - na);
17 }

1、nums[i] = number of keys with 2^(i-1) < k <= 2^i;

2、numusearray计算数组中有效值个数nasize,以及有效值在每个区间的分布情况;

3、numusehash统计hash表中有效值的个数,并且统计hash表中key为整数的个数,合并到nasize中;

4、统计插入当前的值是不是整数值;

5、根据整数key的个数,以及在各个区间的分布,计算合适的数组大小;

6、重新分配空间;

 

统计数组有效值的numusearray:

 1 // nums是一个30的数组,每个数字用来记录
 2 // 2^i到2^(i+1)之间数字的数字个数,数组部分
 3 // 把 t->sizearray数组内的所有数据,按照2^i到2^(i+1)
 4 // 分类统计,返回总共使用的个数;
 5 static int numusearray (const Table *t, int *nums) {
 6   int lg;
 7   int ttlg;  /* 2^lg */
 8   int ause = 0;  /* summation of `nums' */
 9   int i = 1;  /* count to traverse all array keys */
10   for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) {  /* for each slice */
11     int lc = 0;  /* counter */
12     int lim = ttlg;
13     if (lim > t->sizearray) {
14       lim = t->sizearray;  /* adjust upper limit */
15       if (i > lim)
16         break;  /* no more elements to count */
17     }
18     /* count elements in range (2^(lg-1), 2^lg] */
19     for (; i <= lim; i++) {
20       if (!ttisnil(&t->array[i-1]))
21         lc++;
22     }
23     nums[lg] += lc;
24     ause += lc;
25   }
26   return ause;
27 }

 

numusehash统计hash表格中有效数的情况,以及key为整数的个数,累加到数组有效个数中,countint检查是不是整数:

 1 // 统计Node的使用情况,以及key对应到2^i到2^(i+1)之间数字的数字个数
 2 // 并统计hash表中key为整数的个数,可以用来保存到数组中
 3 static int numusehash(const Table *t, int *nums, int *pnasize) {
 4     int totaluse = 0;  /* total number of elements */
 5     int ause = 0;  /* summation of `nums' */
 6     int i = sizenode(t);
 7     while (i--) {
 8         Node *n = &t->node[i];
 9         if (!ttisnil(gval(n))) {
10             // 根据key是否是数值整型,如果是,统计所在的区间
11             ause += countint(gkey(n), nums);
12             totaluse++;
13         }
14     }
15     *pnasize += ause;
16     return totaluse;
17 }

 

重新计算的过程:computesizes,结果必须保证空间一半以上是被利用的:

lua_assert(*narray/2 <= na && na <= *narray);

 1 // 根据每个区域的数量,计算array和node的数量
 2 static int computesizes (int nums[], int *narray) {
 3   int i;
 4   int twotoi;  /* 2^i */
 5   int a = 0;  /* number of elements smaller than 2^i */
 6   int na = 0;  /* number of elements to go to array part */
 7   int n = 0;  /* optimal size for array part */
 8   for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
 9     if (nums[i] > 0) {
10       a += nums[i];
11       if (a > twotoi/2) {  /* more than half elements present? */
12         n = twotoi;  /* optimal size (till now) */
13         na = a;  /* all elements smaller than n will go to array part */
14       }
15     }
16     if (a == *narray) break;  /* all elements already counted */
17   }
18   *narray = n;
19   lua_assert(*narray/2 <= na && na <= *narray);
20   return na;
21 }

 

luaH_resize用来重新根据两个数组大小申请空间,并且把旧的hash表中的元素重新插入新的hash数组中,解释都在注释中:

 1 void luaH_resize(lua_State *L, Table *t, int nasize, int nhsize) {
 2     int i;
 3     int oldasize = t->sizearray;
 4     int oldhsize = t->lsizenode;
 5     Node *nold = t->node;  /* save old hash ... */
 6 
 7     // 这里表明数组是不会缩小的,只会增加;
 8     if (nasize > oldasize)  /* array part must grow? */
 9         setarrayvector(L, t, nasize);
10 
11     // hash表格会调整大小,增大或者缩小;
12     /* create new hash part with appropriate size */
13     setnodevector(L, t, nhsize);
14 
15     // 如果缩小,吧缩小部分的有效值重新hash一次;
16     if (nasize < oldasize) {  /* array part must shrink? */
17         t->sizearray = nasize;
18         /* re-insert elements from vanishing slice */
19         for (i = nasize; i < oldasize; i++) {
20             if (!ttisnil(&t->array[i]))
21                 luaH_setint(L, t, i + 1, &t->array[i]);
22         }
23         /* shrink array */
24         luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
25     }
26 
27     // 如果是增大,重新hash一次,避免冲突结点过多
28     /* re-insert elements from hash part */
29     for (i = twoto(oldhsize) - 1; i >= 0; i--) {
30         Node *old = nold + i;
31         if (!ttisnil(gval(old))) {
32             /* doesn't need barrier/invalidate cache, as entry was
33                already present in the table */
34             setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
35         }
36     }
37 
38     if (!isdummy(nold))
39         luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */
40 }

 

posted @ 2015-01-17 00:23  #shany  阅读(628)  评论(0编辑  收藏  举报