update single

update forward declaration
update container traits usage
fix vector of pair as a usertype
This commit is contained in:
ThePhD 2019-01-13 21:46:53 -05:00
parent 91faa7a014
commit 5b3ca9343c
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
25 changed files with 3031 additions and 2844 deletions

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,15 @@ namespace sol {
constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol2 userdata"; constexpr const char* not_enough_stack_space_userdata = "not enough space left on Lua stack to create a sol2 userdata";
constexpr const char* not_enough_stack_space_generic = "not enough space left on Lua stack to push valuees"; constexpr const char* not_enough_stack_space_generic = "not enough space left on Lua stack to push valuees";
constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment"; constexpr const char* not_enough_stack_space_environment = "not enough space left on Lua stack to retrieve environment";
constexpr const char* protected_function_error = "caught (...) unknown error during protected_function call";
inline void accumulate_and_mark(const std::string& n, std::string& addendum, int& marker) {
if (marker > 0) {
addendum += ", ";
}
addendum += n;
++marker;
}
} }
inline std::string associated_type_name(lua_State* L, int index, type t) { inline std::string associated_type_name(lua_State* L, int index, type t) {
@ -120,14 +129,7 @@ namespace sol {
addendum += detail::demangle<R>(); addendum += detail::demangle<R>();
addendum += "("; addendum += "(";
int marker = 0; int marker = 0;
auto action = [&addendum, &marker](const std::string& n) { (void)detail::swallow{int(), (detail::accumulate_and_mark(detail::demangle<Args>(), addendum, marker), int())...};
if (marker > 0) {
addendum += ", ";
}
addendum += n;
++marker;
};
(void)detail::swallow{int(), (action(detail::demangle<Args>()), int())...};
addendum += ")')"; addendum += ")')";
return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + addendum); return type_panic_string(L, index, expected, actual, message.empty() ? addendum : message + " " + addendum);
} }

View File

@ -150,6 +150,9 @@ namespace sol {
struct this_main_state; struct this_main_state;
struct this_environment; struct this_environment;
class state_view;
class state;
template <typename T> template <typename T>
struct as_table_t; struct as_table_t;
template <typename T> template <typename T>

View File

@ -75,6 +75,34 @@ namespace sol {
return *this; return *this;
} }
namespace detail {
template <typename... R>
struct std_shim {
unsafe_function lua_func_;
std_shim(unsafe_function lua_func) : lua_func_(std::move(lua_func)) {
}
template <typename... Args>
meta::return_type_t<R...> operator()(Args&&... args) {
return lua_func_.call<R...>(std::forward<Args>(args)...);
}
};
template <>
struct std_shim<void> {
unsafe_function lua_func_;
std_shim(unsafe_function lua_func) : lua_func_(std::move(lua_func)) {
}
template <typename... Args>
void operator()(Args&&... args) {
lua_func_.call<void>(std::forward<Args>(args)...);
}
};
} // namespace detail
namespace stack { namespace stack {
template <typename Signature> template <typename Signature>
struct unqualified_getter<std::function<Signature>> { struct unqualified_getter<std::function<Signature>> {
@ -82,29 +110,12 @@ namespace sol {
typedef typename fx_t::args_list args_lists; typedef typename fx_t::args_list args_lists;
typedef meta::tuple_types<typename fx_t::return_type> return_types; typedef meta::tuple_types<typename fx_t::return_type> return_types;
template <typename... Args, typename... Ret> template <typename... R>
static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index) { static std::function<Signature> get_std_func(types<R...>, lua_State* L, int index) {
unsafe_function f(L, index); detail::std_shim<R...> fx(unsafe_function(L, index));
auto fx = [ f = std::move(f) ](Args && ... args) -> meta::return_type_t<Ret...> {
return f.call<Ret...>(std::forward<Args>(args)...);
};
return std::move(fx); return std::move(fx);
} }
template <typename... FxArgs>
static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index) {
unsafe_function f(L, index);
auto fx = [f = std::move(f)](FxArgs&&... args) -> void {
f(std::forward<FxArgs>(args)...);
};
return std::move(fx);
}
template <typename... FxArgs>
static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index) {
return get_std_func(types<void>(), t, L, index);
}
static std::function<Signature> get(lua_State* L, int index, record& tracking) { static std::function<Signature> get(lua_State* L, int index, record& tracking) {
tracking.last = 1; tracking.last = 1;
tracking.used += 1; tracking.used += 1;
@ -112,7 +123,7 @@ namespace sol {
if (t == type::none || t == type::lua_nil) { if (t == type::none || t == type::lua_nil) {
return nullptr; return nullptr;
} }
return get_std_func(return_types(), args_lists(), L, index); return get_std_func(return_types(), L, index);
} }
}; };
} // namespace stack } // namespace stack

View File

@ -88,7 +88,7 @@ namespace sol {
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr);
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); upvalues += stack::push(L, static_cast<void const*>(userptr));
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -133,14 +133,14 @@ namespace sol {
template <bool is_yielding, typename Fx, typename T, typename... Args> template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> dFx; using dFx = std::decay_t<Fx>;
dFx memfxptr(std::forward<Fx>(fx)); dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call; lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); upvalues += stack::push<user<dFx>>(L, memfxptr);
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -158,22 +158,24 @@ namespace sol {
template <bool is_yielding, typename Fx, typename C> template <bool is_yielding, typename Fx, typename C>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx, is_yielding>::call; using dFx = std::decay_t<Fx>;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx); upvalues += stack::push<user<dFx>>(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <bool is_yielding, typename Fx> template <bool is_yielding, typename Fx>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
using dFx = std::decay_t<Fx>;
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx, is_yielding>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx); upvalues += stack::push<user<dFx>>(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }

View File

@ -45,14 +45,14 @@ namespace function_detail {
} }
template <typename Fx, std::size_t I, typename... R, typename... Args> template <typename Fx, std::size_t I, typename... R, typename... Args>
int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int) { static int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, overload_list& ol) {
auto& func = std::get<I>(overloads); auto& func = std::get<I>(ol);
return call_detail::call_wrapped<void, true, false, start_skew>(L, func); return call_detail::call_wrapped<void, true, false, start_skew>(L, func);
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
auto mfx = [&](auto&&... args) { return this->call(std::forward<decltype(args)>(args)...); }; auto mfx = [](auto&&... args) { return call(std::forward<decltype(args)>(args)...); };
return call_detail::overload_match<Functions...>(mfx, L, 1 + start_skew); return call_detail::overload_match<Functions...>(mfx, L, 1 + start_skew, overloads);
} }
}; };
} }

View File

