mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
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:
parent
bd17c83250
commit
5dee45cd9e
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)...);
|
||||
}
|
||||
|
|
|
@ -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???
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -102,103 +102,174 @@ 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool global, bool raw, detail::insert_mode mode, typename Key, typename... Keys>
|
||||
void traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const {
|
||||
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) {
|
||||
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
|
||||
}
|
||||
}
|
||||
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);
|
||||
auto p = stack::probe_get_field<global, raw>(L, key, table_index);
|
||||
lua_pop(L, p.levels);
|
||||
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);
|
||||
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
|
||||
}
|
||||
}
|
||||
else if constexpr((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) {
|
||||
else {
|
||||
stack::set_field<global, raw>(L, std::forward<Key>(key), std::forward<Keys>(keys)..., table_index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr (mode != detail::insert_mode::none) {
|
||||
stack::get_field<global, raw>(L, key, table_index);
|
||||
type vt = type_of(L, -1);
|
||||
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 = std::is_integral_v<KeyU>;
|
||||
constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0;
|
||||
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);
|
||||
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)...);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
333
tests/runtime_tests/source/usertypes.inheritance.multi.cpp
Normal file
333
tests/runtime_tests/source/usertypes.inheritance.multi.cpp
Normal 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());
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user