add ability to have aliasing arguments

This commit is contained in:
ThePhD 2018-06-17 15:42:24 -04:00
parent 860827cb0a
commit 96143d8d79
9 changed files with 114 additions and 71 deletions

View File

@ -26,6 +26,8 @@
#include "feature_test.hpp" #include "feature_test.hpp"
#include <utility>
namespace sol { namespace sol {
template <bool b> template <bool b>
@ -158,6 +160,24 @@ namespace sol {
struct usertype_traits; struct usertype_traits;
template <typename T> template <typename T>
struct unique_usertype_traits; struct unique_usertype_traits;
template <typename... Args>
struct types {
typedef std::make_index_sequence<sizeof...(Args)> indices;
static constexpr std::size_t size() {
return sizeof...(Args);
}
};
template <typename T>
struct derive : std::false_type {
typedef types<> type;
};
template <typename T>
struct base : std::false_type {
typedef types<> type;
};
} // namespace sol } // namespace sol
#endif // SOL_FORWARD_HPP #endif // SOL_FORWARD_HPP

View File

@ -38,16 +38,6 @@ namespace sol {
namespace detail { namespace detail {
template <typename T>
struct derive : std::false_type {
typedef types<> type;
};
template <typename T>
struct base : std::false_type {
typedef types<> type;
};
inline decltype(auto) base_class_check_key() { inline decltype(auto) base_class_check_key() {
static const auto& key = "class_check"; static const auto& key = "class_check";
return key; return key;
@ -68,8 +58,10 @@ namespace sol {
return key; return key;
} }
template <typename T, typename... Bases> template <typename T>
struct inheritance { struct inheritance {
typedef typename base<T>::type bases_t;
static bool type_check_bases(types<>, const std::string&) { static bool type_check_bases(types<>, const std::string&) {
return false; return false;
} }
@ -80,7 +72,7 @@ namespace sol {
} }
static bool type_check(const std::string& ti) { static bool type_check(const std::string& ti) {
return ti == usertype_traits<T>::qualified_name() || type_check_bases(types<Bases...>(), ti); return ti == usertype_traits<T>::qualified_name() || type_check_bases(bases_t(), ti);
} }
static void* type_cast_bases(types<>, T*, const std::string&) { static void* type_cast_bases(types<>, T*, const std::string&) {
@ -95,16 +87,16 @@ namespace sol {
static void* type_cast(void* voiddata, const std::string& ti) { static void* type_cast(void* voiddata, const std::string& ti) {
T* data = static_cast<T*>(voiddata); T* data = static_cast<T*>(voiddata);
return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(types<Bases...>(), data, ti) : data); return static_cast<void*>(ti != usertype_traits<T>::qualified_name() ? type_cast_bases(bases_t(), data, ti) : data);
} }
template <typename U> template <typename U>
static bool type_unique_cast_bases(void*, void*, const string_view&) { static bool type_unique_cast_bases(types<>, void*, void*, const string_view&) {
return false; return 0;
} }
template <typename U, typename Base, typename... Args> template <typename U, typename Base, typename... Args>
static bool type_unique_cast_bases(void* source_data, void* target_data, const string_view& ti) { static int type_unique_cast_bases(types<Base, Args...>, void* source_data, void* target_data, const string_view& ti) {
typedef unique_usertype_traits<U> uu_traits; typedef unique_usertype_traits<U> uu_traits;
typedef typename uu_traits::template rebind_base<Base> base_ptr; typedef typename uu_traits::template rebind_base<Base> base_ptr;
string_view base_ti = usertype_traits<Base>::qualified_name(); string_view base_ti = usertype_traits<Base>::qualified_name();
@ -115,21 +107,26 @@ namespace sol {
// perform proper derived -> base conversion // perform proper derived -> base conversion
*target = *source; *target = *source;
} }
return true; return 2;
} }
return type_unique_cast_bases<U, Args...>(source_data, target_data, ti); return type_unique_cast_bases<U>(types<Args...>(), source_data, target_data, ti);
} }
template <typename U> template <typename U>
static bool type_unique_cast(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { static int type_unique_cast(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) {
typedef unique_usertype_traits<U> uu_traits; typedef unique_usertype_traits<U> uu_traits;
typedef typename uu_traits::template rebind_base<T> rebind_t; typedef typename uu_traits::template rebind_base<void> rebind_t;
string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name(); string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();
if (rebind_ti != this_rebind_ti) { if (rebind_ti != this_rebind_ti) {
// this is not even of the same container type // this is not even of the same unique type
return false; return 0;
} }
return type_unique_cast_bases<U, Bases...>(source_data, target_data, ti); string_view this_ti = usertype_traits<T>::qualified_name();
if (ti == this_ti) {
//
return 1;
}
return type_unique_cast_bases<U>(bases_t(), source_data, target_data, ti);
} }
}; };
@ -139,4 +136,7 @@ namespace sol {
} // namespace detail } // namespace detail
} // namespace sol } // namespace sol
#define SOL_BASE_CLASSES(T, ...) template <> struct ::sol::base<T> : ::std::true_type { typedef ::sol::types<__VA_ARGS__> type; };
//#define SOL_DERIVED_CLASSES(T, ...) template <> struct ::sol::derive<T> : ::std::true_type { typedef ::sol::types<__VA_ARGS__> type; };
#endif // SOL_INHERITANCE_HPP #endif // SOL_INHERITANCE_HPP

View File

@ -29,11 +29,14 @@
namespace sol { namespace sol {
namespace stack { namespace stack {
#if 0
template <typename X> template <typename X>
struct qualified_checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value && !std::is_reference<X>::value>> { struct qualified_checker<X, type::userdata, std::enable_if_t<
is_unique_usertype<X>::value
&& !std::is_reference<X>::value
>> {
typedef unique_usertype_traits<meta::unqualified_t<X>> u_traits; typedef unique_usertype_traits<meta::unqualified_t<X>> u_traits;
typedef typename u_traits::type T; typedef typename u_traits::type T;
typedef typename u_traits::template rebind_base<void> rebind_t;
template <typename Handler> template <typename Handler>
static bool check(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) {
@ -50,23 +53,19 @@ namespace stack {
handler(L, index, type::userdata, indextype, "value is not a userdata"); handler(L, index, type::userdata, indextype, "value is not a userdata");
return false; return false;
} }
if (lua_getmetatable(L, index) == 0) { void* memory = lua_touserdata(L, index);
return true; memory = detail::align_usertype_unique_destructor(memory);
}
int metatableindex = lua_gettop(L);
void* basecastdata = lua_touserdata(L, index);
void* memory = detail::align_usertype_unique_destructor(basecastdata);
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) { if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {
return true; return true;
} }
if (detail::has_derived<T>::value) { if (derive<T>::value) {
memory = detail::align_usertype_unique_cast<true>(memory); memory = detail::align_usertype_unique_tag<true, false>(memory);
detail::inheritance_unique_cast_function ic = reinterpret_cast<detail::inheritance_unique_cast_function>(memory); detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
string_view ti = usertype_traits<T>::qualified_name(); string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<base_id>::qualified_name(); string_view rebind_ti = usertype_traits<rebind_t>::qualified_name();
if (ic(nullptr, basecastdata, ti, rebind_ti)) { if (ic(nullptr, nullptr, ti, rebind_ti) != 0) {
lua_pop(L, 1); return true;
} }
} }
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
@ -75,12 +74,10 @@ namespace stack {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check(meta::neg<std::is_void<typename u_traits::base_id>>(), L, index, std::forward<Handler>(handler), tracking); return check(meta::neg<std::is_void<rebind_t>>(), L, index, std::forward<Handler>(handler), tracking);
} }
}; };
#endif // Not implemented right now...
template <typename X> template <typename X>
struct qualified_checker<X, type::userdata, std::enable_if_t<is_container<meta::unqualified_t<X>>::value && !std::is_reference<X>::value>> { struct qualified_checker<X, type::userdata, std::enable_if_t<is_container<meta::unqualified_t<X>>::value && !std::is_reference<X>::value>> {
template <typename Handler> template <typename Handler>

View File

@ -473,7 +473,7 @@ namespace stack {
if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex)) if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex))
return true; return true;
bool success = false; bool success = false;
if (detail::derive<T>::value) { if (derive<T>::value) {
auto pn = stack::pop_n(L, 1); auto pn = stack::pop_n(L, 1);
lua_pushstring(L, &detail::base_class_check_key()[0]); lua_pushstring(L, &detail::base_class_check_key()[0]);
lua_rawget(L, metatableindex); lua_rawget(L, metatableindex);

View File

@ -52,11 +52,7 @@ namespace sol {
struct as_table_tag {}; struct as_table_tag {};
using unique_destructor = void (*)(void*); using unique_destructor = void (*)(void*);
#if 0
using unique_tag = detail::inheritance_unique_cast_function; using unique_tag = detail::inheritance_unique_cast_function;
#else
using unique_tag = const char*;
#endif
inline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space, std::size_t& required_space) { inline void* align(std::size_t alignment, std::size_t size, void*& ptr, std::size_t& space, std::size_t& required_space) {
// this handels arbitrary alignments... // this handels arbitrary alignments...
@ -108,7 +104,7 @@ namespace sol {
return align(std::alignment_of<void*>::value, sizeof(void*), ptr, space); return align(std::alignment_of<void*>::value, sizeof(void*), ptr, space);
} }
template <bool pre_aligned = false> template <bool pre_aligned = false, bool pre_shifted = false>
inline void* align_usertype_unique_destructor(void* ptr) { inline void* align_usertype_unique_destructor(void* ptr) {
typedef std::integral_constant<bool, typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
@ -120,6 +116,8 @@ namespace sol {
use_align; use_align;
if (!pre_aligned) { if (!pre_aligned) {
ptr = align_usertype_pointer(ptr); ptr = align_usertype_pointer(ptr);
}
if (!pre_shifted) {
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*)); ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*));
} }
if (!use_align::value) { if (!use_align::value) {
@ -129,7 +127,7 @@ namespace sol {
return align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), ptr, space); return align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), ptr, space);
} }
template <bool pre_aligned = false> template <bool pre_aligned = false, bool pre_shifted = false>
inline void* align_usertype_unique_tag(void* ptr) { inline void* align_usertype_unique_tag(void* ptr) {
typedef std::integral_constant<bool, typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
@ -141,6 +139,8 @@ namespace sol {
use_align; use_align;
if (!pre_aligned) { if (!pre_aligned) {
ptr = align_usertype_unique_destructor(ptr); ptr = align_usertype_unique_destructor(ptr);
}
if (!pre_shifted) {
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor)); ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor));
} }
if (!use_align::value) { if (!use_align::value) {
@ -149,7 +149,8 @@ namespace sol {
std::size_t space = (std::numeric_limits<std::size_t>::max)(); std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), ptr, space); return align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), ptr, space);
} }
template <typename T, bool pre_aligned = false>
template <typename T, bool pre_aligned = false, bool pre_shifted = false>
inline void* align_usertype_unique(void* ptr) { inline void* align_usertype_unique(void* ptr) {
typedef std::integral_constant<bool, typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT #if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
@ -161,6 +162,8 @@ namespace sol {
use_align; use_align;
if (!pre_aligned) { if (!pre_aligned) {
ptr = align_usertype_unique_tag(ptr); ptr = align_usertype_unique_tag(ptr);
}
if (!pre_shifted) {
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_tag)); ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_tag));
} }
if (!use_align::value) { if (!use_align::value) {

View File

@ -29,24 +29,57 @@
namespace sol { namespace sol {
namespace stack { namespace stack {
#if 0 // need static reflection / DERIVED_CLASS macros...
template <typename X> template <typename X>
struct qualified_getter<X, std::enable_if_t< struct qualified_getter<X, std::enable_if_t<
!std::is_reference<X>::value && is_unique_usertype<meta::unqualified_t<X>>::value !std::is_reference<X>::value
&& is_unique_usertype<meta::unqualified_t<X>>::value
>> { >> {
typedef typename unique_usertype_traits<meta::unqualified_t<X>>::type P; typedef unique_usertype_traits<meta::unqualified_t<X>> u_traits;
typedef typename unique_usertype_traits<meta::unqualified_t<X>>::actual_type Real; typedef typename u_traits::type T;
typedef typename u_traits::actual_type Real;
typedef typename u_traits::template rebind_base<void> rebind_t;
static Real& get(lua_State* L, int index, record& tracking) { static Real get(lua_State* L, int index, record& tracking) {
tracking.use(1); tracking.use(1);
void* memory = lua_touserdata(L, index); void* memory = lua_touserdata(L, index);
void* del = detail::align_usertype_unique_destructor(memory); memory = detail::align_usertype_unique_destructor(memory);
memory = detail::align_usertype_unique<Real>(memory); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
Real* mem = static_cast<Real*>(memory); if (&detail::usertype_unique_alloc_destroy<T, X> == pdx) {
return *mem; memory = detail::align_usertype_unique_tag<true, false>(memory);
memory = detail::align_usertype_unique<Real, true, false>(memory);
Real* mem = static_cast<Real*>(memory);
return *mem;
}
Real r(nullptr);
if (!derive<T>::value) {
// TODO: abort / terminate, maybe only in debug modes?
return r;
}
memory = detail::align_usertype_unique_tag<true, false>(memory);
detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
memory = detail::align_usertype_unique<Real, true, false>(memory);
string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name();
int cast_operation = ic(memory, &r, ti, rebind_ti);
switch (cast_operation) {
case 1: {
// it's a perfect match,
// alias memory directly
Real* mem = static_cast<Real*>(memory);
return *mem;
}
case 2:
// it's a base match, return the
// aliased creation
return std::move(r);
default:
// uh oh..
break;
}
// TODO: abort / terminate, maybe only in debug modes?
return r;
} }
}; };
#endif // need static reflection
template <typename T> template <typename T>
struct qualified_getter<T, std::enable_if_t< struct qualified_getter<T, std::enable_if_t<
@ -68,3 +101,4 @@ namespace stack {
} // namespace sol::stack } // namespace sol::stack
#endif // SOL_STACK_QUALIFIED_GET_HPP #endif // SOL_STACK_QUALIFIED_GET_HPP

View File

@ -759,7 +759,7 @@ namespace stack {
} }
static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) { static T* get_no_lua_nil_from(lua_State* L, void* udata, int index, record&) {
if (detail::derive<T>::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) { if (derive<T>::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = lua_touserdata(L, -1); void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_cast_function ic = reinterpret_cast<detail::inheritance_cast_function>(basecastdata); detail::inheritance_cast_function ic = reinterpret_cast<detail::inheritance_cast_function>(basecastdata);
// use the casting function to properly adjust the pointer for the desired T // use the casting function to properly adjust the pointer for the desired T

View File

@ -167,11 +167,7 @@ namespace stack {
detail::unique_tag* id = nullptr; detail::unique_tag* id = nullptr;
Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id); Real* mem = detail::usertype_unique_allocate<P, Real>(L, pref, fx, id);
*fx = detail::usertype_unique_alloc_destroy<P, Real>; *fx = detail::usertype_unique_alloc_destroy<P, Real>;
#if 0 *id = &detail::inheritance<P>::type_unique_cast<Real>;
*id = &detail::inheritance<P>::type_unique_cast_bases<Real>;
#else
*id = &usertype_traits<Real>::qualified_name()[0];
#endif
detail::default_construct::construct(mem, std::forward<Args>(args)...); detail::default_construct::construct(mem, std::forward<Args>(args)...);
*pref = unique_usertype_traits<T>::get(*mem); *pref = unique_usertype_traits<T>::get(*mem);
if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) { if (luaL_newmetatable(L, &usertype_traits<detail::unique_usertype<std::remove_cv_t<P>>>::metatable()[0]) == 1) {

View File

@ -32,13 +32,6 @@ namespace sol {
using swallow = std::initializer_list<int>; using swallow = std::initializer_list<int>;
} // namespace detail } // namespace detail
template <typename... Args>
struct types {
typedef std::make_index_sequence<sizeof...(Args)> indices;
static constexpr std::size_t size() {
return sizeof...(Args);
}
};
namespace meta { namespace meta {
namespace detail { namespace detail {
template <typename... Args> template <typename... Args>