Better demangling

Userdata pushed before the usertype is pushed will not latch onto the new metatable if its added
Updated tests
This commit is contained in:
ThePhD 2016-04-22 17:06:56 -04:00
parent 96da27d565
commit 2cfe74cc7f
6 changed files with 87 additions and 43 deletions

View File

@ -33,28 +33,23 @@
namespace sol { namespace sol {
namespace detail { namespace detail {
#ifndef SOL_NO_RTTI
#ifdef _MSC_VER #ifdef _MSC_VER
#ifndef SOL_NO_RTTI
inline std::string get_type_name(const std::type_info& id) { inline std::string get_type_name(const std::type_info& id) {
return id.name(); std::string realname = id.name();
} const static std::array<std::string, 2> removals = { { "struct ", "class " } };
for (std::size_t r = 0; r < removals.size(); ++r) {
#elif defined(__GNUC__) || defined(__clang__) auto found = realname.find(removals[r]);
inline std::string get_type_name(const std::type_info& id) { while (found != std::string::npos) {
int status; realname.erase(found, removals[r].size());
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status); found = realname.find(removals[r]);
std::string realname = unmangled; }
std::free(unmangled); }
return realname; return realname;
} }
#endif // No RTII
#else
#error Compiler not supported for demangling
#endif // compilers
#else
#ifdef _MSC_VER
template <typename T> template <typename T>
inline std::string get_type_name() { inline std::string ctti_get_type_name() {
std::string name = __FUNCSIG__; std::string name = __FUNCSIG__;
std::size_t start = name.find("get_type_name"); std::size_t start = name.find("get_type_name");
if (start == std::string::npos) 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()); while (name.size() > 0 && std::isblank(name.back())) name.erase(--name.end(), name.end());
return name; return name;
} }
#elif defined(__GNUC__) #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 <typename T> template <typename T>
inline std::string get_type_name() { inline std::string ctti_get_type_name() {
std::string name = __PRETTY_FUNCTION__; std::string name = __PRETTY_FUNCTION__;
std::size_t start = name.find_first_of('='); std::size_t start = name.find_first_of('=');
std::size_t end = name.find_last_of(';'); std::size_t end = name.find_last_of(';');
@ -92,8 +95,17 @@ inline std::string get_type_name() {
return name; return name;
} }
#elif defined(__clang__) #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 <typename T> template <typename T>
inline std::string get_type_name() { inline std::string ctti_get_type_name() {
std::string name = __PRETTY_FUNCTION__; std::string name = __PRETTY_FUNCTION__;
std::size_t start = name.find_last_of('['); std::size_t start = name.find_last_of('[');
start = name.find_first_of('=', start); start = name.find_first_of('=', start);
@ -107,36 +119,28 @@ inline std::string get_type_name() {
name = name.substr(start, end - start); name = name.substr(start, end - start);
return name; return name;
} }
#else #else
#error Compiler not supported for demangling #error Compiler not supported for demangling
#endif // compilers #endif // compilers
#endif // No Runtime Type information
template <typename T> template <typename T>
inline std::string demangle_once() { inline std::string demangle_once() {
#ifndef SOL_NO_RTTI #ifndef SOL_NO_RTTI
std::string realname = get_type_name(typeid(T)); std::string realname = get_type_name(typeid(T));
#else #else
std::string realname = get_type_name<T>(); std::string realname = ctti_get_type_name<T>();
#endif // No Runtime Type Information #endif // No Runtime Type Information
const static std::array<std::string, 2> removals = {{ "struct ", "class " }}; return realname;
const static std::array<std::string, 2> 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]);
}
}
for(std::size_t r = 0; r < replacements.size(); r+=2) { template <typename T>
auto found = realname.find(replacements[r]); inline std::string short_demangle_once() {
while(found != std::string::npos) { std::string realname = ctti_get_type_name<T>();
realname.replace(found, replacements[r].size(), replacements[r + 1]); std::size_t idx = realname.find_last_of(":`'\"{}[]|-)(*^&!@#$%`~", std::string::npos, 23);
found = realname.find(replacements[r], found); if (idx != std::string::npos) {
realname.erase(0, realname.length() < idx ? realname.length() : idx + 1);
} }
}
return realname; return realname;
} }
@ -145,6 +149,12 @@ inline std::string demangle() {
static const std::string d = demangle_once<T>(); static const std::string d = demangle_once<T>();
return d; return d;
} }
template <typename T>
inline std::string short_demangle() {
static const std::string d = short_demangle_once<T>();
return d;
}
} // detail } // detail
} // sol } // sol