@ -66,14 +66,12 @@ namespace function_detail {
// idx n + 1: is the object's void pointer // idx n + 1: is the object's void pointer
// We don't need to store the size, because the other side is templated // We don't need to store the size, because the other side is templated
// with the same member function pointer type // with the same member function pointer type
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); function_type& memfx = stack::get<user<function_type>>(L, upvalue_index(2));
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); auto& item = *static_cast<T*>(stack::get<void*>(L, upvalue_index(3)));
function_type& memfx = memberdata.first;
auto& item = *objdata.first;
return call_detail::call_wrapped<T, true, false, -1>(L, memfx, item); return call_detail::call_wrapped<T, true, false, -1>(L, memfx, item);
} }
static int call(lua_State* L) { static int call(lua_State* L) noexcept(traits_type::is_noexcept) {
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) { if (is_yielding) {
return lua_yield(L, nr); return lua_yield(L, nr);
@ -113,7 +111,7 @@ namespace function_detail {
} }
} }
static int call(lua_State* L) { static int call(lua_State* L) noexcept(traits_type::is_noexcept) {
int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L); int nr = detail::typed_static_trampoline<decltype(&real_call), (&real_call)>(L);
if (is_yielding) { if (is_yielding) {
return lua_yield(L, nr); return lua_yield(L, nr);
@ -174,8 +172,7 @@ namespace function_detail {
static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) { static int real_call(lua_State* L) noexcept(traits_type::is_noexcept) {
// Layout: // Layout:
// idx 1...n: verbatim data of member variable pointer // idx 1...n: verbatim data of member variable pointer
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L); function_type& memfx = stack::get<user<function_type>>(L, upvalue_index(2));
function_type& memfx = memberdata.first;
return call_detail::call_wrapped<T, false, false>(L, memfx); return call_detail::call_wrapped<T, false, false>(L, memfx);
} }

View File

@ -34,6 +34,21 @@
namespace sol { namespace sol {
namespace detail {
template <bool b, typename handler_t>
inline void handle_protected_exception(lua_State* L, optional<const std::exception&> maybe_ex, const char* error, detail::protected_handler<b, handler_t>& h) {
h.stackindex = 0;
if (b) {
h.target.push();
detail::call_exception_handler(L, maybe_ex, error);
lua_call(L, 1, 1);
}
else {
detail::call_exception_handler(L, maybe_ex, error);
}
}
}
template <typename base_t, bool aligned = false, typename handler_t = reference> template <typename base_t, bool aligned = false, typename handler_t = reference>
class basic_protected_function : public base_t { class basic_protected_function : public base_t {
public: public:
@ -79,18 +94,6 @@ namespace sol {
int returncount = 0; int returncount = 0;
call_status code = call_status::ok; call_status code = call_status::ok;
#if !defined(SOL_NO_EXCEPTIONS) || !SOL_NO_EXCEPTIONS #if !defined(SOL_NO_EXCEPTIONS) || !SOL_NO_EXCEPTIONS
auto onexcept = [&](optional<const std::exception&> maybe_ex, const char* error) {
h.stackindex = 0;
if (b) {
h.target.push();
detail::call_exception_handler(lua_state(), maybe_ex, error);
lua_call(lua_state(), 1, 1);
}
else {
detail::call_exception_handler(lua_state(), maybe_ex, error);
}
};
(void)onexcept;
#if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT) #if (!defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || !SOL_NO_EXCEPTIONS_SAFE_PROPAGATION) || (defined(SOL_LUAJIT) && SOL_LUAJIT)
try { try {
#endif // Safe Exception Propagation #endif // Safe Exception Propagation
@ -104,17 +107,17 @@ namespace sol {
} }
// Handle C++ errors thrown from C++ functions bound inside of lua // Handle C++ errors thrown from C++ functions bound inside of lua
catch (const char* error) { catch (const char* error) {
onexcept(optional<const std::exception&>(nullopt), error); detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error, h);
firstreturn = lua_gettop(lua_state()); firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
} }
catch (const std::string& error) { catch (const std::string& error) {
onexcept(optional<const std::exception&>(nullopt), error.c_str()); detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), error.c_str(), h);
firstreturn = lua_gettop(lua_state()); firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
} }
catch (const std::exception& error) { catch (const std::exception& error) {
onexcept(optional<const std::exception&>(error), error.what()); detail::handle_protected_exception(lua_state(), optional<const std::exception&>(error), error.what(), h);
firstreturn = lua_gettop(lua_state()); firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
} }
@ -123,7 +126,7 @@ namespace sol {
// but LuaJIT will swallow all C++ errors // but LuaJIT will swallow all C++ errors
// if we don't at least catch std::exception ones // if we don't at least catch std::exception ones
catch (...) { catch (...) {
onexcept(optional<const std::exception&>(nullopt), "caught (...) unknown error during protected_function call"); detail::handle_protected_exception(lua_state(), optional<const std::exception&>(nullopt), detail::protected_function_error, h);
firstreturn = lua_gettop(lua_state()); firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
} }

View File

@ -117,7 +117,6 @@ namespace sol {
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index); return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
} }
struct evaluator {
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) { static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) {
return std::forward<Fx>(fx)(std::forward<Args>(args)...); return std::forward<Fx>(fx)(std::forward<Args>(args)...);
@ -127,7 +126,6 @@ namespace sol {
static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) { static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) {
return eval(types<Args...>(), std::index_sequence<Is...>(), L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)..., stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking)); return eval(types<Args...>(), std::index_sequence<Is...>(), L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)..., stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking));
} }
};
template <bool checkargs = detail::default_safe_function_calls , std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value >> template <bool checkargs = detail::default_safe_function_calls , std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value >>
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
@ -137,7 +135,7 @@ namespace sol {
argument_handler<types<R, Args...>> handler{}; argument_handler<types<R, Args...>> handler{};
multi_check<checkargs, Args...>(L, start, handler); multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); return eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
template <bool checkargs = detail::default_safe_function_calls, std::size_t... I, typename... Args, typename Fx, typename... FxArgs> template <bool checkargs = detail::default_safe_function_calls, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
@ -148,7 +146,7 @@ namespace sol {
argument_handler<types<void, Args...>> handler{}; argument_handler<types<void, Args...>> handler{};
multi_check<checkargs, Args...>(L, start, handler); multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
} // namespace stack_detail } // namespace stack_detail

View File

