Improve unique_usertype handling to avoid needing the rebind_base typedef

This commit is contained in:
ThePhD 2019-04-13 04:05:34 -04:00
parent d17f967e66
commit 6282ed4bf0
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
11 changed files with 393 additions and 216 deletions

View File

@ -29,14 +29,14 @@ This is a customization point for users who need to *work with special kinds of
typedef boost::shared_ptr<T> actual_type; typedef boost::shared_ptr<T> actual_type;
static const bool value = true; static const bool value = true;
static bool is_null(const actual_type& value) { static bool is_null(const actual_type& ptr) {
return value == nullptr; return ptr == nullptr;
} }
static type* get (const actual_type& p) { static type* get (const actual_type& ptr) {
return p.get(); return ptr.get();
} }
} };
} }
This will allow the library to properly handle ``boost::shared_ptr<T>``, with ref-counting and all. The ``type`` is the type that lua and sol will interact with, and will allow you to pull out a non-owning reference / pointer to the data when you just ask for a plain ``T*`` or ``T&`` or ``T`` using the getter functions and properties of Sol. The ``actual_type`` is just the "real type" that controls the semantics (shared, unique, ``CComPtr``, ``ComPtr``, OpenGL handles, DirectX objects, the list goes on). This will allow the library to properly handle ``boost::shared_ptr<T>``, with ref-counting and all. The ``type`` is the type that lua and sol will interact with, and will allow you to pull out a non-owning reference / pointer to the data when you just ask for a plain ``T*`` or ``T&`` or ``T`` using the getter functions and properties of Sol. The ``actual_type`` is just the "real type" that controls the semantics (shared, unique, ``CComPtr``, ``ComPtr``, OpenGL handles, DirectX objects, the list goes on).

View File