View File

@ -235,6 +235,20 @@ struct checker<T*, type::userdata, C> {
} }
}; };
template <typename C>
struct checker<userdata_value, type::userdata, C> {
template <typename Handler>
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 <typename T, typename C> template <typename T, typename C>
struct checker<T, type::userdata, C> { struct checker<T, type::userdata, C> {
template <typename U, typename Handler> template <typename U, typename Handler>

View File

@ -44,7 +44,7 @@ struct pusher {
referencereference = allocationtarget; referencereference = allocationtarget;
std::allocator<T> alloc{}; std::allocator<T> alloc{};
alloc.construct(allocationtarget, std::forward<Args>(args)...); alloc.construct(allocationtarget, std::forward<Args>(args)...);
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]); luaL_newmetatable(L, &usertype_traits<T>::metatable[0]);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return 1; return 1;
} }

View File

@ -449,6 +449,7 @@ private:
template<typename... Args> template<typename... Args>
usertype(usertype_detail::verified_tag, Args&&... args) : indexfunc(nullptr), newindexfunc(nullptr), constructfunc(nullptr), usertype(usertype_detail::verified_tag, Args&&... args) : indexfunc(nullptr), newindexfunc(nullptr), constructfunc(nullptr),
destructfunc(nullptr), functiongcfunc(nullptr), needsindexfunction(false), baseclasscheck(nullptr), baseclasscast(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); functionnames.reserve(sizeof...(args)+3);
functiontable.reserve(sizeof...(args)+3); functiontable.reserve(sizeof...(args)+3);
metafunctiontable.reserve(sizeof...(args)+3); metafunctiontable.reserve(sizeof...(args)+3);

View File

@ -29,13 +29,17 @@ namespace sol {
template<typename T> template<typename T>
struct usertype_traits { struct usertype_traits {
static const std::string name; static const std::string name;
static const std::string qualified_name;
static const std::string metatable; static const std::string metatable;
static const std::string variable_metatable; static const std::string variable_metatable;
static const std::string gc_table; static const std::string gc_table;
}; };
template<typename T> template<typename T>
const std::string usertype_traits<T>::name = detail::demangle<T>(); const std::string usertype_traits<T>::name = detail::short_demangle<T>();
template<typename T>
const std::string usertype_traits<T>::qualified_name = detail::demangle<T>();
template<typename T> template<typename T>
const std::string usertype_traits<T>::metatable = std::string("sol.").append(detail::demangle<T>()); const std::string usertype_traits<T>::metatable = std::string("sol.").append(detail::demangle<T>());

View File

@ -408,13 +408,13 @@ TEST_CASE("usertype/usertype-constructors", "Show that we can create classes fro
lua.set_usertype(lc); lua.set_usertype(lc);
lua.script( lua.script(
"a = crapola_fuser.new(2)\n" "a = fuser.new(2)\n"
"u = a:add(1)\n" "u = a:add(1)\n"
"v = a:add2(1)\n" "v = a:add2(1)\n"
"b = crapola_fuser:new()\n" "b = fuser:new()\n"
"w = b:add(1)\n" "w = b:add(1)\n"
"x = b:add2(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" "y = c:add(1)\n"
"z = c:add2(1)\n"); "z = c:add2(1)\n");
sol::object a = lua.get<sol::object>("a"); sol::object a = lua.get<sol::object>("a");
@ -615,6 +615,21 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
"local x = v.x\n" "local x = v.x\n"
"assert(x == 3)\n" "assert(x == 3)\n"
)); ));
struct breaks {
sol::function f;
};
lua.open_libraries(sol::lib::base);
lua.set("b", breaks());
lua.new_usertype<breaks>("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") { TEST_CASE("usertype/nonmember-functions", "let users set non-member functions that take unqualified T as first parameter to usertype") {