Inheritance

This commit is contained in:
ThePhD 2016-03-05 01:43:45 -05:00
parent 22f74a31a2
commit 19578538e7
4 changed files with 97 additions and 16 deletions

View File

@ -43,10 +43,22 @@
#endif // Lua Version 502, 501 || luajit, 500
#ifdef _MSC_VER
#if _HAS_EXCEPTIONS == 0
// This means VC++ has no exceptions
// Maybe: automatically define SOL_NO_EXCEPTIONS ?
#endif // Automatic Exception Detection
#endif // VC++ Exception Mechanism
#ifndef _CPPUNWIND
#define SOL_NO_EXCEPTIONS 1
#endif // No
#ifndef _CPPRTTI
#define SOL_NO_RTTI 1
#endif // Automatic RTTI
#elif defined(__GNUC__) || defined(__clang__)
#ifndef __EXCEPTIONS
#define SOL_NO_EXCEPTIONS 1
#endif // No Exceptions
#ifndef __GXX_RTTI
#define SOL_NO_RTTI 1
#endif // No RTTI
#endif // vc++ || clang++/g++
#endif // SOL_VERSION_HPP

View File

@ -36,8 +36,11 @@ struct default_construct {
};
} // detail
template <typename... Args>
struct constructor_list {};
template<typename... Args>
using constructors = sol::types<Args...>;
using constructors = constructor_list<Args...>;
const auto default_constructor = constructors<types<>>{};

View File

@ -27,6 +27,7 @@
#include "tuple.hpp"
#include "traits.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "overload.hpp"
#include <utility>
#include <array>
@ -255,22 +256,43 @@ struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
template<typename T>
struct getter<T*> {
static T* get_no_nil(lua_State* L, int index = -1) {
void** pudata = static_cast<void**>(lua_touserdata(L, index));
void* udata = *pudata;
#ifndef SOL_NO_EXCEPTIONS
if (luaL_getmetafield(L, -1, &detail::base_class_check_key[0]) != 0) {
void* basecastdata = stack::get<light_userdata>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
udata = detail::catch_cast<T>( udata, basecast );
lua_pop(L, 1);
}
#elif !defined(SOL_NO_RTTI)
if (luaL_getmetafield(L, -1, &detail::base_class_check_key[0]) != 0) {
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)stack::get<light_userdata>(L);
// use the casting function to properly adjust the pointer for the desired T
udata = ic(udata, typeid(T));
lua_pop(L, 1);
}
#else
// Lol, inheritance could never work like this
#endif // No Runtime Type Information || Exceptions
T* obj = static_cast<T*>(udata);
return obj;
}
static T* get(lua_State* L, int index = -1) {
type t = type_of(L, index);
if (t == type::nil)
return nullptr;
void* udata = lua_touserdata(L, index);
T** obj = static_cast<T**>(udata);
return *obj;
return get_no_nil(L, index);
}
};
template<typename T>
struct getter<T&> {
static T& get(lua_State* L, int index = -1) {
void* udata = lua_touserdata(L, index);
T** obj = static_cast<T**>(udata);
return **obj;
return *getter<T*>::get_no_nil(L, index);
}
};
@ -419,6 +441,22 @@ struct checker<T, type::userdata, C> {
return false;
}
bool success = lua_rawequal(L, -1, -2) == 1;
#ifndef SOL_NO_EXCEPTIONS
if (!success) {
lua_getfield(L, -2, &detail::base_class_check_key[0]);
void* basecastdata = stack::get<light_userdata>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
success |= detail::catch_check<T>(basecast);
lua_pop(L, 1);
}
#elif !defined(SOL_NO_RTTI)
if (!success) {
lua_getfield(L, -2, &detail::base_class_check_key[0]);
detail::inheritance_check_function ic = (detail::inheritance_check_function)stack::get<light_userdata>(L);
success |= ic(typeid(T));
lua_pop(L, 1);
}
#endif // No Runtime Type Information || Exceptions
lua_pop(L, 2);
return success;
}

View File

