lua.5.2.3源码阅读(05):Table表插入流程

通过luaH_new创建的Table开始实际上是一张空表,只是包含了Table本身的数据 结构。创建完以后需要添加元素,

添加到函数为:luaH_set,该函数在设置前会根据key的值去获取对应的Value,如果能找到,则直接设置,如果找

不到,则需要申请一个位置来存放(Key,Value)。

1 TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
2   const TValue *p = luaH_get(t, key);
3   if (p != luaO_nilobject)
4     return cast(TValue *, p);
5   else return luaH_newkey(L, t, key);
6 }

 

luaH_newkey函数是查找一个合适的位置用来存放(Key,value),实际上有可能会申请空间,也可能不会申请空间,

还有一种可能就是,统计表格中的整型key的情况,重新调整数组和hash表达数组大小,让元素更合适的存储。

 1 /*
 2 ** inserts a new key into a hash table; first, check whether key's main
 3 ** position is free. If not, check whether colliding node is in its main
 4 ** position or not: if it is not, move colliding node to an empty place and
 5 ** put new key in its main position; otherwise (colliding node is in its main
 6 ** position), new key goes to an empty position.
 7 */
 8 TValue *luaH_newkey(lua_State *L, Table *t, const TValue *key) {
 9     Node *mp;
10     if (ttisnil(key))
11         luaG_runerror(L, "table index is nil");
12     else if (ttisnumber(key) && luai_numisnan(L, nvalue(key)))
13         luaG_runerror(L, "table index is NaN");

上面的注释的大意:

1、根据key,计算对应的main position,所谓的main position是指作为数组访问时代位置索引,或者hash索引位置的表头。

2、如果main position未被占用,则直接写入对应的位置;

3、如果main position被占用,则检查该main position是不是冲突节点的main position:如果是则重新申请空间写入并

加入main position链表尾部;如果不是,则重新申请空间给冲突节点,main position则写入当前的值。

 

继续读luaH_newkey代码如下:

 1     mp = mainposition(t, key);
 2     if (!ttisnil(gval(mp)) || isdummy(mp)) {  /* main position is taken? */
 3         Node *othern;
 4         Node *n = getfreepos(t);  /* get a free place */
 5         if (n == NULL) {  /* cannot find a free place? */
 6             rehash(L, t, key);  /* grow table */
 7             /* whatever called 'newkey' take care of TM cache and GC barrier */
 8             return luaH_set(L, t, key);  /* insert key into grown table */
 9         }
10         
11 static Node *getfreepos (Table *t) {
12   while (t->lastfree > t->node) {
13     t->lastfree--;
14     if (ttisnil(gkey(t->lastfree)))
15       return t->lastfree;
16   }
17   return NULL;  /* could not find a free place */
18 }

1、如果mainposition被占用,或者该table还是空的,则去查找空闲结点存储;

2、getfreepos函数是从最后的空闲结点中获取逐步查找;

3、如果发现找不到空闲结点时候,则通过rehash申请空间(后续分析),然后重新调用luaH_set;

 

继续读luaH_newkey代码如下:

 1         othern = mainposition(t, gkey(mp));
 2         if (othern != mp) {  /* is colliding node out of its main position? */
 3             /* yes; move colliding node into free position */
 4             while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */
 5             gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */
 6             *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
 7             gnext(mp) = NULL;  /* now `mp' is free */
 8             setnilvalue(gval(mp));
 9         }
10         else {  /* colliding node is in its own main position */
11             /* new node will go into free position */
12             gnext(n) = gnext(mp);  /* chain new position */
13             gnext(mp) = n;
14             mp = n;
15         }

1、主要是检查冲突的结点是不是在其main position;

2、如果不是在main position,则将刚申请的空闲空间用来保存冲突结点;

3、如果是在main position,则挂空闲结点用来保存当前值,并且挂在main position结点后。

 

最后的代码:

 1 setobj2t(L, gkey(mp), key); 

1、把刚申请来存储当前值的结点的key值设置为当前的key。

 

posted @ 2015-01-16 23:47  #shany  阅读(1893)  评论(0编辑  收藏  举报