@ -30,6 +30,7 @@
#include "trampoline.hpp" #include "trampoline.hpp"
#include "filters.hpp" #include "filters.hpp"
#include "stack.hpp" #include "stack.hpp"
#include "unique_usertype_traits.hpp"
namespace sol { namespace sol {
namespace u_detail { namespace u_detail {

View File

@ -26,6 +26,7 @@
#include "types.hpp" #include "types.hpp"
#include "usertype_traits.hpp" #include "usertype_traits.hpp"
#include "unique_usertype_traits.hpp"
namespace sol { namespace sol {
template <typename... Args> template <typename... Args>
@ -108,8 +109,8 @@ namespace sol {
template <typename U, typename Base, typename... Args> template <typename U, typename Base, typename... Args>
static int type_unique_cast_bases(types<Base, Args...>, 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; using uu_traits = unique_usertype_traits<U>;
typedef typename uu_traits::template rebind_base<Base> base_ptr; using base_ptr = typename uu_traits::template rebind_base<Base>;
string_view base_ti = usertype_traits<Base>::qualified_name(); string_view base_ti = usertype_traits<Base>::qualified_name();
if (base_ti == ti) { if (base_ti == ti) {
if (target_data != nullptr) { if (target_data != nullptr) {
@ -126,38 +127,60 @@ namespace sol {
template <typename U> template <typename U>
static int 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<void> rebind_t; if constexpr (is_base_rebindable_v<uu_traits>) {
typedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, bases_t> cond_bases_t; typedef typename uu_traits::template rebind_base<void> rebind_t;
string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name(); typedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, bases_t> cond_bases_t;
if (rebind_ti != this_rebind_ti) { string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();
// this is not even of the same unique type if (rebind_ti != this_rebind_ti) {
return 0; // this is not even of the same unique type
return 0;
}
string_view this_ti = usertype_traits<T>::qualified_name();
if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
string_view this_ti = usertype_traits<T>::qualified_name(); else {
if (ti == this_ti) { (void)rebind_ti;
// direct match, return 1 string_view this_ti = usertype_traits<T>::qualified_name();
return 1; if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti);
} }
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
template <typename U, typename... Bases> template <typename U, typename... Bases>
static int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { static int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) {
using uc_bases_t = types<Bases...>; using uc_bases_t = types<Bases...>;
typedef unique_usertype_traits<U> uu_traits; typedef unique_usertype_traits<U> uu_traits;
typedef typename uu_traits::template rebind_base<void> rebind_t; if constexpr (is_base_rebindable_v<uu_traits>) {
typedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, uc_bases_t> cond_bases_t; using rebind_t = typename uu_traits::template rebind_base<void>;
string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name(); using cond_bases_t = meta::conditional_t<std::is_void<rebind_t>::value, types<>, uc_bases_t>;
if (rebind_ti != this_rebind_ti) { string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();
// this is not even of the same unique type if (rebind_ti != this_rebind_ti) {
return 0; // this is not even of the same unique type
return 0;
}
string_view this_ti = usertype_traits<T>::qualified_name();
if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
string_view this_ti = usertype_traits<T>::qualified_name(); else {
if (ti == this_ti) { (void)rebind_ti;
// direct match, return 1 string_view this_ti = usertype_traits<T>::qualified_name();
return 1; if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti);
} }
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
}; };

View File

@ -33,6 +33,9 @@
#include <cmath> #include <cmath>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#include <optional> #include <optional>
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
#include <variant>
#endif // variant
#endif // C++17 #endif // C++17
@ -64,20 +67,20 @@ namespace stack {
tracking.use(1); tracking.use(1);
return static_cast<T>(lua_tointeger(L, index)); return static_cast<T>(lua_tointeger(L, index));
} }
#endif #endif
int isnum = 0; int isnum = 0;
const lua_Number value = lua_tonumberx(L, index, &isnum); const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) { if (isnum != 0) {
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = llround(value); const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) { if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1); tracking.use(1);
return static_cast<T>(integer_value); return static_cast<T>(integer_value);
} }
#else #else
tracking.use(1); tracking.use(1);
return static_cast<T>(value); return static_cast<T>(value);
#endif #endif
} }
const type t = type_of(L, index); const type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
@ -146,8 +149,8 @@ namespace stack {
}; };
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn> template <typename... Tn, typename C>
struct unqualified_check_getter<std::variant<Tn...>> { struct unqualified_check_getter<std::variant<Tn...>, C> {
typedef std::variant<Tn...> V; typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size; typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;

View File

@ -174,12 +174,10 @@ namespace sol { namespace stack {
return stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking); return stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking);
} }
} }
else if constexpr (!std::is_reference_v< else if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<Tu> && !is_base_rebindable_non_void_v<unique_usertype_traits<Tu>>) {
X> && is_unique_usertype_v<Tu> && !std::is_void_v<typename unique_usertype_traits<Tu>::template rebind_base<void>>) {
using u_traits = unique_usertype_traits<Tu>; using u_traits = unique_usertype_traits<Tu>;
using T = typename u_traits::type; using T = typename u_traits::type;
using Real = typename u_traits::actual_type; using Real = typename u_traits::actual_type;
using rebind_t = typename u_traits::template rebind_base<void>;
tracking.use(1); tracking.use(1);
void* memory = lua_touserdata(L, index); void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory); memory = detail::align_usertype_unique_destructor(memory);
@ -193,15 +191,23 @@ namespace sol { namespace stack {
Real r(nullptr); Real r(nullptr);
if constexpr (!derive<T>::value) { if constexpr (!derive<T>::value) {
// TODO: abort / terminate, maybe only in debug modes? // TODO: abort / terminate, maybe only in debug modes?
return static_cast<Real>(r); return static_cast<Real>(std::move(r));
} }
else { else {
memory = detail::align_usertype_unique_tag<true, false>(memory); memory = detail::align_usertype_unique_tag<true, false>(memory);
detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
memory = detail::align_usertype_unique<Real, true, false>(memory); memory = detail::align_usertype_unique<Real, true, false>(memory);
string_view ti = usertype_traits<T>::qualified_name(); string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name(); int cast_operation;
int cast_operation = ic(memory, &r, ti, rebind_ti); if constexpr (is_base_rebindable_v<u_traits>) {
using rebind_t = typename u_traits::template rebind_base<void>;
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name();
cast_operation = ic(memory, &r, ti, rebind_ti);
}
else {
string_view rebind_ti("");
cast_operation = ic(memory, &r, ti, rebind_ti);
}
switch (cast_operation) { switch (cast_operation) {
case 1: { case 1: {
// it's a perfect match, // it's a perfect match,
@ -974,8 +980,6 @@ namespace sol { namespace stack {
}; };
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn> template <typename... Tn>
struct unqualified_getter<std::variant<Tn...>> { struct unqualified_getter<std::variant<Tn...>> {
@ -1012,6 +1016,7 @@ namespace sol { namespace stack {
}; };
#endif // SOL_STD_VARIANT #endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES #endif // SOL_CXX17_FEATURES
}} // namespace sol::stack }} // namespace sol::stack
#endif // SOL_STACK_UNQUALIFIED_GET_HPP #endif // SOL_STACK_UNQUALIFIED_GET_HPP

View File

@ -196,7 +196,6 @@ namespace sol {
using u_traits = unique_usertype_traits<T>; using u_traits = unique_usertype_traits<T>;
using P = typename u_traits::type; using P = typename u_traits::type;
using Real = typename u_traits::actual_type; using Real = typename u_traits::actual_type;
using rebind_t = typename u_traits::template rebind_base<void>;
template <typename Arg, typename... Args> template <typename Arg, typename... Args>
static int push(lua_State* L, Arg&& arg, Args&&... args) { static int push(lua_State* L, Arg&& arg, Args&&... args) {

View File

@ -148,65 +148,6 @@ namespace sol {
typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref; typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref;
template <typename T>
struct unique_usertype_traits {
typedef T type;
typedef T actual_type;
template <typename X>
using rebind_base = void;
static const bool value = false;
template <typename U>
static bool is_null(U&&) {
return false;
}
template <typename U>
static auto get(U&& value) {
return std::addressof(detail::deref(value));
}
};
template <typename T>
struct unique_usertype_traits<std::shared_ptr<T>> {
typedef T type;
typedef std::shared_ptr<T> actual_type;
// rebind is non-void
// if and only if unique usertype
// is cast-capable
template <typename X>
using rebind_base = std::shared_ptr<X>;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T, typename D>
struct unique_usertype_traits<std::unique_ptr<T, D>> {
typedef T type;
typedef std::unique_ptr<T, D> actual_type;
template <typename X>
using rebind_base = void;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T> template <typename T>
struct non_null {}; struct non_null {};
@ -1176,12 +1117,6 @@ namespace sol {
struct accumulate_list<C, v, V, types<Args...>> : accumulate<C, v, V, Args...> {}; struct accumulate_list<C, v, V, types<Args...>> : accumulate<C, v, V, Args...> {};
} // namespace detail } // namespace detail
template <typename T>
struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {};
template <typename T>
inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value;
template <typename T> template <typename T>
struct lua_type_of : detail::lua_type_of<T> { struct lua_type_of : detail::lua_type_of<T> {
typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;

View File

@ -0,0 +1,124 @@
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2019 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_UNIQUE_USERTYPE_TRAITS_HPP
#define SOL_UNIQUE_USERTYPE_TRAITS_HPP
#include "base_traits.hpp"
#include <memory>
namespace sol {
template <typename T>
struct unique_usertype_traits {
typedef T type;
typedef T actual_type;
template <typename X>
using rebind_base = void;
static const bool value = false;
template <typename U>
static bool is_null(U&&) {
return false;
}
template <typename U>
static auto get(U&& value) {
return std::addressof(detail::deref(value));
}
};
template <typename T>
struct unique_usertype_traits<std::shared_ptr<T>> {
typedef T type;
typedef std::shared_ptr<T> actual_type;
// rebind is non-void
// if and only if unique usertype
// is cast-capable
template <typename X>
using rebind_base = std::shared_ptr<X>;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T, typename D>
struct unique_usertype_traits<std::unique_ptr<T, D>> {
using type = T;
using actual_type = std::unique_ptr<T, D>;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T>
struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {};
template <typename T>
inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value;
namespace detail {
template <typename T>
using is_base_rebindable_test = decltype(T::rebind_base);
}
template <typename T>
using is_base_rebindable = meta::is_detected<detail::is_base_rebindable_test, T>;
template <typename T>
inline constexpr bool is_base_rebindable_v = is_base_rebindable<T>::value;
namespace detail {
template <typename T, typename>
struct is_base_rebindable_non_void_sfinae : std::false_type {};
template <typename T>
struct is_base_rebindable_non_void_sfinae<T, std::enable_if_t<is_base_rebindable_v<T>>>
: std::integral_constant<bool, !std::is_void_v<typename T::template rebind_base<void>>> {};
} // namespace detail
template <typename T>
using is_base_rebindable_non_void = meta::is_detected<detail::is_base_rebindable_test, T>;
template <typename T>
inline constexpr bool is_base_rebindable_non_void_v = is_base_rebindable_non_void<T>::value;
} // namespace sol
#endif // SOL_UNIQUE_USERTYPE_TRAITS_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-04-08 03:11:15.372045 UTC // Generated 2019-04-13 08:04:51.418277 UTC
// This header was generated with sol v3.0.1-beta2 (revision 7cce3e4) // This header was generated with sol v3.0.1-beta2 (revision d17f967)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-04-08 03:11:10.821035 UTC // Generated 2019-04-13 08:04:48.327520 UTC
// This header was generated with sol v3.0.1-beta2 (revision 7cce3e4) // This header was generated with sol v3.0.1-beta2 (revision d17f967)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -6276,65 +6276,6 @@ namespace sol {
typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref; typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref;
template <typename T>
struct unique_usertype_traits {
typedef T type;
typedef T actual_type;
template <typename X>
using rebind_base = void;
static const bool value = false;
template <typename U>
static bool is_null(U&&) {
return false;
}
template <typename U>
static auto get(U&& value) {
return std::addressof(detail::deref(value));
}
};
template <typename T>
struct unique_usertype_traits<std::shared_ptr<T>> {
typedef T type;
typedef std::shared_ptr<T> actual_type;
// rebind is non-void
// if and only if unique usertype
// is cast-capable
template <typename X>
using rebind_base = std::shared_ptr<X>;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T, typename D>
struct unique_usertype_traits<std::unique_ptr<T, D>> {
typedef T type;
typedef std::unique_ptr<T, D> actual_type;
template <typename X>
using rebind_base = void;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T> template <typename T>
struct non_null {}; struct non_null {};
@ -7304,12 +7245,6 @@ namespace sol {
struct accumulate_list<C, v, V, types<Args...>> : accumulate<C, v, V, Args...> {}; struct accumulate_list<C, v, V, types<Args...>> : accumulate<C, v, V, Args...> {};
} // namespace detail } // namespace detail
template <typename T>
struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {};
template <typename T>
inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value;
template <typename T> template <typename T>
struct lua_type_of : detail::lua_type_of<T> { struct lua_type_of : detail::lua_type_of<T> {
typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_;
@ -7923,6 +7858,103 @@ namespace sol {
// end of sol/usertype_traits.hpp // end of sol/usertype_traits.hpp
// beginning of sol/unique_usertype_traits.hpp
namespace sol {
template <typename T>
struct unique_usertype_traits {
typedef T type;
typedef T actual_type;
template <typename X>
using rebind_base = void;
static const bool value = false;
template <typename U>
static bool is_null(U&&) {
return false;
}
template <typename U>
static auto get(U&& value) {
return std::addressof(detail::deref(value));
}
};
template <typename T>
struct unique_usertype_traits<std::shared_ptr<T>> {
typedef T type;
typedef std::shared_ptr<T> actual_type;
// rebind is non-void
// if and only if unique usertype
// is cast-capable
template <typename X>
using rebind_base = std::shared_ptr<X>;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T, typename D>
struct unique_usertype_traits<std::unique_ptr<T, D>> {
using type = T;
using actual_type = std::unique_ptr<T, D>;
static const bool value = true;
static bool is_null(const actual_type& p) {
return p == nullptr;
}
static type* get(const actual_type& p) {
return p.get();
}
};
template <typename T>
struct is_unique_usertype : std::integral_constant<bool, unique_usertype_traits<T>::value> {};
template <typename T>
inline constexpr bool is_unique_usertype_v = is_unique_usertype<T>::value;
namespace detail {
template <typename T>
using is_base_rebindable_test = decltype(T::rebind_base);
}
template <typename T>
using is_base_rebindable = meta::is_detected<detail::is_base_rebindable_test, T>;
template <typename T>
inline constexpr bool is_base_rebindable_v = is_base_rebindable<T>::value;
namespace detail {
template <typename T, typename>
struct is_base_rebindable_non_void_sfinae : std::false_type {};
template <typename T>
struct is_base_rebindable_non_void_sfinae<T, std::enable_if_t<is_base_rebindable_v<T>>>
: std::integral_constant<bool, !std::is_void_v<typename T::template rebind_base<void>>> {};
} // namespace detail
template <typename T>
using is_base_rebindable_non_void = meta::is_detected<detail::is_base_rebindable_test, T>;
template <typename T>
inline constexpr bool is_base_rebindable_non_void_v = is_base_rebindable_non_void<T>::value;
} // namespace sol
// end of sol/unique_usertype_traits.hpp
namespace sol { namespace sol {
template <typename... Args> template <typename... Args>
struct base_list {}; struct base_list {};
@ -8004,8 +8036,8 @@ namespace sol {
template <typename U, typename Base, typename... Args> template <typename U, typename Base, typename... Args>
static int type_unique_cast_bases(types<Base, Args...>, 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; using uu_traits = unique_usertype_traits<U>;
typedef typename uu_traits::template rebind_base<Base> base_ptr; using base_ptr = typename uu_traits::template rebind_base<Base>;
string_view base_ti = usertype_traits<Base>::qualified_name(); string_view base_ti = usertype_traits<Base>::qualified_name();
if (base_ti == ti) { if (base_ti == ti) {
if (target_data != nullptr) { if (target_data != nullptr) {
@ -8022,38 +8054,60 @@ namespace sol {
template <typename U> template <typename U>
static int 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<void> rebind_t; if constexpr (is_base_rebindable_v<uu_traits>) {
typedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, bases_t> cond_bases_t; typedef typename uu_traits::template rebind_base<void> rebind_t;
string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name(); typedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, bases_t> cond_bases_t;
if (rebind_ti != this_rebind_ti) { string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();
// this is not even of the same unique type if (rebind_ti != this_rebind_ti) {
return 0; // this is not even of the same unique type
return 0;
}
string_view this_ti = usertype_traits<T>::qualified_name();
if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
string_view this_ti = usertype_traits<T>::qualified_name(); else {
if (ti == this_ti) { (void)rebind_ti;
// direct match, return 1 string_view this_ti = usertype_traits<T>::qualified_name();
return 1; if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti);
} }
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
template <typename U, typename... Bases> template <typename U, typename... Bases>
static int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) { static int type_unique_cast_with(void* source_data, void* target_data, const string_view& ti, const string_view& rebind_ti) {
using uc_bases_t = types<Bases...>; using uc_bases_t = types<Bases...>;
typedef unique_usertype_traits<U> uu_traits; typedef unique_usertype_traits<U> uu_traits;
typedef typename uu_traits::template rebind_base<void> rebind_t; if constexpr (is_base_rebindable_v<uu_traits>) {
typedef meta::conditional_t<std::is_void<rebind_t>::value, types<>, uc_bases_t> cond_bases_t; using rebind_t = typename uu_traits::template rebind_base<void>;
string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name(); using cond_bases_t = meta::conditional_t<std::is_void<rebind_t>::value, types<>, uc_bases_t>;
if (rebind_ti != this_rebind_ti) { string_view this_rebind_ti = usertype_traits<rebind_t>::qualified_name();
// this is not even of the same unique type if (rebind_ti != this_rebind_ti) {
return 0; // this is not even of the same unique type
return 0;
}
string_view this_ti = usertype_traits<T>::qualified_name();
if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
string_view this_ti = usertype_traits<T>::qualified_name(); else {
if (ti == this_ti) { (void)rebind_ti;
// direct match, return 1 string_view this_ti = usertype_traits<T>::qualified_name();
return 1; if (ti == this_ti) {
// direct match, return 1
return 1;
}
return type_unique_cast_bases<U>(types<>(), source_data, target_data, ti);
} }
return type_unique_cast_bases<U>(cond_bases_t(), source_data, target_data, ti);
} }
}; };
@ -11548,12 +11602,10 @@ namespace sol { namespace stack {
return stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking); return stack_detail::unchecked_unqualified_get<sol::nested<Tu>>(L, index, tracking);
} }
} }
else if constexpr (!std::is_reference_v< else if constexpr (!std::is_reference_v<X> && is_unique_usertype_v<Tu> && !is_base_rebindable_non_void_v<unique_usertype_traits<Tu>>) {
X> && is_unique_usertype_v<Tu> && !std::is_void_v<typename unique_usertype_traits<Tu>::template rebind_base<void>>) {
using u_traits = unique_usertype_traits<Tu>; using u_traits = unique_usertype_traits<Tu>;
using T = typename u_traits::type; using T = typename u_traits::type;
using Real = typename u_traits::actual_type; using Real = typename u_traits::actual_type;
using rebind_t = typename u_traits::template rebind_base<void>;
tracking.use(1); tracking.use(1);
void* memory = lua_touserdata(L, index); void* memory = lua_touserdata(L, index);
memory = detail::align_usertype_unique_destructor(memory); memory = detail::align_usertype_unique_destructor(memory);
@ -11567,15 +11619,23 @@ namespace sol { namespace stack {
Real r(nullptr); Real r(nullptr);
if constexpr (!derive<T>::value) { if constexpr (!derive<T>::value) {
// TODO: abort / terminate, maybe only in debug modes? // TODO: abort / terminate, maybe only in debug modes?
return static_cast<Real>(r); return static_cast<Real>(std::move(r));
} }
else { else {
memory = detail::align_usertype_unique_tag<true, false>(memory); memory = detail::align_usertype_unique_tag<true, false>(memory);
detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory); detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
memory = detail::align_usertype_unique<Real, true, false>(memory); memory = detail::align_usertype_unique<Real, true, false>(memory);
string_view ti = usertype_traits<T>::qualified_name(); string_view ti = usertype_traits<T>::qualified_name();
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name(); int cast_operation;
int cast_operation = ic(memory, &r, ti, rebind_ti); if constexpr (is_base_rebindable_v<u_traits>) {
using rebind_t = typename u_traits::template rebind_base<void>;
string_view rebind_ti = usertype_traits<rebind_t>::qualified_name();
cast_operation = ic(memory, &r, ti, rebind_ti);
}
else {
string_view rebind_ti("");
cast_operation = ic(memory, &r, ti, rebind_ti);
}
switch (cast_operation) { switch (cast_operation) {
case 1: { case 1: {
// it's a perfect match, // it's a perfect match,
@ -12348,7 +12408,6 @@ namespace sol { namespace stack {
}; };
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn> template <typename... Tn>
struct unqualified_getter<std::variant<Tn...>> { struct unqualified_getter<std::variant<Tn...>> {
@ -12385,6 +12444,7 @@ namespace sol { namespace stack {
}; };
#endif // SOL_STD_VARIANT #endif // SOL_STD_VARIANT
#endif // SOL_CXX17_FEATURES #endif // SOL_CXX17_FEATURES
}} // namespace sol::stack }} // namespace sol::stack
// end of sol/stack_get_unqualified.hpp // end of sol/stack_get_unqualified.hpp
@ -12410,6 +12470,8 @@ namespace stack {
// beginning of sol/stack_check_get_unqualified.hpp // beginning of sol/stack_check_get_unqualified.hpp
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
#endif // variant
#endif // C++17 #endif // C++17
namespace sol { namespace sol {
@ -12439,20 +12501,20 @@ namespace stack {
tracking.use(1); tracking.use(1);
return static_cast<T>(lua_tointeger(L, index)); return static_cast<T>(lua_tointeger(L, index));
} }
#endif #endif
int isnum = 0; int isnum = 0;
const lua_Number value = lua_tonumberx(L, index, &isnum); const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) { if (isnum != 0) {
#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = llround(value); const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) { if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1); tracking.use(1);
return static_cast<T>(integer_value); return static_cast<T>(integer_value);
} }
#else #else
tracking.use(1); tracking.use(1);
return static_cast<T>(value); return static_cast<T>(value);
#endif #endif
} }
const type t = type_of(L, index); const type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
@ -12521,8 +12583,8 @@ namespace stack {
}; };
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
template <typename... Tn> template <typename... Tn, typename C>
struct unqualified_check_getter<std::variant<Tn...>> { struct unqualified_check_getter<std::variant<Tn...>, C> {
typedef std::variant<Tn...> V; typedef std::variant<Tn...> V;
typedef std::variant_size<V> V_size; typedef std::variant_size<V> V_size;
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
@ -12785,7 +12847,6 @@ namespace sol {
using u_traits = unique_usertype_traits<T>; using u_traits = unique_usertype_traits<T>;
using P = typename u_traits::type; using P = typename u_traits::type;
using Real = typename u_traits::actual_type; using Real = typename u_traits::actual_type;
using rebind_t = typename u_traits::template rebind_base<void>;
template <typename Arg, typename... Args> template <typename Arg, typename... Args>
static int push(lua_State* L, Arg&& arg, Args&&... args) { static int push(lua_State* L, Arg&& arg, Args&&... args) {

View File

@ -0,0 +1,26 @@
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2019 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "sol_defines.hpp"
#include <sol/unique_usertype_traits.hpp>