mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Inheritance
This commit is contained in:
parent
22f74a31a2
commit
19578538e7
|
@ -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
|
||||
|
|
|
@ -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<>>{};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user