Lua 5.3 源码分析 (六) 表 Table
typedef union TKey {
struct {
TValuefields;
int next; /* for chaining (offset for next node) */
} nk;
TValue tvk;
} TKey;
/* copy a value into a key without messing up field 'next' */
#define setnodekey(L,key,obj) \
{ TKey *k_=(key); const TValue *io_=(obj); \
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
(void)L; checkliveness(G(L),io_); }
typedef struct Node {
TValue i_val;
TKey i_key;
} Node;
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of 'node' array */
unsigned int sizearray; /* size of 'array' array */
TValue *array; /* array part */
Node *node;
Node *lastfree; /* any free position is before this position */
struct Table *metatable;
GCObject *gclist;
} Table;
table 的存储分为 数组部分和哈希表部分。
数组部分索引从1开始。
nil 是唯一不能做哈希键值的类型。
\# 对table 取长度时,也被定义为 整数下表有关,而不是整个table 的长度。
Table *luaH_new (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table));
Table *t = gco2t(o);
t->metatable = NULL;
t->flags = cast_byte(~0);
t->array = NULL;
t->sizearray = 0;
setnodevector(L, t, 0);
return t;
}
void luaH_free (lua_State *L, Table *t) {
if (!isdummy(t->node))
luaM_freearray(L, t->node, cast(size_t, sizenode(t)));
luaM_freearray(L, t->array, t->sizearray);
luaM_free(L, t);
}
用isdummy 判断 哈希表部分是否为空表,当哈希表部分为空时,在析构函数中只需要释放 数组部分占用内存。
数组部分
Table 的数组部分被存储在TValue *array 中, int sizearray 存储着数组长度。
哈希表部分
Table 的哈希表部分被存储在 Node *node , lu_byte lsizenode 存储着哈希表的大小。由于哈希表的大小一定是 2 的整数次幂,所以这里的 lsizenode 表示的是 次幂数,而不是实际大小 (2^lsizenode)。
定义了一个不可写的空哈希表:dummynode , setnodevector 函数用来初始化哈希表部分 , 当 size 参数为0 时,说明是一个空表被初始化,则node 域指向这个dummynode 节点。
#define dummynode (&dummynode_)
#define isdummy(n) ((n) == dummynode)
static const Node dummynode_ = {
{NILCONSTANT}, /* value */
{
{NILCONSTANT, 0}} /* key */
};
表的增删改查
删除
表没有删除操作,使用将对应的键位赋值为nil。
读取
使用 luaH_newkey 负责在哈希表中创建一个不存在的键位,不影响数组部分。
TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
Node *mp;
TValue aux;
if (ttisnil(key))
luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
lua_Number n