Fetch the repository succeeded.
/*
** $Id: ltable.c $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
#define ltable_c
#define LUA_CORE
#include "lprefix.h"
/*
** 表(也是包含数组,对象,hash表)
** table在两个部分保存元素:数组部分和hash部分
** 非负整数key都是保存在数组部分的候选key
** 数组的实际大小是最大的n(最大的非负整数key),至少一半的节点在1-n之间
** 哈希使用了Brent变量的链式hash表的混合
** 这些表的一个主要不变量是,如果一个元素不在它的主位置(即哈希给它的“原始”位置),那么冲突元素就在它自己的主位置
** 因此,即使负载系数达到100%,性能仍然很好
*/
#include <math.h>
#include <limits.h>
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
/*
** MAXABITS: 使 MAXASIZE 能放入一个无符号整数的最大位数
*/
#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1)
/*
** MAXASIZE 数组部分的最大长度
** 在 2^MAXABITS 和 最大 size 之间,确保以字节为单位时在'size_t'范围内
*/
#define MAXASIZE luaM_limitN(1u << MAXABITS, TValue)
/*
** MAXHBITS: 使 2^MAXHBITS 能放在一个有符号整数的最大整数
*/
#define MAXHBITS (MAXABITS - 1)
/*
** MAXHSIZE hash部分的最大长度
** 在 2^MAXHBITS 和 最大 size 之间,确保以字节为单位时在'size_t'范围内
*/
#define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node)
/*
** 当原始hash值是好的时,使用 2 的次方来避免 '%'的消耗
*/
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
/*
** 对于其他类型,最好避免以2的幂取模,因为它们可以有许多2的因子
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p)
#define hashpointer(t,p) hashmod(t, point2uint(p))
#define dummynode (&dummynode_)
// 虚拟节点
static const Node dummynode_ = {
{{NULL}, LUA_VEMPTY, /* 值的值和类型 */
LUA_VNIL, 0, {NULL}} /* 键类型,下一个,键的值 */
};
// 缺省key
static const TValue absentkey = {ABSTKEYCONSTANT};
/*
** 整数的hash,为了允许一个优秀的hash,使用取模操作符('%'),如果整数是一个非负整数,计算整数的模,否则,使用一个无符号整数模,他使用所有位来保证非负结果
*/
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
if (ui <= cast_uint(INT_MAX)) // 非负整数
return hashmod(t, cast_int(ui));
else
return hashmod(t, ui);
}
/*
** 浮点数的hash值
** The main computation should be just
** n = frexp(n, &i); return (n * INT_MAX) + i
** but there are some numerical subtleties.
** In a two-complement representation, INT_MAX does not has an exact
** representation as a float, but INT_MIN does; because the absolute
** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when
** adding 'i'; the use of '~u' (instead of '-u') avoids problems with
** INT_MIN.
*/
#if !defined(l_hashfloat)
static int l_hashfloat (lua_Number n) {
int i;
lua_Integer ni;
n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
return 0;
}
else { /* normal case */
unsigned int u = cast_uint(i) + cast_uint(ni);
return cast_int(u <= cast_uint(INT_MAX) ? u : ~u);
}
}
#endif
/*
** 返回一个元素在table中的main position(hash值对应的索引)
*/
static Node *mainpositionTV (const Table *t, const TValue *key) {
switch (ttypetag(key)) {
case LUA_VNUMINT: {
lua_Integer i = ivalue(key);
return hashint(t, i);
}
case LUA_VNUMFLT: {
lua_Number n = fltvalue(key);
return hashmod(t, l_hashfloat(n));
}
case LUA_VSHRSTR: {
TString *ts = tsvalue(key);
return hashstr(t, ts);
}
case LUA_VLNGSTR: {
TString *ts = tsvalue(key);
return hashpow2(t, luaS_hashlongstr(ts));
}
case LUA_VFALSE:
return hashboolean(t, 0);
case LUA_VTRUE:
return hashboolean(t, 1);
case LUA_VLIGHTUSERDATA: {
void *p = pvalue(key);
return hashpointer(t, p);
}
case LUA_VLCF: {
lua_CFunction f = fvalue(key);
return hashpointer(t, f);
}
default: {
GCObject *o = gcvalue(key);
return hashpointer(t, o);
}
}
}
// 通过node获取main position
l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
TValue key;
getnodekey(cast(lua_State *, NULL), &key, nd);
return mainpositionTV(t, &key);
}
/*
** 检测key 'k1'是否和node 'n2'的节点key相同,这个等式是原生的,不会使用元方法,不会进行类型转换(如float和integer的转换)
** deadok: 是否接收已经移除的key,在默认情况下,通过指针标识比较所有deadkey。(只有可收集的物品才能产生deadkey)
*/
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
if ((rawtt(k1) != keytt(n2)) && /* 类型变体不同? */
!(deadok && keyisdead(n2) && iscollectable(k1)))
return 0;
switch (keytt(n2)) {
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
return 1;
case LUA_VNUMINT:
return (ivalue(k1) == keyival(n2));
case LUA_VNUMFLT:
return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
case LUA_VLIGHTUSERDATA:
return pvalue(k1) == pvalueraw(keyval(n2));
case LUA_VLCF:
return fvalue(k1) == fvalueraw(keyval(n2));
case ctb(LUA_VLNGSTR):
return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
default:
return gcvalue(k1) == gcvalueraw(keyval(n2));
}
}
/*
** 如果‘alimit'等于数组表数组部分的真实大小则返回true (否则,数组部分必须大于’alimit')
*/
#define limitequalsasize(t) (isrealasize(t) || ispow2((t)->alimit))
/*
** 数组部分的真实大小
*/
LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
if (limitequalsasize(t))
return t->alimit;
else {
unsigned int size = t->alimit;
/* 计算2不小于n的最小次幂 */
size |= (size >> 1);
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
#if (UINT_MAX >> 14) > 3 /* 无符号整数超过16个位 */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* 无符号整数超过32个位 */
#endif
#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
return size;
}
}
/*
** 检查数组部分真实大小是否是2的次幂,如果不是,在不改变实际大小的情况下,'alimit'不能更改为任何其他值。
*/
static int ispow2realasize (const Table *t) {
return (!isrealasize(t) || ispow2(t->alimit));
}
// 将alimit设置为数组部分真实长度
static unsigned int setlimittosize (Table *t) {
t->alimit = luaH_realasize(t);
setrealasize(t);
return t->alimit;
}
#define limitasasize(t) check_exp(isrealasize(t), t->alimit)
/*
** 通用的get版本(不通用的情况:数组部分的整数、具有整数值的浮点数)
*/
static const TValue *getgeneric (Table *t, const TValue *key, int deadok) {
Node *n = mainpositionTV(t, key);
for (;;) { /* 检查“key”是否在链中的某个位置 */
if (equalkey(key, n, deadok))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return &absentkey; /* not found */
n += nx;
}
}
}
/*
** 如果k是一个合适的数组部分key则返回k的索引,否则返回0
*/
static unsigned int arrayindex (lua_Integer k) {
if (l_castS2U(k) - 1u < MAXASIZE) /* 'k' in [1, MAXASIZE]? */
return cast_uint(k); /* 'key'相应的数组索引 */
else
return 0;
}
/*
** 返回表遍历的key索引,首先是数组部分的所有元素,然后是hash部分,遍历的开始使用0表示
*/
static unsigned int findindex (lua_State *L, Table *t, TValue *key,
unsigned int asize) {
unsigned int i;
if (ttisnil(key)) return 0; /* 第一次迭代 */
i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0;
if (i - 1u < asize) /* 'key'在数组部分? */
return i; /* yes; that's the index */
else {
const TValue *n = getgeneric(t, key, 1);
if (l_unlikely(isabstkey(n)))
luaG_runerror(L, "invalid key to 'next'"); /* key not found */
i = cast_int(nodefromval(n) - gnode(t, 0)); /* hash部分的key索引 */
/* hash部分计数为array部分之后的 */
return (i + 1) + asize;
}
}
// lua的next函数(找到下一个非空元素(key之后的))
int luaH_next (lua_State *L, Table *t, StkId key) {
unsigned int asize = luaH_realasize(t);
unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */
for (; i < asize; i++) { // 查找数组后面的部分不为空的
if (!isempty(&t->array[i])) { /* a non-empty entry? */
setivalue(s2v(key), i + 1);
setobj2s(L, key + 1, &t->array[i]);
return 1;
}
}
for (i -= asize; cast_int(i) < sizenode(t); i++) {
if (!isempty(gval(gnode(t, i)))) { /* a non-empty entry? */
Node *n = gnode(t, i);
getnodekey(L, s2v(key), n);
setobj2s(L, key + 1, gval(n));
return 1;
}
}
return 0; /* no more elements */
}
// 释放hash部分
static void freehash (lua_State *L, Table *t) {
if (!isdummy(t))
luaM_freearray(L, t->node, cast_sizet(sizenode(t)));
}
/*
** {=============================================================
** Rehash
** ==============================================================
*/
/*
** 计算表的最优数组部分大小
** nums: 计数数组,num[i]表示出现在2^(i-1)和2^i之间的key的个数
** pna: 传入时表的整数key的总个数,离开函数时为数组部分key的总个数
** ('twotoi > 0'用于在twotoi溢出时停止循环)
*/
static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
int i;
unsigned int twotoi; /* 2^i (最优大小候选) */
unsigned int a = 0; /* 小于2^i的元素个数 */
unsigned int na = 0; /* 需要放入数组部分的元素个数 */
unsigned int optimal = 0; /* 数组部分的最优大小 */
/* key可以填满总大小的一半以上时循环 */
for (i = 0, twotoi = 1;
twotoi > 0 && *pna > twotoi / 2;
i++, twotoi *= 2) {
a += nums[i];
if (a > twotoi/2) { /* 出现了超过一半的元素? */
optimal = twotoi; /* 目前的最优大小 */
na = a; /* 所有达到“optimal”的元素都将放入数组部分 */
}
}
lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
*pna = na;
return optimal;
}
// 计算整数key出现的个数,用于computesizes的nums
static int countint (lua_Integer key, unsigned int *nums) {
unsigned int k = arrayindex(key);
if (k != 0) { /* 'key'是一个合适的数组部分索引? */
nums[luaO_ceillog2(k)]++; /* 计数 */
return 1;
}
else
return 0;
}
/*
** 对’t'的数组部分key进行计数:'nums[i]'为相应切片的key数量,并返回非nil键的总数量。
*/
static unsigned int numusearray (const Table *t, unsigned int *nums) {
int lg;
unsigned int ttlg; /* 2^lg */
unsigned int ause = 0; /* 'nums'的总数 */
unsigned int i = 1; /* 遍历的所有数组key计数 */
unsigned int asize = limitasasize(t); /* 真实数组大小 */
for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) {
unsigned int lc = 0; /* 计数 */
unsigned int lim = ttlg;
if (lim > asize) {
lim = asize; /* 适配上限 */
if (i > lim)
break; /* 没有更多的元素需要计数了 */
}
/* 统计key在 2^(lg-1) 至 2^lg 之间的元素个数 */
for (; i <= lim; i++) {
if (!isempty(&t->array[i-1]))
lc++;
}
nums[lg] += lc;
ause += lc;
}
return ause;
}
// 对‘t'的hash部分key进行计数
static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
int totaluse = 0; /* 元素总数 */
int ause = 0; /* 添加到’nums‘中的元素个数(能够放入数组部分的key) */
int i = sizenode(t);
while (i--) {
Node *n = &t->node[i];
if (!isempty(gval(n))) {
if (keyisinteger(n))
ause += countint(keyival(n), nums);
totaluse++;
}
}
*pna += ause;
return totaluse;
}
/*
** 通过size为表的hash部分创建一个数组,或者在size为0时重用虚拟节点
** size溢出计算氛围两步:第一次的比较确保第二次比较中的移位不会溢出
*/
static void setnodevector (lua_State *L, Table *t, unsigned int size) {
if (size == 0) { /* hash部分没有节点? */
t->node = cast(Node *, dummynode); /* 使用公共虚拟节点 */
t->lsizenode = 0;
t->lastfree = NULL; /* 使用虚拟节点标记 */
}
else {
int i;
int lsize = luaO_ceillog2(size);
if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE)
luaG_runerror(L, "table overflow");
size = twoto(lsize);
t->node = luaM_newvector(L, size, Node);
for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
setempty(gval(n));
}
t->lsizenode = cast_byte(lsize);
t->lastfree = gnode(t, size); /* 所有节点都是空闲的 */
}
}
/*
** 将‘ot'的hash部分的所有元素重新插入到’t'中
*/
static void reinsert (lua_State *L, Table *ot, Table *t) {
int j;
int size = sizenode(ot);
for (j = 0; j < size; j++) {
Node *old = gnode(ot, j);
if (!isempty(gval(old))) {
/* 不需要屏障/失效缓存,因为条目已经存在于表中 */
TValue k;
getnodekey(L, &k, old);
luaH_set(L, t, &k, gval(old));
}
}
}
/*
** 交换’t1’和‘t2’的hash部分
*/
static void exchangehashpart (Table *t1, Table *t2) {
lu_byte lsizenode = t1->lsizenode;
Node *node = t1->node;
Node *lastfree = t1->lastfree;
t1->lsizenode = t2->lsizenode;
t1->node = t2->node;
t1->lastfree = t2->lastfree;
t2->lsizenode = lsizenode;
t2->node = node;
t2->lastfree = lastfree;
}
/*
** 调整表't'的大小为newasize
** newasize: 新的数组部分大小
** newhsize: 新的hash部分大小
** (对于哈希部分和数组部分)都可能会失败,这会产生一些微妙之处。
** 如果哈希部分的第一次分配失败,则会引发错误
** 否则,它将从数组的收缩部分(如果正在收缩)复制元素到新的散列中。然后重新分配数组部分。
** 如果失败,表将处于原始状态;该函数释放新的散列部分,然后引发分配错误。否则,它将把新的哈希部分设置到表中,用nil初始化数组的新部分(如果有的话),并将旧哈希的元素重新插入到表的新部分中。
*/
void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
unsigned int nhsize) {
unsigned int i;
Table newt; /* 保留新的hash部分 */
unsigned int oldasize = setlimittosize(t);
TValue *newarray;
/* 通过相应的大小创建‘newt'的hash部分 */
setnodevector(L, &newt, nhsize);
if (newasize < oldasize) { /* 数组部分缩小了? */
t->alimit = newasize; /* 假设数组新大小... */
exchangehashpart(t, &newt); /* 将hash部分设置到‘newt’中 */
/* 将数组部分中oldsize-newsize中的元素放入hash部分 */
for (i = newasize; i < oldasize; i++) {
if (!isempty(&t->array[i]))
luaH_setint(L, t, i + 1, &t->array[i]);
}
t->alimit = oldasize; /* 恢复当前大小... */
exchangehashpart(t, &newt); /* 和hash部分 (发生错误时) */
}
/* 分配新数组 */
newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
if (l_unlikely(newarray == NULL && newasize > 0)) { /* 分配失败? */
freehash(L, &newt); /* 释放新的hash部分 */
luaM_error(L); /* 引发错误 (数组没有修改) */
}
/* 分配成功初始化新的数组部分 */
exchangehashpart(t, &newt); /* 't' 拥有新的hash ('newt' 有老的hash) */
t->array = newarray; /* 设置新的数组部分 */
t->alimit = newasize;
for (i = oldasize; i < newasize; i++) /* 清空数组的新的部分 */
setempty(&t->array[i]);
/* 将老的hash部分重新插入到新的hash部分 */
reinsert(L, &newt, t); /* 'newt'现在有老的hash */
freehash(L, &newt); /* 释放老hash部分内存 */
}
// 为数组部分重新分配大小
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
int nsize = allocsizenode(t);
luaH_resize(L, t, nasize, nsize);
}
/*
** nums[i] = 2^(i - 1) 和 2^i 之间的key的个数
*/
static void rehash (lua_State *L, Table *t, const TValue *ek) {
unsigned int asize; /* 数组的最佳大小 */
unsigned int na; /* 数组部分的key个数 */
unsigned int nums[MAXABITS + 1];
int i;
int totaluse;
for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* 初始化nums */
setlimittosize(t);
na = numusearray(t, nums); /* 数组部分keys计数 */
totaluse = na; /* 所有的这些key都是整数key */
totaluse += numusehash(t, nums, &na); /* hash部分的key计数 */
/* 统计额外的key(触发rehash操作的key) */
if (ttisinteger(ek))
na += countint(ivalue(ek), nums);
totaluse++;
/* 重新计算数组部分的新大小 */
asize = computesizes(nums, &na);
/* 重新设置table的大小为新计算出来的大小 */
luaH_resize(L, t, asize, totaluse - na);
}
/*
** }=============================================================
*/
Table *luaH_new (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
Table *t = gco2t(o);
t->metatable = NULL;
t->flags = cast_byte(maskflags); /* 没有元方法field */
// 数组部分
t->array = NULL;
t->alimit = 0;
// 设置hash部分
setnodevector(L, t, 0);
return t;
}
// 释放table
void luaH_free (lua_State *L, Table *t) {
freehash(L, t);
luaM_freearray(L, t->array, luaH_realasize(t));
luaM_free(L, t);
}
static Node *getfreepos (Table *t) {
if (!isdummy(t)) {
while (t->lastfree > t->node) {
t->lastfree--;
if (keyisnil(t->lastfree))
return t->lastfree;
}
}
return NULL; /* 找不到空闲位置 */
}
/*
** 添加一个新的key到hash表,首先,检查key的主位置是否空闲,如果没有,检测碰撞节点是否在他的main position:
** 如果没有,移动碰撞节点到空位置并且放一个新的key到他的main position,否则创建一个新key到一个空位置
*/
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
Node *mp;
TValue aux;
if (l_unlikely(ttisnil(key)))
luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
lua_Number f = fltvalue(key);
lua_Integer k;
if (luaV_flttointeger(f, &k, F2Ieq)) { /* 是个整数? */
setivalue(&aux, k);
key = &aux; /* 作为整数插入 */
}
else if (l_unlikely(luai_numisnan(f)))
luaG_runerror(L, "table index is NaN");
}
if (ttisnil(value))
return; /* 不插入nil值 */
mp = mainpositionTV(t, key);
if (!isempty(gval(mp)) || isdummy(t)) { /* main position已经被霸占? */
Node *othern;
Node *f = getfreepos(t); /* 获取一个空闲位置 */
if (f == NULL) { /* 不能找到空闲位置或者isdummy(t)是true? */
rehash(L, t, key); /* 扩展table */
luaH_set(L, t, key, value); /* 添加进新的table中 */
return;
}
lua_assert(!isdummy(t));
othern = mainpositionfromnode(t, mp);
if (othern != mp) { /* 碰撞节点不在他自己的main position? */
/* 将碰撞节点移动到空闲位置 */
while (othern + gnext(othern) != mp) /* 查找前一个位置 */
othern += gnext(othern);
gnext(othern) = cast_int(f - othern); /* 重新连接点至'f' */
*f = *mp; /* 复制碰撞节点至空闲节点 (mp->next也跟着走) */
if (gnext(mp) != 0) {
gnext(f) += cast_int(mp - f); /* correct 'next' */
gnext(mp) = 0; /* now 'mp' is free */
}
setempty(gval(mp));
}
else { /* 碰撞节点在他自己的main position */
/* 新节点将进入空闲节点 */
if (gnext(mp) != 0)
gnext(f) = cast_int((mp + gnext(mp)) - f); /* 链接新位置 */
else lua_assert(gnext(f) == 0);
gnext(mp) = cast_int(f - mp);
mp = f;
}
}
setnodekey(L, mp, key);
luaC_barrierback(L, obj2gco(t), key);
lua_assert(isempty(gval(mp)));
setobj2t(L, gval(mp), value);
}
/*
** 整数搜索函数,如果整数在‘alimit’之内,直接从数组部分获取他
** 否则,如果‘alimit'不等于数组的真实长度, key仍然可能在数组部分,这种情况,当key只比限制多一个时尽量避免使用‘luaH_realasize’(这样就可以在不改变数组的实际大小的情况下增加它)
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
if (l_castS2U(key) - 1u < t->alimit) /* 'key' 在 [1, t->alimit]? */
return &t->array[key - 1];
else if (!limitequalsasize(t) && /* key仍然可能在数组中? */
(l_castS2U(key) == t->alimit + 1 || // 在当前alimit后面一个位置,这个时候key为新的alimit
l_castS2U(key) - 1u < luaH_realasize(t))) {
t->alimit = cast_uint(key); /* 可能'#t'就在这里 */
return &t->array[key - 1];
}
else {
Node *n = hashint(t, key);
for (;;) { /* 检测'key'是否在链中 */
if (keyisinteger(n) && keyival(n) == key)
return gval(n);
else {
int nx = gnext(n);
if (nx == 0) break;
n += nx;
}
}
return &absentkey;
}
}
/*
** 短字符串搜索函数
*/
const TValue *luaH_getshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_VSHRSTR);
for (;;) { /* 检查‘key'是否在链中某个位置 */
if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return &absentkey; /* 没有找到,返回缺省值 */
n += nx;
}
}
}
const TValue *luaH_getstr (Table *t, TString *key) {
if (key->tt == LUA_VSHRSTR)
return luaH_getshortstr(t, key);
else { /* 对于长字符串,使用通用逻辑 */
TValue ko;
setsvalue(cast(lua_State *, NULL), &ko, key);
return getgeneric(t, &ko, 0);
}
}
/*
** 主要的查询函数
*/
const TValue *luaH_get (Table *t, const TValue *key) {
switch (ttypetag(key)) {
case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_VNUMINT: return luaH_getint(t, ivalue(key));
case LUA_VNIL: return &absentkey;
case LUA_VNUMFLT: {
lua_Integer k;
if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* 整数索引? */
return luaH_getint(t, k); /* 使用特殊版本 */
/* else... */
} /* 下沉 */
default:
return getgeneric(t, key, 0);
}
}
/*
** 完成一次原生的’set table‘操作,’slot‘表示值应该在的位置(前一次’get table‘的结果).
** 注意: 使用该函数时可能需要检查GC屏障并且使TM缓存失效
*/
void luaH_finishset (lua_State *L, Table *t, const TValue *key,
const TValue *slot, TValue *value) {
if (isabstkey(slot))
luaH_newkey(L, t, key, value);
else
setobj2t(L, cast(TValue *, slot), value);
}
/*
** 注意: 使用该函数时可能需要检查GC屏障并且使TM缓存失效
*/
void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
const TValue *slot = luaH_get(t, key); // 查找key的位置
luaH_finishset(L, t, key, slot, value);
}
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
const TValue *p = luaH_getint(t, key);
if (isabstkey(p)) {
TValue k;
setivalue(&k, key);
luaH_newkey(L, t, &k, value);
}
else
setobj2t(L, cast(TValue *, p), value);
}
/*
** 尝试在表的hash部分查找,通过调用者,我们知道’j'是0或者存在并且‘j+1'存在
From the caller, we know that 'j' is zero or present and that 'j + 1' is present.
** We want to find a larger key that is absent from the table, so that we can do a binary search between the two keys to find a boundary. We keep doubling 'j' until we get an absent index.
** If the doubling would overflow, we try LUA_MAXINTEGER. If it is
** absent, we are ready for the binary search. ('j', being max integer,
** is larger or equal to 'i', but it cannot be equal because it is
** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a
** boundary. ('j + 1' cannot be a present integer key because it is
** not a valid integer in Lua.)
*/
static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
lua_Unsigned i;
if (j == 0) j++; /* the caller ensures 'j + 1' is present */
do {
i = j; /* 'i' is a present index */
if (j <= l_castS2U(LUA_MAXINTEGER) / 2)
j *= 2;
else {
j = LUA_MAXINTEGER;
if (isempty(luaH_getint(t, j))) /* t[j] not present? */
break; /* 'j' now is an absent index */
else /* weird case */
return j; /* well, max integer is a boundary... */
}
} while (!isempty(luaH_getint(t, j))); /* repeat until an absent t[j] */
/* i < j && t[i] present && t[j] absent */
while (j - i > 1u) { /* do a binary search between them */
lua_Unsigned m = (i + j) / 2;
if (isempty(luaH_getint(t, m))) j = m;
else i = m;
}
return i;
}
static unsigned int binsearch (const TValue *array, unsigned int i,
unsigned int j) {
while (j - i > 1u) { /* binary search */
unsigned int m = (i + j) / 2;
if (isempty(&array[m - 1])) j = m;
else i = m;
}
return i;
}
/*
** table的#操作符
** 尝试找到表的边界(一个整数索引,使得t[i]存在而t[i+1]不存在,如果t[1]不存在则为0,如果t[maxinteger]存在则为maxinteger)
** (在下面的解释中,我们使用Lua索引(以1开始)。 代码本身使用table中数组部分的基于0的的索引),代码从'limit = t->alimit'开始(可能是数组部分的边界位置)
**
** (1) 如果't[limit]'为空, 边界一定在这之前
** 一种常见情况(例如,在't[#t]=nil'之后),检查'limit-1'是否存在,如果存在,他就是边界,
** 否则,做0至limit之间做一次二分搜索以查找边界,
** 在这两种情况下,尝试使用这个边界作为新的’limit',作为下一次调用的提示。
**
** (2) 如果't[limit]'不为空并且数组有‘limit'之后的元素,尝试在这找到边界
** 首先尝试一个特殊的情况: 'limit+1'是空的,因此’limit'就是边界,
** 否则,检查数组的最后一个元素,如果他是空,那么检查老的‘limit'(如果存在)和最后一个元素之间(通过二分查找到的)必须存在一个边界(这个边界总是会变成一个新的limit)
**
** (3) 当数组部分没有元素(limit == 0)或者他的最后一个元素(新limit)存在,这种情况,必须检查hash部分
** 如果没有hash部分或者’limit + 1‘不存在,’limit'就是边界,否则,调用‘hash_search'在表的hash部分查找边界
** (在这些情况下,边界不在数组部分内,因此不能用作新的limit。)
*/
lua_Unsigned luaH_getn (Table *t) {
unsigned int limit = t->alimit;
if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */
/* 边界一定在'limit'之前 */
if (limit >= 2 && !isempty(&t->array[limit - 2])) {
/* 'limit - 1' is a boundary; can it be a new limit? */
if (ispow2realasize(t) && !ispow2(limit - 1)) {
t->alimit = limit - 1;
setnorealasize(t); /* now 'alimit' is not the real size */
}
return limit - 1;
}
else { /* must search for a boundary in [0, limit] */
unsigned int boundary = binsearch(t->array, 0, limit);
/* can this boundary represent the real size of the array? */
if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) {
t->alimit = boundary; /* use it as the new limit */
setnorealasize(t);
}
return boundary;
}
}
/* 'limit'==0或者表中存在t[limit] */
if (!limitequalsasize(t)) { /* (2)? */
/* 'limit' > 0 and array has more elements after 'limit' */
if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */
return limit; /* this is the boundary */
/* else, try last element in the array */
limit = luaH_realasize(t);
if (isempty(&t->array[limit - 1])) { /* empty? */
/* there must be a boundary in the array after old limit, and it must be a valid new limit */
unsigned int boundary = binsearch(t->array, t->alimit, limit);
t->alimit = boundary;
return boundary;
}
/* 否则,table中存在新的limit,检查hash表 */
}
/* (3)'limit' is the last element and either is zero or present in table */
lua_assert(limit == luaH_realasize(t) &&
(limit == 0 || !isempty(&t->array[limit - 1])));
if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1))))
return limit; /* 'limit + 1'是缺省key */
else /* 'limit + 1' is also present */
return hash_search(t, limit);
}
#if defined(LUA_DEBUG)
/* export these functions for the test library */
Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
#endif
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。