From 16b5070c0cd56e10c5074eb9903dbc3ae4e15a61 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Tue, 8 Oct 2024 18:42:39 +0200 Subject: Sprinkling StackIndex all over the place --- src/cancel.cpp | 10 ++-- src/compat.cpp | 20 +++---- src/compat.h | 48 ++++++++-------- src/debug.h | 4 +- src/deep.cpp | 24 ++++---- src/deep.h | 6 +- src/intercopycontext.cpp | 82 +++++++++++++-------------- src/intercopycontext.h | 4 +- src/keeper.cpp | 88 ++++++++++++++--------------- src/keeper.h | 10 ++-- src/lane.cpp | 140 ++++++++++++++++++++++++----------------------- src/lane.h | 6 +- src/lanes.cpp | 68 +++++++++++------------ src/linda.cpp | 52 +++++++++--------- src/linda.h | 2 +- src/lindafactory.cpp | 6 +- src/luaerrors.h | 6 +- src/macros_and_utils.h | 5 +- src/nameof.cpp | 18 +++--- src/state.cpp | 6 +- src/tools.cpp | 50 ++++++++--------- src/tools.h | 6 +- src/unique.hpp | 22 +++++--- src/uniquekey.h | 24 ++++---- src/universe.cpp | 47 ++++++++-------- 25 files changed, 384 insertions(+), 370 deletions(-) (limited to 'src') diff --git a/src/cancel.cpp b/src/cancel.cpp index 15a2c83..2cd3c53 100644 --- a/src/cancel.cpp +++ b/src/cancel.cpp @@ -103,7 +103,7 @@ CancelOp WhichCancelOp(std::string_view const& opString_) // ################################################################################################# -[[nodiscard]] static CancelOp WhichCancelOp(lua_State* const L_, int const idx_) +[[nodiscard]] static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_) { if (luaG_type(L_, idx_) == LuaType::STRING) { std::string_view const _str{ luaG_tostring(L_, idx_) }; @@ -141,8 +141,8 @@ LUAG_FUNC(cancel_test) // bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lane]) LUAG_FUNC(thread_cancel) { - Lane* const _lane{ ToLane(L_, 1) }; - CancelOp const _op{ WhichCancelOp(L_, 2) }; // this removes the op string from the stack + Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; + CancelOp const _op{ WhichCancelOp(L_, StackIndex{ 2 }) }; // this removes the op string from the stack int _hook_count{ 0 }; if (static_cast(_op) > static_cast(CancelOp::Soft)) { // hook is requested @@ -154,12 +154,12 @@ LUAG_FUNC(thread_cancel) } std::chrono::time_point _until{ std::chrono::time_point::max() }; - if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion + if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion lua_Duration const duration{ lua_tonumber(L_, 2) }; if (duration.count() >= 0.0) { _until = std::chrono::steady_clock::now() + std::chrono::duration_cast(duration); } else { - raise_luaL_argerror(L_, 2, "duration cannot be < 0"); + raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); } lua_remove(L_, 2); // argument is processed, remove it } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key diff --git a/src/compat.cpp b/src/compat.cpp index 4076aa6..1f8eaf9 100644 --- a/src/compat.cpp +++ b/src/compat.cpp @@ -5,10 +5,10 @@ // ################################################################################################# -int luaG_getalluservalues(lua_State* const L_, int const idx_) +int luaG_getalluservalues(lua_State* const L_, StackIndex const idx_) { STACK_CHECK_START_REL(L_, 0); - int const _idx{ luaG_absindex(L_, idx_) }; + StackIndex const _idx{ luaG_absindex(L_, idx_) }; int _nuv{ 0 }; do { // we don't know how many uservalues we are going to extract, there might be a lot... @@ -27,12 +27,12 @@ int luaG_getalluservalues(lua_State* const L_, int const idx_) LuaType luaG_getmodule(lua_State* const L_, std::string_view const& name_) { STACK_CHECK_START_REL(L_, 0); - LuaType _type{ luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil + LuaType _type{ luaG_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil STACK_CHECK(L_, 1); return _type; } - _type = luaG_getfield(L_, -1, name_); // L_: _R._LOADED {module}|nil + _type = luaG_getfield(L_, kIdxTop, name_); // L_: _R._LOADED {module}|nil lua_remove(L_, -2); // L_: {module}|nil STACK_CHECK(L_, 1); return _type; @@ -45,17 +45,17 @@ LuaType luaG_getmodule(lua_State* const L_, std::string_view const& name_) // ################################################################################################# // Copied from Lua 5.2 loadlib.c -int luaL_getsubtable(lua_State* L_, int idx_, const char* fname_) +int luaL_getsubtable(lua_State* const L_, StackIndex const idx_, char const* fname_) { lua_getfield(L_, idx_, fname_); if (lua_istable(L_, -1)) return 1; /* table already there */ else { lua_pop(L_, 1); /* remove previous result */ - idx_ = luaG_absindex(L_, idx_); + StackIndex const _absidx{ luaG_absindex(L_, idx_) }; lua_newtable(L_); lua_pushvalue(L_, -1); /* copy to be left at top */ - lua_setfield(L_, idx_, fname_); /* assign new table to field */ + lua_setfield(L_, _absidx, fname_); /* assign new table to field */ return 0; /* false, because did not find table there */ } } @@ -66,7 +66,7 @@ void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, in lua_pushcfunction(L_, openf_); lua_pushstring(L_, modname_); /* argument to open function */ lua_call(L_, 1, 1); /* open module */ - luaL_getsubtable(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + luaL_getsubtable(L_, kIdxRegistry, LUA_LOADED_TABLE); lua_pushvalue(L_, -2); /* make copy of module (call result) */ lua_setfield(L_, -2, modname_); /* _LOADED[modname] = module */ lua_pop(L_, 1); /* remove _LOADED table */ @@ -92,7 +92,7 @@ void* lua_newuserdatauv(lua_State* L_, size_t sz_, [[maybe_unused]] int nuvalue_ // ################################################################################################# // push on stack uservalue #n of full userdata at idx -int lua_getiuservalue(lua_State* const L_, int const idx_, int const n_) +int lua_getiuservalue(lua_State* const L_, StackIndex const idx_, int const n_) { STACK_CHECK_START_REL(L_, 0); // full userdata can have only 1 uservalue before 5.4 @@ -129,7 +129,7 @@ int lua_getiuservalue(lua_State* const L_, int const idx_, int const n_) // Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index. // Returns 0 if the userdata does not have that value. -int lua_setiuservalue(lua_State* L_, int idx_, int n_) +int lua_setiuservalue(lua_State* const L_, StackIndex const idx_, int const n_) { if (n_ > 1 #if LUA_VERSION_NUM == 501 diff --git a/src/compat.h b/src/compat.h index 8b3eb98..90e72a3 100644 --- a/src/compat.h +++ b/src/compat.h @@ -32,6 +32,10 @@ // ################################################################################################# +static constexpr StackIndex kIdxRegistry{ LUA_REGISTRYINDEX }; + +// ################################################################################################# + // a strong-typed wrapper over lua types to see them easier in a debugger enum class LuaType { @@ -53,13 +57,13 @@ enum class LuaType // add some Lua 5.3-style API when building for Lua 5.1 #if LUA_VERSION_NUM == 501 -inline size_t lua_rawlen(lua_State* L_, int idx_) +inline size_t lua_rawlen(lua_State* L_, StackIndex idx_) { return lua_objlen(L_, idx_); } void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, int glb_); // implementation copied from Lua 5.2 sources -int luaL_getsubtable(lua_State* L_, int idx_, const char* fname_); +int luaL_getsubtable(lua_State* L_, StackIndex idx_, const char* fname_); #endif // LUA_VERSION_NUM == 501 @@ -80,8 +84,8 @@ inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_) #if LUA_VERSION_NUM < 504 void* lua_newuserdatauv(lua_State* L_, size_t sz_, int nuvalue_); -int lua_getiuservalue(lua_State* L_, int idx_, int n_); -int lua_setiuservalue(lua_State* L_, int idx_, int n_); +int lua_getiuservalue(lua_State* L_, StackIndex idx_, int n_); +int lua_setiuservalue(lua_State* L_, StackIndex idx_, int n_); #define LUA_GNAME "_G" @@ -92,7 +96,7 @@ int lua_setiuservalue(lua_State* L_, int idx_, int n_); // wrap Lua 5.4 calls under Lua 5.1 API when it is simpler that way #if LUA_VERSION_NUM == 504 -inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_) +inline int luaL_optint(lua_State* L_, StackIndex n_, lua_Integer d_) { return static_cast(luaL_optinteger(L_, n_, d_)); } @@ -123,7 +127,7 @@ inline constexpr LuaError ToLuaError(int const rc_) // ################################################################################################# // break lexical order for that one because it's needed below -inline LuaType luaG_type(lua_State* const L_, int const idx_) +inline LuaType luaG_type(lua_State* const L_, StackIndex const idx_) { return static_cast(lua_type(L_, idx_)); } @@ -135,9 +139,9 @@ inline LuaType luaG_type(lua_State* const L_, int const idx_) // ################################################################################################# // use this in place of lua_absindex to save a function call -inline int luaG_absindex(lua_State* L_, int idx_) +inline StackIndex luaG_absindex(lua_State* const L_, StackIndex const idx_) { - return (((idx_) >= 0 || (idx_) <= LUA_REGISTRYINDEX) ? (idx_) : lua_gettop(L_) + (idx_) + 1); + return StackIndex{ (idx_ >= 0 || idx_ <= kIdxRegistry) ? idx_ : lua_gettop(L_) + idx_ + 1 }; } // ################################################################################################# @@ -171,7 +175,7 @@ static inline int luaG_dump(lua_State* const L_, lua_Writer const writer_, void* // ################################################################################################# -int luaG_getalluservalues(lua_State* L_, int idx_); +int luaG_getalluservalues(lua_State* L_, StackIndex idx_); // ################################################################################################# @@ -184,7 +188,7 @@ concept RequiresOldLuaGetfield = requires(LUA_GETFIELD f_) }; template -static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, int const idx_, std::string_view const& name_) +static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, StackIndex const idx_, std::string_view const& name_) { f_(L_, idx_, name_.data()); return lua_type(L_, -1); @@ -201,14 +205,14 @@ concept RequiresNewLuaGetfield = requires(LUA_GETFIELD f_) }; template -static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, int const idx_, std::string_view const& name_) +static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, StackIndex const idx_, std::string_view const& name_) { return f_(L_, idx_, name_.data()); } // ------------------------------------------------------------------------------------------------- -static inline LuaType luaG_getfield(lua_State* const L_, int const idx_, std::string_view const& name_) +static inline LuaType luaG_getfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_) { return static_cast(WrapLuaGetField(lua_getfield, L_, idx_, name_)); } @@ -306,14 +310,14 @@ inline void luaG_pushglobaltable(lua_State* const L_) #ifdef LUA_GLOBALSINDEX // All flavors of Lua 5.1 ::lua_pushvalue(L_, LUA_GLOBALSINDEX); #else // LUA_GLOBALSINDEX - ::lua_rawgeti(L_, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); + ::lua_rawgeti(L_, kIdxRegistry, LUA_RIDX_GLOBALS); #endif // LUA_GLOBALSINDEX } // ################################################################################################# -inline void luaG_setfield(lua_State* const L_, int const idx_, char const* k_) = delete; -inline void luaG_setfield(lua_State* const L_, int const idx_, std::string_view const& k_) +inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, char const* k_) = delete; +inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, std::string_view const& k_) { lua_setfield(L_, idx_, k_.data()); } @@ -336,7 +340,7 @@ inline void luaG_setmetatable(lua_State* const L_, std::string_view const& tname // a small helper to extract a full userdata pointer from the stack in a safe way template -[[nodiscard]] T* luaG_tofulluserdata(lua_State* const L_, int const index_) +[[nodiscard]] T* luaG_tofulluserdata(lua_State* const L_, StackIndex const index_) { LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_type(L_, index_) == LUA_TUSERDATA); return static_cast(lua_touserdata(L_, index_)); @@ -345,7 +349,7 @@ template // ------------------------------------------------------------------------------------------------- template -[[nodiscard]] auto luaG_tolightuserdata(lua_State* const L_, int const index_) +[[nodiscard]] auto luaG_tolightuserdata(lua_State* const L_, StackIndex const index_) { LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_islightuserdata(L_, index_)); if constexpr (std::is_pointer_v) { @@ -364,7 +368,7 @@ template // ------------------------------------------------------------------------------------------------- -[[nodiscard]] inline std::string_view luaG_typename(lua_State* const L_, int const idx_) +[[nodiscard]] inline std::string_view luaG_typename(lua_State* const L_, StackIndex const idx_) { return luaG_typename(L_, luaG_type(L_, idx_)); } @@ -375,21 +379,21 @@ template #define STRINGVIEW_FMT "%.*s" // a replacement of lua_tolstring -[[nodiscard]] inline std::string_view luaG_tostring(lua_State* const L_, int const idx_) +[[nodiscard]] inline std::string_view luaG_tostring(lua_State* const L_, StackIndex const idx_) { size_t _len{ 0 }; char const* _str{ lua_tolstring(L_, idx_, &_len) }; return _str ? std::string_view{ _str, _len } : ""; } -[[nodiscard]] inline std::string_view luaG_checkstring(lua_State* const L_, int const idx_) +[[nodiscard]] inline std::string_view luaG_checkstring(lua_State* const L_, StackIndex const idx_) { size_t _len{ 0 }; char const* _str{ luaL_checklstring(L_, idx_, &_len) }; return std::string_view{ _str, _len }; } -[[nodiscard]] inline std::string_view luaG_optstring(lua_State* const L_, int const idx_, std::string_view const& default_) +[[nodiscard]] inline std::string_view luaG_optstring(lua_State* const L_, StackIndex const idx_, std::string_view const& default_) { if (lua_isnoneornil(L_, idx_)) { return default_; @@ -406,7 +410,7 @@ inline std::string_view luaG_pushstring(lua_State* const L_, std::string_view co if constexpr (LUA_VERSION_NUM == 501) { // lua_pushlstring doesn't return a value in Lua 5.1 lua_pushlstring(L_, str_.data(), str_.size()); - return luaG_tostring(L_, -1); + return luaG_tostring(L_, kIdxTop); } else { return std::string_view{ lua_pushlstring(L_, str_.data(), str_.size()), str_.size() }; } diff --git a/src/debug.h b/src/debug.h index 0f5c6bc..b9a82f1 100644 --- a/src/debug.h +++ b/src/debug.h @@ -36,8 +36,8 @@ class StackChecker int oldtop; public: - using Relative = Unique; - using Absolute = Unique; + DECLARE_UNIQUE_TYPE(Relative, int); + DECLARE_UNIQUE_TYPE(Absolute, int); StackChecker(lua_State* const L_, Relative const offset_, SourceLocation const& where_ = Where()) : L{ L_ } diff --git a/src/deep.cpp b/src/deep.cpp index bac011f..a244f8b 100644 --- a/src/deep.cpp +++ b/src/deep.cpp @@ -70,7 +70,7 @@ namespace { */ [[nodiscard]] static int DeepGC(lua_State* const L_) { - DeepPrelude* const* const _proxy{ luaG_tofulluserdata(L_, 1) }; + DeepPrelude* const* const _proxy{ luaG_tofulluserdata(L_, StackIndex{ 1 }) }; DeepPrelude* const _p{ *_proxy }; // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded @@ -130,7 +130,7 @@ void DeepFactory::DeleteDeepObject(lua_State* const L_, DeepPrelude* const o_) // ################################################################################################# -bool DeepFactory::IsDeepUserdata(lua_State* const L_, int const idx_) +bool DeepFactory::IsDeepUserdata(lua_State* const L_, StackIndex const idx_) { return LookupFactory(L_, idx_, LookupMode::LaneBody) != nullptr; } @@ -138,7 +138,7 @@ bool DeepFactory::IsDeepUserdata(lua_State* const L_, int const idx_) // ################################################################################################# // Return the registered factory for 'index' (deep userdata proxy), or nullptr if 'index' is not a deep userdata proxy. -DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, int const index_, LookupMode const mode_) +DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, StackIndex const index_, LookupMode const mode_) { // when looking inside a keeper, we are 100% sure the object is a deep userdata if (mode_ == LookupMode::FromKeeper) { @@ -159,7 +159,7 @@ DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, int const index_, L // replace metatable with the factory pointer, if it is actually a deep userdata LookupDeep(L_); // L_: deep ... factory|nil - DeepFactory* const _ret{ luaG_tolightuserdata(L_, -1) }; // nullptr if not a userdata + DeepFactory* const _ret{ luaG_tolightuserdata(L_, kIdxTop) }; // nullptr if not a userdata lua_pop(L_, 1); STACK_CHECK(L_, 0); return _ret; @@ -207,7 +207,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_, if (lua_isnil(L_, -1)) { // No metatable yet. lua_pop(L_, 1); // L_: DPC proxy - int const _oldtop{ lua_gettop(L_) }; + StackIndex const _oldtop{ lua_gettop(L_) }; // 1 - make one and register it if (mode_ != LookupMode::ToKeeper) { _factory.createMetatable(L_); // L_: DPC proxy metatable @@ -216,7 +216,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_, raise_luaL_error(errL_, "Bad DeepFactory::createMetatable overload: unexpected pushed value"); } // if the metatable contains a __gc, we will call it from our own - std::ignore = luaG_getfield(L_, -1, "__gc"); // L_: DPC proxy metatable __gc + std::ignore = luaG_getfield(L_, kIdxTop, "__gc"); // L_: DPC proxy metatable __gc } else { // keepers need a minimal metatable that only contains our own __gc lua_createtable(L_, 0, 1); // L_: DPC proxy metatable @@ -245,7 +245,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_, } luaG_pushstring(L_, _modname); // L_: DPC proxy metatable require() "module" - if (luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) != LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED + if (luaG_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) != LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED // no L.registry._LOADED; can this ever happen? lua_pop(L_, 6); // L_: raise_luaL_error(errL_, "unexpected error while requiring a module identified by DeepFactory::moduleName"); @@ -263,7 +263,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_, LuaError const _require_result{ lua_pcall(L_, 1, 0, 0) }; // L_: DPC proxy metatable error? if (_require_result != LuaError::OK) { // failed, raise the error in the proper state - raise_luaL_error(errL_, luaG_tostring(L_, -1)); + raise_luaL_error(errL_, luaG_tostring(L_, kIdxTop)); } } } else { // already loaded, we are happy @@ -272,7 +272,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_, } } STACK_CHECK(L_, 3); // L_: DPC proxy metatable - LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::USERDATA); + LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::USERDATA); LUA_ASSERT(L_, lua_istable(L_, -1)); lua_setmetatable(L_, -2); // L_: DPC proxy @@ -281,7 +281,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_, lua_pushvalue(L_, -2); // L_: DPC proxy deep proxy lua_rawset(L_, -4); // L_: DPC proxy lua_remove(L_, -2); // L_: proxy - LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::USERDATA); + LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::USERDATA); STACK_CHECK(L_, 1); } @@ -306,7 +306,7 @@ void DeepFactory::pushDeepUserdata(DestState const L_, int const nuv_) const { STACK_GROW(L_, 1); STACK_CHECK_START_REL(L_, 0); - int const _oldtop{ lua_gettop(L_) }; + StackIndex const _oldtop{ lua_gettop(L_) }; DeepPrelude* const _prelude{ newDeepObjectInternal(L_) }; if (_prelude == nullptr) { raise_luaL_error(L_, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)"); @@ -365,7 +365,7 @@ void DeepFactory::storeDeepLookup(lua_State* const L_) const * Reference count is not changed, and access to the deep userdata is not * serialized. It is the module's responsibility to prevent conflicting usage. */ -DeepPrelude* DeepFactory::toDeep(lua_State* const L_, int const index_) const +DeepPrelude* DeepFactory::toDeep(lua_State* const L_, StackIndex const index_) const { STACK_CHECK_START_REL(L_, 0); // ensure it is actually a deep userdata we created diff --git a/src/deep.h b/src/deep.h index c4c6fd7..d919f64 100644 --- a/src/deep.h +++ b/src/deep.h @@ -66,11 +66,11 @@ class DeepFactory public: // NVI: public interface static void DeleteDeepObject(lua_State* L_, DeepPrelude* o_); - [[nodiscard]] static bool IsDeepUserdata(lua_State* const L_, int const idx_); - [[nodiscard]] static DeepFactory* LookupFactory(lua_State* L_, int index_, LookupMode mode_); + [[nodiscard]] static bool IsDeepUserdata(lua_State* const L_, StackIndex const idx_); + [[nodiscard]] static DeepFactory* LookupFactory(lua_State* L_, StackIndex index_, LookupMode mode_); static void PushDeepProxy(DestState L_, DeepPrelude* o_, int nuv_, LookupMode mode_, lua_State* errL_); void pushDeepUserdata(DestState L_, int nuv_) const; - [[nodiscard]] DeepPrelude* toDeep(lua_State* L_, int index_) const; + [[nodiscard]] DeepPrelude* toDeep(lua_State* L_, StackIndex index_) const; }; // ################################################################################################# diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index e29132d..d21995c 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp @@ -100,7 +100,7 @@ THE SOFTWARE. lua_pushvalue(L1, L1_i); // L1: ... v ... {} v lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n" } - std::string_view _fqn{ luaG_tostring(L1, -1) }; + std::string_view _fqn{ luaG_tostring(L1, kIdxTop) }; DEBUGSPEW_CODE(DebugSpew(U) << "function [C] " << _fqn << std::endl); // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ... @@ -108,11 +108,12 @@ THE SOFTWARE. if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function (but not for tables) // try to discover the name of the function we want to send kLaneNameRegKey.pushValue(L1); // L1: ... v ... lane_name - std::string_view const _from{ luaG_tostring(L1, -1) }; + std::string_view const _from{ luaG_tostring(L1, kIdxTop) }; lua_pushcfunction(L1, LG_nameof); // L1: ... v ... lane_name LG_nameof lua_pushvalue(L1, L1_i); // L1: ... v ... lane_name LG_nameof t lua_call(L1, 1, 2); // L1: ... v ... lane_name "type" "name"|nil - std::string_view const _typewhat{ (luaG_type(L1, -2) == LuaType::STRING) ? luaG_tostring(L1, -2) : luaG_typename(L1, -2) }; + StackIndex const _indexTypeWhat{ -2 }; + std::string_view const _typewhat{ (luaG_type(L1, _indexTypeWhat) == LuaType::STRING) ? luaG_tostring(L1, _indexTypeWhat) : luaG_typename(L1, _indexTypeWhat) }; // second return value can be nil if the table was not found // probable reason: the function was removed from the source Lua state before Lanes was required. std::string_view _what, _gotchaA, _gotchaB; @@ -123,7 +124,8 @@ THE SOFTWARE. } else { _gotchaA = ""; _gotchaB = ""; - _what = (luaG_type(L1, -1) == LuaType::STRING) ? luaG_tostring(L1, -1) : luaG_typename(L1, -1); + StackIndex const _indexWhat{ kIdxTop }; + _what = (luaG_type(L1, _indexWhat) == LuaType::STRING) ? luaG_tostring(L1, _indexWhat) : luaG_typename(L1, _indexWhat); } raise_luaL_error(L1, "%s%s '%s' not found in %s origin transfer database.%s", _typewhat.data(), _gotchaA.data(), _what.data(), _from.empty() ? "main" : _from.data(), _gotchaB.data()); } @@ -139,15 +141,15 @@ THE SOFTWARE. static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull }; // get a unique ID for metatable at [i]. -[[nodiscard]] static lua_Integer get_mt_id(Universe* U_, lua_State* L_, int idx_) +[[nodiscard]] static lua_Integer get_mt_id(Universe* U_, lua_State* L_, StackIndex const idx_) { - idx_ = luaG_absindex(L_, idx_); + StackIndex const _absidx{ luaG_absindex(L_, idx_) }; STACK_GROW(L_, 3); STACK_CHECK_START_REL(L_, 0); std::ignore = kMtIdRegKey.getSubTable(L_, 0, 0); // L_: ... _R[kMtIdRegKey] - lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt} + lua_pushvalue(L_, _absidx); // L_: ... _R[kMtIdRegKey] {mt} lua_rawget(L_, -2); // L_: ... _R[kMtIdRegKey] mtk? lua_Integer _id{ lua_tointeger(L_, -1) }; // 0 for nil @@ -158,12 +160,12 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull }; _id = U_->nextMetatableId.fetch_add(1, std::memory_order_relaxed); // Create two-way references: id_uint <-> table - lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt} + lua_pushvalue(L_, _absidx); // L_: ... _R[kMtIdRegKey] {mt} lua_pushinteger(L_, _id); // L_: ... _R[kMtIdRegKey] {mt} id lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey] lua_pushinteger(L_, _id); // L_: ... _R[kMtIdRegKey] id - lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] id {mt} + lua_pushvalue(L_, _absidx); // L_: ... _R[kMtIdRegKey] id {mt} lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey] } lua_pop(L_, 1); // L_: ... @@ -223,7 +225,7 @@ void InterCopyContext::copyFunction() const } { - std::string_view const _bytecode{ luaG_tostring(L1, -1) }; // L1: ... b + std::string_view const _bytecode{ luaG_tostring(L1, kIdxTop) }; // L1: ... b LUA_ASSERT(L1, !_bytecode.empty()); STACK_GROW(L2, 2); // Note: Line numbers seem to be taken precisely from the @@ -282,7 +284,7 @@ void InterCopyContext::copyFunction() const STACK_CHECK(L1, 0); // Set upvalues (originally set to 'nil' by 'lua_load') - for (int const _func_index{ lua_gettop(L2) - _n }; _n > 0; --_n) { + for (StackIndex const _func_index{ lua_gettop(L2) - _n }; _n > 0; --_n) { // assign upvalue, popping it from the stack [[maybe_unused]] std::string_view const _upname{ lua_setupvalue(L2, _func_index, _n) };// L2: ... {cache} ... function LUA_ASSERT(L1, !_upname.empty()); // not having enough slots? @@ -325,10 +327,10 @@ void InterCopyContext::lookupNativeFunction() const // anything other than function or table should not happen! if (!lua_isfunction(L2, -1) && !lua_istable(L2, -1)) { kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name - std::string_view const _from{ luaG_tostring(L1, -1) }; + std::string_view const _from{ luaG_tostring(L1, kIdxTop) }; lua_pop(L1, 1); // L1: ... f ... kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name - std::string_view const _to{ luaG_tostring(L2, -1) }; + std::string_view const _to{ luaG_tostring(L2, kIdxTop) }; lua_pop(L2, 1); // L2: {} f raise_luaL_error( getErrL(), @@ -433,17 +435,17 @@ void InterCopyContext::copyCachedFunction() const return false; } else if (!lua_istable(L2, -1)) { // this can happen if someone decides to replace same already registered item (for a example a standard lib function) with a table kLaneNameRegKey.pushValue(L1); // L1: ... t ... lane_name - std::string_view const _from{ luaG_tostring(L1, -1) }; + std::string_view const _from{ luaG_tostring(L1, kIdxTop) }; lua_pop(L1, 1); // L1: ... t ... kLaneNameRegKey.pushValue(L2); // L1: ... t ... L2: {} t lane_name - std::string_view const _to{ luaG_tostring(L2, -1) }; + std::string_view const _to{ luaG_tostring(L2, kIdxTop) }; lua_pop(L2, 1); // L1: ... t ... L2: {} t raise_luaL_error( getErrL(), "%s: source table '%s' found as %s in %s destination transfer database.", _from.empty() ? "main" : _from.data(), _fqn.data(), - luaG_typename(L2, -1).data(), + luaG_typename(L2, kIdxTop).data(), _to.empty() ? "main" : _to.data()); } lua_remove(L2, -2); // L1: ... t ... L2: t @@ -490,13 +492,13 @@ void InterCopyContext::interCopyKeyValuePair() const _valPath = (char*) alloca(name.size() + 32 + 3); // +3 for [] and terminating 0 sprintf(_valPath, "%s[" LUA_NUMBER_FMT "]", name.data(), key); } else if (luaG_type(L1, _key_i) == LuaType::LIGHTUSERDATA) { - void* const key{ lua_touserdata(L1, _key_i) }; + void* const _key{ lua_touserdata(L1, _key_i) }; _valPath = (char*) alloca(name.size() + 16 + 5); // +5 for [U:] and terminating 0 - sprintf(_valPath, "%s[U:%p]", name.data(), key); + sprintf(_valPath, "%s[U:%p]", name.data(), _key); } else if (luaG_type(L1, _key_i) == LuaType::BOOLEAN) { - int const key{ lua_toboolean(L1, _key_i) }; + int const _key{ lua_toboolean(L1, _key_i) }; _valPath = (char*) alloca(name.size() + 8); // +8 for [], 'false' and terminating 0 - sprintf(_valPath, "%s[%s]", name.data(), key ? "true" : "false"); + sprintf(_valPath, "%s[%s]", name.data(), _key ? "true" : "false"); } } @@ -533,7 +535,7 @@ LuaType InterCopyContext::processConversion() const } // we have a metatable // L1: ... mt static constexpr std::string_view kConvertField{ "__lanesconvert" }; - LuaType const _converterType{ luaG_getfield(L1, -1, kConvertField) }; // L1: ... mt kConvertField + LuaType const _converterType{ luaG_getfield(L1, kIdxTop, kConvertField) }; // L1: ... mt kConvertField switch (_converterType) { case LuaType::NIL: // no __lanesconvert, nothing to do @@ -541,7 +543,7 @@ LuaType InterCopyContext::processConversion() const break; case LuaType::LIGHTUSERDATA: - if (kNilSentinel.equals(L1, -1)) { + if (kNilSentinel.equals(L1, kIdxTop)) { DEBUGSPEW_CODE(DebugSpew(U) << "converted " << luaG_typename(L1, _val_type) << " to nil" << std::endl); lua_replace(L1, L1_i); // L1: ... mt lua_pop(L1, 1); // L1: ... @@ -553,7 +555,7 @@ LuaType InterCopyContext::processConversion() const case LuaType::STRING: // kConvertField == "decay" -> replace source value with it's pointer - if (std::string_view const _mode{ luaG_tostring(L1, -1) }; _mode == "decay") { + if (std::string_view const _mode{ luaG_tostring(L1, kIdxTop) }; _mode == "decay") { lua_pop(L1, 1); // L1: ... mt lua_pushlightuserdata(L1, const_cast(lua_topointer(L1, L1_i))); // L1: ... mt decayed lua_replace(L1, L1_i); // L1: ... mt @@ -592,7 +594,7 @@ LuaType InterCopyContext::processConversion() const } STACK_CHECK(L1, 1); - lua_Integer const _mt_id{ get_mt_id(U, L1, -1) }; // Unique id for the metatable + lua_Integer const _mt_id{ get_mt_id(U, L1, kIdxTop) }; // Unique id for the metatable STACK_CHECK_START_REL(L2, 0); STACK_GROW(L2, 4); @@ -693,7 +695,7 @@ LuaType InterCopyContext::processConversion() const } // no __lanesclone? -> not clonable - if (luaG_getfield(L1, -1, "__lanesclone") == LuaType::NIL) { // L1: ... mt nil + if (luaG_getfield(L1, kIdxTop, "__lanesclone") == LuaType::NIL) { // L1: ... mt nil lua_pop(L1, 2); // L1: ... STACK_CHECK(L1, 0); return false; @@ -703,7 +705,7 @@ LuaType InterCopyContext::processConversion() const // we need to copy over the uservalues of the userdata as well { - int const _mt{ luaG_absindex(L1, -2) }; // L1: ... mt __lanesclone + StackIndex const _mt{ luaG_absindex(L1, StackIndex{ -2 }) }; // L1: ... mt __lanesclone size_t const userdata_size{ lua_rawlen(L1, _L1_i) }; // extract all the uservalues, but don't transfer them yet int const _nuv{ luaG_getalluservalues(L1, _L1_i) }; // L1: ... mt __lanesclone [uv]* @@ -738,13 +740,13 @@ LuaType InterCopyContext::processConversion() const // assign uservalues int _uvi{ _nuv }; while (_uvi > 0) { - _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; + _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) }; if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... u uv raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); } lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]* // this pops the value from the stack - lua_setiuservalue(L2, -2, _uvi); // L2: ... u + lua_setiuservalue(L2, StackIndex{ -2 }, _uvi); // L2: ... u --_uvi; } // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination @@ -792,11 +794,11 @@ LuaType InterCopyContext::processConversion() const // transfer all uservalues of the source in the destination { InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name }; - int const _clone_i{ lua_gettop(L2) }; + StackIndex const _clone_i{ lua_gettop(L2) }; STACK_GROW(L2, _nuv); int _uvi{ _nuv }; while (_uvi) { - _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; + _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) }; if (_c.interCopyOne() != InterCopyResult::Success) { // L1: ... deep ... [uv]* L2: deep uv raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); } @@ -862,7 +864,7 @@ LuaType InterCopyContext::processConversion() const _source = lua_touserdata(L1, -1); void* _clone{ nullptr }; // get the number of bytes to allocate for the clone - size_t const userdata_size{ lua_rawlen(L1, -1) }; + size_t const userdata_size{ lua_rawlen(L1, kIdxTop) }; { // extract uservalues (don't transfer them yet) int const _nuv{ luaG_getalluservalues(L1, source_i) }; // L1: ... u [uv]* @@ -880,13 +882,13 @@ LuaType InterCopyContext::processConversion() const InterCopyContext _c{ *this }; int _uvi{ _nuv }; while (_uvi > 0) { - _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; + _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) }; if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... mt u uv raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); } lua_pop(L1, 1); // L1: ... u [uv]* // this pops the value from the stack - lua_setiuservalue(L2, -2, _uvi); // L2: ... mt u + lua_setiuservalue(L2, StackIndex{ -2 }, _uvi); // L2: ... mt u --_uvi; } // when we are done, all uservalues are popped from the stack, we can pop the source as well @@ -897,7 +899,7 @@ LuaType InterCopyContext::processConversion() const // perform the custom cloning part lua_insert(L2, -2); // L2: ... u mt // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with - LuaType const _funcType{ luaG_getfield(L2, -1, "__lanesclone") }; // L2: ... u mt __lanesclone + LuaType const _funcType{ luaG_getfield(L2, kIdxTop, "__lanesclone") }; // L2: ... u mt __lanesclone if (_funcType != LuaType::FUNCTION) { raise_luaL_error(getErrL(), "INTERNAL ERROR: __lanesclone is a %s, not a function", luaG_typename(L2, _funcType).data()); } @@ -1191,7 +1193,7 @@ namespace { { private: lua_State* const L2; - int const top_L2; + StackIndex const top_L2; DEBUGSPEW_CODE(DebugSpewIndentScope scope); public: @@ -1246,7 +1248,7 @@ namespace { STACK_CHECK(L1, 0); } if (_result == InterCopyResult::Success) { - luaG_setfield(L2, -2, _entry); // set package[entry] + luaG_setfield(L2, StackIndex{ -2 }, _entry); // set package[entry] } else { std::string_view const _msg{ luaG_pushstring(L1, "failed to copy package.%s", _entry.data()) }; // raise the error when copying from lane to lane, else just leave it on the stack to be raised later @@ -1273,7 +1275,7 @@ namespace { DEBUGSPEW_CODE(DebugSpew(U) << "InterCopyContext::interCopy()" << std::endl); DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U }); - int const _top_L1{ lua_gettop(L1) }; + StackIndex const _top_L1{ lua_gettop(L1) }; int const _available{ (L1_i != 0) ? (_top_L1 - L1_i + 1) : _top_L1 }; if (n_ > _available) { // requesting to copy more than is available? @@ -1289,17 +1291,17 @@ namespace { * function entries, avoiding the same entries to be passed on as multiple * copies. ESSENTIAL i.e. for handling upvalue tables in the right manner! */ - int const _top_L2{ lua_gettop(L2) }; // L2: ... + StackIndex const _top_L2{ lua_gettop(L2) }; // L2: ... lua_newtable(L2); // L2: ... cache InterCopyContext _c{ U, L2, L1, CacheIndex{ _top_L2 + 1 }, {}, VT::NORMAL, mode, "?" }; InterCopyResult _copyok{ InterCopyResult::Success }; STACK_CHECK_START_REL(L1, 0); // if L1_i is specified, start here, else take the _n items off the top of the stack - for (int _i{ L1_i != 0 ? L1_i : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) { + for (StackIndex _i{ L1_i != 0 ? L1_i : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) { char _tmpBuf[16]; if (U->verboseErrors) { - sprintf(_tmpBuf, "arg_%d", _j); + sprintf(_tmpBuf, "arg_%d", _j.operator int()); _c.name = _tmpBuf; } _c.L1_i = SourceIndex{ _i }; diff --git a/src/intercopycontext.h b/src/intercopycontext.h index 8d4b68f..a9be267 100644 --- a/src/intercopycontext.h +++ b/src/intercopycontext.h @@ -23,8 +23,8 @@ enum class InterCopyResult // ################################################################################################# -using CacheIndex = Unique; -using SourceIndex = Unique; +DECLARE_UNIQUE_TYPE(CacheIndex, StackIndex); +DECLARE_UNIQUE_TYPE(SourceIndex, StackIndex); class InterCopyContext { public: diff --git a/src/keeper.cpp b/src/keeper.cpp index 58796b8..46f580b 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp @@ -82,10 +82,10 @@ class KeyUD [[nodiscard]] bool changeLimit(LindaLimit limit_); [[nodiscard]] static KeyUD* Create(KeeperState K_); - [[nodiscard]] static KeyUD* GetPtr(KeeperState K_, int idx_); + [[nodiscard]] static KeyUD* GetPtr(KeeperState K_, StackIndex idx_); void peek(KeeperState K_, int count_) const; // keepercall_get [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched] - void prepareAccess(KeeperState K_, int idx_) const; + void prepareAccess(KeeperState K_, StackIndex idx_) const; [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set void pushFillStatus(KeeperState K_) const; static void PushFillStatus(KeeperState K_, KeyUD const* key_); @@ -116,14 +116,14 @@ KeyUD* KeyUD::Create(KeeperState const K_) KeyUD* const _key{ new (K_) KeyUD{} }; STACK_CHECK(K_, 1); lua_newtable(K_); - lua_setiuservalue(K_, -2, kContentsTableIndex); + lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); STACK_CHECK(K_, 1); return _key; } // ################################################################################################# -KeyUD* KeyUD::GetPtr(KeeperState const K_, int idx_) +KeyUD* KeyUD::GetPtr(KeeperState const K_, StackIndex const idx_) { return luaG_tofulluserdata(K_, idx_); } @@ -137,7 +137,7 @@ KeyUD* KeyUD::GetPtr(KeeperState const K_, int idx_) void KeyUD::peek(KeeperState const K_, int const count_) const { STACK_CHECK_START_ABS(K_, 1); - LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); // K_: KeyUD + LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: KeyUD if (count <= 0) { // no data is available lua_pop(K_, 1); // K_: lua_pushinteger(K_, 0); // K_: 0 @@ -145,7 +145,7 @@ void KeyUD::peek(KeeperState const K_, int const count_) const } // read value off the fifo, if possible - prepareAccess(K_, -1); // K_: fifo + prepareAccess(K_, kIdxTop); // K_: fifo int const _count{ std::min(count_, count) }; lua_pushinteger(K_, _count); // K_: fifo _count lua_insert(K_, 1); // K_: _count fifo @@ -171,9 +171,9 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) return 0; } int const _popCount{ std::min(count, maxCount_) }; - LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); // K_: ... this - prepareAccess(K_, -1); // K_: ... fifo - int const _fifo_idx{ lua_gettop(K_) }; + LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: ... this + prepareAccess(K_, kIdxTop); // K_: ... fifo + StackIndex const _fifo_idx{ lua_gettop(K_) }; // each iteration pushes a value on the stack! STACK_GROW(K_, _popCount + 2); // skip first item, we will push it last @@ -202,9 +202,9 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) // expects 'this' at the specified index // replaces it by its uservalue on the stack (the table holding the fifo values) -void KeyUD::prepareAccess(KeeperState const K_, int const idx_) const +void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const { - int const _idx{ luaG_absindex(K_, idx_) }; + StackIndex const _idx{ luaG_absindex(K_, idx_) }; LUA_ASSERT(K_, KeyUD::GetPtr(K_, idx_) == this); // we can replace the key userdata in the stack without fear of it being GCed, there are other references around lua_getiuservalue(K_, _idx, kContentsTableIndex); @@ -217,7 +217,7 @@ void KeyUD::prepareAccess(KeeperState const K_, int const idx_) const // out: nothing, removes all pushed values from the stack bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_) { - int const _fifoIdx{ luaG_absindex(K_, -1 - count_) }; + StackIndex const _fifoIdx{ luaG_absindex(K_, StackIndex{ -1 - count_ }) }; LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val... if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room return false; @@ -270,13 +270,13 @@ void KeyUD::PushFillStatus(KeeperState const K_, KeyUD const* const key_) // expects 'this' on top of the stack bool KeyUD::reset(KeeperState const K_) { - LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); + LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); STACK_CHECK_START_REL(K_, 0); bool const _wasFull{ (limit > 0) && (count >= limit) }; // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged! // if we have an actual limit, use it to preconfigure the table lua_createtable(K_, (limit <= 0) ? 0 : limit, 0); // K_: KeysDB key val... KeyUD {} - lua_setiuservalue(K_, -2, kContentsTableIndex); // K_: KeysDB key val... KeyUD + lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD first = 1; count = 0; STACK_CHECK(K_, 0); @@ -290,20 +290,20 @@ bool KeyUD::reset(KeeperState const K_) // out: the KeysDB table of the linda is pushed at the top of the stack // xxh64 of string "kLindasRegKey" generated at https://www.pelock.com/products/hash-calculator static constexpr RegistryUniqueKey kLindasRegKey{ 0x3AE0D5243A88B962ull }; -static void PushKeysDB(KeeperState const K_, int const idx_) +static void PushKeysDB(KeeperState const K_, StackIndex const idx_) { STACK_GROW(K_, 5); STACK_CHECK_START_REL(K_, 0); - int const _idx{ luaG_absindex(K_, idx_) }; + StackIndex const _absidx{ luaG_absindex(K_, idx_) }; kLindasRegKey.pushValue(K_); // K_: ... LindasDB - lua_pushvalue(K_, _idx); // K_: ... LindasDB linda + lua_pushvalue(K_, _absidx); // K_: ... LindasDB linda lua_rawget(K_, -2); // K_: ... LindasDB KeysDB STACK_CHECK(K_, 2); if (lua_isnil(K_, -1)) { lua_pop(K_, 1); // K_: ... LindasDB // add a new KeysDB table for this linda lua_newtable(K_); // K_: ... LindasDB KeysDB - lua_pushvalue(K_, _idx); // K_: ... LindasDB KeysDB linda + lua_pushvalue(K_, _absidx); // K_: ... LindasDB KeysDB linda lua_pushvalue(K_, -2); // K_: ... LindasDB KeysDB linda KeysDB lua_rawset(K_, -4); // K_: ... LindasDB KeysDB } @@ -326,12 +326,12 @@ int keepercall_count(lua_State* const L_) switch (lua_gettop(_K)) { // no key is specified: return a table giving the count of all known keys case 1: // _K: linda - PushKeysDB(_K, 1); // _K: linda KeysDB + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda KeysDB lua_newtable(_K); // _K: linda KeysDB out lua_replace(_K, 1); // _K: out KeysDB lua_pushnil(_K); // _K: out KeysDB nil while (lua_next(_K, 2)) { // _K: out KeysDB key KeyUD - KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; lua_pop(_K, 1); // _K: out KeysDB key lua_pushvalue(_K, -1); // _K: out KeysDB key key lua_pushinteger(_K, _key->count); // _K: out KeysDB key key count @@ -342,13 +342,13 @@ int keepercall_count(lua_State* const L_) // 1 key is specified: return its count case 2: // _K: linda key - PushKeysDB(_K, 1); // _K: linda key KeysDB + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB lua_replace(_K, 1); // _K: KeysDB key lua_rawget(_K, -2); // _K: KeysDB KeyUD|nil if (lua_isnil(_K, -1)) { // the key is unknown // _K: KeysDB nil lua_remove(_K, -2); // _K: nil } else { // the key is known // _K: KeysDB KeyUD - KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; lua_pushinteger(_K, _key->count); // _K: KeysDB KeyUD count lua_replace(_K, -3); // _K: count KeyUD lua_pop(_K, 1); // _K: count @@ -358,14 +358,14 @@ int keepercall_count(lua_State* const L_) // a variable number of keys is specified: return a table of their counts default: // _K: linda keys... key#1 lua_pushvalue(_K, 2); // duplicate the first key of the list // _K: linda keys... key#1 - PushKeysDB(_K, 1); // _K: linda keys... key#1 KeysDB + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda keys... key#1 KeysDB lua_newtable(_K); // _K: linda keys... key#1 KeysDB out lua_replace(_K, 1); // _K: out keys... key#1 KeysDB lua_replace(_K, 2); // the list of keys is the same, but for key#1 moved at the end // _K: out KeysDB keys... while (lua_gettop(_K) > 2) { lua_pushvalue(_K, -1); // _K: out KeysDB keys... key lua_rawget(_K, 2); // _K: out KeysDB keys... KeyUD|nil - KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; lua_pop(_K, 1); // _K: out KeysDB keys... if (_key != nullptr) { // the key is known lua_pushinteger(_K, _key->count); // _K: out KeysDB keys... count @@ -410,11 +410,11 @@ int keepercall_get(lua_State* const L_) _count = static_cast(lua_tointeger(_K, 3)); // linda:get() made sure _count >= 1 lua_pop(_K, 1); // _K: linda key } - PushKeysDB(_K, 1); // _K: linda key KeysDB + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB lua_replace(_K, 1); // _K: KeysDB key lua_rawget(_K, 1); // _K: KeysDB KeyUD lua_remove(_K, 1); // _K: KeyUD - KeyUD const* const _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD const* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; if (_key != nullptr) { _key->peek(_K, _count); // _K: N val... } else { @@ -438,11 +438,11 @@ int keepercall_limit(lua_State* const L_) bool const _reading{ lua_gettop(_K) == 2 }; LindaLimit const _limit{ static_cast(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent lua_settop(_K, 2); // _K: linda key - PushKeysDB(_K, 1); // _K: linda key KeysDB + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB lua_replace(_K, 1); // _K: KeysDB key lua_pushvalue(_K, -1); // _K: KeysDB key key lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil - KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) }; if (_reading) { // remove any clutter on the stack lua_settop(_K, 0); // _K: @@ -476,14 +476,14 @@ int keepercall_limit(lua_State* const L_) int keepercall_receive(lua_State* const L_) { KeeperState const _K{ L_ }; - int const _top{ lua_gettop(_K) }; - PushKeysDB(_K, 1); // _K: linda keys... KeysDB + StackIndex const _top{ lua_gettop(_K) }; + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda keys... KeysDB lua_replace(_K, 1); // _K: KeysDB keys... - for (int const _keyIdx : std::ranges::iota_view{ 2, _top + 1 }) { + for (StackIndex const _keyIdx : std::ranges::iota_view{ StackIndex{ 2 }, _top + 1 }) { lua_pushvalue(_K, _keyIdx); // _K: KeysDB keys... key[i] lua_rawget(_K, 1); // _K: KeysDB keys... KeyUD - KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; if (_key != nullptr) { // it's fine to attempt a read on a key that wasn't yet written to int const _popped{ _key->pop(_K, 1, 1) }; // _K: KeysDB keys... val if (_popped > 0) { @@ -514,12 +514,12 @@ int keepercall_receive_batched(lua_State* const L_) int const _max_count{ static_cast(luaL_optinteger(_K, 4, _min_count)) }; lua_settop(_K, 2); // _K: linda key lua_insert(_K, 1); // _K: key linda - PushKeysDB(_K, 2); // _K: key linda KeysDB + PushKeysDB(_K, StackIndex{ 2 }); // _K: key linda KeysDB lua_remove(_K, 2); // _K: key KeysDB lua_pushvalue(_K, 1); // _K: key KeysDB key lua_rawget(_K, 2); // _K: key KeysDB KeyUD lua_remove(_K, 2); // _K: key KeyUD - KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; if (_key == nullptr || _key->pop(_K, _min_count, _max_count) == 0) { // _K: [key val...]|crap // Lua will adjust the stack for us when we return return 0; @@ -538,7 +538,7 @@ int keepercall_send(lua_State* const L_) KeeperState const _K{ L_ }; int const _n{ lua_gettop(_K) - 2 }; STACK_CHECK_START_REL(_K, 0); // _K: linda key val... - PushKeysDB(_K, 1); // _K: linda key val... KeysDB + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB // get the fifo associated to this key in this linda, create it if it doesn't exist lua_pushvalue(_K, 2); // _K: linda key val... KeysDB key lua_rawget(_K, -2); // _K: linda key val... KeysDB KeyUD|nil @@ -553,7 +553,7 @@ int keepercall_send(lua_State* const L_) lua_replace(_K, 2); // _K: linda KeyUD val... KeysDB lua_pop(_K, 1); // _K: linda KeyUD val... STACK_CHECK(_K, 0); - KeyUD* const _key{ KeyUD::GetPtr(_K, 2) }; + KeyUD* const _key{ KeyUD::GetPtr(_K, StackIndex{ 2 }) }; if (_key && _key->push(_K, _n, true)) { // not enough room? lua_settop(_K, 0); // _K: lua_pushboolean(_K, 1); // _K: true @@ -576,11 +576,11 @@ int keepercall_set(lua_State* const L_) STACK_GROW(_K, 6); // retrieve KeysDB associated with the linda - PushKeysDB(_K, 1); // _K: linda key val... KeysDB + PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB lua_replace(_K, 1); // _K: KeysDB key val... lua_pushvalue(_K, 2); // _K: KeysDB key val... key lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil - KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; + KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) }; if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! @@ -633,11 +633,11 @@ int keepercall_set(lua_State* const L_) * * Returns: number of return values (pushed to 'L'), unset in case of error */ -KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, int starting_index_) +KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua_State* const L_, Linda* const linda_, StackIndex const starting_index_) { KeeperCallResult _result; - int const _args{ starting_index_ ? (lua_gettop(L_) - starting_index_ + 1) : 0 }; // L: ... args... K_: - int const _top_K{ lua_gettop(K_) }; + StackIndex const _args{ starting_index_ ? (lua_gettop(L_) - starting_index_ + 1) : 0 }; // L: ... args... K_: + StackIndex const _top_K{ lua_gettop(K_) }; // if we didn't do anything wrong, the keeper stack should be clean LUA_ASSERT(L_, _top_K == 0); @@ -743,8 +743,8 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) InterCopyContext _c{ linda_.U, L_, SourceState{ _K }, {}, {}, {}, LookupMode::FromKeeper, {} }; lua_pushnil(_K); // _K: KeysDB nil L_: out while (lua_next(_K, -2)) { // _K: KeysDB key KeyUD L_: out - KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; - _key->prepareAccess(_K, -1); // _K: KeysDB key fifo L_: out + KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; + _key->prepareAccess(_K, kIdxTop); // _K: KeysDB key fifo L_: out lua_pushvalue(_K, -2); // _K: KeysDB key fifo key L_: out if (_c.interMove(1) != InterCopyResult::Success) { // _K: KeysDB key fifo L_: out key raise_luaL_error(L_, "Internal error reading Keeper contents"); @@ -928,7 +928,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, int const nbKeepers_, int // copy package.path and package.cpath from the source state if (luaG_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K: // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately - InterCopyContext _c{ U, DestState{ _K }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, -1) }, {}, LookupMode::ToKeeper, {} }; + InterCopyContext _c{ U, DestState{ _K }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, kIdxTop) }, {}, LookupMode::ToKeeper, {} }; if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K: // if something went wrong, the error message is at the top of the stack lua_remove(L, -2); // L_: settings error_msg diff --git a/src/keeper.h b/src/keeper.h index 04bf834..e505361 100644 --- a/src/keeper.h +++ b/src/keeper.h @@ -7,9 +7,9 @@ class Linda; enum class LookupMode; class Universe; -using KeeperState = Unique; -using LindaLimit = Unique; -using KeeperIndex = Unique; +DECLARE_UNIQUE_TYPE(KeeperState,lua_State*); +DECLARE_UNIQUE_TYPE(LindaLimit, int); +DECLARE_UNIQUE_TYPE(KeeperIndex, int); // ################################################################################################# @@ -86,5 +86,5 @@ using keeper_api_t = lua_CFunction; [[nodiscard]] int keepercall_send(lua_State* L_); [[nodiscard]] int keepercall_set(lua_State* L_); -using KeeperCallResult = Unique>; -[[nodiscard]] KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, int starting_index_); +DECLARE_UNIQUE_TYPE(KeeperCallResult, std::optional); +[[nodiscard]] KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, StackIndex starting_index_); diff --git a/src/lane.cpp b/src/lane.cpp index baba0fa..d4d409f 100644 --- a/src/lane.cpp +++ b/src/lane.cpp @@ -47,7 +47,7 @@ static constexpr UniqueKey kCachedTostring{ 0xAB5EA23BCEA0C35Cull }; // lane:get_threadname() static LUAG_FUNC(get_threadname) { - Lane* const _lane{ ToLane(L_, 1) }; + Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; luaL_argcheck(L_, lua_gettop(L_) == 1, 2, "too many arguments"); luaG_pushstring(L_, _lane->getDebugName()); return 1; @@ -70,7 +70,7 @@ static LUAG_FUNC(set_finalizer) // Get the current finalizer table (if any), create one if it doesn't exist std::ignore = kFinalizerRegKey.getSubTable(L_, 1, 0); // L_: finalizer {finalisers} // must cast to int, not lua_Integer, because LuaJIT signature of lua_rawseti is not the same as PUC-Lua. - int const _idx{ static_cast(lua_rawlen(L_, -1) + 1) }; + int const _idx{ static_cast(lua_rawlen(L_, kIdxTop) + 1) }; lua_pushvalue(L_, 1); // L_: finalizer {finalisers} finalizer lua_rawseti(L_, -2, _idx); // L_: finalizer {finalisers} // no need to adjust the stack, Lua does this for us @@ -85,12 +85,12 @@ static LUAG_FUNC(set_finalizer) static LUAG_FUNC(lane_threadname) { // C s_lane structure is a light userdata upvalue - Lane* const _lane{ luaG_tolightuserdata(L_, lua_upvalueindex(1)) }; + Lane* const _lane{ luaG_tolightuserdata(L_, StackIndex{ lua_upvalueindex(1) }) }; LUA_ASSERT(L_, L_ == _lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state if (lua_gettop(L_) == 1) { lua_settop(L_, 1); STACK_CHECK_START_REL(L_, 0); - _lane->changeDebugName(-1); + _lane->changeDebugName(kIdxTop); STACK_CHECK(L_, 0); return 0; } else if (lua_gettop(L_) == 0) { @@ -113,19 +113,19 @@ static LUAG_FUNC(lane_threadname) // static LUAG_FUNC(thread_join) { - Lane* const _lane{ ToLane(L_, 1) }; + Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; std::chrono::time_point _until{ std::chrono::time_point::max() }; - if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion + if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion lua_Duration const duration{ lua_tonumber(L_, 2) }; if (duration.count() >= 0.0) { _until = std::chrono::steady_clock::now() + std::chrono::duration_cast(duration); } else { - raise_luaL_argerror(L_, 2, "duration cannot be < 0"); + raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); } } else if (!lua_isnoneornil(L_, 2)) { - raise_luaL_argerror(L_, 2, "incorrect duration type"); + raise_luaL_argerror(L_, StackIndex{ 2 }, "incorrect duration type"); } lua_settop(L_, 1); // L_: lane @@ -150,7 +150,7 @@ static LUAG_FUNC(thread_join) if (_stored == 0) { raise_luaL_error(L_, _lane->L ? "First return value must be non-nil when using join()" : "Can't join() more than once or after indexing"); } - lua_getiuservalue(L_, 1, 1); // L_: lane {uv} + lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane {uv} for (int _i = 2; _i <= _stored; ++_i) { lua_rawgeti(L_, 2, _i); // L_: lane {uv} results2...N } @@ -163,7 +163,7 @@ static LUAG_FUNC(thread_join) case Lane::Error: { LUA_ASSERT(L_, _stored == 2 || _stored == 3); - lua_getiuservalue(L_, 1, 1); // L_: lane {uv} + lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane {uv} lua_rawgeti(L_, 2, 2); // L_: lane {uv} lua_rawgeti(L_, 2, 3); // L_: lane {uv} |nil if (lua_isnil(L_, -1)) { @@ -178,11 +178,11 @@ static LUAG_FUNC(thread_join) case Lane::Cancelled: LUA_ASSERT(L_, _stored == 2); - lua_getiuservalue(L_, 1, 1); // L_: lane {uv} + lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane {uv} lua_rawgeti(L_, 2, 2); // L_: lane {uv} cancel_error lua_rawgeti(L_, 2, 1); // L_: lane {uv} cancel_error nil lua_replace(L_, -3); // L_: lane nil cancel_error - LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, -1)); + LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, kIdxTop)); _ret = 2; break; @@ -199,8 +199,8 @@ static LUAG_FUNC(thread_join) LUAG_FUNC(thread_resume) { - static constexpr int kSelf{ 1 }; - Lane* const _lane{ ToLane(L_, kSelf) }; + static constexpr StackIndex kIdxSelf{ 1 }; + Lane* const _lane{ ToLane(L_, kIdxSelf) }; lua_State* const _L2{ _lane->L }; // wait until the lane yields @@ -225,7 +225,7 @@ LUAG_FUNC(thread_resume) STACK_CHECK_START_ABS(_L2, _nresults); // clear any fetched returned values that we might have stored previously - _lane->resetResultsStorage(L_, 1); + _lane->resetResultsStorage(L_, kIdxSelf); // to retrieve the yielded value of the coroutine on our stack InterCopyContext _cin{ _lane->U, DestState{ L_ }, SourceState{ _L2 }, {}, {}, {}, {}, {} }; @@ -254,9 +254,9 @@ LUAG_FUNC(thread_resume) // Else If key is found in the environment, return it static int thread_index_number(lua_State* L_) { - static constexpr int kSelf{ 1 }; + static constexpr StackIndex kIdxSelf{ 1 }; - Lane* const _lane{ ToLane(L_, kSelf) }; + Lane* const _lane{ ToLane(L_, kIdxSelf) }; LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane n int const _key{ static_cast(lua_tointeger(L_, 2)) }; lua_pop(L_, 1); // L_: lane @@ -284,13 +284,13 @@ static int thread_index_number(lua_State* L_) // Else raise an error static int thread_index_string(lua_State* L_) { - static constexpr int kSelf{ 1 }; - static constexpr int kKey{ 2 }; + static constexpr StackIndex kIdxSelf{ 1 }; + static constexpr StackIndex kIdxKey{ 2 }; - Lane* const _lane{ ToLane(L_, kSelf) }; + Lane* const _lane{ ToLane(L_, kIdxSelf) }; LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane "key" - std::string_view const _keystr{ luaG_tostring(L_, kKey) }; + std::string_view const _keystr{ luaG_tostring(L_, kIdxKey) }; lua_settop(L_, 2); // keep only our original arguments on the stack if (_keystr == "status") { _lane->pushStatusString(L_); // L_: lane "key" "" @@ -301,7 +301,7 @@ static int thread_index_string(lua_State* L_) return 1; } // return self.metatable[key] - lua_getmetatable(L_, kSelf); // L_: lane "key" mt + lua_getmetatable(L_, kIdxSelf); // L_: lane "key" mt lua_replace(L_, -3); // L_: mt "key" lua_rawget(L_, -2); // L_: mt value // only "cancel" and "join" are registered as functions, any other string will raise an error @@ -316,9 +316,9 @@ static int thread_index_string(lua_State* L_) // lane:__index(key,usr) -> value static LUAG_FUNC(thread_index) { - static constexpr int kSelf{ 1 }; - static constexpr int kKey{ 2 }; - Lane* const _lane{ ToLane(L_, kSelf) }; + static constexpr StackIndex kIdxSelf{ 1 }; + static constexpr StackIndex kKey{ 2 }; + Lane* const _lane{ ToLane(L_, kIdxSelf) }; LUA_ASSERT(L_, lua_gettop(L_) == 2); switch (luaG_type(L_, kKey)) { @@ -329,17 +329,17 @@ static LUAG_FUNC(thread_index) return thread_index_string(L_); // stack modification is undefined, returned value is at the top default: // unknown key - lua_getmetatable(L_, kSelf); // L_: mt + lua_getmetatable(L_, kIdxSelf); // L_: mt kCachedError.pushKey(L_); // L_: mt kCachedError lua_rawget(L_, -2); // L_: mt error() - if (luaG_type(L_, -1) != LuaType::FUNCTION) { - raise_luaL_error(L_, "INTERNAL ERROR: cached error() is a %s, not a function", luaG_typename(L_, -1).data()); + if (luaG_type(L_, kIdxTop) != LuaType::FUNCTION) { + raise_luaL_error(L_, "INTERNAL ERROR: cached error() is a %s, not a function", luaG_typename(L_, kIdxTop).data()); } luaG_pushstring(L_, "Unknown key: "); // L_: mt error() "Unknown key: " kCachedTostring.pushKey(L_); // L_: mt error() "Unknown key: " kCachedTostring lua_rawget(L_, -4); // L_: mt error() "Unknown key: " tostring() - if (luaG_type(L_, -1) != LuaType::FUNCTION) { - raise_luaL_error(L_, "INTERNAL ERROR: cached tostring() is a %s, not a function", luaG_typename(L_, -1).data()); + if (luaG_type(L_, kIdxTop) != LuaType::FUNCTION) { + raise_luaL_error(L_, "INTERNAL ERROR: cached tostring() is a %s, not a function", luaG_typename(L_, kIdxTop).data()); } lua_pushvalue(L_, kKey); // L_: mt error() "Unknown key: " tostring() k lua_call(L_, 1, 1); // L_: mt error() "Unknown key: " "k" @@ -417,7 +417,7 @@ int Lane::LuaErrorHandler(lua_State* L_) // Don't do stack survey for cancelled lanes. // - if (kCancelError.equals(L_, 1)) { + if (kCancelError.equals(L_, StackIndex{ 1 })) { return 1; // just pass on } @@ -436,6 +436,7 @@ int Lane::LuaErrorHandler(lua_State* L_) // table of { "sourcefile.lua:", ... } // lua_newtable(L_); // L_: some_error {} + StackIndex const kIdxTraceTbl{ luaG_absindex(L_, kIdxTop) }; // Best to start from level 1, but in some cases it might be a C function // and we don't get '.currentline' for that. It's okay - just keep level @@ -446,27 +447,27 @@ int Lane::LuaErrorHandler(lua_State* L_) lua_getinfo(L_, _extended ? "Sln" : "Sl", &_ar); if (_extended) { lua_newtable(L_); // L_: some_error {} {} - + StackIndex const kIdxFrameTbl{ luaG_absindex(L_, kIdxTop) }; lua_pushstring(L_, _ar.source); // L_: some_error {} {} source - luaG_setfield(L_, -2, std::string_view{ "source" }); // L_: some_error {} {} + luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "source" }); // L_: some_error {} {} lua_pushinteger(L_, _ar.currentline); // L_: some_error {} {} currentline - luaG_setfield(L_, -2, std::string_view{ "currentline" }); // L_: some_error {} {} + luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "currentline" }); // L_: some_error {} {} lua_pushstring(L_, _ar.name ? _ar.name : ""); // L_: some_error {} {} name - luaG_setfield(L_, -2, std::string_view{ "name" }); // L_: some_error {} {} + luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "name" }); // L_: some_error {} {} lua_pushstring(L_, _ar.namewhat); // L_: some_error {} {} namewhat - luaG_setfield(L_, -2, std::string_view{ "namewhat" }); // L_: some_error {} {} + luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "namewhat" }); // L_: some_error {} {} lua_pushstring(L_, _ar.what); // L_: some_error {} {} what - luaG_setfield(L_, -2, std::string_view{ "what" }); // L_: some_error {} {} + luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "what" }); // L_: some_error {} {} } else if (_ar.currentline > 0) { luaG_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); // L_: some_error {} "blah:blah" } else { luaG_pushstring(L_, "%s:?", _ar.short_src); // L_: some_error {} "blah" } - lua_rawseti(L_, -2, static_cast(_n)); // L_: some_error {} + lua_rawseti(L_, kIdxTraceTbl, static_cast(_n)); // L_: some_error {} } // store the stack trace table in the registry @@ -480,10 +481,10 @@ int Lane::LuaErrorHandler(lua_State* L_) // ########################################## Finalizer ############################################ // ################################################################################################# -[[nodiscard]] static int PushStackTrace(lua_State* const L_, Lane::ErrorTraceLevel const errorTraceLevel_, LuaError const rc_, [[maybe_unused]] int const stk_base_) +[[nodiscard]] static int PushStackTrace(lua_State* const L_, Lane::ErrorTraceLevel const errorTraceLevel_, LuaError const rc_, [[maybe_unused]] StackIndex const stk_base_) { // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry - int const _top{ lua_gettop(L_) }; + StackIndex const _top{ lua_gettop(L_) }; switch (rc_) { case LuaError::OK: // no error, body return values are on the stack break; @@ -499,7 +500,7 @@ int Lane::LuaErrorHandler(lua_State* L_) // For cancellation the error message is kCancelError, and a stack trace isn't placed // For other errors, the message can be whatever was thrown, and we should have a stack trace table - LUA_ASSERT(L_, luaG_type(L_, 1 + stk_base_) == (kCancelError.equals(L_, stk_base_) ? LuaType::NIL : LuaType::TABLE)); + LUA_ASSERT(L_, luaG_type(L_, StackIndex{ 1 + stk_base_ }) == (kCancelError.equals(L_, stk_base_) ? LuaType::NIL : LuaType::TABLE)); // Just leaving the stack trace table on the stack is enough to get it through to the master. } else { // any kind of error can be thrown with error(), or through a lane/linda cancellation @@ -544,7 +545,7 @@ int Lane::LuaErrorHandler(lua_State* L_) STACK_GROW(_L, 5); - int const _finalizers{ lua_gettop(_L) }; + StackIndex const _finalizers{ lua_gettop(_L) }; // always push something as error handler, to have the same stack structure int const _error_handler{ (errorTraceLevel_ != Lane::Minimal) ? (lua_pushcfunction(_L, Lane::LuaErrorHandler), lua_gettop(_L)) @@ -581,7 +582,8 @@ int Lane::LuaErrorHandler(lua_State* L_) // if no error from the main body, finalizer doesn't receive any argument, else it gets the error message and optional stack trace _rc = ToLuaError(lua_pcall(_L, _args, 0, _error_handler)); // _L: ... finalizers error_handler() err_msg2? if (_rc != LuaError::OK) { - _finalizer_pushed = 1 + PushStackTrace(_L, errorTraceLevel_, _rc, lua_gettop(_L)); // _L: ... finalizers error_handler() err_msg2? trace + StackIndex const _top{ lua_gettop(_L) }; + _finalizer_pushed = 1 + PushStackTrace(_L, errorTraceLevel_, _rc, _top); // _L: ... finalizers error_handler() err_msg2? trace // If one finalizer fails, don't run the others. Return this // as the 'real' error, replacing what we could have had (or not) // from the actual code. @@ -610,7 +612,7 @@ int Lane::LuaErrorHandler(lua_State* L_) if (lane_->isCoroutine()) { // only the coroutine thread should remain on the master state when we are done - LUA_ASSERT(_L, lua_gettop(_L) == 1 && luaG_type(_L, 1) == LuaType::THREAD); + LUA_ASSERT(_L, lua_gettop(_L) == 1 && luaG_type(_L, StackIndex{ 1 }) == LuaType::THREAD); } return _rc; @@ -670,7 +672,7 @@ static void PrepareLaneHelpers(Lane* const lane_) lua_State* const _L{ lane_->L }; // Tie "set_finalizer()" to the state lua_pushcfunction(_L, LG_set_finalizer); - tools::PopulateFuncLookupTable(_L, -1, "set_finalizer"); + tools::PopulateFuncLookupTable(_L, kIdxTop, "set_finalizer"); lua_setglobal(_L, "set_finalizer"); // Tie "lane_threadname()" to the state @@ -681,7 +683,7 @@ static void PrepareLaneHelpers(Lane* const lane_) // Tie "cancel_test()" to the state lua_pushcfunction(_L, LG_cancel_test); - tools::PopulateFuncLookupTable(_L, -1, "cancel_test"); + tools::PopulateFuncLookupTable(_L, kIdxTop, "cancel_test"); lua_setglobal(_L, "cancel_test"); } @@ -752,7 +754,7 @@ static void lane_main(Lane* const lane_) } // in case of error and if it exists, fetch stack trace from registry and push it - lane_->nresults += PushStackTrace(_L, lane_->errorTraceLevel, _rc, 1); // L: retvals|error [trace] + lane_->nresults += PushStackTrace(_L, lane_->errorTraceLevel, _rc, StackIndex{ 1 }); // L: retvals|error [trace] DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " body: " << GetErrcodeName(_rc) << " (" << (kCancelError.equals(_L, 1) ? "cancelled" : luaG_typename(_L, 1)) << ")" << std::endl); // Call finalizers, if the script has set them up. @@ -782,7 +784,7 @@ static void lane_main(Lane* const lane_) } // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them - Lane::Status const _st{ (_rc == LuaError::OK) ? Lane::Done : kCancelError.equals(_L, 1) ? Lane::Cancelled : Lane::Error }; + Lane::Status const _st{ (_rc == LuaError::OK) ? Lane::Done : kCancelError.equals(_L, StackIndex{ 1 }) ? Lane::Cancelled : Lane::Error }; // 'doneMutex' protects the -> Done|Error|Cancelled state change, and the Running|Suspended|Resuming state change too std::lock_guard _guard{ lane_->doneMutex }; lane_->status = _st; @@ -794,7 +796,7 @@ static void lane_main(Lane* const lane_) #if LUA_VERSION_NUM >= 504 static LUAG_FUNC(lane_close) { - [[maybe_unused]] Lane* const _lane{ ToLane(L_, 1) }; // L_: lane err|nil + [[maybe_unused]] Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane err|nil // drop the error if any lua_settop(L_, 1); // L_: lane @@ -823,10 +825,10 @@ static LUAG_FUNC(lane_close) static LUAG_FUNC(lane_gc) { bool _have_gc_cb{ false }; - Lane* const _lane{ ToLane(L_, 1) }; // L_: ud + Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: ud // if there a gc callback? - lua_getiuservalue(L_, 1, 1); // L_: ud uservalue + lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: ud uservalue kLaneGC.pushKey(L_); // L_: ud uservalue __gc lua_rawget(L_, -2); // L_: ud uservalue gc_cb|nil if (!lua_isnil(L_, -1)) { @@ -932,7 +934,7 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono: // ################################################################################################# -[[nodiscard]] CancelResult Lane::cancelHard(std::chrono::time_point until_, bool wakeLane_) +[[nodiscard]] CancelResult Lane::cancelHard(std::chrono::time_point const until_, bool const wakeLane_) { cancelRequest = CancelRequest::Hard; // it's now signaled to stop // lane_->thread.get_stop_source().request_stop(); @@ -949,7 +951,7 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono: // ################################################################################################# -[[nodiscard]] CancelResult Lane::cancelSoft(std::chrono::time_point until_, bool wakeLane_) +[[nodiscard]] CancelResult Lane::cancelSoft(std::chrono::time_point const until_, bool const wakeLane_) { cancelRequest = CancelRequest::Soft; // it's now signaled to stop // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own @@ -966,9 +968,9 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono: // ################################################################################################# -void Lane::changeDebugName(int const nameIdx_) +void Lane::changeDebugName(StackIndex const nameIdx_) { - int const _nameIdx{ luaG_absindex(L, nameIdx_) }; + StackIndex const _nameIdx{ luaG_absindex(L, nameIdx_) }; luaL_checktype(L, _nameIdx, LUA_TSTRING); // L: ... "name" ... STACK_CHECK_START_REL(L, 0); // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... @@ -1064,11 +1066,11 @@ void Lane::pushStatusString(lua_State* L_) const void Lane::pushIndexedResult(lua_State* const L_, int const key_) const { - static constexpr int kSelf{ 1 }; - LUA_ASSERT(L_, ToLane(L_, kSelf) == this); // L_: lane ... + static constexpr StackIndex kIdxSelf{ 1 }; + LUA_ASSERT(L_, ToLane(L_, kIdxSelf) == this); // L_: lane ... STACK_GROW(L_, 3); - lua_getiuservalue(L_, kSelf, 1); // L_: lane ... {uv} + lua_getiuservalue(L_, kIdxSelf, 1); // L_: lane ... {uv} if (status != Lane::Error) { lua_rawgeti(L_, -1, key_); // L_: lane ... {uv} uv[i] lua_remove(L_, -2); // L_: lane ... uv[i] @@ -1083,7 +1085,7 @@ void Lane::pushIndexedResult(lua_State* const L_, int const key_) const lua_remove(L_, -2); // L_: lane ... return; } - lua_getmetatable(L_, kSelf); // L_: lane ... {uv} {mt} + lua_getmetatable(L_, kIdxSelf); // L_: lane ... {uv} {mt} lua_replace(L_, -3); // L_: lane ... {mt} // Note: Lua 5.1 interpreter is not prepared to show // non-string errors, so we use 'tostring()' here @@ -1127,11 +1129,11 @@ void Lane::pushIndexedResult(lua_State* const L_, int const key_) const // replace the current uservalue (a table holding the returned values of the lane body) // by a new empty one, but transfer the gc_cb that is stored in there so that it is not lost -void Lane::resetResultsStorage(lua_State* const L_, int const self_idx_) +void Lane::resetResultsStorage(lua_State* const L_, StackIndex const self_idx_) { STACK_GROW(L_, 4); STACK_CHECK_START_REL(L_, 0); - int const _self_idx{ luaG_absindex(L_, self_idx_) }; + StackIndex const _self_idx{ luaG_absindex(L_, self_idx_) }; LUA_ASSERT(L_, ToLane(L_, _self_idx) == this); // L_: ... self ... // create the new table lua_newtable(L_); // L_: ... self ... {} @@ -1154,12 +1156,12 @@ void Lane::resetResultsStorage(lua_State* const L_, int const self_idx_) // ################################################################################################# // intern the debug name in the caller lua state so that the pointer remains valid after the lane's state is closed -void Lane::securizeDebugName(lua_State* L_) +void Lane::securizeDebugName(lua_State* const L_) { STACK_CHECK_START_REL(L_, 0); STACK_GROW(L_, 3); // a Lane's uservalue should be a table - lua_getiuservalue(L_, 1, 1); // L_: lane ... {uv} + lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane ... {uv} LUA_ASSERT(L_, lua_istable(L_, -1)); // we don't care about the actual key, so long as it's unique and can't collide with anything. lua_newtable(L_); // L_: lane ... {uv} {} @@ -1174,7 +1176,7 @@ void Lane::securizeDebugName(lua_State* L_) // ################################################################################################# -void Lane::startThread(int priority_) +void Lane::startThread(int const priority_) { thread = std::thread([this]() { lane_main(this); }); if (priority_ != kThreadPrioDefault) { @@ -1189,12 +1191,12 @@ void Lane::startThread(int priority_) // t[i] = result #i int Lane::storeResults(lua_State* const L_) { - static constexpr int kSelf{ 1 }; - LUA_ASSERT(L_, ToLane(L_, kSelf) == this); + static constexpr StackIndex kIdxSelf{ 1 }; + LUA_ASSERT(L_, ToLane(L_, kIdxSelf) == this); STACK_CHECK_START_REL(L_, 0); - lua_getiuservalue(L_, kSelf, 1); // L_: lane ... {uv} - int const _tidx{ lua_gettop(L_) }; + lua_getiuservalue(L_, kIdxSelf, 1); // L_: lane ... {uv} + StackIndex const _tidx{ lua_gettop(L_) }; int _stored{}; if (nresults == 0) { @@ -1252,7 +1254,7 @@ int Lane::storeResults(lua_State* const L_) case Lane::Cancelled: _stored = 2; // we should have a single value, kCancelError, in the stack of L - LUA_ASSERT(L_, nresults == 1 && lua_gettop(L) == 1 && kCancelError.equals(L, 1)); + LUA_ASSERT(L_, nresults == 1 && lua_gettop(L) == 1 && kCancelError.equals(L, StackIndex{ 1 })); // store nil, cancel_error in the results lua_pushnil(L_); // L_: lane ... {uv} nil lua_rawseti(L_, _tidx, 1); // L_: lane ... {uv} diff --git a/src/lane.h b/src/lane.h index 85994a0..388ac71 100644 --- a/src/lane.h +++ b/src/lane.h @@ -146,7 +146,7 @@ class Lane public: CancelResult cancel(CancelOp op_, int hookCount_, std::chrono::time_point until_, bool wakeLane_); - void changeDebugName(int const nameIdx_); + void changeDebugName(StackIndex nameIdx_); void closeState() { lua_State* _L{ S }; @@ -173,7 +173,7 @@ class Lane static void PushMetatable(lua_State* L_); void pushStatusString(lua_State* L_) const; void pushIndexedResult(lua_State* L_, int key_) const; - void resetResultsStorage(lua_State* const L_, int gc_cb_idx_); + void resetResultsStorage(lua_State* L_, StackIndex self_idx_); void selfdestructAdd(); [[nodiscard]] bool selfdestructRemove(); void securizeDebugName(lua_State* L_); @@ -190,7 +190,7 @@ class Lane // 'Lane' are malloc/free'd and the handle only carries a pointer. // This is not deep userdata since the handle is not portable among lanes. // -[[nodiscard]] inline Lane* ToLane(lua_State* L_, int i_) +[[nodiscard]] inline Lane* ToLane(lua_State* const L_, StackIndex const i_) { return *(static_cast(luaL_checkudata(L_, i_, kLaneMetatableName))); } diff --git a/src/lanes.cpp b/src/lanes.cpp index c820568..3aef572 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp @@ -169,12 +169,12 @@ LUAG_FUNC(sleep) lua_pushcfunction(L_, LG_linda_receive); // L_: duration|nil receive() STACK_CHECK_START_REL(L_, 0); // we pushed the function we intend to call, now prepare the arguments _U->timerLinda->push(L_); // L_: duration|nil receive() timerLinda - if (luaG_tostring(L_, 1) == "indefinitely") { + if (luaG_tostring(L_, StackIndex{ 1 }) == "indefinitely") { lua_pushnil(L_); // L_: duration? receive() timerLinda nil } else if (lua_isnoneornil(L_, 1)) { lua_pushnumber(L_, 0); // L_: duration? receive() timerLinda 0 } else if (!lua_isnumber(L_, 1)) { - raise_luaL_argerror(L_, 1, "invalid duration"); + raise_luaL_argerror(L_, StackIndex{ 1 }, "invalid duration"); } else { lua_pushnumber(L_, lua_tonumber(L_, 1)); // L_: duration? receive() timerLinda duration @@ -193,7 +193,7 @@ LUAG_FUNC(sleep) // upvalue[1]: _G.require LUAG_FUNC(require) { - std::string_view const _name{ luaG_tostring(L_, 1) }; // L_: "name" ... + std::string_view const _name{ luaG_tostring(L_, StackIndex{ 1 }) }; // L_: "name" ... int const _nargs{ lua_gettop(L_) }; DEBUGSPEW_CODE(Universe * _U{ Universe::Get(L_) }); STACK_CHECK_START_REL(L_, 0); @@ -202,7 +202,7 @@ LUAG_FUNC(require) lua_pushvalue(L_, lua_upvalueindex(1)); // L_: "name" ... require lua_insert(L_, 1); // L_: require "name" ... lua_call(L_, _nargs, 1); // L_: module - tools::PopulateFuncLookupTable(L_, -1, _name); + tools::PopulateFuncLookupTable(L_, kIdxTop, _name); DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.require '" << _name << "' END" << std::endl); STACK_CHECK(L_, 0); return 1; @@ -215,8 +215,8 @@ LUAG_FUNC(require) // lanes.register( "modname", module) LUAG_FUNC(register) { - std::string_view const _name{ luaG_checkstring(L_, 1) }; - LuaType const _mod_type{ luaG_type(L_, 2) }; + std::string_view const _name{ luaG_checkstring(L_, StackIndex{ 1 }) }; + LuaType const _mod_type{ luaG_type(L_, StackIndex{ 2 }) }; // ignore extra arguments, just in case lua_settop(L_, 2); luaL_argcheck(L_, (_mod_type == LuaType::TABLE) || (_mod_type == LuaType::FUNCTION), 2, "unexpected module type"); @@ -224,7 +224,7 @@ LUAG_FUNC(register) STACK_CHECK_START_REL(L_, 0); // "name" mod_table DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' BEGIN" << std::endl); DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); - tools::PopulateFuncLookupTable(L_, -1, _name); + tools::PopulateFuncLookupTable(L_, kIdxTop, _name); DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' END" << std::endl); STACK_CHECK(L_, 0); return 0; @@ -249,17 +249,17 @@ LUAG_FUNC(register) // LUAG_FUNC(lane_new) { - static constexpr int kFuncIdx{ 1 }; - static constexpr int kLibsIdx{ 2 }; - static constexpr int kPrioIdx{ 3 }; - static constexpr int kGlobIdx{ 4 }; - static constexpr int kPackIdx{ 5 }; - static constexpr int kRequIdx{ 6 }; - static constexpr int kGcCbIdx{ 7 }; - static constexpr int kNameIdx{ 8 }; - static constexpr int kErTlIdx{ 9 }; - static constexpr int kAsCoro{ 10 }; - static constexpr int kFixedArgsIdx{ 10 }; + static constexpr StackIndex kFuncIdx{ 1 }; + static constexpr StackIndex kLibsIdx{ 2 }; + static constexpr StackIndex kPrioIdx{ 3 }; + static constexpr StackIndex kGlobIdx{ 4 }; + static constexpr StackIndex kPackIdx{ 5 }; + static constexpr StackIndex kRequIdx{ 6 }; + static constexpr StackIndex kGcCbIdx{ 7 }; + static constexpr StackIndex kNameIdx{ 8 }; + static constexpr StackIndex kErTlIdx{ 9 }; + static constexpr StackIndex kAsCoro{ 10 }; + static constexpr StackIndex kFixedArgsIdx{ 10 }; int const _nargs{ lua_gettop(L_) - kFixedArgsIdx }; LUA_ASSERT(L_, _nargs >= 0); @@ -342,7 +342,7 @@ LUAG_FUNC(lane_new) lua_newtable(L); // L: ... lane {uv} // Store the gc_cb callback in the uservalue - int const _gc_cb_idx{ lua_isnoneornil(L, kGcCbIdx) ? 0 : kGcCbIdx }; + StackIndex const _gc_cb_idx{ lua_isnoneornil(L, kGcCbIdx) ? 0 : kGcCbIdx }; if (_gc_cb_idx > 0) { kLaneGC.pushKey(L); // L: ... lane {uv} k lua_pushvalue(L, _gc_cb_idx); // L: ... lane {uv} k gc_cb @@ -350,11 +350,11 @@ LUAG_FUNC(lane_new) } STACK_CHECK(L, 2); // store the uservalue in the Lane full userdata - lua_setiuservalue(L, -2, 1); // L: ... lane + lua_setiuservalue(L, StackIndex{ -2 }, 1); // L: ... lane lua_State* const _L2{ lane->L }; STACK_CHECK_START_REL(_L2, 0); - int const _name_idx{ lua_isnoneornil(L, kNameIdx) ? 0 : kNameIdx }; + StackIndex const _name_idx{ lua_isnoneornil(L, kNameIdx) ? 0 : kNameIdx }; std::string_view const _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} }; if (!_debugName.empty()) { @@ -366,7 +366,7 @@ LUAG_FUNC(lane_new) lua_getinfo(L, ">S", &_ar); // L: ... lane luaG_pushstring(_L2, "%s:%d", _ar.short_src, _ar.linedefined); // L: ... lane L2: "" } - lane->changeDebugName(-1); + lane->changeDebugName(kIdxTop); lua_pop(_L2, 1); // L: ... lane L2: } STACK_CHECK(_L2, 0); @@ -412,7 +412,7 @@ LUAG_FUNC(lane_new) STACK_CHECK_START_REL(L_, 0); // package - int const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? 0 : kPackIdx }; + StackIndex const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? 0 : kPackIdx }; if (_package_idx != 0) { DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: update 'package'" << std::endl); // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack @@ -424,7 +424,7 @@ LUAG_FUNC(lane_new) STACK_CHECK(_L2, 0); // modules to require in the target lane *before* the function is transfered! - int const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx }; + StackIndex const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx }; if (_required_idx != 0) { int _nbRequired{ 1 }; DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl); @@ -436,11 +436,11 @@ LUAG_FUNC(lane_new) lua_pushnil(L_); // L_: [fixed] args... nil L2: while (lua_next(L_, _required_idx) != 0) { // L_: [fixed] args... n "modname" L2: - if (luaG_type(L_, -1) != LuaType::STRING || luaG_type(L_, -2) != LuaType::NUMBER || lua_tonumber(L_, -2) != _nbRequired) { + if (luaG_type(L_, kIdxTop) != LuaType::STRING || luaG_type(L_, StackIndex{ -2 }) != LuaType::NUMBER || lua_tonumber(L_, -2) != _nbRequired) { raise_luaL_error(L_, "required module list should be a list of strings"); } else { // require the module in the target state, and populate the lookup table there too - std::string_view const _name{ luaG_tostring(L_, -1) }; + std::string_view const _name{ luaG_tostring(L_, kIdxTop) }; DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: require '" << _name << "'" << std::endl); // require the module in the target lane @@ -459,7 +459,7 @@ LUAG_FUNC(lane_new) } // here the module was successfully required // L_: [fixed] args... n "modname" L2: ret // after requiring the module, register the functions it exported in our name<->function database - tools::PopulateFuncLookupTable(_L2, -1, _name); + tools::PopulateFuncLookupTable(_L2, kIdxTop, _name); lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: } } @@ -473,7 +473,7 @@ LUAG_FUNC(lane_new) // Appending the specified globals to the global environment // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... // - int const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? 0 : kGlobIdx }; + StackIndex const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? 0 : kGlobIdx }; if (_globals_idx != 0) { DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer globals" << std::endl); if (!lua_istable(L_, _globals_idx)) { @@ -603,7 +603,7 @@ LUAG_FUNC(wakeup_conv) STACK_CHECK_START_REL(L_, 0); auto _readInteger = [L = L_](std::string_view const& name_) { - std::ignore = luaG_getfield(L, 1, name_); + std::ignore = luaG_getfield(L, StackIndex{ 1 }, name_); lua_Integer const val{ lua_tointeger(L, -1) }; lua_pop(L, 1); return static_cast(val); @@ -619,7 +619,7 @@ LUAG_FUNC(wakeup_conv) // If Lua table has '.isdst' we trust that. If it does not, we'll let // 'mktime' decide on whether the time is within DST or not (value -1). // - int const _isdst{ (luaG_getfield(L_, 1, "isdst") == LuaType::BOOLEAN) ? lua_toboolean(L_, -1) : -1 }; + int const _isdst{ (luaG_getfield(L_, StackIndex{ 1 }, "isdst") == LuaType::BOOLEAN) ? lua_toboolean(L_, -1) : -1 }; lua_pop(L_, 1); STACK_CHECK(L_, 0); @@ -682,8 +682,8 @@ LUAG_FUNC(configure) Universe* _U{ Universe::Get(L_) }; bool const _from_master_state{ _U == nullptr }; - std::string_view const _name{ luaG_checkstring(L_, lua_upvalueindex(1)) }; - LUA_ASSERT(L_, luaG_type(L_, 1) == LuaType::TABLE); + std::string_view const _name{ luaG_checkstring(L_, StackIndex{ lua_upvalueindex(1) }) }; + LUA_ASSERT(L_, luaG_type(L_, StackIndex{ 1 }) == LuaType::TABLE); STACK_GROW(L_, 4); STACK_CHECK_START_ABS(L_, 1); // L_: settings @@ -759,7 +759,7 @@ LUAG_FUNC(configure) // register all native functions found in that module in the transferable functions database // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) // for example in package.loaded["lanes.core"].* - tools::PopulateFuncLookupTable(L_, -1, _name); + tools::PopulateFuncLookupTable(L_, kIdxTop, _name); STACK_CHECK(L_, 2); // record all existing C/JIT-fast functions @@ -769,7 +769,7 @@ LUAG_FUNC(configure) // because we will do it after on_state_create() is called, // and we don't want to skip _G because of caching in case globals are created then luaG_pushglobaltable(L_); // L_: settings M _G - tools::PopulateFuncLookupTable(L_, -1, {}); + tools::PopulateFuncLookupTable(L_, kIdxTop, {}); lua_pop(L_, 1); // L_: settings M } lua_pop(L_, 1); // L_: settings diff --git a/src/linda.cpp b/src/linda.cpp index 3f5fd33..bd40f5e 100644 --- a/src/linda.cpp +++ b/src/linda.cpp @@ -280,7 +280,7 @@ void Linda::setName(std::string_view const& name_) LUAG_FUNC(linda_cancel) { Linda* const _linda{ ToLinda(L_, StackIndex{ 1 }) }; - std::string_view const _who{ luaG_optstring(L_, 2, "both") }; + std::string_view const _who{ luaG_optstring(L_, StackIndex{ 2 }, "both") }; // make sure we got 2 arguments: the linda and the cancellation mode luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); @@ -371,7 +371,7 @@ LUAG_FUNC(linda_count) CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ lua_gettop(L_) }); Keeper* const _keeper{ _linda->whichKeeper() }; - KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, 2) }; + KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, StackIndex{ 2 }) }; return OptionalValue(_pushed, L_, "tried to count an invalid key"); } }; @@ -435,7 +435,7 @@ LUAG_FUNC(linda_get) KeeperCallResult _pushed; if (_linda->cancelRequest == CancelRequest::None) { Keeper* const _keeper{ _linda->whichKeeper() }; - _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, 2); + _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, StackIndex{ 2 }); } else { // linda is cancelled // do nothing and return nil,lanes.cancel_error lua_pushnil(L_); @@ -468,10 +468,10 @@ LUAG_FUNC(linda_limit) int const _nargs{ lua_gettop(L_) }; luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); // make sure we got a numeric limit, or "unlimited", (or nothing) - bool const _unlimited{ luaG_tostring(L_, 3) == "unlimited" }; + bool const _unlimited{ luaG_tostring(L_, StackIndex{ 3 }) == "unlimited" }; LindaLimit const _val{ _unlimited ? std::numeric_limits::max() : LindaLimit{ static_cast(luaL_optinteger(L_, 3, 0)) } }; if (_val < 0) { - raise_luaL_argerror(L_, 3, "limit must be >= 0"); + raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0"); } // make sure the key is of a valid type CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); @@ -479,23 +479,23 @@ LUAG_FUNC(linda_limit) KeeperCallResult _pushed; if (_linda->cancelRequest == CancelRequest::None) { if (_unlimited) { - LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, 3) == "unlimited"); + LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, StackIndex{ 3 }) == "unlimited"); // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!) lua_pop(L_, 1); // L_: linda key lua_pushinteger(L_, -1); // L_: linda key nil } Keeper* const _keeper{ _linda->whichKeeper() }; - _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, 2); - LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 2) && luaG_type(L_, -1) == LuaType::STRING); + _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, StackIndex{ 2 }); + LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 2) && luaG_type(L_, kIdxTop) == LuaType::STRING); if (_nargs == 3) { // 3 args: setting the limit // changing the limit: no error, boolean value saying if we should wake blocked writer threads - LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::BOOLEAN); // L_: bool string + LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); // L_: bool string if (lua_toboolean(L_, -2)) { _linda->readHappened.notify_all(); // To be done from within the 'K' locking area } } else { // 2 args: reading the limit // reading the limit: a number >=0 or "unlimited" - LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::NUMBER || luaG_tostring(L_, -2) == "unlimited"); + LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::NUMBER || luaG_tostring(L_, StackIndex{ -2 }) == "unlimited"); } } else { // linda is cancelled // do nothing and return nil,lanes.cancel_error @@ -530,12 +530,12 @@ LUAG_FUNC(linda_receive) StackIndex _key_i{ 2 }; // index of first key, if timeout not there std::chrono::time_point _until{ std::chrono::time_point::max() }; - if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion + if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion lua_Duration const _duration{ lua_tonumber(L_, 2) }; if (_duration.count() >= 0.0) { _until = std::chrono::steady_clock::now() + std::chrono::duration_cast(_duration); } else { - raise_luaL_argerror(L_, 2, "duration cannot be < 0"); + raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); } ++_key_i; } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key @@ -555,14 +555,14 @@ LUAG_FUNC(linda_receive) // we expect a user-defined amount of return value _expected_pushed_min = (int) luaL_checkinteger(L_, _key_i + 1); if (_expected_pushed_min < 1) { - raise_luaL_argerror(L_, _key_i + 1, "bad min count"); + raise_luaL_argerror(L_, StackIndex{ _key_i + 1 }, "bad min count"); } _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min); // don't forget to count the key in addition to the values ++_expected_pushed_min; ++_expected_pushed_max; if (_expected_pushed_min > _expected_pushed_max) { - raise_luaL_argerror(L_, _key_i + 2, "batched min/max error"); + raise_luaL_argerror(L_, StackIndex{ _key_i + 2 }, "batched min/max error"); } } else { // make sure the keys are of a valid type @@ -686,12 +686,12 @@ LUAG_FUNC(linda_send) StackIndex _key_i{ 2 }; // index of first key, if timeout not there std::chrono::time_point _until{ std::chrono::time_point::max() }; - if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion + if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion lua_Duration const _duration{ lua_tonumber(L_, 2) }; if (_duration.count() >= 0.0) { _until = std::chrono::steady_clock::now() + std::chrono::duration_cast(_duration); } else { - raise_luaL_argerror(L_, 2, "duration cannot be < 0"); + raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0"); } ++_key_i; } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key @@ -828,9 +828,9 @@ LUAG_FUNC(linda_set) KeeperCallResult _pushed; if (_linda->cancelRequest == CancelRequest::None) { Keeper* const _keeper{ _linda->whichKeeper() }; - _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, 2); + _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, StackIndex{ 2 }); if (_pushed.has_value()) { // no error? - LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, -1) == LuaType::STRING && luaG_type(L_, -2) == LuaType::BOOLEAN); + LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, kIdxTop) == LuaType::STRING && luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); if (_has_data) { // we put some data in the slot, tell readers that they should wake @@ -922,13 +922,13 @@ namespace { */ LUAG_FUNC(linda) { - static constexpr int kLastArg{ LUA_VERSION_NUM >= 504 ? 3 : 2}; - int const _top{ lua_gettop(L_) }; + static constexpr StackIndex kLastArg{ LUA_VERSION_NUM >= 504 ? 3 : 2 }; + StackIndex const _top{ lua_gettop(L_) }; luaL_argcheck(L_, _top <= kLastArg, _top, "too many arguments"); - int _closeHandlerIdx{}; - int _nameIdx{}; - int _groupIdx{}; - for (int const _i : std::ranges::iota_view{ 1, _top + 1 }) { + StackIndex _closeHandlerIdx{}; + StackIndex _nameIdx{}; + StackIndex _groupIdx{}; + for (StackIndex const _i : std::ranges::iota_view{ StackIndex{ 1 }, StackIndex{ _top + 1 }}) { switch (luaG_type(L_, _i)) { #if LUA_VERSION_NUM >= 504 // to-be-closed support starts with Lua 5.4 case LuaType::FUNCTION: @@ -985,11 +985,11 @@ LUAG_FUNC(linda) LindaFactory::Instance.pushDeepUserdata(DestState{ L_ }, _nuv); // L_: name group close_handler linda if (_closeHandlerIdx != 0) { lua_replace(L_, 2); // L_: name linda close_handler - lua_setiuservalue(L_, 2, 1); // L_: name linda + lua_setiuservalue(L_, StackIndex{ 2 }, 1); // L_: name linda } // depending on whether we have a handler or not, the stack is not in the same state at this point // just make sure we have our Linda at the top - LUA_ASSERT(L_, ToLinda(L_, StackIndex{ -1 })); + LUA_ASSERT(L_, ToLinda(L_, kIdxTop)); return 1; } else { // no to-be-closed support // ensure we have name, group in that order on the stack diff --git a/src/linda.h b/src/linda.h index 4551443..ea660d9 100644 --- a/src/linda.h +++ b/src/linda.h @@ -13,7 +13,7 @@ static constexpr UniqueKey kLindaBatched{ 0xB8234DF772646567ull, "linda.batched" // ################################################################################################# -using LindaGroup = Unique; +DECLARE_UNIQUE_TYPE(LindaGroup, int); class Linda : public DeepPrelude // Deep userdata MUST start with this header diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp index d5ebc9b..e5903fb 100644 --- a/src/lindafactory.cpp +++ b/src/lindafactory.cpp @@ -80,7 +80,7 @@ void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) cons Keeper* const _keeper{ _need_acquire_release ? _linda->acquireKeeper() : _myKeeper }; LUA_ASSERT(L_, _keeper == _myKeeper); // should always be the same // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... - [[maybe_unused]] KeeperCallResult const result{ keeper_call(_keeper->K, KEEPER_API(destruct), L_, _linda, 0) }; + [[maybe_unused]] KeeperCallResult const result{ keeper_call(_keeper->K, KEEPER_API(destruct), L_, _linda, StackIndex{ 0 }) }; LUA_ASSERT(L_, result.has_value() && result.value() == 0); if (_need_acquire_release) { _linda->releaseKeeper(_keeper); @@ -105,7 +105,7 @@ std::string_view LindaFactory::moduleName() const DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* const L_) const { // we always expect name and group at the bottom of the stack (either can be nil). any extra stuff we ignore and keep unmodified - std::string_view _linda_name{ luaG_tostring(L_, 1) }; + std::string_view _linda_name{ luaG_tostring(L_, StackIndex{ 1 }) }; LindaGroup _linda_group{ static_cast(lua_tointeger(L_, 2)) }; // store in the linda the location of the script that created it @@ -118,7 +118,7 @@ DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* const L_) const _linda_name = luaG_pushstring(L_, ""); } // since the name is not empty, it is at slot 1, and we can replace "auto" with the result, just in case - LUA_ASSERT(L_, luaG_tostring(L_, 1) == "auto"); + LUA_ASSERT(L_, luaG_tostring(L_, StackIndex{ 1 }) == "auto"); lua_replace(L_, 1); } diff --git a/src/luaerrors.h b/src/luaerrors.h index 7bc08da..cf04f6c 100644 --- a/src/luaerrors.h +++ b/src/luaerrors.h @@ -1,5 +1,7 @@ #pragma once +#include "unique.hpp" + // ################################################################################################# // use this instead of Lua's lua_error @@ -23,7 +25,7 @@ template // use this instead of Lua's luaL_argerror template -[[noreturn]] static inline void raise_luaL_argerror(lua_State* const L_, int const arg_, std::string_view const& extramsg_) +[[noreturn]] static inline void raise_luaL_argerror(lua_State* const L_, StackIndex const arg_, std::string_view const& extramsg_) { std::ignore = luaL_argerror(L_, arg_, extramsg_.data()); // doesn't return assert(false); // we should never get here, but i'm paranoid @@ -34,7 +36,7 @@ template #if LUA_VERSION_NUM >= 504 // use this instead of Lua's luaL_typeerror template -[[noreturn]] static inline void raise_luaL_typeerror(lua_State* const L_, int const arg_, std::string_view const& tname_) +[[noreturn]] static inline void raise_luaL_typeerror(lua_State* const L_, StackIndex const arg_, std::string_view const& tname_) { std::ignore = luaL_typeerror(L_, arg_, tname_.data()); // doesn't return assert(false); // we should never get here, but i'm paranoid diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h index e73abef..f22d124 100644 --- a/src/macros_and_utils.h +++ b/src/macros_and_utils.h @@ -25,9 +25,8 @@ using lua_Duration = std::chrono::template duration; // ################################################################################################# -using SourceState = Unique; -using DestState = Unique; -using StackIndex = Unique; +DECLARE_UNIQUE_TYPE(SourceState, lua_State*); +DECLARE_UNIQUE_TYPE(DestState, lua_State*); // ################################################################################################# diff --git a/src/nameof.cpp b/src/nameof.cpp index 3c82603..fd31a28 100644 --- a/src/nameof.cpp +++ b/src/nameof.cpp @@ -34,10 +34,10 @@ THE SOFTWARE. // Return some name helping to identify an object [[nodiscard]] static int DiscoverObjectNameRecur(lua_State* L_, int shortest_, int depth_) { - static constexpr int kWhat{ 1 }; // the object to investigate // L_: o "r" {c} {fqn} ... {?} - static constexpr int kResult{ 2 }; // where the result string is stored - static constexpr int kCache{ 3 }; // a cache - static constexpr int kFQN{ 4 }; // the name compositing stack + static constexpr StackIndex kWhat{ 1 }; // the object to investigate // L_: o "r" {c} {fqn} ... {?} + static constexpr StackIndex kResult{ 2 }; // where the result string is stored + static constexpr StackIndex kCache{ 3 }; // a cache + static constexpr StackIndex kFQN{ 4 }; // the name compositing stack // no need to scan this table if the name we will discover is longer than one we already know if (shortest_ <= depth_ + 1) { return shortest_; @@ -80,7 +80,7 @@ THE SOFTWARE. STACK_CHECK(L_, 0); break; } - switch (luaG_type(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k v + switch (luaG_type(L_, kIdxTop)) { // L_: o "r" {c} {fqn} ... {?} k v default: // nil, boolean, light userdata, number and string aren't identifiable break; @@ -126,7 +126,7 @@ THE SOFTWARE. // search in the object's uservalues { int _uvi{ 1 }; - while (lua_getiuservalue(L_, -1, _uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... {?} k U {u} + while (lua_getiuservalue(L_, kIdxTop, _uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... {?} k U {u} if (lua_istable(L_, -1)) { // if it is a table, look inside ++depth_; luaG_pushstring(L_, "uservalue"); // L_: o "r" {c} {fqn} ... {?} k v {u} "uservalue" @@ -167,13 +167,13 @@ THE SOFTWARE. // "type", "name" = lanes.nameof(o) LUAG_FUNC(nameof) { - int const _what{ lua_gettop(L_) }; + StackIndex const _what{ lua_gettop(L_) }; if (_what > 1) { raise_luaL_argerror(L_, _what, "too many arguments."); } // nil, boolean, light userdata, number and string aren't identifiable - if (luaG_type(L_, 1) < LuaType::TABLE) { + if (luaG_type(L_, StackIndex{ 1 }) < LuaType::TABLE) { lua_pushstring(L_, luaL_typename(L_, 1)); // L_: o "type" lua_insert(L_, -2); // L_: "type" o return 2; @@ -197,7 +197,7 @@ LUAG_FUNC(nameof) lua_pop(L_, 1); // L_: o nil {c} {fqn} luaG_pushstring(L_, "_R"); // L_: o nil {c} {fqn} "_R" lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn} - lua_pushvalue(L_, LUA_REGISTRYINDEX); // L_: o nil {c} {fqn} _R + lua_pushvalue(L_, kIdxRegistry); // L_: o nil {c} {fqn} _R std::ignore = DiscoverObjectNameRecur(L_, std::numeric_limits::max(), 1); } lua_pop(L_, 3); // L_: o "result" diff --git a/src/state.cpp b/src/state.cpp index aa6e6a9..4664486 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -103,7 +103,7 @@ namespace { luaL_requiref(L_, _name.data(), _libfunc, !_isLanesCore); // L_: {lib} // lanes.core doesn't declare a global, so scan it here and now if (_isLanesCore) { - tools::PopulateFuncLookupTable(L_, -1, _name); + tools::PopulateFuncLookupTable(L_, kIdxTop, _name); } lua_pop(L_, 1); // L_: STACK_CHECK(L_, 0); @@ -282,7 +282,7 @@ namespace state { STACK_CHECK(_L, 0); // after all this, register everything we find in our name<->function database luaG_pushglobaltable(_L); // L: _G - tools::PopulateFuncLookupTable(_L, -1, {}); + tools::PopulateFuncLookupTable(_L, kIdxTop, {}); lua_pop(_L, 1); // L: STACK_CHECK(_L, 0); @@ -324,7 +324,7 @@ namespace state { lua_newtable(L_); // L_: out for (luaL_Reg const& _entry : local::sLibs) { lua_pushboolean(L_, 1); // L_: out true - luaG_setfield(L_, -2, std::string_view{ _entry.name }); // out[name] = true // L_: out + luaG_setfield(L_, StackIndex{ -2 }, std::string_view{ _entry.name }); // out[name] = true // L_: out } STACK_CHECK(L_, 1); return 1; diff --git a/src/tools.cpp b/src/tools.cpp index d580f67..d0204a6 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -66,7 +66,7 @@ static constexpr int kWriterReturnCode{ 666 }; * +-----------------+-------------------+------------+----------+ */ -FuncSubType luaG_getfuncsubtype(lua_State* const L_, int const i_) +FuncSubType luaG_getfuncsubtype(lua_State* const L_, StackIndex const i_) { if (lua_tocfunction(L_, i_)) { // nullptr for LuaJIT-fast && bytecode functions return FuncSubType::Native; @@ -92,7 +92,7 @@ FuncSubType luaG_getfuncsubtype(lua_State* const L_, int const i_) namespace tools { // inspired from tconcat() in ltablib.c - std::string_view PushFQN(lua_State* const L_, int const t_, int const last_) + std::string_view PushFQN(lua_State* const L_, StackIndex const t_, int const last_) { STACK_CHECK_START_REL(L_, 0); // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... @@ -111,7 +111,7 @@ namespace tools { // &b is popped at that point (-> replaced by the result) luaL_pushresult(&_b); // L_: ... {} ... "" STACK_CHECK(L_, 1); - return luaG_tostring(L_, -1); + return luaG_tostring(L_, kIdxTop); } } // namespace tools @@ -126,12 +126,12 @@ namespace tools { * if we already had an entry of type [o] = ..., replace the name if the new one is shorter * pops the processed object from the stack */ -static void update_lookup_entry(lua_State* L_, int ctxBase_, int depth_) +static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_, int const depth_) { // slot 1 in the stack contains the table that receives everything we found - int const _dest{ ctxBase_ }; + StackIndex const _dest{ ctxBase_ }; // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i - int const _fqn{ ctxBase_ + 1 }; + StackIndex const _fqn{ ctxBase_ + 1 }; DEBUGSPEW_CODE(Universe* const _U{ Universe::Get(L_) }); DEBUGSPEW_CODE(DebugSpew(_U) << "update_lookup_entry()" << std::endl); @@ -141,14 +141,14 @@ static void update_lookup_entry(lua_State* L_, int ctxBase_, int depth_) // first, raise an error if the function is already known lua_pushvalue(L_, -1); // L_: ... {bfc} k o o lua_rawget(L_, _dest); // L_: ... {bfc} k o name? - std::string_view const _prevName{ luaG_tostring(L_, -1) }; // nullptr if we got nil (first encounter of this object) + std::string_view const _prevName{ luaG_tostring(L_, kIdxTop) }; // nullptr if we got nil (first encounter of this object) // push name in fqn stack (note that concatenation will crash if name is a not string or a number) lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k - LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::NUMBER || luaG_type(L_, -1) == LuaType::STRING); - ++depth_; - lua_rawseti(L_, _fqn, depth_); // L_: ... {bfc} k o name? + LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER || luaG_type(L_, kIdxTop) == LuaType::STRING); + int const _deeper{ depth_ + 1 }; + lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k o name? // generate name - std::string_view const _newName{ tools::PushFQN(L_, _fqn, depth_) }; // L_: ... {bfc} k o name? "f.q.n" + std::string_view const _newName{ tools::PushFQN(L_, _fqn, _deeper) }; // L_: ... {bfc} k o name? "f.q.n" // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order // on different VMs even when the tables are populated the exact same way. // Also, when Lua is built with compatibility options (such as LUA_COMPAT_ALL), some base libraries register functions under multiple names. @@ -183,21 +183,20 @@ static void update_lookup_entry(lua_State* L_, int ctxBase_, int depth_) lua_rawset(L_, _dest); // L_: ... {bfc} k // remove table name from fqn stack lua_pushnil(L_); // L_: ... {bfc} k nil - lua_rawseti(L_, _fqn, depth_); // L_: ... {bfc} k + lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k } - --depth_; STACK_CHECK(L_, -1); } // ################################################################################################# -static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_, int depth_) +static void populate_func_lookup_table_recur(lua_State* const L_, StackIndex const dbIdx_, StackIndex const i_, int const depth_) { // slot dbIdx_ contains the lookup database table // slot dbIdx_ + 1 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot i_ - int const _fqn{ dbIdx_ + 1 }; + StackIndex const _fqn{ dbIdx_ + 1 }; // slot dbIdx_ + 2 contains a cache that stores all already visited tables to avoid infinite recursion loops - int const _cache{ dbIdx_ + 2 }; + StackIndex const _cache{ dbIdx_ + 2 }; DEBUGSPEW_CODE(Universe* const _U{ Universe::Get(L_) }); DEBUGSPEW_CODE(DebugSpew(_U) << "populate_func_lookup_table_recur()" << std::endl); DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); @@ -253,7 +252,7 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_, lua_rawset(L_, breadthFirstCache); // L_: ... {i_} {bfc} k {} // generate a name, and if we already had one name, keep whichever is the shorter update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k - } else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, -1) != FuncSubType::Bytecode)) { + } else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, kIdxTop) != FuncSubType::Bytecode)) { // generate a name, and if we already had one name, keep whichever is the shorter // this pops the function from the stack update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k @@ -263,7 +262,7 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_, STACK_CHECK(L_, 2); } // now process the tables we encountered at that depth - ++depth_; + int const _deeper{ depth_ + 1 }; lua_pushnil(L_); // L_: ... {i_} {bfc} nil while (lua_next(L_, breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {} DEBUGSPEW_CODE(std::string_view const _key{ (luaG_type(L_, -2) == LuaType::STRING) ? luaG_tostring(L_, -2) : std::string_view{ "" } }); @@ -272,7 +271,7 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_, // un-visit this table in case we do need to process it lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} lua_rawget(L_, _cache); // L_: ... {i_} {bfc} k {} n - LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::NUMBER); + LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER); _visit_count = lua_tointeger(L_, -1) - 1; lua_pop(L_, 1); // L_: ... {i_} {bfc} k {} lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} @@ -284,15 +283,14 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_, lua_rawset(L_, _cache); // L_: ... {i_} {bfc} k {} // push table name in fqn stack (note that concatenation will crash if name is a not string!) lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k - lua_rawseti(L_, _fqn, depth_); // L_: ... {i_} {bfc} k {} - populate_func_lookup_table_recur(L_, dbIdx_, lua_gettop(L_), depth_); + lua_rawseti(L_, _fqn, _deeper); // L_: ... {i_} {bfc} k {} + populate_func_lookup_table_recur(L_, dbIdx_, StackIndex{ lua_gettop(L_) }, _deeper); lua_pop(L_, 1); // L_: ... {i_} {bfc} k STACK_CHECK(L_, 2); } // remove table name from fqn stack lua_pushnil(L_); // L_: ... {i_} {bfc} nil - lua_rawseti(L_, _fqn, depth_); // L_: ... {i_} {bfc} - --depth_; + lua_rawseti(L_, _fqn, _deeper); // L_: ... {i_} {bfc} // we are done with our cache lua_pop(L_, 1); // L_: ... {i_} STACK_CHECK(L_, 0); @@ -304,9 +302,9 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_, namespace tools { // create a "fully.qualified.name" <-> function equivalence database - void PopulateFuncLookupTable(lua_State* const L_, int const i_, std::string_view const& name_) + void PopulateFuncLookupTable(lua_State* const L_, StackIndex const i_, std::string_view const& name_) { - int const _in_base{ luaG_absindex(L_, i_) }; + StackIndex const _in_base{ luaG_absindex(L_, i_) }; DEBUGSPEW_CODE(Universe* _U = Universe::Get(L_)); std::string_view _name{ name_.empty() ? std::string_view{} : name_ }; DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": PopulateFuncLookupTable('" << _name << "')" << std::endl); @@ -314,7 +312,7 @@ namespace tools { STACK_GROW(L_, 3); STACK_CHECK_START_REL(L_, 0); kLookupRegKey.pushValue(L_); // L_: {} - int const _dbIdx{ lua_gettop(L_) }; + StackIndex const _dbIdx{ lua_gettop(L_) }; STACK_CHECK(L_, 1); LUA_ASSERT(L_, lua_istable(L_, -1)); if (luaG_type(L_, _in_base) == LuaType::FUNCTION) { // for example when a module is a simple function diff --git a/src/tools.h b/src/tools.h index 5127ea0..34cbb8f 100644 --- a/src/tools.h +++ b/src/tools.h @@ -18,7 +18,7 @@ enum class FuncSubType FastJIT }; -[[nodiscard]] FuncSubType luaG_getfuncsubtype(lua_State* L_, int i_); +[[nodiscard]] FuncSubType luaG_getfuncsubtype(lua_State* L_, StackIndex i_); // ################################################################################################# @@ -31,7 +31,7 @@ static constexpr RegistryUniqueKey kLookupRegKey{ 0xBF1FC5CF3C6DD47Bull }; // re // ################################################################################################# namespace tools { - void PopulateFuncLookupTable(lua_State* const L_, int const i_, std::string_view const& name_); - [[nodiscard]] std::string_view PushFQN(lua_State* L_, int t_, int last_); + void PopulateFuncLookupTable(lua_State* L_, StackIndex i_, std::string_view const& name_); + [[nodiscard]] std::string_view PushFQN(lua_State* L_, StackIndex t_, int last_); void SerializeRequire(lua_State* L_); } // namespace tools diff --git a/src/unique.hpp b/src/unique.hpp index aeb7a67..846708e 100644 --- a/src/unique.hpp +++ b/src/unique.hpp @@ -3,7 +3,7 @@ // ################################################################################################# // A unique type generator -template +template class Unique { private: @@ -11,13 +11,15 @@ class Unique public: using type = T; - Unique() = default; + constexpr Unique() = default; operator T() const { return val; } - explicit Unique(T b_) + Unique& operator=(T const&) = delete; + Unique& operator=(T&&) = delete; + explicit constexpr Unique(T b_) : val{ b_ } { } - // pre-imcrement + // pre-increment auto& operator++() { ++val; @@ -26,12 +28,12 @@ class Unique // post-increment auto operator++(int) { - return Unique{ std::exchange(val, val + 1) }; + return Unique{ std::exchange(val, val + 1) }; } }; -template -class Unique>> +template +class Unique>> : public T { public: @@ -42,3 +44,9 @@ class Unique>> { } }; + +#define DECLARE_UNIQUE_TYPE(_name, _type) using _name = Unique<_type, class Unique_##_name##_Tag> + +// putting this here to break a header circular dependency until I find a better place +DECLARE_UNIQUE_TYPE(StackIndex, int); +static constexpr StackIndex kIdxTop{ -1 }; diff --git a/src/uniquekey.h b/src/uniquekey.h index debfee4..14b6d84 100644 --- a/src/uniquekey.h +++ b/src/uniquekey.h @@ -27,7 +27,7 @@ class UniqueKey inline constexpr std::weak_ordering operator<=>(UniqueKey const& rhs_) const { return storage <=> rhs_.storage; } inline constexpr auto operator==(UniqueKey const& rhs_) const { return storage == rhs_.storage; } // --------------------------------------------------------------------------------------------- - bool equals(lua_State* const L_, int const i_) const + bool equals(lua_State* const L_, StackIndex const i_) const { return lua_touserdata(L_, i_) == std::bit_cast(storage); } @@ -50,8 +50,8 @@ class RegistryUniqueKey void pushValue(lua_State* const L_) const { STACK_CHECK_START_REL(L_, 0); - pushKey(L_); - lua_rawget(L_, LUA_REGISTRYINDEX); + pushKey(L_); // L_: ... key + lua_rawget(L_, kIdxRegistry); // L_: ... value STACK_CHECK(L_, 1); } // --------------------------------------------------------------------------------------------- @@ -59,9 +59,9 @@ class RegistryUniqueKey void setValue(lua_State* const L_, OP operation_) const { // Note we can't check stack consistency because operation is not always a push (could be insert, replace, whatever) - pushKey(L_); // ... key - operation_(L_); // ... key value - lua_rawset(L_, LUA_REGISTRYINDEX); // ... + pushKey(L_); // L_: ... key + operation_(L_); // L_: ... key value + lua_rawset(L_, kIdxRegistry); // L_: ... } // --------------------------------------------------------------------------------------------- template @@ -69,9 +69,9 @@ class RegistryUniqueKey { STACK_GROW(L_, 1); STACK_CHECK_START_REL(L_, 0); - pushValue(L_); - T* const value{ luaG_tolightuserdata(L_, -1) }; // lightuserdata/nil - lua_pop(L_, 1); + pushValue(L_); // L_: ... {}|nil + T* const value{ luaG_tolightuserdata(L_, kIdxTop) }; + lua_pop(L_, 1); // L_: ... STACK_CHECK(L_, 0); return value; } @@ -80,9 +80,9 @@ class RegistryUniqueKey { STACK_GROW(L_, 1); STACK_CHECK_START_REL(L_, 0); - pushValue(L_); - bool const value{ lua_toboolean(L_, -1) ? true : false }; // bool/nil - lua_pop(L_, 1); + pushValue(L_); // L_: ... bool|nil + bool const value{ lua_toboolean(L_, -1) ? true : false }; + lua_pop(L_, 1); // L_: ... STACK_CHECK(L_, 0); return value; } diff --git a/src/universe.cpp b/src/universe.cpp index 3800dbb..c435dad 100644 --- a/src/universe.cpp +++ b/src/universe.cpp @@ -100,7 +100,7 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo } kConfigRegKey.pushValue(L_); // L_: config STACK_CHECK(L_, 1); - LuaType const _funcType{ luaG_getfield(L_, -1, kOnStateCreate) }; // L_: config on_state_create() + LuaType const _funcType{ luaG_getfield(L_, kIdxTop, kOnStateCreate) }; // L_: config on_state_create() if (_funcType != LuaType::FUNCTION) { raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaG_typename(L_, _funcType).data()); } @@ -111,29 +111,28 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" }; luaG_pushstring(L_, _stateType); // L_: on_state_create() "" if (lua_pcall(L_, 1, 0, 0) != LUA_OK) { - raise_luaL_error(from_, "%s failed in %s: \"%s\"", kOnStateCreate.data(), _stateType.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, -1).data() : luaG_typename(L_, -1).data()); + raise_luaL_error(from_, "%s failed in %s: \"%s\"", kOnStateCreate.data(), _stateType.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, kIdxTop).data() : luaG_typename(L_, kIdxTop).data()); } STACK_CHECK(L_, 0); } - - // ################################################################################################# // only called from the master state [[nodiscard]] Universe* Universe::Create(lua_State* const L_) { LUA_ASSERT(L_, Universe::Get(L_) == nullptr); + static constexpr StackIndex kIdxSettings{ 1 }; LUA_ASSERT(L_, lua_gettop(L_) == 1 && lua_istable(L_, 1)); STACK_CHECK_START_REL(L_, 0); // L_: settings - std::ignore = luaG_getfield(L_, 1, "nb_user_keepers"); // L_: settings nb_user_keepers + std::ignore = luaG_getfield(L_, kIdxSettings, "nb_user_keepers"); // L_: settings nb_user_keepers int const _nbUserKeepers{ static_cast(lua_tointeger(L_, -1)) + 1}; lua_pop(L_, 1); // L_: settings if (_nbUserKeepers < 1) { raise_luaL_error(L_, "Bad number of additional keepers (%d)", _nbUserKeepers); } STACK_CHECK(L_, 0); - std::ignore = luaG_getfield(L_, 1, "keepers_gc_threshold"); // L_: settings keepers_gc_threshold + std::ignore = luaG_getfield(L_, kIdxSettings, "keepers_gc_threshold"); // L_: settings keepers_gc_threshold int const _keepers_gc_threshold{ static_cast(lua_tointeger(L_, -1)) }; lua_pop(L_, 1); // L_: settings STACK_CHECK(L_, 0); @@ -146,22 +145,22 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); lua_createtable(L_, 0, 1); // L_: settings universe {mt} - std::ignore = luaG_getfield(L_, 1, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout + std::ignore = luaG_getfield(L_, kIdxSettings, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout lua_pushcclosure(L_, LG_universe_gc, 1); // L_: settings universe {mt} LG_universe_gc lua_setfield(L_, -2, "__gc"); // L_: settings universe {mt} lua_setmetatable(L_, -2); // L_: settings universe lua_pop(L_, 1); // L_: settings - std::ignore = luaG_getfield(L_, 1, "strip_functions"); // L_: settings strip_functions + std::ignore = luaG_getfield(L_, kIdxSettings, "strip_functions"); // L_: settings strip_functions _U->stripFunctions = lua_toboolean(L_, -1) ? true : false; lua_pop(L_, 1); // L_: settings - std::ignore = luaG_getfield(L_, 1, "verbose_errors"); // L_: settings verbose_errors + std::ignore = luaG_getfield(L_, kIdxSettings, "verbose_errors"); // L_: settings verbose_errors _U->verboseErrors = lua_toboolean(L_, -1) ? true : false; lua_pop(L_, 1); // L_: settings // tracking - std::ignore = luaG_getfield(L_, 1, "track_lanes"); // L_: settings track_lanes + std::ignore = luaG_getfield(L_, kIdxSettings, "track_lanes"); // L_: settings track_lanes if (lua_toboolean(L_, -1)) { _U->tracker.activate(); } @@ -182,7 +181,7 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo STACK_CHECK(L_, 1); // Proxy userdata contents is only a 'DeepPrelude*' pointer - _U->timerLinda = *luaG_tofulluserdata(L_, -1); + _U->timerLinda = *luaG_tofulluserdata(L_, kIdxTop); // increment refcount so that this linda remains alive as long as the universe exists. _U->timerLinda->refcount.fetch_add(1, std::memory_order_relaxed); lua_pop(L_, 1); // L_: settings @@ -224,13 +223,13 @@ void Universe::initializeAllocatorFunction(lua_State* const L_) // start by just grabbing whatever allocator was provided to the master state protectedAllocator.initFrom(L_); STACK_CHECK_START_REL(L_, 1); // L_: settings - switch (luaG_getfield(L_, -1, "allocator")) { // L_: settings allocator|nil|"protected" + switch (luaG_getfield(L_, kIdxTop, "allocator")) { // L_: settings allocator|nil|"protected" case LuaType::NIL: // nothing else to do break; case LuaType::STRING: - LUA_ASSERT(L_, luaG_tostring(L_, -1) == "protected"); + LUA_ASSERT(L_, luaG_tostring(L_, kIdxTop) == "protected"); // set the original allocator to call from inside protection by the mutex protectedAllocator.installIn(L_); // before a state is created, this function will be called to obtain the allocator @@ -255,14 +254,14 @@ void Universe::initializeAllocatorFunction(lua_State* const L_) break; default: // should be filtered out in lanes.lua - raise_luaL_error(L_, "Bad config.allocator type %s", luaG_typename(L_, -1).data()); + raise_luaL_error(L_, "Bad config.allocator type %s", luaG_typename(L_, kIdxTop).data()); } lua_pop(L_, 1); // L_: settings STACK_CHECK(L_, 1); - std::ignore = luaG_getfield(L_, -1, "internal_allocator"); // L_: settings "libc"|"allocator" - LUA_ASSERT(L_, lua_isstring(L_, -1)); // should be the case due to lanes.lua parameter validation - std::string_view const _allocator{ luaG_tostring(L_, -1) }; + std::ignore = luaG_getfield(L_, kIdxTop, "internal_allocator"); // L_: settings "libc"|"allocator" + LUA_ASSERT(L_, lua_isstring(L_, kIdxTop)); // should be the case due to lanes.lua parameter validation + std::string_view const _allocator{ luaG_tostring(L_, kIdxTop) }; if (_allocator == "libc") { internalAllocator = lanes::AllocatorDefinition{ lanes::AllocatorDefinition::kAllocatorVersion, libc_lua_Alloc, nullptr }; } else { @@ -284,7 +283,7 @@ int Universe::InitializeFinalizer(lua_State* const L_) // make sure we are only called from the Master Lua State! kUniverseFullRegKey.pushValue(L_); // L_: f U - if (luaG_type(L_, -1) != LuaType::USERDATA) { + if (luaG_type(L_, kIdxTop) != LuaType::USERDATA) { raise_luaL_error(L_, "lanes.%s called from inside a lane", kFinally); } lua_pop(L_, 1); // L_: f @@ -300,8 +299,8 @@ int Universe::InitializeFinalizer(lua_State* const L_) void Universe::initializeOnStateCreate(lua_State* const L_) { STACK_CHECK_START_REL(L_, 0); // L_: settings - if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil - LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation + if (luaG_getfield(L_, kIdxTop, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil + LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation // store C function pointer in an internal variable lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create if (_func) { @@ -314,7 +313,7 @@ void Universe::initializeOnStateCreate(lua_State* const L_) // remove this C function from the config table so that it doesn't cause problems // when we transfer the config table in newly created Lua states lua_pushnil(L_); // L_: settings on_state_create nil - luaG_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create + luaG_setfield(L_, StackIndex{ -3 }, kOnStateCreate); // L_: settings on_state_create } else { // the function is still in the config table. we indicate this with the uintptr_t alternative (actual value is irrelevant) onStateCreateFunc.emplace(std::bit_cast(kOnStateCreate.data())); @@ -339,7 +338,7 @@ lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std:: lua_pushcclosure(L_, provideAllocator, 0); // L_: provideAllocator() luaG_pushstring(L_, hint_); // L_: provideAllocator() "" lua_call(L_, 1, 1); // L_: result - lanes::AllocatorDefinition* const _def{ luaG_tofulluserdata(L_, -1) }; + lanes::AllocatorDefinition* const _def{ luaG_tofulluserdata(L_, kIdxTop) }; if (!_def || _def->version != lanes::AllocatorDefinition::kAllocatorVersion) { raise_luaL_error(L_, "Bad config.allocator function, must provide a valid AllocatorDefinition"); } @@ -414,7 +413,7 @@ LUAG_FUNC(universe_gc) { lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; STACK_CHECK_START_ABS(L_, 1); - Universe* const _U{ luaG_tofulluserdata(L_, 1) }; // L_: U + Universe* const _U{ luaG_tofulluserdata(L_, StackIndex{ 1 }) }; // L_: U // attempt to terminate all lanes with increasingly stronger cancel methods bool const _allLanesTerminated{ @@ -433,7 +432,7 @@ LUAG_FUNC(universe_gc) STACK_CHECK(L_, 2); // if some lanes are still running here, we have no other choice than crashing or freezing and let the client figure out what's wrong - bool const _throw{ luaG_tostring(L_, -1) == "throw" }; + bool const _throw{ luaG_tostring(L_, kIdxTop) == "throw" }; lua_pop(L_, 1); // L_: U while (_U->selfdestructFirst != SELFDESTRUCT_END) { -- cgit v1.2.3-55-g6feb