@ -84,15 +84,16 @@ namespace sol {
return align(alignment, size, ptr, space, required_space); return align(alignment, size, ptr, space, required_space);
} }
inline void align_one(std::size_t a, std::size_t s, void*& target_alignment) {
std::size_t space = (std::numeric_limits<std::size_t>::max)();
target_alignment = align(a, s, target_alignment, space);
target_alignment = static_cast<void*>(static_cast<char*>(target_alignment) + s);
}
template <typename... Args> template <typename... Args>
inline std::size_t aligned_space_for(void* alignment = nullptr) { inline std::size_t aligned_space_for(void* alignment = nullptr) {
char* start = static_cast<char*>(alignment); char* start = static_cast<char*>(alignment);
auto specific_align = [&alignment](std::size_t a, std::size_t s) { (void)detail::swallow{ int{}, (align_one(std::alignment_of_v<Args>, sizeof(Args), alignment), int{})... };
std::size_t space = (std::numeric_limits<std::size_t>::max)();
alignment = align(a, s, alignment, space);
alignment = static_cast<void*>(static_cast<char*>(alignment) + s);
};
(void)detail::swallow{ int{}, (specific_align(std::alignment_of<Args>::value, sizeof(Args)), int{})... };
return static_cast<char*>(alignment) - start; return static_cast<char*>(alignment) - start;
} }
@ -236,6 +237,61 @@ namespace sol {
return static_cast<T**>(adjusted); return static_cast<T**>(adjusted);
} }
inline bool attempt_alloc(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t value_align, std::size_t value_size,
std::size_t allocated_size, void*& pointer_adjusted, void*& data_adjusted) {
void* adjusted = lua_newuserdata(L, allocated_size);
pointer_adjusted = align(ptr_align, ptr_size, adjusted, allocated_size);
if (pointer_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
// subtract size of what we're going to allocate there
allocated_size -= ptr_size;
adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size);
data_adjusted = align(value_align, value_size, adjusted, allocated_size);
if (data_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
return true;
}
inline bool attempt_alloc_unique(lua_State* L, std::size_t ptr_align, std::size_t ptr_size, std::size_t real_align, std::size_t real_size,
std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& id_adjusted, void*& data_adjusted) {
void* adjusted = lua_newuserdata(L, allocated_size);
pointer_adjusted = align(ptr_align, ptr_size, adjusted, allocated_size);
if (pointer_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
allocated_size -= ptr_size;
adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + ptr_size);
dx_adjusted = align(std::alignment_of_v<unique_destructor>, sizeof(unique_destructor), adjusted, allocated_size);
if (dx_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
allocated_size -= sizeof(unique_destructor);
adjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor));
id_adjusted = align(std::alignment_of_v<unique_tag>, sizeof(unique_tag), adjusted, allocated_size);
if (id_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
allocated_size -= sizeof(unique_tag);
adjusted = static_cast<void*>(static_cast<char*>(id_adjusted) + sizeof(unique_tag));
data_adjusted = align(real_align, real_size, adjusted, allocated_size);
if (data_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
return true;
}
template <typename T> template <typename T>
inline T* usertype_allocate(lua_State* L) { inline T* usertype_allocate(lua_State* L) {
typedef std::integral_constant<bool, typedef std::integral_constant<bool,
@ -274,30 +330,13 @@ namespace sol {
void* pointer_adjusted; void* pointer_adjusted;
void* data_adjusted; void* data_adjusted;
auto attempt_alloc = [](lua_State* L, std::size_t allocated_size, void*& pointer_adjusted, void*& data_adjusted) -> bool { bool result = attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), initial_size, pointer_adjusted, data_adjusted);
void* adjusted = lua_newuserdata(L, allocated_size);
pointer_adjusted = align(std::alignment_of<T*>::value, sizeof(T*), adjusted, allocated_size);
if (pointer_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
// subtract size of what we're going to allocate there
allocated_size -= sizeof(T*);
adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + sizeof(T*));
data_adjusted = align(std::alignment_of<T>::value, sizeof(T), adjusted, allocated_size);
if (data_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
return true;
};
bool result = attempt_alloc(L, initial_size, pointer_adjusted, data_adjusted);
if (!result) { if (!result) {
// we're likely to get something that fails to perform the proper allocation a second time, // we're likely to get something that fails to perform the proper allocation a second time,
// so we use the suggested_new_size bump to help us out here // so we use the suggested_new_size bump to help us out here
pointer_adjusted = nullptr; pointer_adjusted = nullptr;
data_adjusted = nullptr; data_adjusted = nullptr;
result = attempt_alloc(L, misaligned_size, pointer_adjusted, data_adjusted); result = attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, sizeof(T), misaligned_size, pointer_adjusted, data_adjusted);
if (!result) { if (!result) {
if (pointer_adjusted == nullptr) { if (pointer_adjusted == nullptr) {
luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str());
@ -342,43 +381,16 @@ namespace sol {
void* dx_adjusted; void* dx_adjusted;
void* id_adjusted; void* id_adjusted;
void* data_adjusted; void* data_adjusted;
auto attempt_alloc bool result = attempt_alloc_unique(L,
= [](lua_State* L, std::size_t allocated_size, void*& pointer_adjusted, void*& dx_adjusted, void*& id_adjusted, void*& data_adjusted) std::alignment_of_v<T*>,
-> bool { sizeof(T*),
void* adjusted = lua_newuserdata(L, allocated_size); std::alignment_of_v<Real>,
pointer_adjusted = align(std::alignment_of<T*>::value, sizeof(T*), adjusted, allocated_size); sizeof(Real),
if (pointer_adjusted == nullptr) { initial_size,
lua_pop(L, 1); pointer_adjusted,
return false; dx_adjusted,
} id_adjusted,
allocated_size -= sizeof(T*); data_adjusted);
adjusted = static_cast<void*>(static_cast<char*>(pointer_adjusted) + sizeof(T*));
dx_adjusted = align(std::alignment_of<unique_destructor>::value, sizeof(unique_destructor), adjusted, allocated_size);
if (dx_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
allocated_size -= sizeof(unique_destructor);
adjusted = static_cast<void*>(static_cast<char*>(dx_adjusted) + sizeof(unique_destructor));
id_adjusted = align(std::alignment_of<unique_tag>::value, sizeof(unique_tag), adjusted, allocated_size);
if (id_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
allocated_size -= sizeof(unique_tag);
adjusted = static_cast<void*>(static_cast<char*>(id_adjusted) + sizeof(unique_tag));
data_adjusted = align(std::alignment_of<Real>::value, sizeof(Real), adjusted, allocated_size);
if (data_adjusted == nullptr) {
lua_pop(L, 1);
return false;
}
return true;
};
bool result = attempt_alloc(L, initial_size, pointer_adjusted, dx_adjusted, id_adjusted, data_adjusted);
if (!result) { if (!result) {
// we're likely to get something that fails to perform the proper allocation a second time, // we're likely to get something that fails to perform the proper allocation a second time,
// so we use the suggested_new_size bump to help us out here // so we use the suggested_new_size bump to help us out here
@ -386,7 +398,16 @@ namespace sol {
dx_adjusted = nullptr; dx_adjusted = nullptr;
id_adjusted = nullptr; id_adjusted = nullptr;
data_adjusted = nullptr; data_adjusted = nullptr;
result = attempt_alloc(L, misaligned_size, pointer_adjusted, dx_adjusted, id_adjusted, data_adjusted); result = attempt_alloc_unique(L,
std::alignment_of_v<T*>,
sizeof(T*),
std::alignment_of_v<Real>,
sizeof(Real),
misaligned_size,
pointer_adjusted,
dx_adjusted,
id_adjusted,
data_adjusted);
if (!result) { if (!result) {
if (pointer_adjusted == nullptr) { if (pointer_adjusted == nullptr) {
luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str()); luaL_error(L, "aligned allocation of userdata block (pointer section) for '%s' failed", detail::demangle<T>().c_str());

View File

@ -45,6 +45,77 @@
namespace sol { namespace stack { namespace sol { namespace stack {
namespace stack_detail {
template <typename Ch>
struct count_code_units_utf {
std::size_t needed_size;
count_code_units_utf() : needed_size(0) {
}
void operator()(const unicode::encoded_result<Ch> er) {
needed_size += er.code_units_size;
}
};
template <typename Ch, typename ErCh>
struct copy_code_units_utf {
Ch* target_;
copy_code_units_utf(Ch* target) : target_(target) {
}
void operator()(const unicode::encoded_result<ErCh> er) {
std::memcpy(target_, er.code_units.data(), er.code_units_size * sizeof(ErCh));
target_ += er.code_units_size;
}
};
template <typename Ch, typename F>
inline void convert(const char* strb, const char* stre, F&& f) {
char32_t cp = 0;
for (const char* strtarget = strb; strtarget < stre;) {
auto dr = unicode::utf8_to_code_point(strtarget, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
++strtarget;
}
else {
cp = dr.codepoint;
strtarget = dr.next;
}
if constexpr(std::is_same_v<Ch, char32_t>) {
auto er = unicode::code_point_to_utf32(cp);
f(er);
}
else {
auto er = unicode::code_point_to_utf16(cp);
f(er);
}
}
}
template <typename BaseCh, typename S>
inline S get_into(lua_State* L, int index, record& tracking) {
typedef typename S::value_type Ch;
tracking.use(1);
size_t len;
auto utf8p = lua_tolstring(L, index, &len);
if (len < 1)
return S();
const char* strb = utf8p;
const char* stre = utf8p + len;
stack_detail::count_code_units_utf<BaseCh> count_units;
convert<BaseCh>(strb, stre, count_units);
S r(count_units.needed_size, static_cast<Ch>(0));
r.resize(count_units.needed_size);
Ch* target = &r[0];
stack_detail::copy_code_units_utf<Ch, BaseCh> copy_units(target);
convert<BaseCh>(strb, stre, copy_units);
return r;
}
}
template <typename U> template <typename U>
struct userdata_getter<U> { struct userdata_getter<U> {
typedef stack_detail::strip_extensible_t<U> T; typedef stack_detail::strip_extensible_t<U> T;
@ -99,7 +170,7 @@ namespace sol { namespace stack {
template <typename T> template <typename T>
struct unqualified_getter<as_table_t<T>> { struct unqualified_getter<as_table_t<T>> {
typedef meta::unqualified_t<T> Tu; using Tu = meta::unqualified_t<T>;
template <typename V> template <typename V>
static void push_back_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) { static void push_back_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
@ -113,8 +184,8 @@ namespace sol { namespace stack {
template <typename V> template <typename V>
static void insert_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) { static void insert_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
using std::end; using std::cend;
arr.insert(end(arr), stack::get<V>(L, -lua_size<V>::value)); arr.insert(cend(arr), stack::get<V>(L, -lua_size<V>::value));
} }
template <typename V> template <typename V>
@ -131,11 +202,11 @@ namespace sol { namespace stack {
} }
static T get(lua_State* L, int relindex, record& tracking) { static T get(lua_State* L, int relindex, record& tracking) {
return get(meta::has_key_value_pair<meta::unqualified_t<T>>(), L, relindex, tracking); return get(meta::is_associative<Tu>(), L, relindex, tracking);
} }
static T get(std::false_type, lua_State* L, int relindex, record& tracking) { static T get(std::false_type, lua_State* L, int relindex, record& tracking) {
typedef typename T::value_type V; typedef typename Tu::value_type V;
return get(types<V>(), L, relindex, tracking); return get(types<V>(), L, relindex, tracking);
} }
@ -143,15 +214,50 @@ namespace sol { namespace stack {
static T get(types<V> t, lua_State* L, int relindex, record& tracking) { static T get(types<V> t, lua_State* L, int relindex, record& tracking) {
tracking.use(1); tracking.use(1);
// the W4 flag is really great,
// so great that it can tell my for loops (2-nested)
// below never actually terminate without hitting a "return arr;"
// where the goto's are now so it would tell
// me that the return arr at the end of this function
// is W4XXX unreachable,
// which is fair until other compilers complain
// that there isn't a return and that based on
// SOME MAGICAL FORCE
// control flow falls off the end of a non-void function
// so it needs to be there for the compilers that are
// too flimsy to analyze the basic blocks...
// (I'm sure I should file a bug but those compilers are already
// in the wild; it doesn't matter if I fix them,
// someone else is still going to get some old-ass compiler
// and then bother me about the unclean build for the 30th
// time)
// "Why not an IIFE?"
// Because additional lambdas / functions which serve as
// capture-all-and-then-invoke bloat binary sizes
// by an actually detectable amount
// (one user uses sol2 pretty heavily and 22 MB of binary size
// was saved by reducing reliance on lambdas in templates)
// This would really be solved by having break N;
// be a real, proper thing...
// but instead, we have to use labels and gotos
// and earn the universal vitriol of the dogmatic
// programming community
// all in all: W4 is great!~
int index = lua_absindex(L, relindex); int index = lua_absindex(L, relindex);
T arr; T arr;
std::size_t idx = 0; std::size_t idx = 0;
#if SOL_LUA_VERSION >= 503 #if SOL_LUA_VERSION >= 503
// This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 // This method is HIGHLY performant over regular table iteration
// thanks to the Lua API changes in 5.3
// Questionable in 5.4 // Questionable in 5.4
for (lua_Integer i = 0;; i += lua_size<V>::value) { for (lua_Integer i = 0;; i += lua_size<V>::value) {
if (max_size_check(meta::has_max_size<Tu>(), arr, idx)) { if (max_size_check(meta::has_max_size<Tu>(), arr, idx)) {
return arr; // see above comment
goto done;
} }
bool isnil = false; bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) { for (int vi = 0; vi < lua_size<V>::value; ++vi) {
@ -181,7 +287,8 @@ namespace sol { namespace stack {
#else #else
lua_pop(L, (vi + 1)); lua_pop(L, (vi + 1));
#endif #endif
return arr; // see above comment
goto done;
} }
} }
if (isnil) { if (isnil) {
@ -199,7 +306,8 @@ namespace sol { namespace stack {
// Zzzz slower but necessary thanks to the lower version API and missing functions qq // Zzzz slower but necessary thanks to the lower version API and missing functions qq
for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) { for (lua_Integer i = 0;; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) { if (idx >= arr.max_size()) {
return arr; // see above comment
goto done;
} }
#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK
luaL_checkstack(L, 2, detail::not_enough_stack_space_generic); luaL_checkstack(L, 2, detail::not_enough_stack_space_generic);
@ -215,7 +323,8 @@ namespace sol { namespace stack {
break; break;
} }
lua_pop(L, (vi + 1)); lua_pop(L, (vi + 1));
return arr; // see above comment
goto done;
} }
} }
if (isnil) if (isnil)
@ -224,11 +333,12 @@ namespace sol { namespace stack {
++idx; ++idx;
} }
#endif #endif
done:
return arr; return arr;
} }
static T get(std::true_type, lua_State* L, int index, record& tracking) { static T get(std::true_type, lua_State* L, int index, record& tracking) {
typedef typename T::value_type P; typedef typename Tu::value_type P;
typedef typename P::first_type K; typedef typename P::first_type K;
typedef typename P::second_type V; typedef typename P::second_type V;
return get(types<K, V>(), L, index, tracking); return get(types<K, V>(), L, index, tracking);
@ -377,22 +487,11 @@ namespace sol { namespace stack {
}; };
template <typename T> template <typename T>
struct unqualified_getter<nested<T>, struct unqualified_getter<nested<T>, std::enable_if_t<is_container<T>::value>> {
std::enable_if_t< using Tu = meta::unqualified_t<T>;
meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
typedef typename T::value_type V;
unqualified_getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<nested<V>>(), L, index, tracking);
}
};
template <typename T>
struct unqualified_getter<nested<T>,
std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::value>> {
static T get(lua_State* L, int index, record& tracking) { static T get(lua_State* L, int index, record& tracking) {
if constexpr(meta::is_associative<Tu>::value) {
typedef typename T::value_type P; typedef typename T::value_type P;
typedef typename P::first_type K; typedef typename P::first_type K;
typedef typename P::second_type V; typedef typename P::second_type V;
@ -401,6 +500,14 @@ namespace sol { namespace stack {
(void)g; (void)g;
return g.get(types<K, nested<V>>(), L, index, tracking); return g.get(types<K, nested<V>>(), L, index, tracking);
} }
else {
typedef typename T::value_type V;
unqualified_getter<as_table_t<T>> g;
// VC++ has a bad warning here: shut it up
(void)g;
return g.get(types<nested<V>>(), L, index, tracking);
}
}
}; };
template <typename T> template <typename T>
@ -513,114 +620,24 @@ namespace sol { namespace stack {
template <typename Traits, typename Al> template <typename Traits, typename Al>
struct unqualified_getter<std::basic_string<wchar_t, Traits, Al>> { struct unqualified_getter<std::basic_string<wchar_t, Traits, Al>> {
typedef std::basic_string<wchar_t, Traits, Al> S; using S = std::basic_string<wchar_t, Traits, Al>;
static S get(lua_State* L, int index, record& tracking) { static S get(lua_State* L, int index, record& tracking) {
typedef std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t> Ch; using Ch = std::conditional_t<sizeof(wchar_t) == 2, char16_t, char32_t>;
typedef typename std::allocator_traits<Al>::template rebind_alloc<Ch> ChAl; return stack_detail::get_into<Ch, S>(L, index, tracking);
typedef std::char_traits<Ch> ChTraits;
unqualified_getter<std::basic_string<Ch, ChTraits, ChAl>> g;
(void)g;
return g.template get_into<S>(L, index, tracking);
} }
}; };
template <typename Traits, typename Al> template <typename Traits, typename Al>
struct unqualified_getter<std::basic_string<char16_t, Traits, Al>> { struct unqualified_getter<std::basic_string<char16_t, Traits, Al>> {
template <typename F>
static void convert(const char* strb, const char* stre, F&& f) {
char32_t cp = 0;
for (const char* strtarget = strb; strtarget < stre;) {
auto dr = unicode::utf8_to_code_point(strtarget, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
++strtarget;
}
else {
cp = dr.codepoint;
strtarget = dr.next;
}
auto er = unicode::code_point_to_utf16(cp);
f(er);
}
}
template <typename S>
static S get_into(lua_State* L, int index, record& tracking) {
typedef typename S::value_type Ch;
tracking.use(1);
size_t len;
auto utf8p = lua_tolstring(L, index, &len);
if (len < 1)
return S();
std::size_t needed_size = 0;
const char* strb = utf8p;
const char* stre = utf8p + len;
auto count_units
= [&needed_size](const unicode::encoded_result<char16_t> er) { needed_size += er.code_units_size; };
convert(strb, stre, count_units);
S r(needed_size, static_cast<Ch>(0));
r.resize(needed_size);
Ch* target = &r[0];
auto copy_units = [&target](const unicode::encoded_result<char16_t> er) {
std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch));
target += er.code_units_size;
};
convert(strb, stre, copy_units);
return r;
}
static std::basic_string<char16_t, Traits, Al> get(lua_State* L, int index, record& tracking) { static std::basic_string<char16_t, Traits, Al> get(lua_State* L, int index, record& tracking) {
return get_into<std::basic_string<char16_t, Traits, Al>>(L, index, tracking); return stack_detail::get_into<char16_t, std::basic_string<char16_t, Traits, Al>>(L, index, tracking);
} }
}; };
template <typename Traits, typename Al> template <typename Traits, typename Al>
struct unqualified_getter<std::basic_string<char32_t, Traits, Al>> { struct unqualified_getter<std::basic_string<char32_t, Traits, Al>> {
template <typename F>
static void convert(const char* strb, const char* stre, F&& f) {
char32_t cp = 0;
for (const char* strtarget = strb; strtarget < stre;) {
auto dr = unicode::utf8_to_code_point(strtarget, stre);
if (dr.error != unicode::error_code::ok) {
cp = unicode::unicode_detail::replacement;
++strtarget;
}
else {
cp = dr.codepoint;
strtarget = dr.next;
}
auto er = unicode::code_point_to_utf32(cp);
f(er);
}
}
template <typename S>
static S get_into(lua_State* L, int index, record& tracking) {
typedef typename S::value_type Ch;
tracking.use(1);
size_t len;
auto utf8p = lua_tolstring(L, index, &len);
if (len < 1)
return S();
std::size_t needed_size = 0;
const char* strb = utf8p;
const char* stre = utf8p + len;
auto count_units
= [&needed_size](const unicode::encoded_result<char32_t> er) { needed_size += er.code_units_size; };
convert(strb, stre, count_units);
S r(needed_size, static_cast<Ch>(0));
r.resize(needed_size);
Ch* target = &r[0];
auto copy_units = [&target](const unicode::encoded_result<char32_t> er) {
std::memcpy(target, er.code_units.data(), er.code_units_size * sizeof(Ch));
target += er.code_units_size;
};
convert(strb, stre, copy_units);
return r;
}
static std::basic_string<char32_t, Traits, Al> get(lua_State* L, int index, record& tracking) { static std::basic_string<char32_t, Traits, Al> get(lua_State* L, int index, record& tracking) {
return get_into<std::basic_string<char32_t, Traits, Al>>(L, index, tracking); return stack_detail::get_into<char32_t, std::basic_string<char32_t, Traits, Al>>(L, index, tracking);
} }
}; };

View File

@ -111,7 +111,7 @@ namespace sol {
template <typename... Args> template <typename... Args>
void open_libraries(Args&&... args) { void open_libraries(Args&&... args) {
static_assert(meta::all_same<lib, Args...>::value, "all types must be libraries"); static_assert(meta::all_same<lib, Args...>::value, "all types must be libraries");
if (sizeof...(args) == 0) { if constexpr (sizeof...(args) == 0) {
luaL_openlibs(L); luaL_openlibs(L);
return; return;
} }

View File

@ -465,6 +465,39 @@ namespace sol {
return nested<meta::unqualified_t<T>>(std::forward<T>(container)); return nested<meta::unqualified_t<T>>(std::forward<T>(container));
} }
template <typename T>
struct as_container_t {
T source;
as_container_t(T value) : source(std::move(value)) {
}
operator std::add_rvalue_reference_t<T>() {
return std::move(source);
}
operator std::add_lvalue_reference_t<std::add_const_t<T>>() const {
return source;
}
};
template <typename T>
struct as_container_t<T&> {
std::reference_wrapper<T> source;
as_container_t(T& value) : source(value) {
}
operator T&() {
return source;
}
};
template <typename T>
auto as_container(T&& value) {
return as_container_t<T>(std::forward<T>(value));
}
struct this_state { struct this_state {
lua_State* L; lua_State* L;

View File

@ -77,6 +77,19 @@ namespace sol {
static constexpr auto continuation_mask = 0xC0u; static constexpr auto continuation_mask = 0xC0u;
static constexpr auto continuation_signature = 0x80u; static constexpr auto continuation_signature = 0x80u;
static constexpr bool is_invalid(unsigned char b) {
return b == 0xC0 || b == 0xC1 || b > 0xF4;
}
static constexpr bool is_continuation(unsigned char b) {
return (b & unicode_detail::continuation_mask) == unicode_detail::continuation_signature;
}
static constexpr bool is_overlong(char32_t u, std::size_t bytes) {
return u <= unicode_detail::last_1byte_value || (u <= unicode_detail::last_2byte_value && bytes > 2)
|| (u <= unicode_detail::last_3byte_value && bytes > 3);
}
static constexpr int sequence_length(unsigned char b) { static constexpr int sequence_length(unsigned char b) {
return (b & start_2byte_mask) == 0 ? 1 return (b & start_2byte_mask) == 0 ? 1
: (b & start_3byte_mask) != start_3byte_mask ? 2 : (b & start_3byte_mask) != start_3byte_mask ? 2
@ -193,12 +206,7 @@ namespace sol {
return dr; return dr;
} }
auto is_invalid = [](unsigned char b) { return b == 0xC0 || b == 0xC1 || b > 0xF4; }; if (unicode_detail::is_invalid(b0) || unicode_detail::is_continuation(b0)) {
auto is_continuation = [](unsigned char b) {
return (b & unicode_detail::continuation_mask) == unicode_detail::continuation_signature;
};
if (is_invalid(b0) || is_continuation(b0)) {
dr.error = error_code::invalid_code_unit; dr.error = error_code::invalid_code_unit;
dr.next = it; dr.next = it;
return dr; return dr;
@ -209,7 +217,7 @@ namespace sol {
b[0] = b0; b[0] = b0;
for (std::size_t i = 1; i < length; ++i) { for (std::size_t i = 1; i < length; ++i) {
b[i] = *it; b[i] = *it;
if (!is_continuation(b[i])) { if (!unicode_detail::is_continuation(b[i])) {
dr.error = error_code::invalid_code_unit; dr.error = error_code::invalid_code_unit;
dr.next = it; dr.next = it;
return dr; return dr;
@ -230,12 +238,7 @@ namespace sol {
break; break;
} }
auto is_overlong = [](char32_t u, std::size_t bytes) { if (unicode_detail::is_overlong(decoded, length)) {
return u <= unicode_detail::last_1byte_value
|| (u <= unicode_detail::last_2byte_value && bytes > 2)
|| (u <= unicode_detail::last_3byte_value && bytes > 3);
};
if (is_overlong(decoded, length)) {
dr.error = error_code::overlong_sequence; dr.error = error_code::overlong_sequence;
return dr; return dr;
} }

View File

@ -25,7 +25,7 @@
#define SOL_USERTYPE_HPP #define SOL_USERTYPE_HPP
#include "usertype_core.hpp" #include "usertype_core.hpp"
#include "usertype_container.hpp" #include "usertype_container_launch.hpp"
#include "usertype_storage.hpp" #include "usertype_storage.hpp"
#include "usertype_proxy.hpp" #include "usertype_proxy.hpp"
#include "metatable.hpp" #include "metatable.hpp"
@ -47,11 +47,16 @@ namespace sol {
void tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) { void tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) {
using args_tuple = std::tuple<Args...>&&; using args_tuple = std::tuple<Args...>&&;
optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state()); optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state());
if constexpr(sizeof...(I) > 0) {
if (maybe_uts) { if (maybe_uts) {
u_detail::usertype_storage<T>& uts = *maybe_uts; u_detail::usertype_storage<T>& uts = *maybe_uts;
detail::swallow{ 0, (uts.set(this->lua_state(), std::get<I * 2>(std::forward<args_tuple>(args)), std::get<I * 2 + 1>(std::forward<args_tuple>(args))), 0)... }; detail::swallow{ 0, (uts.set(this->lua_state(), std::get<I * 2>(std::forward<args_tuple>(args)), std::get<I * 2 + 1>(std::forward<args_tuple>(args))), 0)... };
} }
} }
else {
(void)args;
}
}
template <typename Key, typename Value> template <typename Key, typename Value>
void set(Key&& key, Value&& value) { void set(Key&& key, Value&& value) {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,458 @@
// sol3
// The MIT License (MIT)
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_USERTYPE_CONTAINER_LAUNCH_HPP
#define SOL_USERTYPE_CONTAINER_LAUNCH_HPP
#include "stack.hpp"
#include "usertype_container.hpp"
#include "map.hpp"
namespace sol {
namespace container_detail {
template <typename X>
struct u_c_launch {
using T = std::remove_pointer_t<meta::unqualified_t<X>>;
using uc = usertype_container<T>;
using default_uc = usertype_container_default<T>;
static inline int real_index_get_traits(std::true_type, lua_State* L) {
return uc::index_get(L);
}
static inline int real_index_get_traits(std::false_type, lua_State* L) {
return default_uc::index_get(L);
}
static inline int real_index_call(lua_State* L) {
typedef detail::unordered_map<string_view, lua_CFunction> call_map;
static const call_map calls{
{ "at", &real_at_call },
{ "get", &real_get_call },
{ "set", &real_set_call },
{ "size", &real_length_call },
{ "add", &real_add_call },
{ "empty", &real_empty_call },
{ "insert", &real_insert_call },
{ "clear", &real_clear_call },
{ "find", &real_find_call },
{ "index_of", &real_index_of_call },
{ "erase", &real_erase_call },
{ "pairs", &pairs_call },
{ "next", &next_call },
};
auto maybenameview = stack::unqualified_check_get<string_view>(L, 2);
if (maybenameview) {
const string_view& name = *maybenameview;
auto it = calls.find(name);
if (it != calls.cend()) {
return stack::push(L, it->second);
}
}
return real_index_get_traits(container_detail::has_traits_index_get<uc>(), L);
}
static inline int real_at_traits(std::true_type, lua_State* L) {
return uc::at(L);
}
static inline int real_at_traits(std::false_type, lua_State* L) {
return default_uc::at(L);
}
static inline int real_at_call(lua_State* L) {
return real_at_traits(container_detail::has_traits_at<uc>(), L);
}
static inline int real_get_traits(std::true_type, lua_State* L) {
return uc::get(L);
}
static inline int real_get_traits(std::false_type, lua_State* L) {
return default_uc::get(L);
}
static inline int real_get_call(lua_State* L) {
return real_get_traits(container_detail::has_traits_get<uc>(), L);
}
static inline int real_set_traits(std::true_type, lua_State* L) {
return uc::set(L);
}
static inline int real_set_traits(std::false_type, lua_State* L) {
return default_uc::set(L);
}
static inline int real_set_call(lua_State* L) {
return real_set_traits(container_detail::has_traits_set<uc>(), L);
}
static inline int real_index_set_traits(std::true_type, lua_State* L) {
return uc::index_set(L);
}
static inline int real_index_set_traits(std::false_type, lua_State* L) {
return default_uc::index_set(L);
}
static inline int real_new_index_call(lua_State* L) {
return real_index_set_traits(container_detail::has_traits_index_set<uc>(), L);
}
static inline int real_pairs_traits(std::true_type, lua_State* L) {
return uc::pairs(L);
}
static inline int real_pairs_traits(std::false_type, lua_State* L) {
return default_uc::pairs(L);
}
static inline int real_pairs_call(lua_State* L) {
return real_pairs_traits(container_detail::has_traits_pairs<uc>(), L);
}
static inline int real_ipairs_traits(std::true_type, lua_State* L) {
return uc::ipairs(L);
}
static inline int real_ipairs_traits(std::false_type, lua_State* L) {
return default_uc::ipairs(L);
}
static inline int real_ipairs_call(lua_State* L) {
return real_ipairs_traits(container_detail::has_traits_ipairs<uc>(), L);
}
static inline int real_next_traits(std::true_type, lua_State* L) {
return uc::next(L);
}
static inline int real_next_traits(std::false_type, lua_State* L) {
return default_uc::next(L);
}
static inline int real_next_call(lua_State* L) {
return real_next_traits(container_detail::has_traits_next<uc>(), L);
}
static inline int real_size_traits(std::true_type, lua_State* L) {
return uc::size(L);
}
static inline int real_size_traits(std::false_type, lua_State* L) {
return default_uc::size(L);
}
static inline int real_length_call(lua_State* L) {
return real_size_traits(container_detail::has_traits_size<uc>(), L);
}
static inline int real_add_traits(std::true_type, lua_State* L) {
return uc::add(L);
}
static inline int real_add_traits(std::false_type, lua_State* L) {
return default_uc::add(L);
}
static inline int real_add_call(lua_State* L) {
return real_add_traits(container_detail::has_traits_add<uc>(), L);
}
static inline int real_insert_traits(std::true_type, lua_State* L) {
return uc::insert(L);
}
static inline int real_insert_traits(std::false_type, lua_State* L) {
return default_uc::insert(L);
}
static inline int real_insert_call(lua_State* L) {
return real_insert_traits(container_detail::has_traits_insert<uc>(), L);
}
static inline int real_clear_traits(std::true_type, lua_State* L) {
return uc::clear(L);
}
static inline int real_clear_traits(std::false_type, lua_State* L) {
return default_uc::clear(L);
}
static inline int real_clear_call(lua_State* L) {
return real_clear_traits(container_detail::has_traits_clear<uc>(), L);
}
static inline int real_empty_traits(std::true_type, lua_State* L) {
return uc::empty(L);
}
static inline int real_empty_traits(std::false_type, lua_State* L) {
return default_uc::empty(L);
}
static inline int real_empty_call(lua_State* L) {
return real_empty_traits(container_detail::has_traits_empty<uc>(), L);
}
static inline int real_erase_traits(std::true_type, lua_State* L) {
return uc::erase(L);
}
static inline int real_erase_traits(std::false_type, lua_State* L) {
return default_uc::erase(L);
}
static inline int real_erase_call(lua_State* L) {
return real_erase_traits(container_detail::has_traits_erase<uc>(), L);
}
static inline int real_find_traits(std::true_type, lua_State* L) {
return uc::find(L);
}
static inline int real_find_traits(std::false_type, lua_State* L) {
return default_uc::find(L);
}
static inline int real_find_call(lua_State* L) {
return real_find_traits(container_detail::has_traits_find<uc>(), L);
}
static inline int real_index_of_call(lua_State* L) {
if constexpr(container_detail::has_traits_index_of<uc>()) {
return uc::index_of(L);
}
else {
return default_uc::index_of(L);
}
}
static inline int add_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_add_call), (&real_add_call)>(L);
}
static inline int erase_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_erase_call), (&real_erase_call)>(L);
}
static inline int insert_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_insert_call), (&real_insert_call)>(L);
}
static inline int clear_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_clear_call), (&real_clear_call)>(L);
}
static inline int empty_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_empty_call), (&real_empty_call)>(L);
}
static inline int find_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_find_call), (&real_find_call)>(L);
}
static inline int index_of_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_index_of_call), (&real_index_of_call)>(L);
}
static inline int length_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_length_call), (&real_length_call)>(L);
}
static inline int pairs_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_pairs_call), (&real_pairs_call)>(L);
}
static inline int ipairs_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_ipairs_call), (&real_ipairs_call)>(L);
}
static inline int next_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_next_call), (&real_next_call)>(L);
}
static inline int at_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_at_call), (&real_at_call)>(L);
}
static inline int get_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_get_call), (&real_get_call)>(L);
}
static inline int set_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_set_call), (&real_set_call)>(L);
}
static inline int index_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L);
}
static inline int new_index_call(lua_State* L) {
return detail::typed_static_trampoline<decltype(&real_new_index_call), (&real_new_index_call)>(L);
}
};
} // namespace container_detail
namespace stack {
namespace stack_detail {
template <typename T, bool is_shim = false>
struct metatable_setup {
lua_State* L;
metatable_setup(lua_State* L)
: L(L) {
}
void operator()() {
using meta_usertype_container = container_detail::u_c_launch<
std::conditional_t<is_shim, as_container_t<std::remove_pointer_t<T>>, std::remove_pointer_t<T>>>;
static const char* metakey = is_shim ? &usertype_traits<as_container_t<std::remove_pointer_t<T>>>::metatable()[0] : &usertype_traits<T>::metatable()[0];
static const std::array<luaL_Reg, 20> reg = { {
// clang-format off
{ "__pairs", &meta_usertype_container::pairs_call },
{ "__ipairs", &meta_usertype_container::ipairs_call },
{ "__len", &meta_usertype_container::length_call },
{ "__index", &meta_usertype_container::index_call },
{ "__newindex", &meta_usertype_container::new_index_call },
{ "pairs", &meta_usertype_container::pairs_call },
{ "next", &meta_usertype_container::next_call },
{ "at", &meta_usertype_container::at_call },
{ "get", &meta_usertype_container::get_call },
{ "set", &meta_usertype_container::set_call },
{ "size", &meta_usertype_container::length_call },
{ "empty", &meta_usertype_container::empty_call },
{ "clear", &meta_usertype_container::clear_call },
{ "insert", &meta_usertype_container::insert_call },
{ "add", &meta_usertype_container::add_call },
{ "find", &meta_usertype_container::find_call },
{ "index_of", &meta_usertype_container::index_of_call },
{ "erase", &meta_usertype_container::erase_call },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct<T> },
{ nullptr, nullptr }
// clang-format on
} };
if (luaL_newmetatable(L, metakey) == 1) {
luaL_setfuncs(L, reg.data(), 0);
}
lua_setmetatable(L, -2);
}
};
} // namespace stack_detail
template <typename T>
struct unqualified_pusher<as_container_t<T>> {
typedef meta::unqualified_t<T> C;
static int push_lvalue(std::true_type, lua_State* L, const C& cont) {
stack_detail::metatable_setup<C*, true> fx(L);
return stack::push<detail::as_pointer_tag<const C>>(L, detail::with_function_tag(), fx, detail::ptr(cont));
}
static int push_lvalue(std::false_type, lua_State* L, const C& cont) {
stack_detail::metatable_setup<C, true> fx(L);
return stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, cont);
}
static int push_rvalue(std::true_type, lua_State* L, C&& cont) {
stack_detail::metatable_setup<C, true> fx(L);
return stack::push<detail::as_value_tag<C>>(L, detail::with_function_tag(), fx, std::move(cont));
}
static int push_rvalue(std::false_type, lua_State* L, const C& cont) {
return push_lvalue(std::is_lvalue_reference<T>(), L, cont);
}
static int push(lua_State* L, const as_container_t<T>& as_cont) {
return push_lvalue(std::is_lvalue_reference<T>(), L, as_cont.source);
}
static int push(lua_State* L, as_container_t<T>&& as_cont) {
return push_rvalue(meta::all<std::is_rvalue_reference<T>, meta::neg<std::is_lvalue_reference<T>>>(), L, std::forward<T>(as_cont.source));
}
};
template <typename T>
struct unqualified_pusher<as_container_t<T*>> {
typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C;
static int push(lua_State* L, T* cont) {
stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont);
}
};
template <typename T>
struct unqualified_pusher<T, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> {
typedef meta::unqualified_t<T> C;
static int push(lua_State* L, const T& cont) {
stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_value_tag<T>>(L, detail::with_function_tag(), fx, cont);
}
static int push(lua_State* L, T&& cont) {
stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_value_tag<T>>(L, detail::with_function_tag(), fx, std::move(cont));
}
};
template <typename T>
struct unqualified_pusher<T*, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<is_lua_reference<meta::unqualified_t<T>>>>::value>> {
typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C;
static int push(lua_State* L, T* cont) {
stack_detail::metatable_setup<C> fx(L);
return stack::push<detail::as_pointer_tag<T>>(L, detail::with_function_tag(), fx, cont);
}
};
template <typename T, typename C>
struct unqualified_checker<as_container_t<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T>
struct unqualified_getter<as_container_t<T>> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::unqualified_get<T>(L, index, tracking);
}
};
template <typename T>
struct unqualified_getter<as_container_t<T>*> {
static decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack::unqualified_get<T*>(L, index, tracking);
}
};
} // namespace stack
} // namespace sol
#endif // SOL_USERTYPE_CONTAINER_LAUNCH_HPP

View File

@ -34,7 +34,7 @@
#include "deprecate.hpp" #include "deprecate.hpp"
#include "object.hpp" #include "object.hpp"
#include "function_types.hpp" #include "function_types.hpp"
#include "usertype_container.hpp" #include "usertype_container_launch.hpp"
#include <sstream> #include <sstream>
#include <type_traits> #include <type_traits>
@ -141,7 +141,7 @@ namespace sol {
ifx(meta_function::equal_to, f); ifx(meta_function::equal_to, f);
} }
if (fx(meta_function::pairs)) { if (fx(meta_function::pairs)) {
ifx(meta_function::pairs, &usertype_container<as_container_t<T>>::pairs_call); ifx(meta_function::pairs, &container_detail::u_c_launch<as_container_t<T>>::pairs_call);
} }
if (fx(meta_function::length)) { if (fx(meta_function::length)) {
if constexpr (meta::has_size<const T>::value || meta::has_size<T>::value) { if constexpr (meta::has_size<const T>::value || meta::has_size<T>::value) {

View File

@ -942,7 +942,7 @@ namespace sol { namespace u_detail {
stack::set_field<false, true>(L, detail::base_class_cast_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_cast), t.stack_index()); stack::set_field<false, true>(L, detail::base_class_cast_key(), reinterpret_cast<void*>(&detail::inheritance<T>::type_cast), t.stack_index());
auto prop_fx = detail::properties_enrollment_allowed(storage.properties, enrollments); auto prop_fx = detail::properties_enrollment_allowed(storage.properties, enrollments);
auto insert_fx = [&](meta_function mf, lua_CFunction reg) { auto insert_fx = [&L, &t, &storage](meta_function mf, lua_CFunction reg) {
stack::set_field<false, true>(L, mf, reg, t.stack_index()); stack::set_field<false, true>(L, mf, reg, t.stack_index());
storage.properties[static_cast<int>(mf)] = true; storage.properties[static_cast<int>(mf)] = true;
}; };

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-01-05 18:55:40.545875 UTC // Generated 2019-01-14 02:43:17.627340 UTC
// This header was generated with sol v2.20.6 (revision d9f973e) // This header was generated with sol v2.20.6 (revision 91faa7a)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -366,6 +366,9 @@ namespace sol {
struct this_main_state; struct this_main_state;
struct this_environment; struct this_environment;
class state_view;
class state;
template <typename T> template <typename T>
struct as_table_t; struct as_table_t;
template <typename T> template <typename T>

File diff suppressed because it is too large Load Diff

View File

@ -23,4 +23,4 @@
#include "sol_defines.hpp" #include "sol_defines.hpp"
#include <sol/container_traits.hpp> #include <sol/usertype_container_launch.hpp>

View File

@ -36,7 +36,6 @@
#include <set> #include <set>
#include <unordered_set> #include <unordered_set>
class int_shim { class int_shim {
public: public:
int_shim() = default; int_shim() = default;
@ -143,7 +142,7 @@ namespace sol {
struct is_container<my_vec> : std::true_type {}; struct is_container<my_vec> : std::true_type {};
template <> template <>
struct container_traits<my_vec> { struct usertype_container<my_vec> {
static auto begin(lua_State*, my_vec& self) { static auto begin(lua_State*, my_vec& self) {
return self.begin(); return self.begin();
} }
@ -157,6 +156,21 @@ namespace sol {
} // namespace sol } // namespace sol
struct order_suit {
std::vector<std::pair<int, int64_t>> objs;
std::vector<std::pair<int64_t, int>> objs2;
order_suit(int pairs) {
objs.reserve(pairs);
objs2.reserve(pairs * 2);
for (int i = 0; i < pairs; ++i) {
objs.push_back({ i, i * 10 });
objs2.push_back({ (i + pairs) * 2, (i * 2) * 50 });
objs2.push_back({ ((i + pairs) * 2) + 1, (i * 2 + 1) * 50 });
}
}
};
TEST_CASE("containers/input iterators", "test shitty input iterators that are all kinds of B L E H") { TEST_CASE("containers/input iterators", "test shitty input iterators that are all kinds of B L E H") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package); lua.open_libraries(sol::lib::base, sol::lib::package);
@ -255,3 +269,43 @@ TEST_CASE("containers/containers of pointers", "containers of pointers shouldn't
REQUIRE(*bp == 600); REQUIRE(*bp == 600);
} }
} }
TEST_CASE("containers/pair container in usertypes", "make sure containers that use pairs in usertypes do not trigger compiler errors") {
sol::state lua;
lua.open_libraries(sol::lib::base);
auto orderSuit = lua.new_usertype<order_suit>("order_suit", sol::constructors<order_suit(int)>());
#define SET_PROP(__PROP__) orderSuit.set(#__PROP__, &order_suit::__PROP__)
SET_PROP(objs);
SET_PROP(objs2);
#undef SET_PROP
auto result1 = lua.safe_script("osobj = order_suit.new(5)", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("pvec = osobj.objs", sol::script_pass_on_error);
REQUIRE(result2.valid());
auto result3 = lua.safe_script("pvec2 = osobj.objs2", sol::script_pass_on_error);
REQUIRE(result3.valid());
using vec_t = std::remove_reference_t<decltype(std::declval<order_suit>().objs)>;
using vec2_t = std::remove_reference_t<decltype(std::declval<order_suit>().objs2)>;
vec_t& pvec = lua["pvec"];
vec2_t& pvec2 = lua["pvec2"];
REQUIRE(pvec.size() == 5);
REQUIRE(pvec2.size() == 10);
REQUIRE(pvec[0].first == 0);
REQUIRE(pvec[0].second == 0);
REQUIRE(pvec[1].first == 1);
REQUIRE(pvec[1].second == 10);
REQUIRE(pvec[2].first == 2);
REQUIRE(pvec[2].second == 20);
REQUIRE(pvec2[0].first == 10);
REQUIRE(pvec2[0].second == 0);
REQUIRE(pvec2[1].first == 11);
REQUIRE(pvec2[1].second == 50);
REQUIRE(pvec2[2].first == 12);
REQUIRE(pvec2[2].second == 100);
REQUIRE(pvec2[3].first == 13);
REQUIRE(pvec2[3].second == 150);
}

View File

@ -429,7 +429,7 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
} }
#if !defined(SOL2_CI) && ((!defined(_M_IX86) || defined(_M_IA64)) || (defined(_WIN64)) || (defined(__LLP64__) || defined(__LP64__)) ) #if !defined(SOL2_CI) && ((!defined(_M_IX86) || defined(_M_IA64)) || (defined(_WIN64)) || (defined(__LLP64__) || defined(__LP64__)) )
TEST_CASE("functions/unsafe protected_function_result handlers", "This test will thrash the stack and allocations on weaker compilers (e.g., non 64-bit ones). Run with caution.") { TEST_CASE("functions/safe protected_function_result handlers", "These tests will (hopefully) not destroy the stack since they are supposed to be mildly safe. Still, run with caution.") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::debug); lua.open_libraries(sol::lib::base, sol::lib::debug);
static const char unhandlederrormessage[] = "true error message"; static const char unhandlederrormessage[] = "true error message";
@ -449,22 +449,10 @@ TEST_CASE("functions/unsafe protected_function_result handlers", "This test will
return handlederrormessage; return handlederrormessage;
}; };
lua.set_function("cpphandler", cpphandlerfx); lua.set_function("cpphandler", cpphandlerfx);
auto nontrampolinefx = [](lua_State*) -> int {
// this code shoots an exception
// through the C API, without the trampoline
// present.
// it is probably guaranteed to kill our code.
throw "x";
};
lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx);
lua.set_function("bark", []() -> int { return 100; });
sol::function cpphandler = lua["cpphandler"]; sol::function cpphandler = lua["cpphandler"];
sol::protected_function luadoom(lua["luadoom"]); sol::protected_function luadoom(lua["luadoom"]);
sol::protected_function nontrampoline = lua["nontrampoline"];
luadoom.error_handler = cpphandler; luadoom.error_handler = cpphandler;
nontrampoline.error_handler = cpphandler;
bool present = true; bool present = true;
{ {
@ -479,12 +467,40 @@ TEST_CASE("functions/unsafe protected_function_result handlers", "This test will
sol::error err = result; sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s); REQUIRE(err.what() == handlederrormessage_s);
} }
}
TEST_CASE("functions/unsafe protected_function_result handlers",
"This test will thrash the stack and allocations on weaker compilers (e.g., non 64-bit ones). Run with caution.") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::debug);
static const char handlederrormessage[] = "doodle";
static const std::string handlederrormessage_s = handlederrormessage;
auto cpphandlerfx = [](std::string x) {
INFO("c++ handler called with: " << x);
return handlederrormessage;
};
lua.set_function("cpphandler", cpphandlerfx);
auto nontrampolinefx = [](lua_State*) -> int {
// this code shoots an exception
// through the C API, without the trampoline
// present.
// it is probably guaranteed to kill our code.
throw "x";
};
lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx);
sol::function cpphandler = lua["cpphandler"];
sol::protected_function nontrampoline = lua["nontrampoline"];
nontrampoline.error_handler = cpphandler;
{ {
sol::protected_function_result result = nontrampoline(); sol::protected_function_result result = nontrampoline();
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
sol::optional<sol::error> operr = result; sol::optional<sol::error> operr = result;
sol::optional<int> opvalue = result; sol::optional<int> opvalue = result;
present = (bool)operr; bool present = (bool)operr;
REQUIRE(present); REQUIRE(present);
present = (bool)opvalue; present = (bool)opvalue;
REQUIRE_FALSE(present); REQUIRE_FALSE(present);
@ -492,7 +508,7 @@ TEST_CASE("functions/unsafe protected_function_result handlers", "This test will
REQUIRE(err.what() == handlederrormessage_s); REQUIRE(err.what() == handlederrormessage_s);
} }
} }
#endif // This test will thrash the stack and allocations on weaker compilers #endif // These tests will thrash the stack and allocations on weaker compilers
TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") { TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") {
sol::state lua; sol::state lua;
@ -670,12 +686,16 @@ N = n(1, 2, 3)
REQUIRE(N == 13); REQUIRE(N == 13);
// Work that compiler, WORK IT! // Work that compiler, WORK IT!
test_2 test_2_instance;
lua.set("o", &test_1::bark); lua.set("o", &test_1::bark);
lua.set("p", test_1::x_bark); lua.set("p", test_1::x_bark);
lua.set("q", sol::c_call<decltype(&test_1::bark_mem), &test_1::bark_mem>); lua.set("q", sol::c_call<decltype(&test_1::bark_mem), &test_1::bark_mem>);
lua.set("r", &test_2::a); lua.set("r", &test_2::a);
lua.set("s", sol::readonly(&test_2::a)); lua.set("s", sol::readonly(&test_2::a));
lua.set_function("t", sol::readonly(&test_2::a), test_2()); lua.set_function("t", sol::readonly(&test_2::a), test_2());
lua.set_function("t2", sol::readonly(&test_2::a), &test_2_instance);
lua.set_function("t3", sol::readonly(&test_2::a), std::ref(test_2_instance));
lua.set_function("t4", sol::readonly(&test_2::a), std::cref(test_2_instance));
lua.set_function("u", &nested::i, nested()); lua.set_function("u", &nested::i, nested());
lua.set("v", &nested::i); lua.set("v", &nested::i);
lua.set("nested", nested()); lua.set("nested", nested());
@ -687,6 +707,12 @@ N = n(1, 2, 3)
{ {
auto result = lua.safe_script("t(2)", sol::script_pass_on_error); auto result = lua.safe_script("t(2)", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
auto result2 = lua.safe_script("t2(2)", sol::script_pass_on_error);
REQUIRE_FALSE(result2.valid());
auto result3 = lua.safe_script("t3(2)", sol::script_pass_on_error);
REQUIRE_FALSE(result3.valid());
auto result4 = lua.safe_script("t4(2)", sol::script_pass_on_error);
REQUIRE_FALSE(result4.valid());
} }
{ {
auto result = lua.safe_script("u(inner)", sol::script_pass_on_error); auto result = lua.safe_script("u(inner)", sol::script_pass_on_error);