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 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<std::string, 2> 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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
inline std::string demangle_once() {
#ifndef SOL_NO_RTTI
std::string realname = get_type_name(typeid(T));
#else
std::string realname = get_type_name<T>();
std::string realname = ctti_get_type_name<T>();
#endif // No Runtime Type Information
const static std::array<std::string, 2> removals = {{ "struct ", "class " }};
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]);
}
}
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 <typename T>
inline std::string short_demangle_once() {
std::string realname = ctti_get_type_name<T>();
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<T>();
return d;
}
template <typename T>
inline std::string short_demangle() {
static const std::string d = short_demangle_once<T>();
return d;
}
} // detail
} // 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>
struct checker<T, type::userdata, C> {
template <typename U, typename Handler>

View File

@ -44,7 +44,7 @@ struct pusher {
referencereference = allocationtarget;
std::allocator<T> alloc{};
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);
return 1;
}

View File

@ -449,6 +449,7 @@ private:
template<typename... Args>
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);

View File

@ -29,13 +29,17 @@ namespace sol {
template<typename T>
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<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>
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.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<sol::object>("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>("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") {