lua源码阅读(4)---表
2017-09-18 16:21
218 查看
lua中只有一种数据结构,表,可以可以存储任意类型,只要键不是nil。在Lobject.h中,有表的定义:
如在lua中 a={3,2,4,x=10},则3,2,4存储在数组部分,x=10存储在hash表部分
在ltable.c中,定义了一些对表的操作的函数。
luaH_set,;uaH_setnum.luaH_strstr是进行新增元素的操作。首先进行查找,如果表中没有改元素,则进行添加的操作,最终调用了newkey函数
首先根据key 计算位置,如果该位置没有存储,则直接存储,否则,发生了hash冲突,需要找到新的空闲位置,存储,加入到链表中。该链表比较特殊,是通过数组实现的。
结构如图
在hash部分的数组中,每一个位置都有一个指针,用于形成链表。这样,hash值相同的元素存储在数组中后,又形成了一条链表。整个hash部分会形成多条链表。这种用数组实现链表的方式与普通的链地址法有些差异。
理解了table的存储结构,其余的操作也就比较好理解了。
typedef struct Table { CommonHeader; //表示存在哪些元方法 lu_byte flags; /* 1<<p means tagmethod(p) is not present */ // log2( node数组大小) lu_byte lsizenode; /* log2 of size of `node' array */ //元表 struct Table *metatable; //数组部分 TValue *array; /* array part */ // Node数组 Node *node; Node *lastfree; /* any free position is before this position */ GCObject *gclist; //array大小 int sizearray; /* size of `array' array */ } Table;lua中的表包含了两部分,一个是数组部分,存储在array指向的数组中,另一个是hash表部分,存储在node指向的数组中。其中Node类型如下:
typedef union TKey { struct { TValuefields; //Value value; int tt struct Node *next; /* for chaining */ } nk; TValue tvk; } TKey; typedef struct Node { TValue i_val; TKey i_key; } Node;Node包含了key和value。
如在lua中 a={3,2,4,x=10},则3,2,4存储在数组部分,x=10存储在hash表部分
在ltable.c中,定义了一些对表的操作的函数。
luaH_set,;uaH_setnum.luaH_strstr是进行新增元素的操作。首先进行查找,如果表中没有改元素,则进行添加的操作,最终调用了newkey函数
static TValue *newkey (lua_State *L, Table *t, const TValue *key) { //计算hash值,得到key所在的hash表中的位置 Node *mp = mainposition(t, key); //如果该位置已经存储了元素 if (!ttisnil(gval(mp)) || mp == dummynode) { Node *othern; //获取一个空闲的位置 Node *n = getfreepos(t); /* get a free place */ if (n == NULL) { /* cannot find a free place? */ //扩展 rehash(L, t, key); /* grow table */ return luaH_set(L, t, key); /* re-insert key into grown table */ } lua_assert(n != dummynode); //#define key2tval(n) (&(n)->i_key.tvk) othern = mainposition(t, key2tval(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ gnext(mp) = NULL; /* now `mp' is free */ setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ gnext(n) = gnext(mp); /* chain new position */ gnext(mp) = n; mp = n; } } gkey(mp)->value = key->value; gkey(mp)->tt = key->tt; luaC_barriert(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); }
首先根据key 计算位置,如果该位置没有存储,则直接存储,否则,发生了hash冲突,需要找到新的空闲位置,存储,加入到链表中。该链表比较特殊,是通过数组实现的。
结构如图
在hash部分的数组中,每一个位置都有一个指针,用于形成链表。这样,hash值相同的元素存储在数组中后,又形成了一条链表。整个hash部分会形成多条链表。这种用数组实现链表的方式与普通的链地址法有些差异。
理解了table的存储结构,其余的操作也就比较好理解了。
相关文章推荐
- lua5.3.1 源码阅读记录(基础)
- Lua源码阅读二——lua内存管理
- Lua5.2.3源码阅读(1)-TValue,TString
- Lua源码阅读建议
- lua源码阅读(2)---数据类型
- lua源码阅读(5)-lua_State
- lua源码阅读(6)-函数
- 阅读Lua源码
- Lua5.2.3源码阅读(1)-TValue,TString
- lua源码阅读(7)-指令
- lua源码阅读(8)-虚拟机
- cpython和lua源码阅读
- Lua源码阅读顺序推荐
- Lua5.2.3源码阅读(3)-Table(ipairs,pairs)
- Lua5.2.3源码阅读(2)-Table
- lua 源码阅读顺序
- Lua5.2.3源码阅读(2)-Table
- lua源码阅读(3)----字符串
- Lua源码建议阅读顺序
- LUA 源码阅读笔记(一)