diff --git a/include/lua.h b/include/lua.h index 769d472..334b2c7 100644 --- a/include/lua.h +++ b/include/lua.h @@ -148,7 +148,8 @@ LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API size_t (lua_objlen) (lua_State *L, int idx); // Cobalt-compatible length +LUA_API size_t (lua_totalobjlen) (lua_State *L, int idx); // PUC-compatible length LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); diff --git a/src/lapi.c b/src/lapi.c index 39bf61b..5a71d84 100644 --- a/src/lapi.c +++ b/src/lapi.c @@ -381,6 +381,32 @@ LUA_API size_t lua_objlen (lua_State *L, int idx) { } } +LUA_API size_t lua_totalobjlen (lua_State *L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TSTRING: return tsvalue(o)->len; + case LUA_TUSERDATA: return uvalue(o)->len; + case LUA_TTABLE: { + Table* t = hvalue(o); + size_t n; + for (n = t->sizearray; n > 0; --n) { + if (ttype(luaH_getnum(t, n)) != LUA_TNIL) { + return n; + } + } + return 0; + } + case LUA_TNUMBER: { + size_t l; + lua_lock(L); /* `luaV_tostring' may create a new string */ + l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0); + lua_unlock(L); + return l; + } + default: return 0; + } +} + LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2adr(L, idx); diff --git a/src/lauxlib.c b/src/lauxlib.c index c9c98e5..a70379e 100644 --- a/src/lauxlib.c +++ b/src/lauxlib.c @@ -393,7 +393,7 @@ LUALIB_API int luaL_igetn (lua_State *L, int t, int ictx) { } lua_pop(L, 2); } - return (int)lua_objlen(L, t); + return (int)lua_totalobjlen(L, t); } #endif diff --git a/src/ltable.c b/src/ltable.c index ec84f4f..fced7eb 100644 --- a/src/ltable.c +++ b/src/ltable.c @@ -558,21 +558,23 @@ static int unbound_search (Table *t, unsigned int j) { ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { - unsigned int j = t->sizearray; - if (j > 0 && ttisnil(&t->array[j - 1])) { - /* there is a boundary in the array part: (binary) search for it */ - unsigned int i = 0; - while (j - i > 1) { - unsigned int m = (i+j)/2; - if (ttisnil(&t->array[m - 1])) j = m; - else i = m; + /* Algorithm from Cobalt */ + unsigned int a = t->sizearray; + unsigned int n, m = 0; + n = a + 1; + while (ttype(luaH_getnum(t, n)) != LUA_TNIL) { + m = n; + n += a + sizenode(t) + 1; + } + while (n > m + 1) { + unsigned int k = (n + m) / 2; + if (ttype(luaH_getnum(t, k)) != LUA_TNIL) { + m = k; + } else { + n = k; } - return i; } - /* else must find a boundary in hash part */ - else if (t->node == dummynode) /* hash part is empty? */ - return j; /* that is easy... */ - else return unbound_search(t, j); + return m; } diff --git a/src/lua.h b/src/lua.h index 8759ada..75c9692 100644 --- a/src/lua.h +++ b/src/lua.h @@ -148,7 +148,8 @@ LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API size_t (lua_objlen) (lua_State *L, int idx); // Cobalt-compatible length +LUA_API size_t (lua_totalobjlen) (lua_State *L, int idx); // PUC-compatible length LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);