@ -25,6 +25,7 @@
#include "state.hpp"
#include "function_types.hpp"
#include "usertype_traits.hpp"
#include "inheritance.hpp"
#include "raii.hpp"
#include "deprecate.hpp"
#include <vector>
@ -114,10 +115,20 @@ template <typename... Args>
using has_destructor = meta::Or<is_destructor<meta::Unqualified<Args>>...>;
template<typename T, bool refmeta, typename Funcs, typename FuncTable, typename MetaFuncTable>
inline void push_metatable(lua_State* L, bool needsindexfunction, Funcs&& funcs, FuncTable&& functable, MetaFuncTable&& metafunctable) {
inline void push_metatable(lua_State* L, bool needsindexfunction, Funcs&& funcs, FuncTable&& functable, MetaFuncTable&& metafunctable, void* baseclasscheck, void* baseclasscast) {
static const auto& gcname = meta_function_names[static_cast<int>(meta_function::garbage_collect)];
luaL_newmetatable(L, &usertype_traits<T>::metatable[0]);
int metatableindex = lua_gettop(L);
#if !defined(SOL_NO_EXCEPTIONS) || !defined(SOL_NO_RTTI)
if (baseclasscheck != nullptr) {
stack::push(L, light_userdata(baseclasscheck));
lua_setfield(L, metatableindex, &detail::base_class_check_key[0]);
}
if (baseclasscast != nullptr) {
stack::push(L, light_userdata(baseclasscast));
lua_setfield(L, metatableindex, &detail::base_class_cast_key[0]);
}
#endif // No Exceptions || RTTI
if (funcs.size() < 1 && metafunctable.size() < 2) {
return;
}
@ -181,6 +192,8 @@ private:
lua_CFunction destructfunc;
lua_CFunction functiongcfunc;
bool needsindexfunction;
void* baseclasscheck;
void* baseclasscast;
template<typename... Functions>
std::unique_ptr<function_detail::base_function> make_function(const std::string&, overload_set<Functions...> func) {
@ -328,6 +341,20 @@ private:
build_function_tables<N>(funcname, std::forward<Fx>(func), std::forward<Args>(args)...);
}
template<std::size_t N, typename... Bases, typename... Args>
void build_function_tables(bases<>, bases<Bases...>, Args&&... args) {
#ifndef SOL_NO_EXCEPTIONS
static_assert(sizeof(void*) <= sizeof(detail::throw_cast), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscast = (void*)&detail::throw_as<T>;
#elif !defined(SOL_NO_RTTI)
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscheck = (void*)&detail::userdata_check<T, Bases...>::check;
baseclasscast = (void*)&detail::userdata_check<T, Bases...>::cast;
#endif // No Runtime Type Information vs. Throw-Style Inheritance
build_function_tables<N>(std::forward<Args>(args)...);
}
template<std::size_t N>
void build_function_tables() {
int variableend = 0;
@ -358,7 +385,8 @@ private:
}
template<typename... Args>
usertype(usertype_detail::verified_tag, Args&&... args) : indexfunc(nullptr), newindexfunc(nullptr), constructfunc(nullptr), destructfunc(nullptr), functiongcfunc(nullptr), needsindexfunction(false) {
usertype(usertype_detail::verified_tag, Args&&... args) : indexfunc(nullptr), newindexfunc(nullptr), constructfunc(nullptr),
destructfunc(nullptr), functiongcfunc(nullptr), needsindexfunction(false), baseclasscheck(nullptr), baseclasscast(nullptr) {
functionnames.reserve(sizeof...(args)+3);
functiontable.reserve(sizeof...(args)+3);
metafunctiontable.reserve(sizeof...(args)+3);
@ -386,11 +414,11 @@ public:
int push(lua_State* L) {
// push pointer tables first,
usertype_detail::push_metatable<T*, true>(L, needsindexfunction, functions, functiontable, metafunctiontable);
usertype_detail::push_metatable<T*, true>(L, needsindexfunction, functions, functiontable, metafunctiontable, baseclasscheck, baseclasscast);
lua_pop(L, 1);
// but leave the regular T table on last
// so it can be linked to a type for usage with `.new(...)` or `:new(...)`
usertype_detail::push_metatable<T, false>(L, needsindexfunction, functions, functiontable, metafunctiontable);
usertype_detail::push_metatable<T, false>(L, needsindexfunction, functions, functiontable, metafunctiontable, baseclasscheck, baseclasscast);
// Make sure to drop a table in the global namespace to properly destroy the pushed functions
// at some later point in life
usertype_detail::set_global_deleter<T>(L, functiongcfunc, functions);