Rework table internals for more performance in more cases and handle additional cases of update_if_empty and create_if_nil

This commit is contained in:
ThePhD 2019-05-21 02:13:56 -04:00
parent bd17c83250
commit 5dee45cd9e
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
16 changed files with 991 additions and 610 deletions

View File

@ -70,8 +70,8 @@ add_library(${catch_lib} INTERFACE)
target_include_directories(${catch_lib} INTERFACE ${catch_include_dirs})
if (MSVC)
target_compile_options(${catch_lib} INTERFACE
/D_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING)
target_compile_definitions(${catch_lib} INTERFACE
_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING)
endif()
set(CATCH_FOUND TRUE)

View File

@ -85,7 +85,7 @@ namespace detail {
}
#elif defined(_MSC_VER)
template <typename T>
inline std::string ctti_get_type_name() {
std::string ctti_get_type_name() {
std::string name = __FUNCSIG__;
std::size_t start = name.find("get_type_name");
if (start == std::string::npos)
@ -122,13 +122,13 @@ namespace detail {
#endif // compilers
template <typename T>
inline std::string demangle_once() {
std::string demangle_once() {
std::string realname = ctti_get_type_name<T>();
return realname;
}
template <typename T>
inline std::string short_demangle_once() {
std::string short_demangle_once() {
std::string realname = ctti_get_type_name<T>();
// This isn't the most complete but it'll do for now...?
static const std::array<std::string, 10> ops = {{"operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*"}};
@ -166,13 +166,13 @@ namespace detail {
}
template <typename T>
inline const std::string& demangle() {
const std::string& demangle() {
static const std::string d = demangle_once<T>();
return d;
}
template <typename T>
inline const std::string& short_demangle() {
const std::string& short_demangle() {
static const std::string d = short_demangle_once<T>();
return d;
}

View File

@ -32,7 +32,7 @@
namespace sol {
template <typename... Ret, typename... Args>
inline decltype(auto) stack_proxy::call(Args&&... args) {
decltype(auto) stack_proxy::call(Args&&... args) {
stack_function sf(this->lua_state(), this->stack_index());
return sf.template call<Ret...>(std::forward<Args>(args)...);
}

View File

@ -42,7 +42,7 @@ namespace sol {
struct call_indicator {};
template <bool yielding>
inline int lua_c_wrapper(lua_State* L) {
int lua_c_wrapper(lua_State* L) {
lua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2));
int nr = cf(L);
if constexpr (yielding) {
@ -54,7 +54,7 @@ namespace sol {
}
template <bool yielding>
inline int lua_c_noexcept_wrapper(lua_State* L) noexcept {
int lua_c_noexcept_wrapper(lua_State* L) noexcept {
detail::lua_CFunction_noexcept cf = reinterpret_cast<detail::lua_CFunction_noexcept>(lua_tocfunction(L, lua_upvalueindex(2)));
int nr = cf(L);
if constexpr (yielding) {
@ -68,10 +68,10 @@ namespace sol {
struct c_function_invocation {};
template <bool is_yielding, typename Fx, typename... Args>
inline void select(lua_State* L, Fx&& fx, Args&&... args);
void select(lua_State* L, Fx&& fx, Args&&... args);
template <bool is_yielding, typename Fx, typename... Args>
inline void select_set_fx(lua_State* L, Args&&... args) {
void select_set_fx(lua_State* L, Args&&... args) {
lua_CFunction freefunc = detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>;
int upvalues = 0;
@ -81,7 +81,7 @@ namespace sol {
}
template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args>
inline void select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
void select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
using dFx = std::decay_t<meta::unwrap_unqualified_t<Fx>>;
using fx_ptr_t = R (*)(A...);
constexpr bool is_convertible = std::is_convertible_v<dFx, fx_ptr_t>;
@ -96,13 +96,13 @@ namespace sol {
}
template <bool is_yielding, typename Fx, typename... Args>
inline void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename... Args>
inline void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) {
void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) {
using uFx = meta::unqualified_t<Fx>;
if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<uFx>::object_type;
@ -152,7 +152,7 @@ namespace sol {
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
inline void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
using dFx = std::decay_t<Fx>;
using Tu = meta::unqualified_t<T>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
@ -185,7 +185,7 @@ namespace sol {
}
template <bool is_yielding, typename Fx, typename... Args>
inline void select_member_function(lua_State* L, Fx&& fx, Args&&... args) {
void select_member_function(lua_State* L, Fx&& fx, Args&&... args) {
using dFx = std::decay_t<Fx>;
if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type;
@ -202,7 +202,7 @@ namespace sol {
}
template <bool is_yielding, typename Fx, typename... Args>
inline void select(lua_State* L, Fx&& fx, Args&&... args) {
void select(lua_State* L, Fx&& fx, Args&&... args) {
using uFx = meta::unqualified_t<Fx>;
if constexpr (is_lua_reference_v<uFx>) {
// TODO: hoist into lambda in this case for yielding???

View File

@ -32,7 +32,7 @@
namespace sol {
namespace function_detail {
template <typename Fx, int start = 1, bool is_yielding = false>
inline int call(lua_State* L) {
int call(lua_State* L) {
Fx& fx = stack::get<user<Fx>>(L, upvalue_index(start));
int nr = fx(L);
if (is_yielding) {

View File

@ -91,7 +91,7 @@ namespace sol {
}
template <typename... Args>
inline std::size_t aligned_space_for(void* alignment = nullptr) {
std::size_t aligned_space_for(void* alignment = nullptr) {
char* start = static_cast<char*>(alignment);
(void)detail::swallow{ int{}, (align_one(std::alignment_of_v<Args>, sizeof(Args), alignment), int{})... };
return static_cast<char*>(alignment) - start;
@ -113,7 +113,7 @@ namespace sol {
}
template <bool pre_aligned = false, bool pre_shifted = false>
inline void* align_usertype_unique_destructor(void* ptr) {
void* align_usertype_unique_destructor(void* ptr) {
using use_align = std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -135,7 +135,7 @@ namespace sol {
}
template <bool pre_aligned = false, bool pre_shifted = false>
inline void* align_usertype_unique_tag(void* ptr) {
void* align_usertype_unique_tag(void* ptr) {
using use_align = std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -157,7 +157,7 @@ namespace sol {
}
template <typename T, bool pre_aligned = false, bool pre_shifted = false>
inline void* align_usertype_unique(void* ptr) {
void* align_usertype_unique(void* ptr) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -180,7 +180,7 @@ namespace sol {
}
template <typename T>
inline void* align_user(void* ptr) {
void* align_user(void* ptr) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -197,7 +197,7 @@ namespace sol {
}
template <typename T>
inline T** usertype_allocate_pointer(lua_State* L) {
T** usertype_allocate_pointer(lua_State* L) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -290,7 +290,7 @@ namespace sol {
}
template <typename T>
inline T* usertype_allocate(lua_State* L) {
T* usertype_allocate(lua_State* L) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -355,7 +355,7 @@ namespace sol {
}
template <typename T, typename Real>
inline Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) {
Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -429,7 +429,7 @@ namespace sol {
}
template <typename T>
inline T* user_allocate(lua_State* L) {
T* user_allocate(lua_State* L) {
typedef std::integral_constant<bool,
#if defined(SOL_NO_MEMORY_ALIGNMENT) && SOL_NO_MEMORY_ALIGNMENT
false
@ -464,7 +464,7 @@ namespace sol {
}
template <typename T>
inline int usertype_alloc_destruct(lua_State* L) {
int usertype_alloc_destruct(lua_State* L) {
void* memory = lua_touserdata(L, 1);
memory = align_usertype_pointer(memory);
T** pdata = static_cast<T**>(memory);
@ -475,7 +475,7 @@ namespace sol {
}
template <typename T>
inline int unique_destruct(lua_State* L) {
int unique_destruct(lua_State* L) {
void* memory = lua_touserdata(L, 1);
memory = align_usertype_unique_destructor(memory);
unique_destructor& dx = *static_cast<unique_destructor*>(memory);
@ -485,7 +485,7 @@ namespace sol {
}
template <typename T>
inline int user_alloc_destruct(lua_State* L) {
int user_alloc_destruct(lua_State* L) {
void* memory = lua_touserdata(L, 1);
memory = align_user<T>(memory);
T* data = static_cast<T*>(memory);
@ -495,7 +495,7 @@ namespace sol {
}
template <typename T, typename Real>
inline void usertype_unique_alloc_destroy(void* memory) {
void usertype_unique_alloc_destroy(void* memory) {
memory = align_usertype_unique<Real, true>(memory);
Real* target = static_cast<Real*>(memory);
std::allocator<Real> alloc;
@ -503,7 +503,7 @@ namespace sol {
}
template <typename T>
inline int cannot_destruct(lua_State* L) {
int cannot_destruct(lua_State* L) {
return luaL_error(L,
"cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= "
"delete' and thusly this type is being destroyed without properly destructing, invoking undefined "
@ -650,7 +650,8 @@ namespace sol {
= decltype(sol_lua_interop_check(types<T>(), static_cast<lua_State*>(nullptr), -1, type::none, no_panic, std::declval<stack::record&>()));
template <typename T>
using adl_sol_lua_check_get_test_t = decltype(sol_lua_check_get(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()));
using adl_sol_lua_check_get_test_t
= decltype(sol_lua_check_get(types<T>(), static_cast<lua_State*>(nullptr), -1, no_panic, std::declval<stack::record&>()));
template <typename... Args>
using adl_sol_lua_push_test_t = decltype(sol_lua_push(static_cast<lua_State*>(nullptr), std::declval<Args>()...));
@ -723,7 +724,7 @@ namespace sol {
}
template <typename T>
inline decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) {
decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_get_v<Tu>) {
return sol_lua_get(types<Tu>(), L, index, tracking);
@ -736,7 +737,7 @@ namespace sol {
}
template <typename T>
inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_get_v<T>) {
return sol_lua_get(types<T>(), L, index, tracking);
}
@ -748,7 +749,7 @@ namespace sol {
}
template <typename T>
inline decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {
decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<Tu>) {
return sol_lua_interop_get(types<Tu>(), L, index, unadjusted_pointer, tracking);
@ -764,7 +765,7 @@ namespace sol {
}
template <typename T>
inline decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {
decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<T>) {
return sol_lua_interop_get(types<T>(), L, index, unadjusted_pointer, tracking);
}
@ -798,7 +799,7 @@ namespace sol {
return unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking);
}
}
using undefined_method_func = void (*)(stack_reference);
struct undefined_metatable {
@ -874,7 +875,7 @@ namespace sol {
}
template <typename T, typename... Args>
inline int push(lua_State* L, T&& t, Args&&... args) {
int push(lua_State* L, T&& t, Args&&... args) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, T, Args...>) {
return sol_lua_push(types<T>(), L, std::forward<T>(t), std::forward<Args>(args)...);
@ -894,7 +895,7 @@ namespace sol {
// overload allows to use a pusher of a specific type, but pass in any kind of args
template <typename T, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same<T, Arg>::value>>
inline int push(lua_State* L, Arg&& arg, Args&&... args) {
int push(lua_State* L, Arg&& arg, Args&&... args) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, Arg, Args...>) {
return sol_lua_push(types<T>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...);
@ -915,7 +916,7 @@ namespace sol {
namespace stack_detail {
template <typename T, typename Arg, typename... Args>
inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) {
int push_reference(lua_State* L, Arg&& arg, Args&&... args) {
using use_reference_tag = meta::all<std::is_lvalue_reference<T>,
meta::neg<std::is_const<T>>,
meta::neg<is_lua_primitive<meta::unqualified_t<T>>>,
@ -927,12 +928,12 @@ namespace sol {
} // namespace stack_detail
template <typename T, typename... Args>
inline int push_reference(lua_State* L, T&& t, Args&&... args) {
int push_reference(lua_State* L, T&& t, Args&&... args) {
return stack_detail::push_reference<T>(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Arg, typename... Args>
inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) {
int push_reference(lua_State* L, Arg&& arg, Args&&... args) {
return stack_detail::push_reference<T>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
@ -942,7 +943,7 @@ namespace sol {
}
template <typename T, typename... Args>
inline int multi_push(lua_State* L, T&& t, Args&&... args) {
int multi_push(lua_State* L, T&& t, Args&&... args) {
int pushcount = push(L, std::forward<T>(t));
void(detail::swallow{ (pushcount += stack::push(L, std::forward<Args>(args)), 0)... });
return pushcount;
@ -954,7 +955,7 @@ namespace sol {
}
template <typename T, typename... Args>
inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) {
int multi_push_reference(lua_State* L, T&& t, Args&&... args) {
int pushcount = push_reference(L, std::forward<T>(t));
void(detail::swallow{ (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... });
return pushcount;
@ -1039,7 +1040,7 @@ namespace sol {
}
template <typename T, typename Handler>
inline decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) {
return sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking);
@ -1055,19 +1056,19 @@ namespace sol {
}
template <typename T, typename Handler>
inline decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) {
decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) {
record tracking{};
return unqualified_check_get<T>(L, index, handler, tracking);
}
template <typename T>
inline decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return unqualified_check_get<T>(L, index, handler);
}
template <typename T, typename Handler>
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) {
return sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking);
}
@ -1079,13 +1080,13 @@ namespace sol {
}
template <typename T, typename Handler>
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) {
decltype(auto) check_get(lua_State* L, int index, Handler&& handler) {
record tracking{};
return check_get<T>(L, index, handler, tracking);
}
template <typename T>
inline decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return check_get<T>(L, index, handler);
}
@ -1093,19 +1094,19 @@ namespace sol {
namespace stack_detail {
template <typename Handler>
inline bool check_types(lua_State*, int, Handler&&, record&) {
bool check_types(lua_State*, int, Handler&&, record&) {
return true;
}
template <typename T, typename... Args, typename Handler>
inline bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) {
bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) {
if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))
return false;
return check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking);
}
template <typename... Args, typename Handler>
inline bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) {
bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) {
return check_types<Args...>(L, index, std::forward<Handler>(handler), tracking);
}
@ -1128,7 +1129,7 @@ namespace sol {
}
template <typename T>
inline auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get<T>(L, index, tracking)) {
auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get<T>(L, index, tracking)) {
#if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER
static constexpr bool is_op = meta::is_specialization_of_v<T, optional>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
@ -1151,13 +1152,13 @@ namespace sol {
}
template <typename T>
inline decltype(auto) unqualified_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
decltype(auto) unqualified_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking{};
return unqualified_get<T>(L, index, tracking);
}
template <typename T>
inline auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
#if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER
static constexpr bool is_op = meta::is_specialization_of_v<T, optional>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
@ -1180,25 +1181,25 @@ namespace sol {
}
template <typename T>
inline decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking{};
return get<T>(L, index, tracking);
}
template <typename T>
inline decltype(auto) get_usertype(lua_State* L, int index, record& tracking) {
decltype(auto) get_usertype(lua_State* L, int index, record& tracking) {
using UT = meta::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>;
return get<UT>(L, index, tracking);
}
template <typename T>
inline decltype(auto) get_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
decltype(auto) get_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking{};
return get_usertype<T>(L, index, tracking);
}
template <typename T>
inline decltype(auto) pop(lua_State* L) {
decltype(auto) pop(lua_State* L) {
return popper<meta::unqualified_t<T>>{}.pop(L);
}
@ -1263,7 +1264,7 @@ namespace sol {
}
template <typename T, typename F>
inline void modify_unique_usertype_as(const stack_reference& obj, F&& f) {
void modify_unique_usertype_as(const stack_reference& obj, F&& f) {
using u_traits = unique_usertype_traits<T>;
void* raw = lua_touserdata(obj.lua_state(), obj.stack_index());
void* ptr_memory = detail::align_usertype_pointer(raw);
@ -1274,7 +1275,7 @@ namespace sol {
}
template <typename F>
inline void modify_unique_usertype(const stack_reference& obj, F&& f) {
void modify_unique_usertype(const stack_reference& obj, F&& f) {
using bt = meta::bind_traits<meta::unqualified_t<F>>;
using T = typename bt::template arg_at<0>;
using Tu = meta::unqualified_t<T>;
@ -1286,7 +1287,7 @@ namespace sol {
namespace detail {
template <typename T>
inline lua_CFunction make_destructor(std::true_type) {
lua_CFunction make_destructor(std::true_type) {
if constexpr (is_unique_usertype_v<T>) {
return &unique_destruct<T>;
}
@ -1299,12 +1300,12 @@ namespace sol {
}
template <typename T>
inline lua_CFunction make_destructor(std::false_type) {
lua_CFunction make_destructor(std::false_type) {
return &cannot_destruct<T>;
}
template <typename T>
inline lua_CFunction make_destructor() {
lua_CFunction make_destructor() {
return make_destructor<T>(std::is_destructible<T>());
}
@ -1316,18 +1317,18 @@ namespace sol {
};
template <typename T>
inline int is_check(lua_State* L) {
int is_check(lua_State* L) {
return stack::push(L, stack::check<T>(L, 1, &no_panic));
}
template <typename T>
inline int member_default_to_string(std::true_type, lua_State* L) {
int member_default_to_string(std::true_type, lua_State* L) {
decltype(auto) ts = stack::get<T>(L, 1).to_string();
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
inline int member_default_to_string(std::false_type, lua_State* L) {
int member_default_to_string(std::false_type, lua_State* L) {
return luaL_error(L,
"cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member "
"function, or operator<<(ostream&, ...) present",
@ -1335,36 +1336,36 @@ namespace sol {
}
template <typename T>
inline int adl_default_to_string(std::true_type, lua_State* L) {
int adl_default_to_string(std::true_type, lua_State* L) {
using namespace std;
decltype(auto) ts = to_string(stack::get<T>(L, 1));
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
inline int adl_default_to_string(std::false_type, lua_State* L) {
int adl_default_to_string(std::false_type, lua_State* L) {
return member_default_to_string<T>(meta::supports_to_string_member<T>(), L);
}
template <typename T>
inline int oss_default_to_string(std::true_type, lua_State* L) {
int oss_default_to_string(std::true_type, lua_State* L) {
std::ostringstream oss;
oss << stack::unqualified_get<T>(L, 1);
return stack::push(L, oss.str());
}
template <typename T>
inline int oss_default_to_string(std::false_type, lua_State* L) {
int oss_default_to_string(std::false_type, lua_State* L) {
return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L);
}
template <typename T>
inline int default_to_string(lua_State* L) {
int default_to_string(lua_State* L) {
return oss_default_to_string<T>(meta::supports_ostream_op<T>(), L);
}
template <typename T>
inline int default_size(lua_State* L) {
int default_size(lua_State* L) {
decltype(auto) self = stack::unqualified_get<T>(L, 1);
return stack::push(L, self.size());
}
@ -1391,8 +1392,8 @@ namespace sol {
}
else {
if constexpr (std::is_same_v<std::equal_to<>, Op> // clang-format hack
|| std::is_same_v<std::less_equal<>, Op> //
|| std::is_same_v<std::less_equal<>, Op>) { //
|| std::is_same_v<std::less_equal<>, Op> //
|| std::is_same_v<std::less_equal<>, Op>) { //
if (detail::ptr(l) == detail::ptr(r)) {
return stack::push(L, true);
}

View File

@ -39,7 +39,7 @@ namespace stack {
template <typename Key>
void get(lua_State* L, Key&& key, int tableindex = default_table_index) {
if constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t>) {
if constexpr (std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, override_value_t> || std::is_same_v<T, create_if_nil_t>) {
(void)L;
(void)key;
(void)tableindex;

View File

@ -102,58 +102,120 @@ namespace sol {
template <bool raw, typename Ret, typename... Keys>
decltype(auto) traverse_get_single(int table_index, Keys&&... keys) const {
constexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value;
constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);
if constexpr (meta::is_optional_v<meta::unqualified_t<Ret>>) {
int popcount = 0;
detail::ref_clean c(base_t::lua_state(), popcount);
return traverse_get_deep_optional<global, raw, Ret>(popcount, table_index, std::forward<Keys>(keys)...);
return traverse_get_deep_optional<global, raw, detail::insert_mode::none, Ret>(popcount, table_index, std::forward<Keys>(keys)...);
}
else {
detail::clean<sizeof...(Keys)> c(base_t::lua_state());
return traverse_get_deep<global, raw, Ret>(table_index, std::forward<Keys>(keys)...);
detail::clean<sizeof...(Keys) - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>> c(base_t::lua_state());
return traverse_get_deep<global, raw, detail::insert_mode::none, Ret>(table_index, std::forward<Keys>(keys)...);
}
}
template <bool raw, typename Pairs, std::size_t... I>
void tuple_set(std::index_sequence<I...>, Pairs&& pairs) {
constexpr bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<decltype(std::get<I * 2>(std::forward<Pairs>(pairs)))>...>::value;
constexpr static bool global = top_level && (meta::count_even_for_pack_v<meta::is_c_str, meta::unqualified_t<decltype(std::get<I * 2>(std::forward<Pairs>(pairs)))>...> > 0);
auto pp = stack::push_pop<global>(*this);
int table_index = pp.index_of(*this);
lua_State* L = base_t::lua_state();
(void)table_index;
(void)L;
void(detail::swallow{ (stack::set_field<top_level, raw>(L,
void(detail::swallow{ (stack::set_field<(top_level), raw>(L,
std::get<I * 2>(std::forward<Pairs>(pairs)),
std::get<I * 2 + 1>(std::forward<Pairs>(pairs)),
table_index),
0)... });
}
template <bool global, bool raw, typename T, typename Key, typename... Keys>
template <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys>
decltype(auto) traverse_get_deep(int table_index, Key&& key, Keys&&... keys) const {
lua_State* L = base_t::lua_state();
stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
(void)detail::swallow{ 0, (stack::get_field<false, raw>(L, std::forward<Keys>(keys), lua_gettop(L)), 0)... };
return stack::get<T>(L);
}
template <bool global, bool raw, typename T, typename Key, typename... Keys>
decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const {
lua_State* L = base_t::lua_state();
if constexpr (sizeof...(Keys) > 0) {
auto p = stack::probe_get_field<global>(L, std::forward<Key>(key), table_index);
popcount += p.levels;
if (!p.success)
return T(nullopt);
return traverse_get_deep_optional<false, raw, T>(popcount, lua_gettop(L), std::forward<Keys>(keys)...);
if constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) {
(void)key;
return traverse_get_deep<false, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil), T>(
table_index, std::forward<Keys>(keys)...);
}
else {
using R = decltype(stack::get<T>(L));
auto p = stack::probe_get_field<global, raw, T>(L, std::forward<Key>(key), table_index);
popcount += p.levels;
if (!p.success)
return R(nullopt);
return stack::get<T>(L);
lua_State* L = base_t::lua_state();
stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
if constexpr (sizeof...(Keys) > 0) {
if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
type t = type_of(L, -1);
if (t == type::nil || t == type::none) {
lua_pop(L, 1);
stack::push(L, new_table(0, 0));
}
}
return traverse_get_deep<false, raw, mode, T>(lua_gettop(L), std::forward<Keys>(keys)...);
}
else {
if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
type t = type_of(L, -1);
if ((t == type::nil || t == type::none) && (is_table_like_v<T>)) {
lua_pop(L, 1);
stack::push(L, new_table(0, 0));
}
}
return stack::get<T>(L);
}
}
}
template <bool global, bool raw, detail::insert_mode mode, typename T, typename Key, typename... Keys>
decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const {
if constexpr (std::is_same_v<meta::unqualified_t<Key>, create_if_nil_t>) {
constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil);
(void)key;
return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);
}
else if constexpr (std::is_same_v<meta::unqualified_t<Key>, update_if_empty_t>) {
constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty);
(void)key;
return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);
}
else if constexpr (std::is_same_v<meta::unqualified_t<Key>, override_value_t>) {
constexpr detail::insert_mode new_mode = static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value);
(void)key;
return traverse_get_deep_optional<global, raw, new_mode, T>(popcount, table_index, std::forward<Keys>(keys)...);
}
else {
if constexpr (sizeof...(Keys) > 0) {
lua_State* L = base_t::lua_state();
auto p = stack::probe_get_field<global, raw>(L, std::forward<Key>(key), table_index);
popcount += p.levels;
if (!p.success) {
if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
lua_pop(L, 1);
constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0;
stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));
stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
}
else {
return T(nullopt);
}
}
return traverse_get_deep_optional<false, raw, mode, T>(popcount, lua_gettop(L), std::forward<Keys>(keys)...);
}
else {
using R = decltype(stack::get<T>(nullptr));
using value_type = typename meta::unqualified_t<R>::value_type;
lua_State* L = base_t::lua_state();
auto p = stack::probe_get_field<global, raw, value_type>(L, key, table_index);
popcount += p.levels;
if (!p.success) {
if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
lua_pop(L, 1);
stack::push(L, new_table(0, 0));
stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
if (stack::check<value_type>(L, lua_gettop(L), no_panic)) {
return stack::get<T>(L);
}
}
return R(nullopt);
}
return stack::get<T>(L);
}
}
}
@ -162,19 +224,25 @@ namespace sol {
using KeyU = meta::unqualified_t<Key>;
if constexpr (std::is_same_v<KeyU, update_if_empty_t>) {
(void)key;
traverse_set_deep<false, raw, detail::insert_mode::update_if_empty>(table_index, std::forward<Keys>(keys)...);
traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::update_if_empty)>(table_index, std::forward<Keys>(keys)...);
}
else if constexpr (std::is_same_v<KeyU, create_if_nil_t>) {
(void)key;
traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::create_if_nil)>(
table_index, std::forward<Keys>(keys)...);
}
else if constexpr (std::is_same_v<KeyU, override_value_t>) {
(void)key;
traverse_set_deep<false, raw, detail::insert_mode::override_value>(table_index, std::forward<Keys>(keys)...);
traverse_set_deep<global, raw, static_cast<detail::insert_mode>(mode | detail::insert_mode::override_value)>(
table_index, std::forward<Keys>(keys)...);
}
else {
lua_State* L = base_t::lua_state();
if constexpr (sizeof...(Keys) == 1) {
if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) {
stack::get_field<global, raw>(L, key, table_index);
type vt = type_of(L, -1);
if (vt == type::lua_nil || vt == type::none) {
auto p = stack::probe_get_field<global, raw>(L, key, table_index);
lua_pop(L, p.levels);
if (!p.success) {
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
}
}
@ -183,22 +251,25 @@ namespace sol {
}
}
else {
if constexpr ((mode & detail::insert_mode::override_value) == detail::insert_mode::override_value) {
stack::probe p = stack::probe_get_field<global, raw>(L, key, table_index);
if (!p.success) {
constexpr bool is_seq = std::is_integral_v<KeyU>;
stack::set_field<global, raw>(L, key, new_table(static_cast<int>(is_seq), !static_cast<int>(is_seq)), table_index);
stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
}
}
else if constexpr((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) {
if constexpr (mode != detail::insert_mode::none) {
stack::get_field<global, raw>(L, key, table_index);
type vt = type_of(L, -1);
if (vt == type::lua_nil || vt == type::none) {
constexpr bool is_seq = std::is_integral_v<KeyU>;
lua_pop(L, 1);
stack::set_field<global, raw>(L, key, new_table(static_cast<int>(is_seq), !static_cast<int>(is_seq)), table_index);
stack::get_field<global, raw>(L, std::forward<Key>(key), table_index);
if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty
|| (mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) {
if (vt == type::lua_nil || vt == type::none) {
constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0;
lua_pop(L, 1);
stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));
stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
}
}
else {
if (vt != type::table) {
constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0;
lua_pop(L, 1);
stack::push(L, new_table(static_cast<int>(is_seq), static_cast<int>(!is_seq)));
stack::set_field<global, raw>(L, std::forward<Key>(key), stack_reference(L, -1), table_index);
}
}
}
else {
@ -336,7 +407,8 @@ namespace sol {
template <typename T, typename... Keys>
decltype(auto) traverse_get(Keys&&... keys) const {
constexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value;
static_assert(sizeof...(Keys) > 0, "must pass at least 1 key to get");
constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);
auto pp = stack::push_pop<global>(*this);
int table_index = pp.index_of(*this);
return traverse_get_single<false, T>(table_index, std::forward<Keys>(keys)...);
@ -344,11 +416,12 @@ namespace sol {
template <typename... Keys>
basic_table_core& traverse_set(Keys&&... keys) {
constexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value;
static_assert(sizeof...(Keys) > 1, "must pass at least 1 key and 1 value to set");
constexpr static bool global = top_level && (meta::count_when_for_to_pack_v<detail::is_not_insert_mode, 1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);
auto pp = stack::push_pop<global>(*this);
int table_index = pp.index_of(*this);
lua_State* L = base_t::lua_state();
auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2));
auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack_v<detail::is_insert_mode, meta::unqualified_t<Keys>...>));
traverse_set_deep<top_level, false, detail::insert_mode::none>(table_index, std::forward<Keys>(keys)...);
return *this;
}
@ -367,7 +440,7 @@ namespace sol {
template <typename... Ret, typename... Keys>
decltype(auto) raw_get(Keys&&... keys) const {
static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match");
constexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value;
constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);
auto pp = stack::push_pop<global>(*this);
int table_index = pp.index_of(*this);
return tuple_get<true, Ret...>(table_index, std::forward<Keys>(keys)...);
@ -394,7 +467,7 @@ namespace sol {
template <typename T, typename... Keys>
decltype(auto) traverse_raw_get(Keys&&... keys) const {
constexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value;
constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);
auto pp = stack::push_pop<global>(*this);
int table_index = pp.index_of(*this);
return traverse_get_single<true, T>(table_index, std::forward<Keys>(keys)...);
@ -402,10 +475,10 @@ namespace sol {
template <typename... Keys>
basic_table_core& traverse_raw_set(Keys&&... keys) {
constexpr static bool global = meta::all<meta::boolean<top_level>, meta::is_c_str<meta::unqualified_t<Keys>>...>::value;
constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t<Keys>...> > 0);
auto pp = stack::push_pop<global>(*this);
lua_State* L = base_t::lua_state();
auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2));
auto pn = stack::pop_n(L, static_cast<int>(sizeof...(Keys) - 2 - meta::count_for_pack<detail::is_insert_mode, meta::unqualified_t<Keys>...>));
traverse_set_deep<top_level, true, false>(std::forward<Keys>(keys)...);
return *this;
}
@ -572,7 +645,7 @@ namespace sol {
template <typename... Args>
static inline table create_with(lua_State* L, Args&&... args) {
static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list.");
static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value);
constexpr int narr = static_cast<int>(meta::count_odd_for_pack_v<std::is_integral, Args...>);
return create(L, narr, static_cast<int>((sizeof...(Args) / 2) - narr), std::forward<Args>(args)...);
}
@ -606,7 +679,7 @@ namespace sol {
template <typename Name, typename... Args>
table create_named(Name&& name, Args&&... args) {
static const int narr = static_cast<int>(meta::count_2_for_pack<std::is_integral, Args...>::value);
static const int narr = static_cast<int>(meta::count_even_for_pack_v<std::is_integral, Args...>);
return create(std::forward<Name>(name), narr, (sizeof...(Args) / 2) - narr, std::forward<Args>(args)...);
}
};

View File

@ -179,23 +179,30 @@ namespace sol {
};
namespace meta_detail {
template <std::size_t Limit, std::size_t I, template <typename...> class Pred, typename... Ts>
struct count_for_pack : std::integral_constant<std::size_t, 0> {};
template <std::size_t Limit, std::size_t I, template <typename...> class Pred, typename T, typename... Ts>
struct count_for_pack<Limit, I, Pred, T, Ts...> : conditional_t < sizeof...(Ts)
== 0
|| Limit<2, std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>,
count_for_pack<Limit - 1, I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>> {};
template <std::size_t I, template <typename...> class Pred, typename... Ts>
struct count_2_for_pack : std::integral_constant<std::size_t, 0> {};
template <std::size_t I, template <typename...> class Pred, typename T, typename U, typename... Ts>
struct count_2_for_pack<I, Pred, T, U, Ts...>
: conditional_t<sizeof...(Ts) == 0, std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>,
count_2_for_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>> {};
template <typename, typename TI>
using on_even = meta::boolean<(TI::value % 2) == 0>;
template <typename, typename TI>
using on_odd = meta::boolean<(TI::value % 2) == 1>;
template <typename, typename>
using on_always = std::true_type;
template <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename... Ts>
struct count_when_for_pack : std::integral_constant<std::size_t, 0> {};
template <template <typename...> class When, std::size_t Limit, std::size_t I, template <typename...> class Pred, typename T, typename... Ts>
struct count_when_for_pack<When, Limit, I, Pred, T, Ts...> : conditional_t<
sizeof...(Ts) == 0 || Limit < 2,
std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>,
count_when_for_pack<When, Limit - static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value), I + static_cast<std::size_t>(When<T, std::integral_constant<std::size_t, I>>::value && Pred<T>::value), Pred, Ts...>
> {};
} // namespace meta_detail
template <template <typename...> class Pred, typename... Ts>
struct count_for_pack : meta_detail::count_for_pack<sizeof...(Ts), 0, Pred, Ts...> {};
struct count_for_pack : meta_detail::count_when_for_pack<meta_detail::on_always, sizeof...(Ts), 0, Pred, Ts...> {};
template <template <typename...> class Pred, typename... Ts>
inline constexpr std::size_t count_for_pack_v = count_for_pack<Pred, Ts...>::value;
template <template <typename...> class Pred, typename List>
struct count_for;
@ -204,10 +211,28 @@ namespace sol {
struct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> {};
template <std::size_t Limit, template <typename...> class Pred, typename... Ts>
struct count_for_to_pack : meta_detail::count_for_pack<Limit, 0, Pred, Ts...> {};
struct count_for_to_pack : meta_detail::count_when_for_pack<meta_detail::on_always, Limit, 0, Pred, Ts...> {};
template <std::size_t Limit, template <typename...> class Pred, typename... Ts>
inline constexpr std::size_t count_for_to_pack_v = count_for_to_pack<Limit, Pred, Ts...>::value;
template <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts>
struct count_when_for_to_pack : meta_detail::count_when_for_pack<When, Limit, 0, Pred, Ts...> {};
template <template <typename...> class When, std::size_t Limit, template <typename...> class Pred, typename... Ts>
inline constexpr std::size_t count_when_for_to_pack_v = count_when_for_to_pack<When, Limit, Pred, Ts...>::value;
template <template <typename...> class Pred, typename... Ts>
struct count_2_for_pack : meta_detail::count_2_for_pack<0, Pred, Ts...> {};
using count_even_for_pack = count_when_for_to_pack<meta_detail::on_even, sizeof...(Ts), Pred, Ts...>;
template <template <typename...> class Pred, typename... Ts>
inline constexpr std::size_t count_even_for_pack_v = count_even_for_pack<Pred, Ts...>::value;
template <template <typename...> class Pred, typename... Ts>
using count_odd_for_pack = count_when_for_to_pack<meta_detail::on_odd, sizeof...(Ts), Pred, Ts...>;
template <template <typename...> class Pred, typename... Ts>
inline constexpr std::size_t count_odd_for_pack_v = count_odd_for_pack<Pred, Ts...>::value;
template <typename... Args>
struct return_type {

View File

@ -530,10 +530,19 @@ namespace sol {
constexpr inline override_value_t override_value = override_value_t();
struct update_if_empty_t {};
constexpr inline update_if_empty_t update_if_empty = update_if_empty_t();
struct create_if_nil_t {};
constexpr inline create_if_nil_t create_if_nil = create_if_nil_t();
namespace detail {
enum insert_mode { none = 0x0, update_if_empty = 0x01, override_value = 0x02 };
}
enum insert_mode { none = 0x0, update_if_empty = 0x01, override_value = 0x02, create_if_nil = 0x04 };
template <typename T, typename...>
using is_insert_mode = std::integral_constant<bool,
std::is_same_v<T, override_value_t> || std::is_same_v<T, update_if_empty_t> || std::is_same_v<T, create_if_nil_t>>;
template <typename T, typename...>
using is_not_insert_mode = meta::neg<is_insert_mode<T>>;
} // namespace detail
struct this_state {
lua_State* L;
@ -1250,6 +1259,11 @@ namespace sol {
struct is_table : std::false_type {};
template <bool x, typename T>
struct is_table<basic_table_core<x, T>> : std::true_type {};
template <typename T>
struct is_table<basic_lua_table<T>> : std::true_type {};
template <typename T>
inline constexpr bool is_table_v = is_table<T>::value;
template <typename T>
struct is_function : std::false_type {};
@ -1258,18 +1272,30 @@ namespace sol {
template <typename T, bool aligned, typename Handler>
struct is_function<basic_protected_function<T, aligned, Handler>> : std::true_type {};
template <typename T>
struct is_lightuserdata : std::false_type {};
template <typename T>
struct is_lightuserdata<basic_lightuserdata<T>> : std::true_type {};
template <typename T>
struct is_userdata : std::false_type {};
template <typename T>
struct is_userdata<basic_userdata<T>> : std::true_type {};
using is_lightuserdata = meta::is_specialization_of<T, basic_lightuserdata>;
template <typename T>
struct is_environment : std::integral_constant<bool, is_userdata<T>::value || is_table<T>::value> {};
inline constexpr bool is_lightuserdata_v = is_lightuserdata<T>::value;
template <typename T>
using is_userdata = meta::is_specialization_of<T, basic_userdata>;
template <typename T>
inline constexpr bool is_userdata_v = is_userdata<T>::value;
template <typename T>
using is_environment = std::integral_constant<bool, is_userdata_v<T> || is_table_v<T> || meta::is_specialization_of_v<T, basic_environment>>;
template <typename T>
inline constexpr bool is_environment_v = is_environment<T>::value;
template <typename T>
using is_table_like = std::integral_constant<bool, is_table_v<T> || is_environment_v<T> || is_userdata_v<T>>;
template <typename T>
inline constexpr bool is_table_like_v = is_table_like<T>::value;
template <typename T>
struct is_automagical

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2019-04-29 09:16:12.925937 UTC
// This header was generated with sol v3.0.1-beta2 (revision c442c6c)
// Generated 2019-05-21 06:13:48.131882 UTC
// This header was generated with sol v3.0.1-beta2 (revision bd17c83)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

File diff suppressed because it is too large Load Diff

View File

@ -137,3 +137,59 @@ TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it
REQUIRE(*totally_there_still == 357);
}
}
TEST_CASE("tables/get create_if_nil", "create tables all the way down") {
SECTION("traverse non-optional") {
sol::state lua;
sol::stack_guard luasg_outer(lua);
{
sol::stack_guard luasg_inner_1(lua);
sol::optional<sol::table> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
}
{
sol::stack_guard luasg_inner_2(lua);
sol::table totally_created = lua.traverse_get<sol::table>(sol::create_if_nil, "a", "b", "c");
REQUIRE(totally_created.size() == 0);
}
}
SECTION("traverse") {
sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<sol::table> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
sol::optional<sol::table> totally_created = lua.traverse_get<sol::optional<sol::table>>(sol::create_if_nil, "a", "b", "c");
sol::optional<sol::table> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_created));
REQUIRE(static_cast<bool>(totally_there));
}
SECTION("proxy non-optional") {
sol::state lua;
sol::stack_guard luasg_outer(lua);
{
sol::stack_guard luasg_inner_1(lua);
sol::optional<sol::table> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
}
{
sol::stack_guard luasg_inner_2(lua);
sol::table totally_created = lua[sol::create_if_nil]["a"]["b"]["c"];
REQUIRE(totally_created.size() == 0);
}
}
SECTION("proxy") {
sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<sol::table> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there));
sol::optional<sol::table> totally_created = lua[sol::create_if_nil]["a"]["b"]["c"];
sol::optional<sol::table> totally_there = lua["a"]["b"]["c"];
REQUIRE(static_cast<bool>(totally_created));
REQUIRE(static_cast<bool>(totally_there));
}
}

View File

@ -29,52 +29,6 @@
#include <iostream>
class TestClass00 {
public:
TestClass00() {
}
int Thing() const {
return 123;
}
};
class TestClass01 : public TestClass00 {
public:
TestClass01() : a(1) {
}
TestClass01(const TestClass00& other) : a(other.Thing()) {
}
int a;
};
class TestClass02 : public TestClass01 {
public:
TestClass02() : b(2) {
}
TestClass02(const TestClass01& other) : b(other.a) {
}
TestClass02(const TestClass00& other) : b(other.Thing()) {
}
int b;
};
class TestClass03 : public TestClass02 {
public:
TestClass03() : c(2) {
}
TestClass03(const TestClass02& other) : c(other.b) {
}
TestClass03(const TestClass01& other) : c(other.a) {
}
TestClass03(const TestClass00& other) : c(other.Thing()) {
}
int c;
};
struct inh_test_A {
int a = 5;
};
@ -95,13 +49,6 @@ struct inh_test_D : inh_test_C {
}
};
SOL_BASE_CLASSES(TestClass03, TestClass02);
SOL_BASE_CLASSES(TestClass02, TestClass01);
SOL_BASE_CLASSES(TestClass01, TestClass00);
SOL_DERIVED_CLASSES(TestClass02, TestClass03);
SOL_DERIVED_CLASSES(TestClass01, TestClass02);
SOL_DERIVED_CLASSES(TestClass00, TestClass01);
SOL_BASE_CLASSES(inh_test_D, inh_test_C);
SOL_BASE_CLASSES(inh_test_C, inh_test_B, inh_test_A);
SOL_DERIVED_CLASSES(inh_test_C, inh_test_D);
@ -109,7 +56,6 @@ SOL_DERIVED_CLASSES(inh_test_B, inh_test_C);
SOL_DERIVED_CLASSES(inh_test_A, inh_test_B);
TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
sol::state lua;
int begintop = 0, endtop = 0;
lua.new_usertype<inh_test_A>("A", "a", &inh_test_A::a);
@ -140,126 +86,6 @@ TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
REQUIRE(a == 5);
}
TEST_CASE("inheritance/multi base", "test that multiple bases all work and overloading for constructors works with them") {
sol::state lua;
sol::usertype<TestClass00> s_TestUsertype00
= lua.new_usertype<TestClass00>("TestClass00", sol::call_constructor, sol::constructors<TestClass00()>(), "Thing", &TestClass00::Thing);
sol::usertype<TestClass01> s_TestUsertype01 = lua.new_usertype<TestClass01>("TestClass01",
sol::call_constructor,
sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
sol::base_classes,
sol::bases<TestClass00>(),
"a",
&TestClass01::a);
sol::usertype<TestClass02> s_TestUsertype02 = lua.new_usertype<TestClass02>("TestClass02",
sol::call_constructor,
sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes,
sol::bases<TestClass01, TestClass00>(),
"b",
&TestClass02::b);
sol::usertype<TestClass03> s_TestUsertype03 = lua.new_usertype<TestClass03>("TestClass03",
sol::call_constructor,
sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes,
sol::bases<TestClass02, TestClass01, TestClass00>(),
"c",
&TestClass03::c);
auto result1 = lua.safe_script(R"(
tc0 = TestClass00()
tc2 = TestClass02(tc0)
tc1 = TestClass01()
tc3 = TestClass03(tc1)
)",
sol::script_pass_on_error);
REQUIRE(result1.valid());
TestClass00& tc0 = lua["tc0"];
TestClass01& tc1 = lua["tc1"];
TestClass02& tc2 = lua["tc2"];
TestClass03& tc3 = lua["tc3"];
REQUIRE(tc0.Thing() == 123);
REQUIRE(tc1.a == 1);
REQUIRE(tc2.a == 1);
REQUIRE(tc2.b == 123);
REQUIRE(tc3.a == 1);
REQUIRE(tc3.b == 2);
REQUIRE(tc3.c == 1);
}
TEST_CASE("inheritance/runtime multi base", "test that multiple bases all work and overloading for constructors works with them when just using sol::bases") {
struct runtime_A {
int a = 5;
};
struct runtime_B {
int b2 = 46;
int b() {
return 10;
}
};
struct runtime_C : runtime_B, runtime_A {
double c = 2.4;
};
struct runtime_D : runtime_C {
bool d() const {
return true;
}
};
sol::state lua;
lua.new_usertype<runtime_A>("A", "a", &runtime_A::a);
lua.new_usertype<runtime_B>("B", "b", &runtime_B::b);
lua.new_usertype<runtime_C>("C", "c", &runtime_C::c, sol::base_classes, sol::bases<runtime_B, runtime_A>());
lua.new_usertype<runtime_D>("D", "d", &runtime_D::d, sol::base_classes, sol::bases<runtime_C, runtime_B, runtime_A>());
auto result1 = lua.safe_script("obj = D.new()", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("d = obj:d()", sol::script_pass_on_error);
REQUIRE(result2.valid());
bool d = lua["d"];
auto result3 = lua.safe_script("c = obj.c", sol::script_pass_on_error);
REQUIRE(result3.valid());
double c = lua["c"];
auto result4 = lua.safe_script("b = obj:b()", sol::script_pass_on_error);
REQUIRE(result4.valid());
int b = lua["b"];
auto result5 = lua.safe_script("a = obj.a", sol::script_pass_on_error);
REQUIRE(result5.valid());
int a = lua["a"];
REQUIRE(d);
REQUIRE(c == 2.4);
REQUIRE(b == 10);
REQUIRE(a == 5);
runtime_D& d_obj = lua["obj"];
REQUIRE(d_obj.d());
REQUIRE(d_obj.c == 2.4);
REQUIRE(d_obj.b() == 10);
REQUIRE(d_obj.b2 == 46);
REQUIRE(d_obj.a == 5);
runtime_C& c_obj = lua["obj"];
REQUIRE(c_obj.c == 2.4);
REQUIRE(c_obj.b() == 10);
REQUIRE(c_obj.b2 == 46);
REQUIRE(c_obj.a == 5);
runtime_B& b_obj = lua["obj"];
REQUIRE(b_obj.b() == 10);
REQUIRE(b_obj.b2 == 46);
runtime_A& a_obj = lua["obj"];
REQUIRE(a_obj.a == 5);
}
TEST_CASE("inheritance/usertype derived non-hiding", "usertype classes must play nice when a derived class does not overload a publically visible base function") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -287,113 +113,3 @@ TEST_CASE("inheritance/usertype derived non-hiding", "usertype classes must play
REQUIRE((lua.get<int>("dgn10") == 70));
REQUIRE((lua.get<int>("dgn") == 7));
}
TEST_CASE("inheritance/bad_base-class", "check to make sure bad/unregistered base classes do not blow up usertypes") {
struct a {
a(sol::this_state ts, sol::this_environment) {
lua_State* L = ts;
ud = sol::userdata(L, -2);
}
sol::object get_property_lua(const char* name, sol::this_state) {
return props[name];
}
void set_property_lua(const char* name, sol::stack_object object) {
props[name] = object.as<sol::object>();
}
std::unordered_map<std::string, sol::object> props;
sol::userdata ud;
};
struct nofun {
nofun() {
}
};
struct b : public a, public nofun {
b(sol::this_state ts, sol::this_environment te, int) : a(ts, te) {
sol::state_view lua = ts;
lua.script("function break_crap(b_obj) b_obj.test3 = {} end");
sol::protected_function pf = lua["break_crap"];
sol::optional<sol::error> result = pf(this);
REQUIRE_FALSE(result.has_value());
}
b(sol::this_state ts, sol::this_environment te, int, int) : a(ts, te) {
}
~b() {
}
};
struct c : public b {
c(sol::this_state ts, sol::this_environment te, int ab) : b(ts, te, ab) {
}
c(sol::this_state ts, sol::this_environment te, int ab, int bc) : b(ts, te, ab, bc) {
}
~c() {
}
};
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::package, sol::lib::debug);
lua.new_usertype<a>("a", sol::meta_function::new_index, &a::set_property_lua, sol::meta_function::index, &a::get_property_lua);
lua.new_usertype<b>("b",
sol::constructors<b(sol::this_state, sol::this_environment, int), b(sol::this_state, sol::this_environment, int, int)>(),
sol::meta_function::new_index,
&b::set_property_lua,
sol::meta_function::index,
&b::get_property_lua,
sol::base_classes,
sol::bases<a, nofun>());
lua.new_usertype<c>("c",
sol::constructors<c(sol::this_state, sol::this_environment, int), c(sol::this_state, sol::this_environment, int, int)>(),
sol::meta_function::new_index,
&c::set_property_lua,
sol::meta_function::index,
&c::get_property_lua,
sol::base_classes,
sol::bases<b>());
lua.script(R"(
function init_entity(e)
init_entity_properties(e)
return true
end
function init_entity_properties(e)
e._internal_entity_properties_ = {}
function e : GetName()
return self._internal_entity_properties_['name']
end
function e : SetName(s)
self._internal_entity_properties_['name'] = s
end
--return e
end
)");
sol::optional<sol::error> result = lua.safe_script("b_tmp = b.new(1)", sol::script_pass_on_error);
REQUIRE_FALSE(result.has_value());
a* b_base = lua["b_tmp"]; // get the base...
sol::protected_function pf = lua["init_entity"];
sol::optional<sol::error> result1 = pf(b_base);
REQUIRE_FALSE(result1.has_value());
sol::optional<sol::error> result2 = lua.script("c_tmp = c.new(1)", sol::script_pass_on_error);
REQUIRE_FALSE(result2.has_value());
}

View File

@ -0,0 +1,333 @@
// 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_test.hpp"
#include "common_classes.hpp"
#include <catch.hpp>
#include <iostream>
class TestClass00 {
public:
TestClass00() {
}
int Thing() const {
return 123;
}
};
class TestClass01 : public TestClass00 {
public:
TestClass01() : a(1) {
}
TestClass01(const TestClass00& other) : a(other.Thing()) {
}
int a;
};
class TestClass02 : public TestClass01 {
public:
TestClass02() : b(2) {
}
TestClass02(const TestClass01& other) : b(other.a) {
}
TestClass02(const TestClass00& other) : b(other.Thing()) {
}
int b;
};
class TestClass03 : public TestClass02 {
public:
TestClass03() : c(2) {
}
TestClass03(const TestClass02& other) : c(other.b) {
}
TestClass03(const TestClass01& other) : c(other.a) {
}
TestClass03(const TestClass00& other) : c(other.Thing()) {
}
int c;
};
struct inh_test_A {
int a = 5;
};
struct inh_test_B {
int b() {
return 10;
}
};
struct inh_test_C : inh_test_B, inh_test_A {
double c = 2.4;
};
struct inh_test_D : inh_test_C {
bool d() const {
return true;
}
};
SOL_BASE_CLASSES(TestClass03, TestClass02);
SOL_BASE_CLASSES(TestClass02, TestClass01);
SOL_BASE_CLASSES(TestClass01, TestClass00);
SOL_DERIVED_CLASSES(TestClass02, TestClass03);
SOL_DERIVED_CLASSES(TestClass01, TestClass02);
SOL_DERIVED_CLASSES(TestClass00, TestClass01);
TEST_CASE("inheritance/multi base", "test that multiple bases all work and overloading for constructors works with them") {
sol::state lua;
sol::usertype<TestClass00> s_TestUsertype00
= lua.new_usertype<TestClass00>("TestClass00", sol::call_constructor, sol::constructors<TestClass00()>(), "Thing", &TestClass00::Thing);
sol::usertype<TestClass01> s_TestUsertype01 = lua.new_usertype<TestClass01>("TestClass01",
sol::call_constructor,
sol::constructors<sol::types<>, sol::types<const TestClass00&>>(),
sol::base_classes,
sol::bases<TestClass00>(),
"a",
&TestClass01::a);
sol::usertype<TestClass02> s_TestUsertype02 = lua.new_usertype<TestClass02>("TestClass02",
sol::call_constructor,
sol::constructors<sol::types<>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes,
sol::bases<TestClass01, TestClass00>(),
"b",
&TestClass02::b);
sol::usertype<TestClass03> s_TestUsertype03 = lua.new_usertype<TestClass03>("TestClass03",
sol::call_constructor,
sol::constructors<sol::types<>, sol::types<const TestClass02&>, sol::types<const TestClass01&>, sol::types<const TestClass00&>>(),
sol::base_classes,
sol::bases<TestClass02, TestClass01, TestClass00>(),
"c",
&TestClass03::c);
auto result1 = lua.safe_script(R"(
tc0 = TestClass00()
tc2 = TestClass02(tc0)
tc1 = TestClass01()
tc3 = TestClass03(tc1)
)",
sol::script_pass_on_error);
REQUIRE(result1.valid());
TestClass00& tc0 = lua["tc0"];
TestClass01& tc1 = lua["tc1"];
TestClass02& tc2 = lua["tc2"];
TestClass03& tc3 = lua["tc3"];
REQUIRE(tc0.Thing() == 123);
REQUIRE(tc1.a == 1);
REQUIRE(tc2.a == 1);
REQUIRE(tc2.b == 123);
REQUIRE(tc3.a == 1);
REQUIRE(tc3.b == 2);
REQUIRE(tc3.c == 1);
}
TEST_CASE("inheritance/runtime multi base", "test that multiple bases all work and overloading for constructors works with them when just using sol::bases") {
struct runtime_A {
int a = 5;
};
struct runtime_B {
int b2 = 46;
int b() {
return 10;
}
};
struct runtime_C : runtime_B, runtime_A {
double c = 2.4;
};
struct runtime_D : runtime_C {
bool d() const {
return true;
}
};
sol::state lua;
lua.new_usertype<runtime_A>("A", "a", &runtime_A::a);
lua.new_usertype<runtime_B>("B", "b", &runtime_B::b);
lua.new_usertype<runtime_C>("C", "c", &runtime_C::c, sol::base_classes, sol::bases<runtime_B, runtime_A>());
lua.new_usertype<runtime_D>("D", "d", &runtime_D::d, sol::base_classes, sol::bases<runtime_C, runtime_B, runtime_A>());
auto result1 = lua.safe_script("obj = D.new()", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("d = obj:d()", sol::script_pass_on_error);
REQUIRE(result2.valid());
bool d = lua["d"];
auto result3 = lua.safe_script("c = obj.c", sol::script_pass_on_error);
REQUIRE(result3.valid());
double c = lua["c"];
auto result4 = lua.safe_script("b = obj:b()", sol::script_pass_on_error);
REQUIRE(result4.valid());
int b = lua["b"];
auto result5 = lua.safe_script("a = obj.a", sol::script_pass_on_error);
REQUIRE(result5.valid());
int a = lua["a"];
REQUIRE(d);
REQUIRE(c == 2.4);
REQUIRE(b == 10);
REQUIRE(a == 5);
runtime_D& d_obj = lua["obj"];
REQUIRE(d_obj.d());
REQUIRE(d_obj.c == 2.4);
REQUIRE(d_obj.b() == 10);
REQUIRE(d_obj.b2 == 46);
REQUIRE(d_obj.a == 5);
runtime_C& c_obj = lua["obj"];
REQUIRE(c_obj.c == 2.4);
REQUIRE(c_obj.b() == 10);
REQUIRE(c_obj.b2 == 46);
REQUIRE(c_obj.a == 5);
runtime_B& b_obj = lua["obj"];
REQUIRE(b_obj.b() == 10);
REQUIRE(b_obj.b2 == 46);
runtime_A& a_obj = lua["obj"];
REQUIRE(a_obj.a == 5);
}
TEST_CASE("inheritance/bad_base-class", "check to make sure bad/unregistered base classes do not blow up usertypes") {
struct a {
a(sol::this_state ts, sol::this_environment) {
lua_State* L = ts;
ud = sol::userdata(L, -2);
}
sol::object get_property_lua(const char* name, sol::this_state) {
return props[name];
}
void set_property_lua(const char* name, sol::stack_object object) {
props[name] = object.as<sol::object>();
}
std::unordered_map<std::string, sol::object> props;
sol::userdata ud;
};
struct nofun {
nofun() {
}
};
struct b : public a, public nofun {
b(sol::this_state ts, sol::this_environment te, int) : a(ts, te) {
sol::state_view lua = ts;
lua.script("function break_crap(b_obj) b_obj.test3 = {} end");
sol::protected_function pf = lua["break_crap"];
sol::optional<sol::error> result = pf(this);
REQUIRE_FALSE(result.has_value());
}
b(sol::this_state ts, sol::this_environment te, int, int) : a(ts, te) {
}
~b() {
}
};
struct c : public b {
c(sol::this_state ts, sol::this_environment te, int ab) : b(ts, te, ab) {
}
c(sol::this_state ts, sol::this_environment te, int ab, int bc) : b(ts, te, ab, bc) {
}
~c() {
}
};
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::package, sol::lib::debug);
lua.new_usertype<a>("a", sol::meta_function::new_index, &a::set_property_lua, sol::meta_function::index, &a::get_property_lua);
lua.new_usertype<b>("b",
sol::constructors<b(sol::this_state, sol::this_environment, int), b(sol::this_state, sol::this_environment, int, int)>(),
sol::meta_function::new_index,
&b::set_property_lua,
sol::meta_function::index,
&b::get_property_lua,
sol::base_classes,
sol::bases<a, nofun>());
lua.new_usertype<c>("c",
sol::constructors<c(sol::this_state, sol::this_environment, int), c(sol::this_state, sol::this_environment, int, int)>(),
sol::meta_function::new_index,
&c::set_property_lua,
sol::meta_function::index,
&c::get_property_lua,
sol::base_classes,
sol::bases<b>());
lua.script(R"(
function init_entity(e)
init_entity_properties(e)
return true
end
function init_entity_properties(e)
e._internal_entity_properties_ = {}
function e : GetName()
return self._internal_entity_properties_['name']
end
function e : SetName(s)
self._internal_entity_properties_['name'] = s
end
--return e
end
)");
sol::optional<sol::error> result = lua.safe_script("b_tmp = b.new(1)", sol::script_pass_on_error);
REQUIRE_FALSE(result.has_value());
a* b_base = lua["b_tmp"]; // get the base...
sol::protected_function pf = lua["init_entity"];
sol::optional<sol::error> result1 = pf(b_base);
REQUIRE_FALSE(result1.has_value());
sol::optional<sol::error> result2 = lua.script("c_tmp = c.new(1)", sol::script_pass_on_error);
REQUIRE_FALSE(result2.has_value());
}

View File

@ -238,6 +238,20 @@ TEST_CASE("usertype/static-properties", "allow for static functions to get and s
REQUIRE(v2a == 60.5);
}
TEST_CASE("usertype/var with string literals", "String literals are the bane of my existence and one day C++ will make them not be fucking arrays") {
struct blah {};
sol::state lua;
sol::usertype<blah> x = lua.new_usertype<blah>("blah");
x["__className"] = sol::var("Entity");
std::string cxx_name = x["__className"];
std::string lua_name = lua.script("return blah.__className");
REQUIRE(cxx_name == lua_name);
REQUIRE(cxx_name == "Entity");
REQUIRE(lua_name == "Entity");
}
TEST_CASE("usertype/var-and-property", "make sure const vars are readonly and properties can handle lambdas") {
const static int arf = 20;