From 38a9cded72d663f48eb3154ed2eb495bbf3f80f3 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Thu, 6 Jun 2024 11:57:49 +0200 Subject: Fix deep_test for all flavors of Lua --- deep_test/deep_test.cpp | 135 +++++++++++++++++++-------------------- deep_test/deep_test.vcxproj | 2 +- deep_test/deep_test.vcxproj.user | 13 ++-- deep_test/deeptest.lua | 19 ++++-- src/compat.h | 64 +++++++++++++++++++ 5 files changed, 152 insertions(+), 81 deletions(-) diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp index 0a09921..da467f3 100644 --- a/deep_test/deep_test.cpp +++ b/deep_test/deep_test.cpp @@ -1,18 +1,12 @@ #include "lanes/src/deep.h" #include "lanes/src/compat.h" -#include -#include -#include - class MyDeepFactory : public DeepFactory { public: - static MyDeepFactory Instance; private: - void createMetatable(lua_State* const L_) const override { luaL_getmetatable(L_, "deep"); @@ -28,6 +22,7 @@ class MyDeepFactory : public DeepFactory // a lanes-deep userdata. needs DeepPrelude and luaG_newdeepuserdata from Lanes code. struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a DeepPrelude { + std::atomic inUse{}; lua_Integer val{ 0 }; }; @@ -49,22 +44,20 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c // ################################################################################################# -[[nodiscard]] static int deep_set(lua_State* const L_) +[[nodiscard]] static int deep_gc(lua_State* L) { - MyDeepUserdata* const _self{ static_cast(MyDeepFactory::Instance.toDeep(L_, 1)) }; - lua_Integer i = lua_tointeger(L_, 2); - _self->val = i; + MyDeepUserdata* const _self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; return 0; } // ################################################################################################# -[[nodiscard]] static int deep_setuv(lua_State* L) +[[nodiscard]] static int deep_tostring(lua_State* L) { - MyDeepUserdata* const self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; - int uv = (int) luaL_optinteger(L, 2, 1); - lua_settop( L, 3); - lua_pushboolean( L, lua_setiuservalue( L, 1, uv) != 0); + MyDeepUserdata* const _self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; + _self->inUse.fetch_add(1, std::memory_order_seq_cst); + lua_pushfstring(L, "%p:deep(%d)", lua_topointer(L, 1), _self->val); + _self->inUse.fetch_sub(1, std::memory_order_seq_cst); return 1; } @@ -73,44 +66,53 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c // won't actually do anything as deep userdata don't have uservalue slots [[nodiscard]] static int deep_getuv(lua_State* L) { - MyDeepUserdata* const self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; - int uv = (int) luaL_optinteger(L, 2, 1); - lua_getiuservalue( L, 1, uv); + MyDeepUserdata* const _self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; + _self->inUse.fetch_add(1, std::memory_order_seq_cst); + int _uv = (int) luaL_optinteger(L, 2, 1); + lua_getiuservalue(L, 1, _uv); + _self->inUse.fetch_sub(1, std::memory_order_seq_cst); return 1; } // ################################################################################################# -[[nodiscard]] static int deep_tostring(lua_State* L) +[[nodiscard]] static int deep_set(lua_State* const L_) { - MyDeepUserdata* const self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; - lua_pushfstring(L, "%p:deep(%d)", lua_topointer(L, 1), self->val); - return 1; + MyDeepUserdata* const _self{ static_cast(MyDeepFactory::Instance.toDeep(L_, 1)) }; + _self->inUse.fetch_add(1, std::memory_order_seq_cst); + lua_Integer _i = lua_tointeger(L_, 2); + _self->val = _i; + _self->inUse.fetch_sub(1, std::memory_order_seq_cst); + return 0; } // ################################################################################################# -[[nodiscard]] static int deep_gc(lua_State* L) +[[nodiscard]] static int deep_setuv(lua_State* L) { - MyDeepUserdata* const self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; - return 0; + MyDeepUserdata* const _self{ static_cast(MyDeepFactory::Instance.toDeep(L, 1)) }; + _self->inUse.fetch_add(1, std::memory_order_seq_cst); + int _uv = (int) luaL_optinteger(L, 2, 1); + lua_settop(L, 3); + lua_pushboolean(L, lua_setiuservalue(L, 1, _uv) != 0); + _self->inUse.fetch_sub(1, std::memory_order_seq_cst); + return 1; } // ################################################################################################# -static luaL_Reg const deep_mt[] = -{ - { "__tostring", deep_tostring}, - { "__gc", deep_gc}, - { "set", deep_set}, - { "setuv", deep_setuv}, - { "getuv", deep_getuv}, +static luaL_Reg const deep_mt[] = { + { "__gc", deep_gc }, + { "__tostring", deep_tostring }, + { "getuv", deep_getuv }, + { "set", deep_set }, + { "setuv", deep_setuv }, { nullptr, nullptr } }; // ################################################################################################# -int luaD_new_deep( lua_State* L) +int luaD_new_deep(lua_State* L) { int const nuv{ static_cast(luaL_optinteger(L, 1, 0)) }; lua_settop(L, 0); @@ -141,8 +143,8 @@ struct MyClonableUserdata { MyClonableUserdata* self = static_cast(lua_touserdata(L, 1)); int uv = (int) luaL_optinteger(L, 2, 1); - lua_settop( L, 3); - lua_pushboolean( L, lua_setiuservalue( L, 1, uv) != 0); + lua_settop(L, 3); + lua_pushboolean(L, lua_setiuservalue(L, 1, uv) != 0); return 1; } @@ -152,7 +154,7 @@ struct MyClonableUserdata { MyClonableUserdata* self = static_cast(lua_touserdata(L, 1)); int uv = (int) luaL_optinteger(L, 2, 1); - lua_getiuservalue( L, 1, uv); + lua_getiuservalue(L, 1, uv); return 1; } @@ -178,19 +180,18 @@ struct MyClonableUserdata // this is all we need to make a userdata lanes-clonable. no dependency on Lanes code. [[nodiscard]] static int clonable_lanesclone(lua_State* L) { - switch( lua_gettop(L)) - { - case 3: + switch (lua_gettop(L)) { + case 3: { MyClonableUserdata* self = static_cast(lua_touserdata(L, 1)); MyClonableUserdata* from = static_cast(lua_touserdata(L, 2)); size_t len = lua_tointeger(L, 3); - assert( len == sizeof(MyClonableUserdata)); + assert(len == sizeof(MyClonableUserdata)); *self = *from; } return 0; - default: + default: raise_luaL_error(L, "Lanes called clonable_lanesclone with unexpected parameters"); } return 0; @@ -198,34 +199,32 @@ struct MyClonableUserdata // ################################################################################################# -static luaL_Reg const clonable_mt[] = -{ - { "__tostring", clonable_tostring}, - { "__gc", clonable_gc}, - { "__lanesclone", clonable_lanesclone}, - { "set", clonable_set}, - { "setuv", clonable_setuv}, - { "getuv", clonable_getuv}, +static luaL_Reg const clonable_mt[] = { + { "__tostring", clonable_tostring }, + { "__gc", clonable_gc }, + { "__lanesclone", clonable_lanesclone }, + { "set", clonable_set }, + { "setuv", clonable_setuv }, + { "getuv", clonable_getuv }, { nullptr, nullptr } }; // ################################################################################################# -int luaD_new_clonable( lua_State* L) +int luaD_new_clonable(lua_State* L) { - int const nuv{ static_cast(luaL_optinteger(L, 1, 1)) }; - lua_newuserdatauv( L, sizeof(MyClonableUserdata), nuv); - luaL_setmetatable( L, "clonable"); + int const _nuv{ static_cast(luaL_optinteger(L, 1, 1)) }; + lua_newuserdatauv(L, sizeof(MyClonableUserdata), _nuv); + luaG_setmetatable(L, "clonable"); return 1; } // ################################################################################################# // ################################################################################################# -static luaL_Reg const deep_module[] = -{ - { "new_deep", luaD_new_deep}, - { "new_clonable", luaD_new_clonable}, +static luaL_Reg const deep_module[] = { + { "new_deep", luaD_new_deep }, + { "new_clonable", luaD_new_clonable }, { nullptr, nullptr } }; @@ -233,24 +232,24 @@ static luaL_Reg const deep_module[] = LANES_API int luaopen_deep_test(lua_State* L) { - luaL_newlib( L, deep_module); // M + luaG_newlib(L, deep_module); // M // preregister the metatables for the types we can instantiate so that Lanes can know about them - if (luaL_newmetatable( L, "clonable")) // M mt + if (luaL_newmetatable(L, "clonable")) // M mt { - luaL_setfuncs( L, clonable_mt, 0); - lua_pushvalue(L, -1); // M mt mt - lua_setfield(L, -2, "__index"); // M mt + luaG_registerlibfuncs(L, clonable_mt); + lua_pushvalue(L, -1); // M mt mt + lua_setfield(L, -2, "__index"); // M mt } - lua_setfield(L, -2, "__clonableMT"); // M + lua_setfield(L, -2, "__clonableMT"); // M - if (luaL_newmetatable( L, "deep")) // mt + if (luaL_newmetatable(L, "deep")) // mt { - luaL_setfuncs( L, deep_mt, 0); - lua_pushvalue(L, -1); // mt mt - lua_setfield(L, -2, "__index"); // mt + luaG_registerlibfuncs(L, deep_mt); + lua_pushvalue(L, -1); // mt mt + lua_setfield(L, -2, "__index"); // mt } - lua_setfield(L, -2, "__deepMT"); // M + lua_setfield(L, -2, "__deepMT"); // M return 1; } diff --git a/deep_test/deep_test.vcxproj b/deep_test/deep_test.vcxproj index 43b7ce0..298594e 100644 --- a/deep_test/deep_test.vcxproj +++ b/deep_test/deep_test.vcxproj @@ -556,7 +556,7 @@ xcopy /R /F /Y /I "$(TargetPath)" $(SolutionDir)..\Lua51\bin\$(Platform)\Debug\ - Copy to Lua 5.2 + Copy to Lua 5.1 lua51.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) diff --git a/deep_test/deep_test.vcxproj.user b/deep_test/deep_test.vcxproj.user index 24e3d31..257d4e9 100644 --- a/deep_test/deep_test.vcxproj.user +++ b/deep_test/deep_test.vcxproj.user @@ -3,20 +3,23 @@ $(SolutionDir)..\Lua53\bin\$(Platform)\Debug\lua53.exe WindowsLocalDebugger - -i + deeptest.lua $(SolutionDir)Lanes\lanes\deep_test\ + deeptest.lua - $(SolutionDir)..\Lua52\bin\$(Platform)\Debug\lua51.exe + $(SolutionDir)..\Lua51\bin\$(Platform)\Debug\lua51.exe WindowsLocalDebugger - -i + -i deeptest.lua $(SolutionDir)Lanes\lanes\deep_test\ + -i deeptest.lua - $(SolutionDir)..\Lua51\bin\$(Platform)\Debug\lua52.exe + $(SolutionDir)..\Lua52\bin\$(Platform)\Debug\lua52.exe WindowsLocalDebugger - -i + -i deeptest.lua $(SolutionDir)Lanes\lanes\deep_test\ + -i deeptest.lua $(SolutionDir)..\LuaJIT-2.1.0-beta3\bin\$(Platform)\luajit210.exe diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua index 09b638c..89e6f0d 100644 --- a/deep_test/deeptest.lua +++ b/deep_test/deeptest.lua @@ -6,16 +6,21 @@ local dt = lanes.require "deep_test" local test_deep = true local test_clonable = true -local test_uvtype = "string" +-- lua 5.1->5.2 support a single table uservalue +-- lua 5.3->5.4 supports an arbitrary type uservalue +local test_uvtype = (_VERSION == "Lua 5.4") and "function" or (_VERSION == "Lua 5.3") and "string" or "table" +-- lua 5.4 supports multiple uservalues local nupvals = _VERSION == "Lua 5.4" and 3 or 1 local makeUserValue = function( obj_) - if test_uvtype == "string" then + if test_uvtype == "table" then + return {"some uservalue"} + elseif test_uvtype == "string" then return "some uservalue" elseif test_uvtype == "function" then -- a function that pull the userdata as upvalue local f = function() - return tostring( obj_) + return "-> '" .. tostring( obj_) .. "'" end return f end @@ -25,7 +30,7 @@ local printDeep = function( prefix_, obj_, t_) print( prefix_, obj_) for uvi = 1, nupvals do local uservalue = obj_:getuv(uvi) - print ( "uv #" .. uvi, uservalue, type( uservalue) == "function" and uservalue() or "") + print ("uv #" .. uvi, type( uservalue), uservalue, type(uservalue) == "function" and uservalue() or "") end if t_ then for k, v in pairs( t_) do @@ -38,10 +43,7 @@ end local performTest = function( obj_) -- setup the userdata with some value and a uservalue obj_:set( 666) - -- lua 5.1->5.2 support a single table uservalue - -- lua 5.3 supports an arbitrary type uservalue obj_:setuv( 1, makeUserValue( obj_)) - -- lua 5.4 supports multiple uservalues of arbitrary types if nupvals > 1 then -- keep uv #2 as nil obj_:setuv( 3, "ENDUV") @@ -95,3 +97,6 @@ if test_clonable then print "CLONABLE" performTest( dt.new_clonable(nupvals)) end + +print "================================================================" +print "TEST OK" \ No newline at end of file diff --git a/src/compat.h b/src/compat.h index 1789a8b..58af985 100644 --- a/src/compat.h +++ b/src/compat.h @@ -172,10 +172,22 @@ struct Wrap return ::lua_dump(L_, writer_, data_, strip_); } + template + static inline void (luaL_newlib)(lua_State* const L_, luaL_Reg const (&funcs_)[N]) + { + lua_createtable(L_, 0, N - 1); + ::luaL_setfuncs(L_, funcs_, 0); + } + static void luaL_setfuncs(lua_State* const L_, luaL_Reg const funcs_[], int nup_) { ::luaL_setfuncs(L_, funcs_, nup_); } + + static void luaL_setmetatable(lua_State* const L_, std::string_view const& tname_) + { + ::luaL_setmetatable(L_, tname_.data()); + } }; // ################################################################################################# @@ -188,10 +200,22 @@ struct Wrap::type> return ::lua_dump(L_, writer_, data_, strip_); } + template + static inline void (luaL_newlib)(lua_State* const L_, luaL_Reg const (&funcs_)[N]) + { + lua_createtable(L_, 0, N - 1); + ::luaL_setfuncs(L_, funcs_, 0); + } + static void luaL_setfuncs(lua_State* const L_, luaL_Reg const funcs_[], int const nup_) { ::luaL_setfuncs(L_, funcs_, nup_); } + + static void luaL_setmetatable(lua_State* const L_, std::string_view const& tname_) + { + ::luaL_setmetatable(L_, tname_.data()); + } }; // ################################################################################################# @@ -204,10 +228,22 @@ struct Wrap::type> return ::lua_dump(L_, writer_, data_); } + template + static inline void (luaL_newlib)(lua_State* const L_, luaL_Reg const (&funcs_)[N]) + { + lua_createtable(L_, 0, N - 1); + ::luaL_setfuncs(L_, funcs_, 0); + } + static void luaL_setfuncs(lua_State* const L_, luaL_Reg const funcs_[], int const nup_) { ::luaL_setfuncs(L_, funcs_, nup_); } + + static void luaL_setmetatable(lua_State* const L_, std::string_view const& tname_) + { + ::luaL_setmetatable(L_, tname_.data()); + } }; // ################################################################################################# @@ -220,10 +256,23 @@ struct Wrap::type> return ::lua_dump(L_, writer_, data_); } + template + static inline void (luaL_newlib)(lua_State* const L_, luaL_Reg const (&funcs_)[N]) + { + lua_createtable(L_, 0, N - 1); + ::luaL_register(L_, nullptr, funcs_); + } + static void luaL_setfuncs(lua_State* const L_, luaL_Reg const funcs_[], [[maybe_unused]] int const nup_) { ::luaL_register(L_, nullptr, funcs_); } + + static void luaL_setmetatable(lua_State* const L_, std::string_view const& tname_) + { + luaL_getmetatable(L_, tname_.data()); + lua_setmetatable(L_, -2); + } }; // ################################################################################################# @@ -248,11 +297,26 @@ LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_); // ------------------------------------------------------------------------------------------------- +template +inline void luaG_newlib(lua_State* const L_, luaL_Reg const (&funcs_)[N]) +{ + (Wrap::luaL_newlib)(L_, funcs_); +} + +// ------------------------------------------------------------------------------------------------- + inline void luaG_registerlibfuncs(lua_State* L_, luaL_Reg const funcs_[]) { Wrap::luaL_setfuncs(L_, funcs_, 0); } +// ------------------------------------------------------------------------------------------------- + +inline void luaG_setmetatable(lua_State* const L_, std::string_view const& tname_) +{ + return Wrap::luaL_setmetatable(L_, tname_); +} + // ################################################################################################# // must keep as a macro as long as we do constant string concatenations -- cgit v1.2.3-55-g6feb