From 9243c414d92c253edd908f438caa31e2aa16f3f4 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 23 Feb 2018 10:16:18 -0300 Subject: [PATCH] first version of empty entries in tables (so that, in the future, tables can contain regular nil entries) --- lapi.c | 30 +++++++++++++++----------- lgc.c | 58 +++++++++++++++++++++++++------------------------- llex.c | 4 ++-- lobject.h | 30 +++++++++++++++++++++++--- ltable.c | 63 +++++++++++++++++++++++++++++-------------------------- ltable.h | 7 ++++++- ltests.c | 6 +++--- ltm.c | 8 +++---- ltm.h | 8 ++++++- lvm.c | 21 ++++++++++--------- lvm.h | 10 ++++----- 11 files changed, 146 insertions(+), 99 deletions(-) diff --git a/lapi.c b/lapi.c index 78ae7e0b..0debc1d3 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.283 2018/02/05 17:10:52 roberto Exp roberto $ +** $Id: lapi.c,v 2.285 2018/02/20 16:52:50 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -657,14 +657,26 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { } +static int finishrawget (lua_State *L, const TValue *val) { + if (isempty(val)) /* avoid copying empty items to the stack */ + setnilvalue(s2v(L->top)); + else + setobj2s(L, L->top, val); + api_incr_top(L); + lua_unlock(L); + return ttnov(s2v(L->top - 1)); +} + + LUA_API int lua_rawget (lua_State *L, int idx) { TValue *t; + const TValue *val; lua_lock(L); t = index2value(L, idx); api_check(L, ttistable(t), "table expected"); - setobj2s(L, L->top - 1, luaH_get(hvalue(t), s2v(L->top - 1))); - lua_unlock(L); - return ttnov(s2v(L->top - 1)); + val = luaH_get(hvalue(t), s2v(L->top - 1)); + L->top--; /* remove key */ + return finishrawget(L, val); } @@ -673,10 +685,7 @@ LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { lua_lock(L); t = index2value(L, idx); api_check(L, ttistable(t), "table expected"); - setobj2s(L, L->top, luaH_getint(hvalue(t), n)); - api_incr_top(L); - lua_unlock(L); - return ttnov(s2v(L->top - 1)); + return finishrawget(L, luaH_getint(hvalue(t), n)); } @@ -687,10 +696,7 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { t = index2value(L, idx); api_check(L, ttistable(t), "table expected"); setpvalue(&k, cast_voidp(p)); - setobj2s(L, L->top, luaH_get(hvalue(t), &k)); - api_incr_top(L); - lua_unlock(L); - return ttnov(s2v(L->top - 1)); + return finishrawget(L, luaH_get(hvalue(t), &k)); } diff --git a/lgc.c b/lgc.c index 7cb3c18d..8245dc21 100644 --- a/lgc.c +++ b/lgc.c @@ -145,12 +145,13 @@ static GCObject **getgclist (GCObject *o) { ** Clear keys for empty entries in tables. If entry is empty ** and its key is not marked, mark its entry as dead. This allows the ** collection of the key, but keeps its entry in the table (its removal -** could break a chain). Other places never manipulate dead keys, -** because its associated nil value is enough to signal that the entry -** is logically empty. +** could break a chain). The main feature of a dead key is that it must +** be different from any other value, to do not disturb searches. +** Other places never manipulate dead keys, because its associated empty +** value is enough to signal that the entry is logically empty. */ -static void removeentry (Node *n) { - lua_assert(ttisnil(gval(n))); +static void clearkey (Node *n) { + lua_assert(isempty(gval(n))); if (keyiswhite(n)) setdeadkey(n); /* unused and unmarked key; remove it */ } @@ -386,8 +387,8 @@ static void traverseweakvalue (global_State *g, Table *h) { worth traversing it now just to check) */ int hasclears = (h->sizearray > 0); for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ else { lua_assert(!keyisnil(n)); markkey(g, n); @@ -428,8 +429,8 @@ static int traverseephemeron (global_State *g, Table *h) { } /* traverse hash part */ for (n = gnode(h, 0); n < limit; n++) { - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ 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? */ @@ -461,8 +462,8 @@ static void traversestrongtable (global_State *g, Table *h) { for (i = 0; i < h->sizearray; i++) /* traverse array part */ markvalue(g, &h->array[i]); for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ - if (ttisnil(gval(n))) /* entry is empty? */ - removeentry(n); /* remove it */ + if (isempty(gval(n))) /* entry is empty? */ + clearkey(n); /* clear its key */ else { lua_assert(!keyisnil(n)); markkey(g, n); @@ -681,15 +682,16 @@ static void clearprotolist (global_State *g) { /* ** clear entries with unmarked keys from all weaktables in list 'l' */ -static void clearkeys (global_State *g, GCObject *l) { +static void clearbykeys (global_State *g, GCObject *l) { for (; l; l = gco2t(l)->gclist) { Table *h = gco2t(l); - Node *n, *limit = gnodelast(h); + Node *limit = gnodelast(h); + Node *n; for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && (iscleared(g, gckeyN(n)))) /* unmarked key? */ - setnilvalue(gval(n)); /* clear value */ - if (ttisnil(gval(n))) /* is entry empty? */ - removeentry(n); /* remove it from table */ + if (isempty(gval(n))) /* is entry empty? */ + clearkey(n); /* clear its key */ + else if (iscleared(g, gckeyN(n))) /* unmarked key? */ + setempty(gval(n)); /* remove entry */ } } } @@ -699,7 +701,7 @@ static void clearkeys (global_State *g, GCObject *l) { ** clear entries with unmarked values from all weaktables in list 'l' up ** to element 'f' */ -static void clearvalues (global_State *g, GCObject *l, GCObject *f) { +static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); @@ -707,13 +709,13 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; if (iscleared(g, gcvalueN(o))) /* value was collected? */ - setnilvalue(o); /* remove value */ + setempty(o); /* remove entry */ } for (n = gnode(h, 0); n < limit; n++) { if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ - setnilvalue(gval(n)); /* clear value */ - if (ttisnil(gval(n))) /* is entry empty? */ - removeentry(n); /* remove it from table */ + setempty(gval(n)); /* remove entry */ + if (isempty(gval(n))) /* is entry empty? */ + clearkey(n); /* clear its key */ } } } @@ -1372,8 +1374,8 @@ static lu_mem atomic (lua_State *L) { convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ /* Clear values from weak tables, before checking finalizers */ - clearvalues(g, g->weak, NULL); - clearvalues(g, g->allweak, NULL); + clearbyvalues(g, g->weak, NULL); + clearbyvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; separatetobefnz(g, 0); /* separate objects to be finalized */ work += markbeingfnz(g); /* mark objects that will be finalized */ @@ -1381,11 +1383,11 @@ static lu_mem atomic (lua_State *L) { convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ - clearkeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ - clearkeys(g, g->allweak); /* clear keys from all 'allweak' tables */ + clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ + clearbykeys(g, g->allweak); /* clear keys from all 'allweak' tables */ /* clear values from resurrected weak tables */ - clearvalues(g, g->weak, origweak); - clearvalues(g, g->allweak, origall); + clearbyvalues(g, g->weak, origweak); + clearbyvalues(g, g->allweak, origall); luaS_clearcache(g); clearprotolist(g); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ diff --git a/llex.c b/llex.c index be775146..5d5efb07 100644 --- a/llex.c +++ b/llex.c @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.98 2017/06/29 15:06:44 roberto Exp roberto $ +** $Id: llex.c,v 2.99 2018/01/28 15:13:26 roberto Exp roberto $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -130,7 +130,7 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TString *ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ o = luaH_set(L, ls->h, s2v(L->top - 1)); - if (ttisnil(o)) { /* not in use yet? */ + if (isempty(o)) { /* not in use yet? */ /* boolean value does not need GC barrier; table is not a metatable, so it does not need to invalidate cache */ setbvalue(o, 1); /* t[string] = true */ diff --git a/lobject.h b/lobject.h index 2b65da36..c6590cf0 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.135 2018/02/21 16:28:12 roberto Exp roberto $ +** $Id: lobject.h,v 2.136 2018/02/22 17:28:10 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -100,7 +100,7 @@ typedef struct TValue { #define setobj(L,obj1,obj2) \ { TValue *io1=(obj1); const TValue *io2=(obj2); \ io1->value_ = io2->value_; io1->tt_ = io2->tt_; \ - (void)L; checkliveness(L,io1); } + (void)L; checkliveness(L,io1); lua_assert(!isreallyempty(io1)); } /* ** different types of assignments, according to destination @@ -148,6 +148,30 @@ typedef StackValue *StkId; /* index to stack elements */ /* (address of) a fixed nil value */ #define luaO_nilobject (&luaO_nilobject_) + +/* +** Variant tag, used only in tables to signal an empty slot +** (which might be different from a slot containing nil) +*/ +#define LUA_TEMPTY (LUA_TNIL | (1 << 4)) + +#define ttisnilorempty(v) checktype((v), LUA_TNIL) +/* +** By default, entries with any kind of nil are considered empty +*/ +#define isempty(v) ttisnilorempty(v) + +#define isreallyempty(v) checktag((v), LUA_TEMPTY) + +/* macro defining an empty value */ +#define EMPTYCONSTANT {NULL}, LUA_TEMPTY + + +/* mark an entry as empty */ +#define setempty(v) settt_(v, LUA_TEMPTY) + + + /* }================================================================== */ @@ -644,7 +668,7 @@ typedef struct Table { /* ** Use a "nil table" to mark dead keys in a table. Those keys serve -** only to keep space for removed entries, which may still be part of +** to keep space for removed entries, which may still be part of ** chains. Note that the 'keytt' does not have the BIT_ISCOLLECTABLE ** set, so these values are considered not collectable and are different ** from any valid value. diff --git a/ltable.c b/ltable.c index 5378e31a..c71d627a 100644 --- a/ltable.c +++ b/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.132 2018/02/19 20:06:56 roberto Exp roberto $ +** $Id: ltable.c,v 2.133 2018/02/21 12:54:26 roberto Exp roberto $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -88,11 +88,14 @@ #define dummynode (&dummynode_) static const Node dummynode_ = { - {{NULL}, LUA_TNIL, /* value's value and type */ + {{NULL}, LUA_TEMPTY, /* value's value and type */ LUA_TNIL, 0, {NULL}} /* key type, next, and key value */ }; +LUAI_DDEF const TValue luaH_emptyobject_ = {EMPTYCONSTANT}; + + /* ** Hash for floating-point numbers. ** The main computation should be just @@ -200,7 +203,7 @@ static const TValue *getgeneric (Table *t, const TValue *key) { else { int nx = gnext(n); if (nx == 0) - return luaO_nilobject; /* not found */ + return luaH_emptyobject; /* not found */ n += nx; } } @@ -232,7 +235,7 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key) { return i; /* yes; that's the index */ else { const TValue *n = getgeneric(t, key); - if (n == luaO_nilobject) + if (n == luaH_emptyobject) luaG_runerror(L, "invalid key to 'next'"); /* key not found */ i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ @@ -244,14 +247,14 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key) { int luaH_next (lua_State *L, Table *t, StkId key) { unsigned int i = findindex(L, t, s2v(key)); /* find original element */ for (; i < t->sizearray; i++) { /* try first array part */ - if (!ttisnil(&t->array[i])) { /* a non-nil value? */ + 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 -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ - if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + 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)); @@ -336,7 +339,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) { } /* count elements in range (2^(lg - 1), 2^lg] */ for (; i <= lim; i++) { - if (!ttisnil(&t->array[i-1])) + if (!isempty(&t->array[i-1])) lc++; } nums[lg] += lc; @@ -352,7 +355,7 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { int i = sizenode(t); while (i--) { Node *n = &t->node[i]; - if (!ttisnil(gval(n))) { + if (!isempty(gval(n))) { if (keyisinteger(n)) ause += countint(keyival(n), nums); totaluse++; @@ -387,7 +390,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { Node *n = gnode(t, i); gnext(n) = 0; setnilkey(n); - setnilvalue(gval(n)); + setempty(gval(n)); } t->lsizenode = cast_byte(lsize); t->lastfree = gnode(t, size); /* all positions are free */ @@ -403,7 +406,7 @@ static void reinsert (lua_State *L, Table *ot, Table *t) { int size = sizenode(ot); for (j = 0; j < size; j++) { Node *old = gnode(ot, j); - if (!ttisnil(gval(old))) { + if (!isempty(gval(old))) { /* doesn't need barrier/invalidate cache, as entry was already present in the table */ TValue k; @@ -456,7 +459,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, exchangehashpart(t, &newt); /* and new hash */ /* re-insert into the new hash the elements from vanishing slice */ for (i = newasize; i < oldasize; i++) { - if (!ttisnil(&t->array[i])) + if (!isempty(&t->array[i])) luaH_setint(L, t, i + 1, &t->array[i]); } t->sizearray = oldasize; /* restore current size... */ @@ -473,7 +476,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, t->array = newarray; /* set new array part */ t->sizearray = newasize; for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ - setnilvalue(&t->array[i]); + setempty(&t->array[i]); /* re-insert elements from old hash part into new parts */ reinsert(L, &newt, t); /* 'newt' now has the old hash */ freehash(L, &newt); /* free old hash part */ @@ -569,7 +572,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { luaG_runerror(L, "table index is NaN"); } mp = mainpositionTV(t, key); - if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */ + if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ Node *othern; Node *f = getfreepos(t); /* get a free place */ if (f == NULL) { /* cannot find a free place? */ @@ -589,7 +592,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { gnext(f) += cast_int(mp - f); /* correct 'next' */ gnext(mp) = 0; /* now 'mp' is free */ } - setnilvalue(gval(mp)); + setempty(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ @@ -602,7 +605,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { } setnodekey(L, mp, key); luaC_barrierback(L, obj2gco(t), key); - lua_assert(ttisnil(gval(mp))); + lua_assert(isempty(gval(mp))); return gval(mp); } @@ -625,7 +628,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) { n += nx; } } - return luaO_nilobject; + return luaH_emptyobject; } } @@ -642,7 +645,7 @@ const TValue *luaH_getshortstr (Table *t, TString *key) { else { int nx = gnext(n); if (nx == 0) - return luaO_nilobject; /* not found */ + return luaH_emptyobject; /* not found */ n += nx; } } @@ -667,7 +670,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); - case LUA_TNIL: return luaO_nilobject; + case LUA_TNIL: return luaH_emptyobject; case LUA_TNUMFLT: { lua_Integer k; if (luaV_flttointeger(fltvalue(key), &k, 0)) /* index is an integral? */ @@ -686,7 +689,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { */ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { const TValue *p = luaH_get(t, key); - if (p != luaO_nilobject) + if (p != luaH_emptyobject) return cast(TValue *, p); else return luaH_newkey(L, t, key); } @@ -695,7 +698,7 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { const TValue *p = luaH_getint(t, key); TValue *cell; - if (p != luaO_nilobject) + if (p != luaH_emptyobject) cell = cast(TValue *, p); else { TValue k; @@ -728,16 +731,16 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { j *= 2; else { j = LUA_MAXINTEGER; - if (ttisnil(luaH_getint(t, j))) /* t[j] == nil? */ + 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 (!ttisnil(luaH_getint(t, j))); /* repeat until t[j] == nil */ - /* i < j && t[i] !≃ nil && t[j] == nil */ + } 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 (ttisnil(luaH_getint(t, m))) j = m; + if (isempty(luaH_getint(t, m))) j = m; else i = m; } return i; @@ -746,27 +749,27 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { /* ** Try to find a boundary in table 't'. (A 'boundary' is an integer index -** such that t[i] is non-nil and t[i+1] is nil, plus 0 if t[1] is nil -** and 'maxinteger' if t[maxinteger] is not nil.) +** such that t[i] is present and t[i+1] is absent, or 0 if t[1] is absent +** and 'maxinteger' if t[maxinteger] is present.) ** First, try the array part: if there is an array part and its last -** element is nil, there must be a boundary there; a binary search +** element is absent, there must be a boundary there; a binary search ** finds that boundary. Otherwise, if the hash part is empty or does not ** contain 'j + 1', 'j' is a boundary. Otherwize, call 'hash_search' ** to find a boundary in the hash part. */ lua_Unsigned luaH_getn (Table *t) { unsigned int j = t->sizearray; - if (j > 0 && ttisnil(&t->array[j - 1])) { + if (j > 0 && isempty(&t->array[j - 1])) { unsigned int i = 0; while (j - i > 1u) { /* binary search */ unsigned int m = (i + j) / 2; - if (ttisnil(&t->array[m - 1])) j = m; + if (isempty(&t->array[m - 1])) j = m; else i = m; } return i; } else { /* 'j' is zero or present in table */ - if (isdummy(t) || ttisnil(luaH_getint(t, l_castU2S(j + 1)))) + if (isdummy(t) || isempty(luaH_getint(t, l_castU2S(j + 1)))) return j; /* 'j + 1' is absent... */ else /* 'j + 1' is also present */ return hash_search(t, j); diff --git a/ltable.h b/ltable.h index 88f90636..bcf92984 100644 --- a/ltable.h +++ b/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.24 2017/05/19 12:48:15 roberto Exp roberto $ +** $Id: ltable.h,v 2.25 2017/06/09 16:48:44 roberto Exp roberto $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -21,6 +21,8 @@ /* true when 't' is using 'dummynode' as its hash part */ #define isdummy(t) ((t)->lastfree == NULL) +#define luaH_emptyobject (&luaH_emptyobject_) + /* allocated size for hash nodes */ #define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t)) @@ -30,6 +32,9 @@ #define nodefromval(v) cast(Node *, (v)) +LUAI_DDEC const TValue luaH_emptyobject_; + + LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value); diff --git a/ltests.c b/ltests.c index 97d1abd4..a5781fb6 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.240 2018/01/28 15:13:26 roberto Exp roberto $ +** $Id: ltests.c,v 2.241 2018/02/20 16:52:50 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -254,7 +254,7 @@ static void checktable (global_State *g, Table *h) { for (i = 0; i < h->sizearray; i++) checkvalref(g, hgc, &h->array[i]); for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n))) { + if (!isempty(gval(n))) { TValue k; getnodekey(g->mainthread, &k, n); lua_assert(!keyisnil(n)); @@ -842,7 +842,7 @@ static int table_query (lua_State *L) { else if ((i -= t->sizearray) < sizenode(t)) { TValue k; getnodekey(L, &k, gnode(t, i)); - if (!ttisnil(gval(gnode(t, i))) || + if (!isempty(gval(gnode(t, i))) || ttisnil(&k) || ttisnumber(&k)) { pushobject(L, &k); diff --git a/ltm.c b/ltm.c index 3f29c83b..0187c6f5 100644 --- a/ltm.c +++ b/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.62 2018/02/17 19:20:00 roberto Exp roberto $ +** $Id: ltm.c,v 2.63 2018/02/21 15:49:32 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -60,7 +60,7 @@ void luaT_init (lua_State *L) { const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *tm = luaH_getshortstr(events, ename); lua_assert(event <= TM_EQ); - if (ttisnil(tm)) { /* no tag method? */ + if (notm(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) diff --git a/lvm.c b/lvm.c index efde6fb2..99e0d6b7 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.345 2018/02/21 15:49:32 roberto Exp roberto $ +** $Id: lvm.c,v 2.346 2018/02/21 19:43:44 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -168,7 +168,7 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, /* ** Finish the table access 'val = t[key]'. ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to -** t[k] entry (which must be nil). +** t[k] entry (which must be empty). */ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *slot) { @@ -178,12 +178,12 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, if (slot == NULL) { /* 't' is not a table? */ lua_assert(!ttistable(t)); tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (ttisnil(tm)) + if (notm(tm)) luaG_typeerror(L, t, "index"); /* no metamethod */ /* else will try the metamethod */ } else { /* 't' is a table */ - lua_assert(ttisnil(slot)); + lua_assert(isempty(slot)); tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ if (tm == NULL) { /* no metamethod? */ setnilvalue(s2v(val)); /* result is nil */ @@ -209,8 +209,8 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, /* ** Finish a table assignment 't[key] = val'. ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points -** to the entry 't[key]', or to 'luaO_nilobject' if there is no such -** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastget' +** to the entry 't[key]', or to 'luaH_emptyobject' if there is no such +** entry. (The value at 'slot' must be empty, otherwise 'luaV_fastget' ** would have done the job.) */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, @@ -220,10 +220,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, const TValue *tm; /* '__newindex' metamethod */ if (slot != NULL) { /* is 't' a table? */ Table *h = hvalue(t); /* save 't' table */ - lua_assert(ttisnil(slot)); /* old value must be nil */ + lua_assert(isempty(slot)); /* slot must be empty */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ if (tm == NULL) { /* no metamethod? */ - if (slot == luaO_nilobject) /* no previous entry? */ + if (slot == luaH_emptyobject) /* no previous entry? */ slot = luaH_newkey(L, h, key); /* create one */ /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, slot), val); /* set its new value */ @@ -234,7 +234,8 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, /* else will try the metamethod */ } else { /* not a table; check metamethod */ - if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); + if (notm(tm)) luaG_typeerror(L, t, "index"); } /* try the metamethod */ @@ -586,7 +587,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); - if (ttisnil(tm)) /* no metamethod? */ + if (notm(tm)) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } diff --git a/lvm.h b/lvm.h index cbf7e922..c5d5206d 100644 --- a/lvm.h +++ b/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.49 2018/02/19 20:06:56 roberto Exp roberto $ +** $Id: lvm.h,v 2.50 2018/02/21 12:54:26 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -64,17 +64,17 @@ /* -** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, +** fast track for 'gettable': if 't' is a table and 't[k]' is present, ** return 1 with 'slot' pointing to 't[k]' (position of final result). ** Otherwise, return 0 (meaning it will have to check metamethod) -** with 'slot' pointing to a nil 't[k]' (if 't' is a table) or NULL +** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL ** (otherwise). 'f' is the raw get function to use. */ #define luaV_fastget(L,t,k,slot,f) \ (!ttistable(t) \ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ : (slot = f(hvalue(t), k), /* else, do raw access */ \ - !ttisnil(slot))) /* result not nil? */ + !isempty(slot))) /* result not empty? */ /* @@ -86,7 +86,7 @@ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ : (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \ ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ - !ttisnil(slot))) /* result not nil? */ + !isempty(slot))) /* result not empty? */ /*