#define ltable_c
#define LUA_CORE
#include "lprefix.h"
#include <math.h>
#include <limits.h>
#include <string.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"
#define LIMFORLAST 3
typedef struct { Node *dummy; Node follows_pNode; } Limbox_aux;
typedef union {
Node *lastfree;
char padding[offsetof(Limbox_aux, follows_pNode)];
} Limbox;
#define haslastfree(t) ((t)->lsizenode >= LIMFORLAST)
#define getlastfree(t) ((cast(Limbox *, (t)->node) - 1)->lastfree)
#define MAXABITS (l_numbits(int) - 1)
#define MAXASIZEB (MAX_SIZET/(sizeof(Value) + 1))
#define MAXASIZE \
(((1u << MAXABITS) < MAXASIZEB) ? (1u << MAXABITS) : cast_uint(MAXASIZEB))
#define MAXHBITS (MAXABITS - 1)
#define MAXHSIZE luaM_limitN(1 << MAXHBITS, Node)
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1u)|1u))))
#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_TDEADKEY, 0, {NULL}}
};
static const TValue absentkey = {ABSTKEYCONSTANT};
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
if (ui <= cast_uint(INT_MAX))
return gnode(t, cast_int(ui) % cast_int((sizenode(t)-1) | 1));
else
return hashmod(t, ui);
}
#if !defined(l_hashfloat)
static unsigned 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)) {
lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
return 0;
}
else {
unsigned int u = cast_uint(i) + cast_uint(ni);
return (u <= cast_uint(INT_MAX) ? u : ~u);
}
}
#endif
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);
}
}
}
l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
TValue key;
getnodekey(cast(lua_State *, NULL), &key, nd);
return mainpositionTV(t, &key);
}
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
if (rawtt(k1) != keytt(n2)) {
if (keyisshrstr(n2) && ttislngstring(k1)) {
return luaS_eqstr(tsvalue(k1), keystrval(n2));
}
else if (deadok && keyisdead(n2) && iscollectable(k1)) {
return gcvalue(k1) == gcvalueraw(keyval(n2));
}
else
return 0;
}
else {
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_eqstr(tsvalue(k1), keystrval(n2));
default:
return gcvalue(k1) == gcvalueraw(keyval(n2));
}
}
}
static const TValue *getgeneric (Table *t, const TValue *key, int deadok) {
Node *n = mainpositionTV(t, key);
for (;;) {
if (equalkey(key, n, deadok))
return gval(n);
else {
int nx = gnext(n);
if (nx == 0)
return &absentkey;
n += nx;
}
}
}
static unsigned checkrange (lua_Integer k, unsigned limit) {
return (l_castS2U(k) - 1u < limit) ? cast_uint(k) : 0;
}
#define arrayindex(k) checkrange(k, MAXASIZE)
#define ikeyinarray(t,k) checkrange(k, t->asize)
static unsigned keyinarray (Table *t, const TValue *key) {
return (ttisinteger(key)) ? ikeyinarray(t, ivalue(key)) : 0;
}
static unsigned findindex (lua_State *L, Table *t, TValue *key,
unsigned asize) {
unsigned int i;
if (ttisnil(key)) return 0;
i = keyinarray(t, key);
if (i != 0)
return i;
else {
const TValue *n = getgeneric(t, key, 1);
if (l_unlikely(isabstkey(n)))
luaG_runerror(L, "invalid key to 'next'");
i = cast_uint(nodefromval(n) - gnode(t, 0));
return (i + 1) + asize;
}
}
int luaH_next (lua_State *L, Table *t, StkId key) {
unsigned int asize = t->asize;
unsigned int i = findindex(L, t, s2v(key), asize);
for (; i < asize; i++) {
lu_byte tag = *getArrTag(t, i);
if (!tagisempty(tag)) {
setivalue(s2v(key), cast_int(i) + 1);
farr2val(t, i, tag, s2v(key + 1));
return 1;
}
}
for (i -= asize; i < sizenode(t); i++) {
if (!isempty(gval(gnode(t, i)))) {
Node *n = gnode(t, i);
getnodekey(L, s2v(key), n);
setobj2s(L, key + 1, gval(n));
return 1;
}
}
return 0;
}
#define extraLastfree(t) (haslastfree(t) ? sizeof(Limbox) : 0)
static size_t sizehash (Table *t) {
return cast_sizet(sizenode(t)) * sizeof(Node) + extraLastfree(t);
}
static void freehash (lua_State *L, Table *t) {
if (!isdummy(t)) {
char *arr = cast_charp(t->node) - extraLastfree(t);
luaM_freearray(L, arr, sizehash(t));
}
}
static int insertkey (Table *t, const TValue *key, TValue *value);
static void newcheckedkey (Table *t, const TValue *key, TValue *value);
typedef struct {
unsigned total;
unsigned na;
int deleted;
unsigned nums[MAXABITS + 1];
} Counters;
#define arrayXhash(na,nh) (cast_sizet(na) <= cast_sizet(nh) * 3)
static unsigned computesizes (Counters *ct) {
int i;
unsigned int twotoi;
unsigned int a = 0;
unsigned int na = 0;
unsigned int optimal = 0;
for (i = 0, twotoi = 1;
twotoi > 0 && arrayXhash(twotoi, ct->na);
i++, twotoi *= 2) {
unsigned nums = ct->nums[i];
a += nums;
if (nums > 0 &&
arrayXhash(twotoi, a)) {
optimal = twotoi;
na = a;
}
}
ct->na = na;
return optimal;
}
static void countint (lua_Integer key, Counters *ct) {
unsigned int k = arrayindex(key);
if (k != 0) {
ct->nums[luaO_ceillog2(k)]++;
ct->na++;
}
}
l_sinline int arraykeyisempty (const Table *t, unsigned key) {
int tag = *getArrTag(t, key - 1);
return tagisempty(tag);
}
static void numusearray (const Table *t, Counters *ct) {
int lg;
unsigned int ttlg;
unsigned int ause = 0;
unsigned int i = 1;
unsigned int asize = t->asize;
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;
}
for (; i <= lim; i++) {
if (!arraykeyisempty(t, i))
lc++;
}
ct->nums[lg] += lc;
ause += lc;
}
ct->total += ause;
ct->na += ause;
}
static void numusehash (const Table *t, Counters *ct) {
unsigned i = sizenode(t);
unsigned total = 0;
while (i--) {
Node *n = &t->node[i];
if (isempty(gval(n))) {
lua_assert(!keyisnil(n));
ct->deleted = 1;
}
else {
total++;
if (keyisinteger(n))
countint(keyival(n), ct);
}
}
ct->total += total;
}
static size_t concretesize (unsigned int size) {
if (size == 0)
return 0;
else
return size * (sizeof(Value) + 1) + sizeof(unsigned);
}
static Value *resizearray (lua_State *L , Table *t,
unsigned oldasize,
unsigned newasize) {
if (oldasize == newasize)
return t->array;
else if (newasize == 0) {
Value *op = t->array - oldasize;
luaM_freemem(L, op, concretesize(oldasize));
return NULL;
}
else {
size_t newasizeb = concretesize(newasize);
Value *np = cast(Value *,
luaM_reallocvector(L, NULL, 0, newasizeb, lu_byte));
if (np == NULL)
return NULL;
np += newasize;
if (oldasize > 0) {
size_t oldasizeb = concretesize(oldasize);
Value *op = t->array;
unsigned tomove = (oldasize < newasize) ? oldasize : newasize;
size_t tomoveb = (oldasize < newasize) ? oldasizeb : newasizeb;
lua_assert(tomoveb > 0);
memcpy(np - tomove, op - tomove, tomoveb);
luaM_freemem(L, op - oldasize, oldasizeb);
}
return np;
}
}
static void setnodevector (lua_State *L, Table *t, unsigned size) {
if (size == 0) {
t->node = cast(Node *, dummynode);
t->lsizenode = 0;
setdummy(t);
}
else {
int i;
int lsize = luaO_ceillog2(size);
if (lsize > MAXHBITS || (1 << lsize) > MAXHSIZE)
luaG_runerror(L, "table overflow");
size = twoto(lsize);
if (lsize < LIMFORLAST)
t->node = luaM_newvector(L, size, Node);
else {
size_t bsize = size * sizeof(Node) + sizeof(Limbox);
char *node = luaM_newblock(L, bsize);
t->node = cast(Node *, node + sizeof(Limbox));
getlastfree(t) = gnode(t, size);
}
t->lsizenode = cast_byte(lsize);
setnodummy(t);
for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
setempty(gval(n));
}
}
}
static void reinserthash (lua_State *L, Table *ot, Table *t) {
unsigned j;
unsigned size = sizenode(ot);
for (j = 0; j < size; j++) {
Node *old = gnode(ot, j);
if (!isempty(gval(old))) {
TValue k;
getnodekey(L, &k, old);
newcheckedkey(t, &k, gval(old));
}
}
}
static void exchangehashpart (Table *t1, Table *t2) {
lu_byte lsizenode = t1->lsizenode;
Node *node = t1->node;
int bitdummy1 = t1->flags & BITDUMMY;
t1->lsizenode = t2->lsizenode;
t1->node = t2->node;
t1->flags = cast_byte((t1->flags & NOTBITDUMMY) | (t2->flags & BITDUMMY));
t2->lsizenode = lsizenode;
t2->node = node;
t2->flags = cast_byte((t2->flags & NOTBITDUMMY) | bitdummy1);
}
static void reinsertOldSlice (Table *t, unsigned oldasize,
unsigned newasize) {
unsigned i;
for (i = newasize; i < oldasize; i++) {
lu_byte tag = *getArrTag(t, i);
if (!tagisempty(tag)) {
TValue key, aux;
setivalue(&key, l_castU2S(i) + 1);
farr2val(t, i, tag, &aux);
insertkey(t, &key, &aux);
}
}
}
static void clearNewSlice (Table *t, unsigned oldasize, unsigned newasize) {
for (; oldasize < newasize; oldasize++)
*getArrTag(t, oldasize) = LUA_VEMPTY;
}
void luaH_resize (lua_State *L, Table *t, unsigned newasize,
unsigned nhsize) {
Table newt;
unsigned oldasize = t->asize;
Value *newarray;
if (newasize > MAXASIZE)
luaG_runerror(L, "table overflow");
newt.flags = 0;
setnodevector(L, &newt, nhsize);
if (newasize < oldasize) {
exchangehashpart(t, &newt);
reinsertOldSlice(t, oldasize, newasize);
exchangehashpart(t, &newt);
}
newarray = resizearray(L, t, oldasize, newasize);
if (l_unlikely(newarray == NULL && newasize > 0)) {
freehash(L, &newt);
luaM_error(L);
}
exchangehashpart(t, &newt);
t->array = newarray;
t->asize = newasize;
if (newarray != NULL)
*lenhint(t) = newasize / 2u;
clearNewSlice(t, oldasize, newasize);
reinserthash(L, &newt, t);
freehash(L, &newt);
}
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
unsigned nsize = allocsizenode(t);
luaH_resize(L, t, nasize, nsize);
}
static void rehash (lua_State *L, Table *t, const TValue *ek) {
unsigned asize;
Counters ct;
unsigned i;
unsigned nsize;
for (i = 0; i <= MAXABITS; i++) ct.nums[i] = 0;
ct.na = 0;
ct.deleted = 0;
ct.total = 1;
if (ttisinteger(ek))
countint(ivalue(ek), &ct);
numusehash(t, &ct);
if (ct.na == 0) {
asize = t->asize;
}
else {
numusearray(t, &ct);
asize = computesizes(&ct);
}
nsize = ct.total - ct.na;
if (ct.deleted) {
nsize += nsize >> 2;
}
luaH_resize(L, t, asize, nsize);
}
Table *luaH_new (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
Table *t = gco2t(o);
t->metatable = NULL;
t->flags = maskflags;
t->array = NULL;
t->asize = 0;
setnodevector(L, t, 0);
return t;
}
lu_mem luaH_size (Table *t) {
lu_mem sz = cast(lu_mem, sizeof(Table)) + concretesize(t->asize);
if (!isdummy(t))
sz += sizehash(t);
return sz;
}
void luaH_free (lua_State *L, Table *t) {
freehash(L, t);
resizearray(L, t, t->asize, 0);
luaM_free(L, t);
}
static Node *getfreepos (Table *t) {
if (haslastfree(t)) {
while (getlastfree(t) > t->node) {
Node *free = --getlastfree(t);
if (keyisnil(free))
return free;
}
}
else {
unsigned i = sizenode(t);
while (i--) {
Node *free = gnode(t, i);
if (keyisnil(free))
return free;
}
}
return NULL;
}
static int insertkey (Table *t, const TValue *key, TValue *value) {
Node *mp = mainpositionTV(t, key);
lua_assert(isabstkey(getgeneric(t, key, 0)));
if (!isempty(gval(mp)) || isdummy(t)) {
Node *othern;
Node *f = getfreepos(t);
if (f == NULL)
return 0;
lua_assert(!isdummy(t));
othern = mainpositionfromnode(t, mp);
if (othern != mp) {
while (othern + gnext(othern) != mp)
othern += gnext(othern);
gnext(othern) = cast_int(f - othern);
*f = *mp;
if (gnext(mp) != 0) {
gnext(f) += cast_int(mp - f);
gnext(mp) = 0;
}
setempty(gval(mp));
}
else {
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(mp, key);
lua_assert(isempty(gval(mp)));
setobj2t(cast(lua_State *, 0), gval(mp), value);
return 1;
}
static void newcheckedkey (Table *t, const TValue *key, TValue *value) {
unsigned i = keyinarray(t, key);
if (i > 0)
obj2arr(t, i - 1, value);
else {
int done = insertkey(t, key, value);
lua_assert(done);
cast(void, done);
}
}
static void luaH_newkey (lua_State *L, Table *t, const TValue *key,
TValue *value) {
if (!ttisnil(value)) {
int done = insertkey(t, key, value);
if (!done) {
rehash(L, t, key);
newcheckedkey(t, key, value);
}
luaC_barrierback(L, obj2gco(t), key);
condchangemem(L, (void)0, (void)0, 1);
}
}
static const TValue *getintfromhash (Table *t, lua_Integer key) {
Node *n = hashint(t, key);
lua_assert(!ikeyinarray(t, key));
for (;;) {
if (keyisinteger(n) && keyival(n) == key)
return gval(n);
else {
int nx = gnext(n);
if (nx == 0) break;
n += nx;
}
}
return &absentkey;
}
static int hashkeyisempty (Table *t, lua_Unsigned key) {
const TValue *val = getintfromhash(t, l_castU2S(key));
return isempty(val);
}
static lu_byte finishnodeget (const TValue *val, TValue *res) {
if (!ttisnil(val)) {
setobj(((lua_State*)NULL), res, val);
}
return ttypetag(val);
}
lu_byte luaH_getint (Table *t, lua_Integer key, TValue *res) {
unsigned k = ikeyinarray(t, key);
if (k > 0) {
lu_byte tag = *getArrTag(t, k - 1);
if (!tagisempty(tag))
farr2val(t, k - 1, tag, res);
return tag;
}
else
return finishnodeget(getintfromhash(t, key), res);
}
const TValue *luaH_Hgetshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(strisshr(key));
for (;;) {
if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
return gval(n);
else {
int nx = gnext(n);
if (nx == 0)
return &absentkey;
n += nx;
}
}
}
lu_byte luaH_getshortstr (Table *t, TString *key, TValue *res) {
return finishnodeget(luaH_Hgetshortstr(t, key), res);
}
static const TValue *Hgetlongstr (Table *t, TString *key) {
TValue ko;
lua_assert(!strisshr(key));
setsvalue(cast(lua_State *, NULL), &ko, key);
return getgeneric(t, &ko, 0);
}
static const TValue *Hgetstr (Table *t, TString *key) {
if (strisshr(key))
return luaH_Hgetshortstr(t, key);
else
return Hgetlongstr(t, key);
}
lu_byte luaH_getstr (Table *t, TString *key, TValue *res) {
return finishnodeget(Hgetstr(t, key), res);
}
lu_byte luaH_get (Table *t, const TValue *key, TValue *res) {
const TValue *slot;
switch (ttypetag(key)) {
case LUA_VSHRSTR:
slot = luaH_Hgetshortstr(t, tsvalue(key));
break;
case LUA_VNUMINT:
return luaH_getint(t, ivalue(key), res);
case LUA_VNIL:
slot = &absentkey;
break;
case LUA_VNUMFLT: {
lua_Integer k;
if (luaV_flttointeger(fltvalue(key), &k, F2Ieq))
return luaH_getint(t, k, res);
}
default:
slot = getgeneric(t, key, 0);
break;
}
return finishnodeget(slot, res);
}
static int retpsetcode (Table *t, const TValue *slot) {
if (isabstkey(slot))
return HNOTFOUND;
else
return cast_int((cast(Node*, slot) - t->node)) + HFIRSTNODE;
}
static int finishnodeset (Table *t, const TValue *slot, TValue *val) {
if (!ttisnil(slot)) {
setobj(((lua_State*)NULL), cast(TValue*, slot), val);
return HOK;
}
else
return retpsetcode(t, slot);
}
static int rawfinishnodeset (const TValue *slot, TValue *val) {
if (isabstkey(slot))
return 0;
else {
setobj(((lua_State*)NULL), cast(TValue*, slot), val);
return 1;
}
}
int luaH_psetint (Table *t, lua_Integer key, TValue *val) {
lua_assert(!ikeyinarray(t, key));
return finishnodeset(t, getintfromhash(t, key), val);
}
static int psetint (Table *t, lua_Integer key, TValue *val) {
int hres;
luaH_fastseti(t, key, val, hres);
return hres;
}
int luaH_psetshortstr (Table *t, TString *key, TValue *val) {
const TValue *slot = luaH_Hgetshortstr(t, key);
if (!ttisnil(slot)) {
setobj(((lua_State*)NULL), cast(TValue*, slot), val);
return HOK;
}
else if (checknoTM(t->metatable, TM_NEWINDEX)) {
if (ttisnil(val))
return HOK;
if (isabstkey(slot) &&
!(isblack(t) && iswhite(key))) {
TValue tk;
setsvalue(cast(lua_State *, NULL), &tk, key);
if (insertkey(t, &tk, val)) {
invalidateTMcache(t);
return HOK;
}
}
}
return retpsetcode(t, slot);
}
int luaH_psetstr (Table *t, TString *key, TValue *val) {
if (strisshr(key))
return luaH_psetshortstr(t, key, val);
else
return finishnodeset(t, Hgetlongstr(t, key), val);
}
int luaH_pset (Table *t, const TValue *key, TValue *val) {
switch (ttypetag(key)) {
case LUA_VSHRSTR: return luaH_psetshortstr(t, tsvalue(key), val);
case LUA_VNUMINT: return psetint(t, ivalue(key), val);
case LUA_VNIL: return HNOTFOUND;
case LUA_VNUMFLT: {
lua_Integer k;
if (luaV_flttointeger(fltvalue(key), &k, F2Ieq))
return psetint(t, k, val);
}
default:
return finishnodeset(t, getgeneric(t, key, 0), val);
}
}
void luaH_finishset (lua_State *L, Table *t, const TValue *key,
TValue *value, int hres) {
lua_assert(hres != HOK);
if (hres == HNOTFOUND) {
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");
}
else if (isextstr(key)) {
TString *ts = luaS_normstr(L, tsvalue(key));
setsvalue2s(L, L->top.p++, ts);
luaH_newkey(L, t, s2v(L->top.p - 1), value);
L->top.p--;
return;
}
luaH_newkey(L, t, key, value);
}
else if (hres > 0) {
setobj2t(L, gval(gnode(t, hres - HFIRSTNODE)), value);
}
else {
hres = ~hres;
obj2arr(t, cast_uint(hres), value);
}
}
void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
int hres = luaH_pset(t, key, value);
if (hres != HOK)
luaH_finishset(L, t, key, value, hres);
}
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
unsigned ik = ikeyinarray(t, key);
if (ik > 0)
obj2arr(t, ik - 1, value);
else {
int ok = rawfinishnodeset(getintfromhash(t, key), value);
if (!ok) {
TValue k;
setivalue(&k, key);
luaH_newkey(L, t, &k, value);
}
}
}
static lua_Unsigned hash_search (lua_State *L, Table *t, unsigned asize) {
lua_Unsigned i = asize + 1;
unsigned rnd = G(L)->seed;
int n = (asize > 0) ? luaO_ceillog2(asize) : 0;
unsigned mask = (1u << n) - 1;
unsigned incr = (rnd & mask) + 1;
lua_Unsigned j = (incr <= l_castS2U(LUA_MAXINTEGER) - i) ? i + incr : i + 1;
rnd >>= n;
while (!hashkeyisempty(t, j)) {
i = j;
if (j <= l_castS2U(LUA_MAXINTEGER)/2 - 1) {
j = j*2 + (rnd & 1);
rnd >>= 1;
}
else {
j = LUA_MAXINTEGER;
if (hashkeyisempty(t, j))
break;
else
return j;
}
}
while (j - i > 1u) {
lua_Unsigned m = (i + j) / 2;
if (hashkeyisempty(t, m)) j = m;
else i = m;
}
return i;
}
static unsigned int binsearch (Table *array, unsigned int i, unsigned int j) {
lua_assert(i <= j);
while (j - i > 1u) {
unsigned int m = (i + j) / 2;
if (arraykeyisempty(array, m)) j = m;
else i = m;
}
return i;
}
static lua_Unsigned newhint (Table *t, unsigned hint) {
lua_assert(hint <= t->asize);
*lenhint(t) = hint;
return hint;
}
lua_Unsigned luaH_getn (lua_State *L, Table *t) {
unsigned asize = t->asize;
if (asize > 0) {
const unsigned maxvicinity = 4;
unsigned limit = *lenhint(t);
if (limit == 0)
limit = 1;
if (arraykeyisempty(t, limit)) {
unsigned i;
for (i = 0; i < maxvicinity && limit > 1; i++) {
limit--;
if (!arraykeyisempty(t, limit))
return newhint(t, limit);
}
return newhint(t, binsearch(t, 0, limit));
}
else {
unsigned i;
for (i = 0; i < maxvicinity && limit < asize; i++) {
limit++;
if (arraykeyisempty(t, limit))
return newhint(t, limit - 1);
}
if (arraykeyisempty(t, asize)) {
return newhint(t, binsearch(t, limit, asize));
}
}
*lenhint(t) = asize;
}
lua_assert(asize == 0 || !arraykeyisempty(t, asize));
if (isdummy(t) || hashkeyisempty(t, asize + 1))
return asize;
else
return hash_search(L, t, asize);
}
#if defined(LUA_DEBUG)
Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
#endif