From 2cfe74cc7f239bc231208b38cf5901d8ee9823de Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 22 Apr 2016 17:06:56 -0400 Subject: [PATCH] Better demangling Userdata pushed before the usertype is pushed will not latch onto the new metatable if its added Updated tests --- sol/demangle.hpp | 86 +++++++++++++++++++++++------------------ sol/stack_check.hpp | 14 +++++++ sol/stack_push.hpp | 2 +- sol/usertype.hpp | 1 + sol/usertype_traits.hpp | 6 ++- tests.cpp | 21 ++++++++-- 6 files changed, 87 insertions(+), 43 deletions(-) diff --git a/sol/demangle.hpp b/sol/demangle.hpp index 210e08cd..dc4f8a03 100644 --- a/sol/demangle.hpp +++ b/sol/demangle.hpp @@ -33,28 +33,23 @@ namespace sol { namespace detail { -#ifndef SOL_NO_RTTI #ifdef _MSC_VER +#ifndef SOL_NO_RTTI inline std::string get_type_name(const std::type_info& id) { - return id.name(); -} - -#elif defined(__GNUC__) || defined(__clang__) -inline std::string get_type_name(const std::type_info& id) { - int status; - char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status); - std::string realname = unmangled; - std::free(unmangled); + std::string realname = id.name(); + const static std::array removals = { { "struct ", "class " } }; + for (std::size_t r = 0; r < removals.size(); ++r) { + auto found = realname.find(removals[r]); + while (found != std::string::npos) { + realname.erase(found, removals[r].size()); + found = realname.find(removals[r]); + } + } return realname; } - -#else -#error Compiler not supported for demangling -#endif // compilers -#else -#ifdef _MSC_VER +#endif // No RTII template -inline std::string get_type_name() { +inline std::string ctti_get_type_name() { std::string name = __FUNCSIG__; std::size_t start = name.find("get_type_name"); if (start == std::string::npos) @@ -75,10 +70,18 @@ inline std::string get_type_name() { while (name.size() > 0 && std::isblank(name.back())) name.erase(--name.end(), name.end()); return name; } - #elif defined(__GNUC__) +#ifndef SOL_NO_RTTI +inline std::string get_type_name(const std::type_info& id) { + int status; + char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status); + std::string realname = unmangled; + std::free(unmangled); + return realname; +} +#endif // No RTII template -inline std::string get_type_name() { +inline std::string ctti_get_type_name() { std::string name = __PRETTY_FUNCTION__; std::size_t start = name.find_first_of('='); std::size_t end = name.find_last_of(';'); @@ -92,8 +95,17 @@ inline std::string get_type_name() { return name; } #elif defined(__clang__) +#ifndef SOL_NO_RTTI +inline std::string get_type_name(const std::type_info& id) { + int status; + char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status); + std::string realname = unmangled; + std::free(unmangled); + return realname; +} +#endif // No RTII template -inline std::string get_type_name() { +inline std::string ctti_get_type_name() { std::string name = __PRETTY_FUNCTION__; std::size_t start = name.find_last_of('['); start = name.find_first_of('=', start); @@ -107,36 +119,28 @@ inline std::string get_type_name() { name = name.substr(start, end - start); return name; } + #else #error Compiler not supported for demangling #endif // compilers -#endif // No Runtime Type information template inline std::string demangle_once() { #ifndef SOL_NO_RTTI std::string realname = get_type_name(typeid(T)); #else - std::string realname = get_type_name(); + std::string realname = ctti_get_type_name(); #endif // No Runtime Type Information - const static std::array removals = {{ "struct ", "class " }}; - const static std::array replacements = {{ "::", "_" }}; - for(std::size_t r = 0; r < removals.size(); ++r) { - auto found = realname.find(removals[r]); - while(found != std::string::npos) { - realname.erase(found, removals[r].size()); - found = realname.find(removals[r]); - } - } + return realname; +} - for(std::size_t r = 0; r < replacements.size(); r+=2) { - auto found = realname.find(replacements[r]); - while(found != std::string::npos) { - realname.replace(found, replacements[r].size(), replacements[r + 1]); - found = realname.find(replacements[r], found); - } +template +inline std::string short_demangle_once() { + std::string realname = ctti_get_type_name(); + std::size_t idx = realname.find_last_of(":`'\"{}[]|-)(*^&!@#$%`~", std::string::npos, 23); + if (idx != std::string::npos) { + realname.erase(0, realname.length() < idx ? realname.length() : idx + 1); } - return realname; } @@ -145,6 +149,12 @@ inline std::string demangle() { static const std::string d = demangle_once(); return d; } + +template +inline std::string short_demangle() { + static const std::string d = short_demangle_once(); + return d; +} } // detail } // sol diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index d23643e2..b4b3d036 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -235,6 +235,20 @@ struct checker { } }; +template +struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler) { + type t = type_of(L, index); + bool success = t == type::userdata || t == type::lightuserdata; + if (!success) { + // expected type, actual type + handler(L, index, type::lightuserdata, t); + } + return success; + } +}; + template struct checker { template diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index c0817502..e8d2d286 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -44,7 +44,7 @@ struct pusher { referencereference = allocationtarget; std::allocator alloc{}; alloc.construct(allocationtarget, std::forward(args)...); - luaL_getmetatable(L, &usertype_traits::metatable[0]); + luaL_newmetatable(L, &usertype_traits::metatable[0]); lua_setmetatable(L, -2); return 1; } diff --git a/sol/usertype.hpp b/sol/usertype.hpp index ce9c16fa..a533bbf4 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -449,6 +449,7 @@ private: template usertype(usertype_detail::verified_tag, Args&&... args) : indexfunc(nullptr), newindexfunc(nullptr), constructfunc(nullptr), destructfunc(nullptr), functiongcfunc(nullptr), needsindexfunction(false), baseclasscheck(nullptr), baseclasscast(nullptr) { + static_assert((sizeof...(Args) % 2) == 0, "incorrect pairing of arguments to usertype creation: maybe forgotten comma somewhere"); functionnames.reserve(sizeof...(args)+3); functiontable.reserve(sizeof...(args)+3); metafunctiontable.reserve(sizeof...(args)+3); diff --git a/sol/usertype_traits.hpp b/sol/usertype_traits.hpp index 7869befe..4d44aef9 100644 --- a/sol/usertype_traits.hpp +++ b/sol/usertype_traits.hpp @@ -29,13 +29,17 @@ namespace sol { template struct usertype_traits { static const std::string name; + static const std::string qualified_name; static const std::string metatable; static const std::string variable_metatable; static const std::string gc_table; }; template -const std::string usertype_traits::name = detail::demangle(); +const std::string usertype_traits::name = detail::short_demangle(); + +template +const std::string usertype_traits::qualified_name = detail::demangle(); template const std::string usertype_traits::metatable = std::string("sol.").append(detail::demangle()); diff --git a/tests.cpp b/tests.cpp index 15814f2d..3b416a33 100644 --- a/tests.cpp +++ b/tests.cpp @@ -408,13 +408,13 @@ TEST_CASE("usertype/usertype-constructors", "Show that we can create classes fro lua.set_usertype(lc); lua.script( - "a = crapola_fuser.new(2)\n" + "a = fuser.new(2)\n" "u = a:add(1)\n" "v = a:add2(1)\n" - "b = crapola_fuser:new()\n" + "b = fuser:new()\n" "w = b:add(1)\n" "x = b:add2(1)\n" - "c = crapola_fuser.new(2, 3)\n" + "c = fuser.new(2, 3)\n" "y = c:add(1)\n" "z = c:add2(1)\n"); sol::object a = lua.get("a"); @@ -615,6 +615,21 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as "local x = v.x\n" "assert(x == 3)\n" )); + + struct breaks { + sol::function f; + }; + + lua.open_libraries(sol::lib::base); + lua.set("b", breaks()); + lua.new_usertype("breaks", + "f", &breaks::f + ); + + breaks& b = lua["b"]; + REQUIRE_NOTHROW(lua.script("b.f = function () print('BARK!') end")); + REQUIRE_NOTHROW(lua.script("b.f()")); + REQUIRE_NOTHROW(b.f()); } TEST_CASE("usertype/nonmember-functions", "let users set non-member functions that take unqualified T as first parameter to usertype") {