mirror of https://github.com/rusefi/lua.git
in hash nodes, keys are stored in separate pieces to avoid wasting
space with alignments
This commit is contained in:
parent
4bb30f461b
commit
b6f87491af
42
lgc.c
42
lgc.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: lgc.c,v 2.229 2017/05/26 19:14:29 roberto Exp roberto $
|
||||
** $Id: lgc.c,v 2.230 2017/06/01 19:16:34 roberto Exp roberto $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -73,7 +73,9 @@
|
|||
|
||||
#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
|
||||
|
||||
#define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n)))
|
||||
#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n)))
|
||||
|
||||
#define checkdeadkey(n) lua_assert(!keyisdead(n) || ttisnil(gval(n)))
|
||||
|
||||
|
||||
#define checkconsistency(obj) \
|
||||
|
@ -83,6 +85,8 @@
|
|||
#define markvalue(g,o) { checkconsistency(o); \
|
||||
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
|
||||
|
||||
#define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); }
|
||||
|
||||
#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }
|
||||
|
||||
/*
|
||||
|
@ -125,8 +129,8 @@ static lu_mem atomic (lua_State *L);
|
|||
*/
|
||||
static void removeentry (Node *n) {
|
||||
lua_assert(ttisnil(gval(n)));
|
||||
if (valiswhite(gkey(n)))
|
||||
setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */
|
||||
if (keyiswhite(n))
|
||||
setdeadkey(n); /* unused and unmarked key; remove it */
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,13 +141,13 @@ static void removeentry (Node *n) {
|
|||
** other objects: if really collected, cannot keep them; for objects
|
||||
** being finalized, keep them in keys, but not in values
|
||||
*/
|
||||
static int iscleared (global_State *g, const TValue *o) {
|
||||
if (!iscollectable(o)) return 0;
|
||||
else if (ttisstring(o)) {
|
||||
markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */
|
||||
static int iscleared (global_State *g, const GCObject *o) {
|
||||
if (o == NULL) return 0; /* non-collectable value */
|
||||
else if (novariant(o->tt) == LUA_TSTRING) {
|
||||
markobject(g, o); /* strings are 'values', so are never weak */
|
||||
return 0;
|
||||
}
|
||||
else return iswhite(gcvalue(o));
|
||||
else return iswhite(o);
|
||||
}
|
||||
|
||||
|
||||
|
@ -391,9 +395,9 @@ static void traverseweakvalue (global_State *g, Table *h) {
|
|||
if (ttisnil(gval(n))) /* entry is empty? */
|
||||
removeentry(n); /* remove it */
|
||||
else {
|
||||
lua_assert(!ttisnil(gkey(n)));
|
||||
markvalue(g, gkey(n)); /* mark key */
|
||||
if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */
|
||||
lua_assert(!keyisnil(n));
|
||||
markkey(g, n);
|
||||
if (!hasclears && iscleared(g, gcvalueN(gval(n)))) /* a white value? */
|
||||
hasclears = 1; /* table will have to be cleared */
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +437,7 @@ static int traverseephemeron (global_State *g, Table *h) {
|
|||
checkdeadkey(n);
|
||||
if (ttisnil(gval(n))) /* entry is empty? */
|
||||
removeentry(n); /* remove it */
|
||||
else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */
|
||||
else if (iscleared(g, gckeyN(n))) { /* key is not marked (yet)? */
|
||||
hasclears = 1; /* table must be cleared */
|
||||
if (valiswhite(gval(n))) /* value not marked yet? */
|
||||
hasww = 1; /* white-white entry */
|
||||
|
@ -468,9 +472,9 @@ static void traversestrongtable (global_State *g, Table *h) {
|
|||
if (ttisnil(gval(n))) /* entry is empty? */
|
||||
removeentry(n); /* remove it */
|
||||
else {
|
||||
lua_assert(!ttisnil(gkey(n)));
|
||||
markvalue(g, gkey(n)); /* mark key */
|
||||
markvalue(g, gval(n)); /* mark value */
|
||||
lua_assert(!keyisnil(n));
|
||||
markkey(g, n);
|
||||
markvalue(g, gval(n));
|
||||
}
|
||||
}
|
||||
if (g->gckind == KGC_GEN) {
|
||||
|
@ -691,7 +695,7 @@ static void clearkeys (global_State *g, GCObject *l) {
|
|||
Table *h = gco2t(l);
|
||||
Node *n, *limit = gnodelast(h);
|
||||
for (n = gnode(h, 0); n < limit; n++) {
|
||||
if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
|
||||
if (!ttisnil(gval(n)) && (iscleared(g, gckeyN(n)))) {
|
||||
setnilvalue(gval(n)); /* remove value ... */
|
||||
removeentry(n); /* and remove entry from table */
|
||||
}
|
||||
|
@ -711,11 +715,11 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
|
|||
unsigned int i;
|
||||
for (i = 0; i < h->sizearray; i++) {
|
||||
TValue *o = &h->array[i];
|
||||
if (iscleared(g, o)) /* value was collected? */
|
||||
if (iscleared(g, gcvalueN(o))) /* value was collected? */
|
||||
setnilvalue(o); /* remove value */
|
||||
}
|
||||
for (n = gnode(h, 0); n < limit; n++) {
|
||||
if (iscleared(g, gval(n))) {
|
||||
if (iscleared(g, gcvalueN(gval(n)))) {
|
||||
setnilvalue(gval(n)); /* remove value ... */
|
||||
removeentry(n); /* and remove entry from table */
|
||||
}
|
||||
|
|
6
llex.c
6
llex.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp roberto $
|
||||
** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp roberto $
|
||||
** Lexical Analyzer
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -132,12 +132,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
|||
o = luaH_set(L, ls->h, L->top - 1);
|
||||
if (ttisnil(o)) { /* not in use yet? */
|
||||
/* boolean value does not need GC barrier;
|
||||
table has no metatable, so it does not need to invalidate cache */
|
||||
table is not a metatable, so it does not need to invalidate cache */
|
||||
setbvalue(o, 1); /* t[string] = true */
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
else { /* string already present */
|
||||
ts = tsvalue(keyfromval(o)); /* re-use value previously stored */
|
||||
ts = keystrval(nodefromval(o)); /* re-use value previously stored */
|
||||
}
|
||||
L->top--; /* remove string from stack */
|
||||
return ts;
|
||||
|
|
98
lobject.h
98
lobject.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: lobject.h,v 2.120 2017/04/30 20:43:26 roberto Exp roberto $
|
||||
** $Id: lobject.h,v 2.121 2017/06/01 20:24:05 roberto Exp roberto $
|
||||
** Type definitions for Lua objects
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -122,6 +122,7 @@ typedef struct lua_TValue {
|
|||
|
||||
|
||||
#define val_(o) ((o)->value_)
|
||||
#define valraw(o) (&val_(o))
|
||||
|
||||
|
||||
/* raw type tag of a TValue */
|
||||
|
@ -131,7 +132,8 @@ typedef struct lua_TValue {
|
|||
#define novariant(x) ((x) & 0x0F)
|
||||
|
||||
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
|
||||
#define ttype(o) (rttype(o) & 0x3F)
|
||||
#define ttyperaw(t) ((t) & 0x3F)
|
||||
#define ttype(o) ttyperaw(rttype(o))
|
||||
|
||||
/* type tag of a TValue with no variants (bits 0-3) */
|
||||
#define ttnov(o) (novariant(rttype(o)))
|
||||
|
@ -157,7 +159,19 @@ typedef struct lua_TValue {
|
|||
#define ttislcf(o) checktag((o), LUA_TLCF)
|
||||
#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))
|
||||
#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD))
|
||||
#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY)
|
||||
|
||||
|
||||
/*
|
||||
** Macros to access unstructured values (may come both from
|
||||
** 'TValue's and table keys)
|
||||
*/
|
||||
#define ivalueraw(v) ((v).i)
|
||||
#define fltvalueraw(v) ((v).n)
|
||||
#define gcvalueraw(v) ((v).gc)
|
||||
#define pvalueraw(v) ((v).p)
|
||||
#define tsvalueraw(v) (gco2ts((v).gc))
|
||||
#define fvalueraw(v) ((v).f)
|
||||
#define bvalueraw(v) ((v).b)
|
||||
|
||||
|
||||
/* Macros to access values */
|
||||
|
@ -176,8 +190,6 @@ typedef struct lua_TValue {
|
|||
#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc))
|
||||
#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)
|
||||
#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc))
|
||||
/* a dead value may get the 'gc' field, but cannot access its contents */
|
||||
#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))
|
||||
|
||||
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
|
||||
|
||||
|
@ -185,6 +197,12 @@ typedef struct lua_TValue {
|
|||
#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
|
||||
|
||||
|
||||
/*
|
||||
** Protected access to objects in values
|
||||
*/
|
||||
#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL)
|
||||
|
||||
|
||||
/* Macros for internal tests */
|
||||
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
|
||||
|
||||
|
@ -253,8 +271,6 @@ typedef struct lua_TValue {
|
|||
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
|
||||
checkliveness(L,io); }
|
||||
|
||||
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
|
||||
|
||||
|
||||
|
||||
#define setobj(L,obj1,obj2) \
|
||||
|
@ -485,26 +501,37 @@ typedef union Closure {
|
|||
** Tables
|
||||
*/
|
||||
|
||||
typedef union TKey {
|
||||
struct {
|
||||
TValuefields;
|
||||
int next; /* for chaining (offset for next node) */
|
||||
} nk;
|
||||
TValue tvk;
|
||||
} TKey;
|
||||
|
||||
/*
|
||||
** Nodes for Hash tables. A pack of two TValue's (key-value pairs)
|
||||
** plus a 'next' field to link colliding entries. The distribuition
|
||||
** of the key's fields ('key_tt' and 'key_val') not forming a proper
|
||||
** 'TValue' allows for a smaller size for 'Node' both in 4-byte
|
||||
** and 8-byte alignments.
|
||||
*/
|
||||
typedef union Node {
|
||||
struct NodeKey {
|
||||
TValuefields; /* fields for value */
|
||||
lu_byte key_tt; /* key type */
|
||||
int next; /* for chaining */
|
||||
Value key_val; /* key value */
|
||||
} u;
|
||||
TValue i_val; /* direct access to node's value as a proper 'TValue' */
|
||||
} Node;
|
||||
|
||||
|
||||
/* 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_; \
|
||||
/* copy a value into a key */
|
||||
#define setnodekey(L,node,obj) \
|
||||
{ Node *n_=(node); const TValue *io_=(obj); \
|
||||
n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
|
||||
(void)L; checkliveness(L,io_); }
|
||||
|
||||
|
||||
typedef struct Node {
|
||||
TValue i_val;
|
||||
TKey i_key;
|
||||
} Node;
|
||||
/* copy a value from a key */
|
||||
#define getnodekey(L,obj,node) \
|
||||
{ TValue *io_=(obj); const Node *n_=(node); \
|
||||
io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \
|
||||
(void)L; checkliveness(L,io_); }
|
||||
|
||||
|
||||
typedef struct Table {
|
||||
|
@ -520,6 +547,33 @@ typedef struct Table {
|
|||
} Table;
|
||||
|
||||
|
||||
/*
|
||||
** Macros to manipulate keys inserted in nodes
|
||||
*/
|
||||
#define keytt(node) ((node)->u.key_tt)
|
||||
#define keyval(node) ((node)->u.key_val)
|
||||
|
||||
#define keyisnil(node) (keytt(node) == LUA_TNIL)
|
||||
#define keyisinteger(node) (keytt(node) == LUA_TNUMINT)
|
||||
#define keyival(node) (keyval(node).i)
|
||||
#define keyisshrstr(node) (keytt(node) == ctb(LUA_TSHRSTR))
|
||||
#define keystrval(node) (gco2ts(keyval(node).gc))
|
||||
|
||||
#define keyisdead(node) (keytt(node) == LUA_TDEADKEY)
|
||||
|
||||
#define setnilkey(node) (keytt(node) = LUA_TNIL)
|
||||
#define setdeadkey(node) (keytt(node) = LUA_TDEADKEY)
|
||||
|
||||
/* a dead value may get the 'gc' field, but cannot access its contents */
|
||||
#define deadkey(n) \
|
||||
check_exp(keytt(n) == LUA_TDEADKEY, cast(void *, keyval(n).gc))
|
||||
|
||||
#define keyiscollectable(n) (keytt(n) & BIT_ISCOLLECTABLE)
|
||||
|
||||
#define gckey(n) (keyval(n).gc)
|
||||
#define gckeyN(n) (keyiscollectable(n) ? gckey(n) : NULL)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** 'module' operation for hashing (size is always a power of 2)
|
||||
|
|
131
ltable.c
131
ltable.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: ltable.c,v 2.121 2017/05/19 12:47:00 roberto Exp roberto $
|
||||
** $Id: ltable.c,v 2.122 2017/05/19 12:57:10 roberto Exp roberto $
|
||||
** Lua tables (hash)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -75,8 +75,8 @@
|
|||
#define dummynode (&dummynode_)
|
||||
|
||||
static const Node dummynode_ = {
|
||||
{NILCONSTANT}, /* value */
|
||||
{{NILCONSTANT, 0}} /* key */
|
||||
{{NULL}, LUA_TNIL, /* value's value and type */
|
||||
LUA_TNIL, 0, {NULL}} /* key type, next, and key value */
|
||||
};
|
||||
|
||||
|
||||
|
@ -111,43 +111,79 @@ static int l_hashfloat (lua_Number n) {
|
|||
|
||||
|
||||
/*
|
||||
** returns the 'main' position of an element in a table (that is, the index
|
||||
** of its hash value)
|
||||
** returns the 'main' position of an element in a table (that is,
|
||||
** the index of its hash value). The key comes broken (tag in 'ktt'
|
||||
** and value in 'vkl') so that we can call it on keys inserted into
|
||||
** nodes.
|
||||
*/
|
||||
static Node *mainposition (const Table *t, const TValue *key) {
|
||||
switch (ttype(key)) {
|
||||
static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
|
||||
switch (ttyperaw(ktt)) {
|
||||
case LUA_TNUMINT:
|
||||
return hashint(t, ivalue(key));
|
||||
return hashint(t, ivalueraw(*kvl));
|
||||
case LUA_TNUMFLT:
|
||||
return hashmod(t, l_hashfloat(fltvalue(key)));
|
||||
return hashmod(t, l_hashfloat(fltvalueraw(*kvl)));
|
||||
case LUA_TSHRSTR:
|
||||
return hashstr(t, tsvalue(key));
|
||||
return hashstr(t, tsvalueraw(*kvl));
|
||||
case LUA_TLNGSTR:
|
||||
return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
|
||||
return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl)));
|
||||
case LUA_TBOOLEAN:
|
||||
return hashboolean(t, bvalue(key));
|
||||
return hashboolean(t, bvalueraw(*kvl));
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return hashpointer(t, pvalue(key));
|
||||
return hashpointer(t, pvalueraw(*kvl));
|
||||
case LUA_TLCF:
|
||||
return hashpointer(t, fvalue(key));
|
||||
return hashpointer(t, fvalueraw(*kvl));
|
||||
default:
|
||||
lua_assert(!ttisdeadkey(key));
|
||||
return hashpointer(t, gcvalue(key));
|
||||
return hashpointer(t, gcvalueraw(*kvl));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Node *mainpositionTV (const Table *t, const TValue *key) {
|
||||
return mainposition(t, rttype(key), valraw(key));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether key 'k1' is equal to the key in node 'n2'.
|
||||
** This equality is raw, so there are no metamethods. Floats
|
||||
** with integer values have been normalized, so integers cannot
|
||||
** be equal to floats. It is assumed that 'eqshrstr' is simply
|
||||
** pointer equality, so that short strings are handled in the
|
||||
** default case.
|
||||
*/
|
||||
static int equalkey (const TValue *k1, const Node *n2) {
|
||||
if (rttype(k1) != keytt(n2)) /* not the same variants? */
|
||||
return 0; /* cannot be same key */
|
||||
switch (ttype(k1)) {
|
||||
case LUA_TNIL:
|
||||
return 1;
|
||||
case LUA_TNUMINT:
|
||||
return (ivalue(k1) == keyival(n2));
|
||||
case LUA_TNUMFLT:
|
||||
return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
|
||||
case LUA_TBOOLEAN:
|
||||
return bvalue(k1) == bvalueraw(keyval(n2));
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return pvalue(k1) == pvalueraw(keyval(n2));
|
||||
case LUA_TLCF:
|
||||
return fvalue(k1) == fvalueraw(keyval(n2));
|
||||
case LUA_TLNGSTR:
|
||||
return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
|
||||
default:
|
||||
return gcvalue(k1) == gcvalueraw(keyval(n2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** returns the index for 'key' if 'key' is an appropriate key to live in
|
||||
** the array part of the table, 0 otherwise.
|
||||
** returns the index for 'k' if 'k' is an appropriate key to live in
|
||||
** the array part of a table, 0 otherwise.
|
||||
*/
|
||||
static unsigned int arrayindex (const TValue *key) {
|
||||
if (ttisinteger(key)) {
|
||||
lua_Integer k = ivalue(key);
|
||||
if (0 < k && (lua_Unsigned)k <= MAXASIZE)
|
||||
static unsigned int arrayindex (lua_Integer k) {
|
||||
if (0 < k && l_castS2U(k) <= MAXASIZE)
|
||||
return cast(unsigned int, k); /* 'key' is an appropriate array index */
|
||||
}
|
||||
return 0; /* 'key' did not match some condition */
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -159,17 +195,17 @@ static unsigned int arrayindex (const TValue *key) {
|
|||
static unsigned int findindex (lua_State *L, Table *t, StkId key) {
|
||||
unsigned int i;
|
||||
if (ttisnil(key)) return 0; /* first iteration */
|
||||
i = arrayindex(key);
|
||||
i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0;
|
||||
if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */
|
||||
return i; /* yes; that's the index */
|
||||
else {
|
||||
int nx;
|
||||
Node *n = mainposition(t, key);
|
||||
Node *n = mainpositionTV(t, key);
|
||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
||||
/* key may be dead already, but it is ok to use it in 'next' */
|
||||
if (luaV_rawequalobj(gkey(n), key) ||
|
||||
(ttisdeadkey(gkey(n)) && iscollectable(key) &&
|
||||
deadvalue(gkey(n)) == gcvalue(key))) {
|
||||
if (equalkey(key, n) ||
|
||||
(keyisdead(n) && iscollectable(key) &&
|
||||
deadkey(n) == gcvalue(key))) {
|
||||
i = cast_int(n - gnode(t, 0)); /* key index in hash table */
|
||||
/* hash elements are numbered after array ones */
|
||||
return (i + 1) + t->sizearray;
|
||||
|
@ -194,8 +230,9 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
|
|||
}
|
||||
for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */
|
||||
if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
|
||||
setobj2s(L, key, gkey(gnode(t, i)));
|
||||
setobj2s(L, key+1, gval(gnode(t, i)));
|
||||
Node *n = gnode(t, i);
|
||||
getnodekey(L, key, n);
|
||||
setobj2s(L, key + 1, gval(n));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +276,7 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
|
|||
}
|
||||
|
||||
|
||||
static int countint (const TValue *key, unsigned int *nums) {
|
||||
static int countint (lua_Integer key, unsigned int *nums) {
|
||||
unsigned int k = arrayindex(key);
|
||||
if (k != 0) { /* is 'key' an appropriate array index? */
|
||||
nums[luaO_ceillog2(k)]++; /* count as such */
|
||||
|
@ -288,7 +325,8 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
|
|||
while (i--) {
|
||||
Node *n = &t->node[i];
|
||||
if (!ttisnil(gval(n))) {
|
||||
ause += countint(gkey(n), nums);
|
||||
if (keyisinteger(n))
|
||||
ause += countint(keyival(n), nums);
|
||||
totaluse++;
|
||||
}
|
||||
}
|
||||
|
@ -322,7 +360,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
|
|||
for (i = 0; i < (int)size; i++) {
|
||||
Node *n = gnode(t, i);
|
||||
gnext(n) = 0;
|
||||
setnilvalue(wgkey(n));
|
||||
setnilkey(n);
|
||||
setnilvalue(gval(n));
|
||||
}
|
||||
t->lsizenode = cast_byte(lsize);
|
||||
|
@ -358,7 +396,8 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
|
|||
if (!ttisnil(gval(old))) {
|
||||
/* doesn't need barrier/invalidate cache, as entry was
|
||||
already present in the table */
|
||||
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
|
||||
TValue k; getnodekey(L, &k, old);
|
||||
setobjt2t(L, luaH_set(L, t, &k), gval(old));
|
||||
}
|
||||
}
|
||||
if (oldhsize > 0) /* not the dummy node? */
|
||||
|
@ -385,7 +424,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) {
|
|||
totaluse = na; /* all those keys are integer keys */
|
||||
totaluse += numusehash(t, nums, &na); /* count keys in hash part */
|
||||
/* count extra key */
|
||||
na += countint(ek, nums);
|
||||
if (ttisinteger(ek))
|
||||
na += countint(ivalue(ek), nums);
|
||||
totaluse++;
|
||||
/* compute new size for array part */
|
||||
asize = computesizes(nums, &na);
|
||||
|
@ -424,7 +464,7 @@ static Node *getfreepos (Table *t) {
|
|||
if (!isdummy(t)) {
|
||||
while (t->lastfree > t->node) {
|
||||
t->lastfree--;
|
||||
if (ttisnil(gkey(t->lastfree)))
|
||||
if (keyisnil(t->lastfree))
|
||||
return t->lastfree;
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +493,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
|
|||
else if (luai_numisnan(fltvalue(key)))
|
||||
luaG_runerror(L, "table index is NaN");
|
||||
}
|
||||
mp = mainposition(t, key);
|
||||
mp = mainpositionTV(t, key);
|
||||
if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */
|
||||
Node *othern;
|
||||
Node *f = getfreepos(t); /* get a free place */
|
||||
|
@ -463,7 +503,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
|
|||
return luaH_set(L, t, key); /* insert key into grown table */
|
||||
}
|
||||
lua_assert(!isdummy(t));
|
||||
othern = mainposition(t, gkey(mp));
|
||||
othern = mainposition(t, keytt(mp), &keyval(mp));
|
||||
if (othern != mp) { /* is colliding node out of its main position? */
|
||||
/* yes; move colliding node into free position */
|
||||
while (othern + gnext(othern) != mp) /* find previous */
|
||||
|
@ -485,7 +525,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
|
|||
mp = f;
|
||||
}
|
||||
}
|
||||
setnodekey(L, &mp->i_key, key);
|
||||
setnodekey(L, mp, key);
|
||||
luaC_barrierback(L, t, key);
|
||||
lua_assert(ttisnil(gval(mp)));
|
||||
return gval(mp);
|
||||
|
@ -502,7 +542,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
|
|||
else {
|
||||
Node *n = hashint(t, key);
|
||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
||||
if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)
|
||||
if (keyisinteger(n) && keyival(n) == key)
|
||||
return gval(n); /* that's it */
|
||||
else {
|
||||
int nx = gnext(n);
|
||||
|
@ -522,8 +562,7 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
|
|||
Node *n = hashstr(t, key);
|
||||
lua_assert(key->tt == LUA_TSHRSTR);
|
||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
||||
const TValue *k = gkey(n);
|
||||
if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
|
||||
if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
|
||||
return gval(n); /* that's it */
|
||||
else {
|
||||
int nx = gnext(n);
|
||||
|
@ -540,9 +579,9 @@ const TValue *luaH_getshortstr (Table *t, TString *key) {
|
|||
** which may be in array part, nor for floats with integral values.)
|
||||
*/
|
||||
static const TValue *getgeneric (Table *t, const TValue *key) {
|
||||
Node *n = mainposition(t, key);
|
||||
Node *n = mainpositionTV(t, key);
|
||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
||||
if (luaV_rawequalobj(gkey(n), key))
|
||||
if (equalkey(key, n))
|
||||
return gval(n); /* that's it */
|
||||
else {
|
||||
int nx = gnext(n);
|
||||
|
@ -683,7 +722,7 @@ lua_Unsigned luaH_getn (Table *t) {
|
|||
#if defined(LUA_DEBUG)
|
||||
|
||||
Node *luaH_mainposition (const Table *t, const TValue *key) {
|
||||
return mainposition(t, key);
|
||||
return mainpositionTV(t, key);
|
||||
}
|
||||
|
||||
int luaH_isdummy (const Table *t) { return isdummy(t); }
|
||||
|
|
18
ltable.h
18
ltable.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp roberto $
|
||||
** $Id: ltable.h,v 2.24 2017/05/19 12:48:15 roberto Exp roberto $
|
||||
** Lua tables (hash)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -12,18 +12,9 @@
|
|||
|
||||
#define gnode(t,i) (&(t)->node[i])
|
||||
#define gval(n) (&(n)->i_val)
|
||||
#define gnext(n) ((n)->i_key.nk.next)
|
||||
#define gnext(n) ((n)->u.next)
|
||||
|
||||
|
||||
/* 'const' to avoid wrong writings that can mess up field 'next' */
|
||||
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
|
||||
|
||||
/*
|
||||
** writable version of 'gkey'; allows updates to individual fields,
|
||||
** but not to the whole (which has incompatible type)
|
||||
*/
|
||||
#define wgkey(n) (&(n)->i_key.nk)
|
||||
|
||||
#define invalidateTMcache(t) ((t)->flags = 0)
|
||||
|
||||
|
||||
|
@ -35,9 +26,8 @@
|
|||
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
|
||||
|
||||
|
||||
/* returns the key, given the value of a table entry */
|
||||
#define keyfromval(v) \
|
||||
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
|
||||
/* returns the Node, given the value of a table entry */
|
||||
#define nodefromval(v) cast(Node *, (v))
|
||||
|
||||
|
||||
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
|
||||
|
|
16
ltests.c
16
ltests.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: ltests.c,v 2.217 2017/05/04 13:32:01 roberto Exp $
|
||||
** $Id: ltests.c,v 2.218 2017/05/31 18:54:58 roberto Exp roberto $
|
||||
** Internal Module for Debugging of the Lua Implementation
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -253,8 +253,10 @@ static void checktable (global_State *g, Table *h) {
|
|||
checkvalref(g, hgc, &h->array[i]);
|
||||
for (n = gnode(h, 0); n < limit; n++) {
|
||||
if (!ttisnil(gval(n))) {
|
||||
lua_assert(!ttisnil(gkey(n)));
|
||||
checkvalref(g, hgc, gkey(n));
|
||||
TValue k;
|
||||
getnodekey(g->mainthread, &k, n);
|
||||
lua_assert(!keyisnil(n));
|
||||
checkvalref(g, hgc, &k);
|
||||
checkvalref(g, hgc, gval(n));
|
||||
}
|
||||
}
|
||||
|
@ -802,10 +804,12 @@ static int table_query (lua_State *L) {
|
|||
lua_pushnil(L);
|
||||
}
|
||||
else if ((i -= t->sizearray) < sizenode(t)) {
|
||||
TValue k;
|
||||
getnodekey(L, &k, gnode(t, i));
|
||||
if (!ttisnil(gval(gnode(t, i))) ||
|
||||
ttisnil(gkey(gnode(t, i))) ||
|
||||
ttisnumber(gkey(gnode(t, i)))) {
|
||||
pushobject(L, gkey(gnode(t, i)));
|
||||
ttisnil(&k) ||
|
||||
ttisnumber(&k)) {
|
||||
pushobject(L, &k);
|
||||
}
|
||||
else
|
||||
lua_pushliteral(L, "<undef>");
|
||||
|
|
Loading…
Reference in New Issue