2 Star 8 Fork 3

SimanX/lua-Chinese

Create your Gitee Account
Explore and code with more than 14 million developers,Free private repositories !:)
Sign up
文件
This repository doesn't specify license. Please pay attention to the specific project description and its upstream code dependency when using it.
Clone or Download
ltable.c 29.12 KB
Copy Edit Raw Blame History
SimanX authored 2024-01-08 17:17 +08:00 . 源码阅读
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
/*
** $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
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/SimanX/lua-Chinese.git
git@gitee.com:SimanX/lua-Chinese.git
SimanX
lua-Chinese
lua-Chinese
master

Search