Herpin' that derp.

SOL_NO_COMPAT is now in the proper place and documented in the compatibility part of the API.
Basic test for `table::add`
This commit is contained in:
ThePhD 2016-06-19 19:02:40 -04:00
parent 556be8da98
commit b6928b4b4e
17 changed files with 1327 additions and 1272 deletions

View File

@ -7,6 +7,8 @@ This is a detail header used to maintain compatability with the 5.2 and 5.3 APIs
It is not fully documented as this header's only purpose is for internal use to make sure Sol compiles across all platforms / distributions with no errors or missing Lua functionality. If you think there's some compatibility features we are missing or if you are running into redefinition errors, please make an `issue in the issue tracker`_. It is not fully documented as this header's only purpose is for internal use to make sure Sol compiles across all platforms / distributions with no errors or missing Lua functionality. If you think there's some compatibility features we are missing or if you are running into redefinition errors, please make an `issue in the issue tracker`_.
If you have this already in your project or you have your own compatibility layer, then please ``#define SOL_NO_COMPAT 1`` before including ``sol.hpp`` or pass this flag on the command line to turn off the compatibility wrapper.
For the licenses, see :doc:`here<../licenses>` For the licenses, see :doc:`here<../licenses>`
.. _issue in the issue tracker: https://github.com/ThePhD/sol2/issues/ .. _issue in the issue tracker: https://github.com/ThePhD/sol2/issues/

View File

@ -1,218 +1,242 @@
#pragma once // The MIT License (MIT)
// Copyright (c) 2013-2016 Rappt1101010z, 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_BIND_TRAITS_HPP
#define SOL_BIND_TRAITS_HPP
#include "tuple.hpp" #include "tuple.hpp"
namespace sol { namespace sol {
namespace meta { namespace meta {
namespace meta_detail { namespace meta_detail {
template<class F> template<class F>
struct check_deducible_signature { struct check_deducible_signature {
struct nat {}; struct nat {};
template<class G> template<class G>
static auto test(int) -> decltype(&G::operator(), void()); static auto test(int) -> decltype(&G::operator(), void());
template<class> template<class>
static auto test(...) -> nat; static auto test(...)->nat;
using type = std::is_void<decltype(test<F>(0))>; using type = std::is_void<decltype(test<F>(0))>;
}; };
} // meta_detail } // meta_detail
template<class F> template<class F>
struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { }; struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { };
namespace meta_detail { namespace meta_detail {
template <std::size_t I, typename T> template <std::size_t I, typename T>
struct void_tuple_element : meta::tuple_element<I, T> {}; struct void_tuple_element : meta::tuple_element<I, T> {};
template <std::size_t I> template <std::size_t I>
struct void_tuple_element<I, std::tuple<>> { typedef void type; }; struct void_tuple_element<I, std::tuple<>> { typedef void type; };
template <std::size_t I, typename T> template <std::size_t I, typename T>
using void_tuple_element_t = typename void_tuple_element<I, T>::type; using void_tuple_element_t = typename void_tuple_element<I, T>::type;
template <bool has_c_variadic, typename T, typename R, typename... Args> template <bool has_c_variadic, typename T, typename R, typename... Args>
struct basic_traits { struct basic_traits {
private: private:
typedef std::conditional_t<std::is_void<T>::value, int, T>& first_type; typedef std::conditional_t<std::is_void<T>::value, int, T>& first_type;
public: public:
static const bool is_member_function = std::is_void<T>::value; static const bool is_member_function = std::is_void<T>::value;
static const bool has_c_var_arg = has_c_variadic; static const bool has_c_var_arg = has_c_variadic;
static const std::size_t arity = sizeof...(Args); static const std::size_t arity = sizeof...(Args);
static const std::size_t free_arity = sizeof...(Args) + static_cast<std::size_t>(!std::is_void<T>::value); static const std::size_t free_arity = sizeof...(Args)+static_cast<std::size_t>(!std::is_void<T>::value);
typedef types<Args...> args_list; typedef types<Args...> args_list;
typedef std::tuple<Args...> args_tuple; typedef std::tuple<Args...> args_tuple;
typedef T object_type; typedef T object_type;
typedef R return_type; typedef R return_type;
typedef tuple_types<R> returns_list; typedef tuple_types<R> returns_list;
typedef R(function_type)(Args...); typedef R(function_type)(Args...);
typedef std::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list; typedef std::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list;
typedef std::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type; typedef std::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type;
typedef std::conditional_t<std::is_void<T>::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type; typedef std::conditional_t<std::is_void<T>::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type;
typedef std::remove_pointer_t<free_function_pointer_type> signature_type; typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
template<std::size_t i> template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple>; using arg_at = void_tuple_element_t<i, args_tuple>;
}; };
template<typename Signature, bool b = has_deducible_signature<Signature>::value> template<typename Signature, bool b = has_deducible_signature<Signature>::value>
struct fx_traits : basic_traits<false, void, void> {}; struct fx_traits : basic_traits<false, void, void> {};
// Free Functions // Free Functions
template<typename R, typename... Args> template<typename R, typename... Args>
struct fx_traits<R(Args...), false> : basic_traits<false, void, R, Args...> { struct fx_traits<R(Args...), false> : basic_traits<false, void, R, Args...> {
typedef R(*function_pointer_type)(Args...); typedef R(*function_pointer_type)(Args...);
}; };
template<typename R, typename... Args> template<typename R, typename... Args>
struct fx_traits<R(*)(Args...), false> : basic_traits<false, void, R, Args...> { struct fx_traits<R(*)(Args...), false> : basic_traits<false, void, R, Args...> {
typedef R(*function_pointer_type)(Args...); typedef R(*function_pointer_type)(Args...);
}; };
template<typename R, typename... Args> template<typename R, typename... Args>
struct fx_traits<R(Args..., ...), false> : basic_traits<true, void, R, Args...> { struct fx_traits<R(Args..., ...), false> : basic_traits<true, void, R, Args...> {
typedef R(*function_pointer_type)(Args..., ...); typedef R(*function_pointer_type)(Args..., ...);
}; };
template<typename R, typename... Args> template<typename R, typename... Args>
struct fx_traits<R(*)(Args..., ...), false> : basic_traits<true, void, R, Args...> { struct fx_traits<R(*)(Args..., ...), false> : basic_traits<true, void, R, Args...> {
typedef R(*function_pointer_type)(Args..., ...); typedef R(*function_pointer_type)(Args..., ...);
}; };
// Member Functions // Member Functions
/* C-Style Variadics */ /* C-Style Variadics */
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...), false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...), false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...); typedef R(T::* function_pointer_type)(Args...);
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...), false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...), false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...); typedef R(T::* function_pointer_type)(Args..., ...);
}; };
/* Const Volatile */ /* Const Volatile */
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) const, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const; typedef R(T::* function_pointer_type)(Args...) const;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) const, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const; typedef R(T::* function_pointer_type)(Args..., ...) const;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const volatile, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) const volatile, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const volatile; typedef R(T::* function_pointer_type)(Args...) const volatile;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const volatile, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) const volatile, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const volatile; typedef R(T::* function_pointer_type)(Args..., ...) const volatile;
}; };
/* Member Function Qualifiers */ /* Member Function Qualifiers */
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) &, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) &, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) &; typedef R(T::* function_pointer_type)(Args...) &;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) &, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) &, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) &; typedef R(T::* function_pointer_type)(Args..., ...) &;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const &, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) const &, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const &; typedef R(T::* function_pointer_type)(Args...) const &;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const &, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) const &, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const &; typedef R(T::* function_pointer_type)(Args..., ...) const &;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const volatile &, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) const volatile &, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const volatile &; typedef R(T::* function_pointer_type)(Args...) const volatile &;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const volatile &, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) const volatile &, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &; typedef R(T::* function_pointer_type)(Args..., ...) const volatile &;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) &&, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) && , false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) &&; typedef R(T::* function_pointer_type)(Args...) && ;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) &&, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) && , false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) &&; typedef R(T::* function_pointer_type)(Args..., ...) && ;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const &&, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) const &&, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const &&; typedef R(T::* function_pointer_type)(Args...) const &&;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const &&, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) const &&, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const &&; typedef R(T::* function_pointer_type)(Args..., ...) const &&;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const volatile &&, false> : basic_traits<false, T, R, Args...> { struct fx_traits<R(T::*)(Args...) const volatile &&, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const volatile &&; typedef R(T::* function_pointer_type)(Args...) const volatile &&;
}; };
template<typename T, typename R, typename... Args> template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const volatile &&, false> : basic_traits<true, T, R, Args...> { struct fx_traits<R(T::*)(Args..., ...) const volatile &&, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&; typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&;
}; };
template<typename Signature> template<typename Signature>
struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {}; struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {};
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value> template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
struct callable_traits : fx_traits<std::decay_t<Signature>> { struct callable_traits : fx_traits<std::decay_t<Signature>> {
}; };
template<typename R, typename T> template<typename R, typename T>
struct callable_traits<R(T::*), true> { struct callable_traits<R(T::*), true> {
typedef R Arg; typedef R Arg;
typedef T object_type; typedef T object_type;
using signature_type = R(T::*); using signature_type = R(T::*);
static const bool is_member_function = false; static const bool is_member_function = false;
static const std::size_t arity = 1; static const std::size_t arity = 1;
static const std::size_t free_arity = 2; static const std::size_t free_arity = 2;
typedef std::tuple<Arg> args_tuple; typedef std::tuple<Arg> args_tuple;
typedef R return_type; typedef R return_type;
typedef types<Arg> args_list; typedef types<Arg> args_list;
typedef meta::tuple_types<R> returns_list; typedef meta::tuple_types<R> returns_list;
typedef R(function_type)(T&, R); typedef R(function_type)(T&, R);
typedef R(*function_pointer_type)(T&, R); typedef R(*function_pointer_type)(T&, R);
typedef R(*free_function_pointer_type)(T&, R); typedef R(*free_function_pointer_type)(T&, R);
template<std::size_t i> template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple>; using arg_at = void_tuple_element_t<i, args_tuple>;
}; };
} // meta_detail } // meta_detail
template<typename Signature> template<typename Signature>
struct bind_traits : meta_detail::callable_traits<Signature> {}; struct bind_traits : meta_detail::callable_traits<Signature> {};
template<typename Signature> template<typename Signature>
using function_args_t = typename bind_traits<Signature>::args_list; using function_args_t = typename bind_traits<Signature>::args_list;
template<typename Signature> template<typename Signature>
using function_signature_t = typename bind_traits<Signature>::signature_type; using function_signature_t = typename bind_traits<Signature>::signature_type;
template<typename Signature> template<typename Signature>
using function_return_t = typename bind_traits<Signature>::return_type; using function_return_t = typename bind_traits<Signature>::return_type;
} // meta } // meta
} // sol } // sol
#endif // SOL_BIND_TRAITS

View File

@ -1,6 +1,6 @@
// The MIT License (MIT) // The MIT License (MIT)
// Copyright (c) 2013-2016 Rappt1101010z, ThePhD and contributors // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of // 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 // this software and associated documentation files (the "Software"), to deal in
@ -26,294 +26,114 @@
#include "property.hpp" #include "property.hpp"
#include "stack.hpp" #include "stack.hpp"
namespace sol { namespace sol {
namespace call_detail { namespace call_detail {
template <bool b, typename F>
inline decltype(auto) pick(std::integral_constant<bool, b>, F&& f) {
return std::forward<F>(f);
}
template <typename R, typename W> template <bool b, typename F>
inline auto& pick(std::true_type, property_wrapper<R, W>& f) { inline decltype(auto) pick(std::integral_constant<bool, b>, F&& f) {
return f.read; return std::forward<F>(f);
}
template <typename R, typename W>
inline auto& pick(std::false_type, property_wrapper<R, W>& f) {
return f.write;
}
template <typename T, typename List>
struct void_call;
template <typename T, typename... Args>
struct void_call<T, types<Args...>> {
static void call(Args...) {}
};
template <typename T, int additional_pop = 0>
struct constructor_match {
T* obj;
constructor_match(T* obj) : obj(obj) {}
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
detail::default_construct func{};
return stack::call_into_lua<additional_pop, false>(r, a, L, start, func, obj);
}
};
template <typename T>
inline int destruct(lua_State* L) {
T* obj = stack::get<non_null<T*>>(L, 1);
std::allocator<T> alloc{};
alloc.destroy(obj);
return 0;
}
namespace overload_detail {
template <std::size_t... M, typename Match, typename... Args>
inline int overload_match_arity(sol::types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) {
return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types");
} }
template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args> template <typename R, typename W>
inline int overload_match_arity(sol::types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits; return f.read;
typedef meta::tuple_types<typename traits::return_type> return_types; }
typedef typename traits::free_args_list args_list;
typedef typename args_list::indices args_indices; template <typename R, typename W>
// compile-time eliminate any functions that we know ahead of time are of improper arity inline auto& pick(std::false_type, property_wrapper<R, W>& f) {
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) { return f.write;
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); }
template <typename T, typename List>
struct void_call;
template <typename T, typename... Args>
struct void_call<T, types<Args...>> {
static void call(Args...) {}
};
template <typename T, int additional_pop = 0>
struct constructor_match {
T* obj;
constructor_match(T* obj) : obj(obj) {}
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
detail::default_construct func{};
return stack::call_into_lua<additional_pop, false>(r, a, L, start, func, obj);
} }
if (traits::free_arity != fxarity) { };
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start, no_panic)) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
}
} // overload_detail
template <typename... Functions, typename Match, typename... Args> template <typename T>
inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { inline int destruct(lua_State* L) {
return overload_detail::overload_match_arity(types<Functions...>(), std::make_index_sequence<sizeof...(Functions)>(), std::index_sequence<>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...); T* obj = stack::get<non_null<T*>>(L, 1);
} std::allocator<T> alloc{};
alloc.destroy(obj);
template <typename... Functions, typename Match, typename... Args>
inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {
int fxarity = lua_gettop(L) - (start - 1);
return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename T, typename... TypeLists, typename Match, typename... Args>
inline int construct(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
// use same overload resolution matching as all other parts of the framework
return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename T, typename... TypeLists>
inline int construct(lua_State* L) {
static const auto& meta = usertype_traits<T>::metatable;
int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, meta, 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax);
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& referencepointer = *pointerpointer;
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj;
reference userdataref(L, -1);
userdataref.pop();
construct<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &meta[0]);
if (type_of(L, -1) == type::nil) {
lua_pop(L, 1);
return luaL_error(L, "sol: unable to get usertype metatable");
}
lua_setmetatable(L, -2);
return 1;
}
template <typename F, bool is_index, bool is_variable, typename = void>
struct agnostic_lua_call_wrapper {
static int var_call(std::true_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::free_args_list args_list;
typedef typename wrap::caller caller;
return stack::call_into_lua<is_index ? 1 : 2>(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f);
}
static int var_call(std::false_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::free_args_list args_list;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
return stack::call_into_lua(returns_list(), args_list(), L, 1, caller(), f);
}
static int call(lua_State* L, F& f) {
return var_call(std::integral_constant<bool, is_variable>(), L, f);
}
};
template <typename F, bool is_index, bool is_variable>
struct agnostic_lua_call_wrapper<F, is_index, is_variable, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
static int call(lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::args_list args_list;
typedef typename wrap::caller caller;
typedef typename wrap::object_type object_type;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, C> {
static int call(lua_State* L, lua_r_CFunction f) {
return f(L);
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, C> {
static int call(lua_State* L, lua_CFunction f) {
return f(L);
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, C> {
static int call(lua_State* L, no_prop&) {
return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
}
};
template <typename F, bool is_variable>
struct agnostic_lua_call_wrapper<F, false, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call_assign(std::true_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::args_list args_list;
typedef typename wrap::object_type object_type;
typedef typename wrap::caller caller;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)");
}
return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
static int call_assign(std::false_type, lua_State* L, F&) {
return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available");
}
static int call_const(std::false_type, lua_State* L, F& f) {
typedef typename traits_type::return_type R;
return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, f);
}
static int call_const(std::true_type, lua_State* L, F&) {
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
}
static int call(lua_State* L, F& f) {
return call_const(std::is_const<typename traits_type::return_type>(), L, f);
}
};
template <typename F, bool is_variable>
struct agnostic_lua_call_wrapper<F, true, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call(lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: 'self' argument is nil (bad '.' access?)");
}
return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, C> {
static int call(lua_State* L, no_construction&) {
return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
}
};
template <typename... Args, bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, C> {
static int call(lua_State*, bases<Args...>&) {
// Uh. How did you even call this, lul
return 0; return 0;
} }
};
template <typename T, typename F, bool is_index, bool is_variable, typename = void> namespace overload_detail {
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable> {}; template <std::size_t... M, typename Match, typename... Args>
inline int overload_match_arity(sol::types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) {
return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types");
}
template <typename T, typename... Args, bool is_index, bool is_variable, typename C> template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
struct lua_call_wrapper<T, sol::constructor_list<Args...>, is_index, is_variable, C> { inline int overload_match_arity(sol::types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
typedef sol::constructor_list<Args...> F; typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
typedef meta::tuple_types<typename traits::return_type> return_types;
typedef typename traits::free_args_list args_list;
typedef typename args_list::indices args_indices;
// compile-time eliminate any functions that we know ahead of time are of improper arity
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (traits::free_arity != fxarity) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start, no_panic)) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
}
} // overload_detail
static int call(lua_State* L, F&) { template <typename... Functions, typename Match, typename... Args>
static const auto& metakey = usertype_traits<T>::metatable; inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
return overload_detail::overload_match_arity(types<Functions...>(), std::make_index_sequence<sizeof...(Functions)>(), std::index_sequence<>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename... Functions, typename Match, typename... Args>
inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {
int fxarity = lua_gettop(L) - (start - 1);
return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename T, typename... TypeLists, typename Match, typename... Args>
inline int construct(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
// use same overload resolution matching as all other parts of the framework
return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename T, typename... TypeLists>
inline int construct(lua_State* L) {
static const auto& meta = usertype_traits<T>::metatable;
int argcount = lua_gettop(L); int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, metakey, 1) : call_syntax::dot; call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, meta, 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax); argcount -= static_cast<int>(syntax);
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T))); T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
reference userdataref(L, -1);
T*& referencepointer = *pointerpointer; T*& referencepointer = *pointerpointer;
T* obj = reinterpret_cast<T*>(pointerpointer + 1); T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj; referencepointer = obj;
reference userdataref(L, -1);
construct<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax)); userdataref.pop();
construct<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push(); userdataref.push();
luaL_getmetatable(L, &metakey[0]); luaL_getmetatable(L, &meta[0]);
if (type_of(L, -1) == type::nil) { if (type_of(L, -1) == type::nil) {
lua_pop(L, 1); lua_pop(L, 1);
return luaL_error(L, "sol: unable to get usertype metatable"); return luaL_error(L, "sol: unable to get usertype metatable");
@ -322,108 +142,288 @@ namespace call_detail {
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return 1; return 1;
} }
};
template <typename T, typename... Cxs, bool is_index, bool is_variable, typename C> template <typename F, bool is_index, bool is_variable, typename = void>
struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, C> { struct agnostic_lua_call_wrapper {
typedef sol::constructor_wrapper<Cxs...> F; static int var_call(std::true_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::free_args_list args_list;
typedef typename wrap::caller caller;
return stack::call_into_lua<is_index ? 1 : 2>(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f);
}
static int var_call(std::false_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::free_args_list args_list;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
return stack::call_into_lua(returns_list(), args_list(), L, 1, caller(), f);
}
static int call(lua_State* L, F& f) {
return var_call(std::integral_constant<bool, is_variable>(), L, f);
}
};
template <typename F, bool is_index, bool is_variable>
struct agnostic_lua_call_wrapper<F, is_index, is_variable, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
static int call(lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::args_list args_list;
typedef typename wrap::caller caller;
typedef typename wrap::object_type object_type;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, C> {
static int call(lua_State* L, lua_r_CFunction f) {
return f(L);
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, C> {
static int call(lua_State* L, lua_CFunction f) {
return f(L);
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, C> {
static int call(lua_State* L, no_prop&) {
return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
}
};
template <typename F, bool is_variable>
struct agnostic_lua_call_wrapper<F, false, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call_assign(std::true_type, lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::args_list args_list;
typedef typename wrap::object_type object_type;
typedef typename wrap::caller caller;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)");
}
return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
static int call_assign(std::false_type, lua_State* L, F&) {
return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available");
}
static int call_const(std::false_type, lua_State* L, F& f) {
typedef typename traits_type::return_type R;
return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, f);
}
static int call_const(std::true_type, lua_State* L, F&) {
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
}
static int call(lua_State* L, F& f) {
return call_const(std::is_const<typename traits_type::return_type>(), L, f);
}
};
template <typename F, bool is_variable>
struct agnostic_lua_call_wrapper<F, true, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call(lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::caller caller;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: 'self' argument is nil (bad '.' access?)");
}
return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o);
#endif // Safety
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, C> {
static int call(lua_State* L, no_construction&) {
return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
}
};
template <typename... Args, bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, C> {
static int call(lua_State*, bases<Args...>&) {
// Uh. How did you even call this, lul
return 0;
}
};
template <typename T, typename F, bool is_index, bool is_variable, typename = void>
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable> {};
template <typename T, typename... Args, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, sol::constructor_list<Args...>, is_index, is_variable, C> {
typedef sol::constructor_list<Args...> F;
static int call(lua_State* L, F&) {
static const auto& metakey = usertype_traits<T>::metatable;
int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, metakey, 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax);
struct onmatch {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T))); T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
reference userdataref(L, -1); reference userdataref(L, -1);
T*& referencepointer = *pointerpointer; T*& referencepointer = *pointerpointer;
T* obj = reinterpret_cast<T*>(pointerpointer + 1); T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj; referencepointer = obj;
auto& func = std::get<I>(f.set); construct<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax));
stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
userdataref.push(); userdataref.push();
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]); luaL_getmetatable(L, &metakey[0]);
if (type_of(L, -1) == type::nil) { if (type_of(L, -1) == type::nil) {
lua_pop(L, 1); lua_pop(L, 1);
std::string err = "sol: unable to get usertype metatable for "; return luaL_error(L, "sol: unable to get usertype metatable");
err += usertype_traits<T>::name;
return luaL_error(L, err.c_str());
} }
lua_setmetatable(L, -2);
lua_setmetatable(L, -2);
return 1; return 1;
} }
}; };
static int call(lua_State* L, F& f) { template <typename T, typename... Cxs, bool is_index, bool is_variable, typename C>
call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::metatable); struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, C> {
int syntaxval = static_cast<int>(syntax); typedef sol::constructor_wrapper<Cxs...> F;
int argcount = lua_gettop(L) - syntaxval;
return construct<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
}
}; struct onmatch {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
reference userdataref(L, -1);
T*& referencepointer = *pointerpointer;
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj;
template <typename T, typename Fx, bool is_index, bool is_variable> auto& func = std::get<I>(f.set);
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<std::is_void<Fx>::value>> { stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
typedef sol::destructor_wrapper<Fx> F;
static int call(lua_State* L, F&) { userdataref.push();
return destruct<T>(L); luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
} if (type_of(L, -1) == type::nil) {
}; lua_pop(L, 1);
std::string err = "sol: unable to get usertype metatable for ";
err += usertype_traits<T>::name;
return luaL_error(L, err.c_str());
}
lua_setmetatable(L, -2);
template <typename T, typename Fx, bool is_index, bool is_variable> return 1;
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<!std::is_void<Fx>::value>> { }
typedef sol::destructor_wrapper<Fx> F; };
static int call(lua_State* L, F& f) { static int call(lua_State* L, F& f) {
T* obj = stack::get<non_null<T*>>(L); call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::metatable);
f.fx(detail::implicit_wrapper<T>(obj)); int syntaxval = static_cast<int>(syntax);
return 0; int argcount = lua_gettop(L) - syntaxval;
} return construct<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
}; }
template <typename T, typename... Fs, bool is_index, bool is_variable, typename C> };
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, C> {
typedef overload_set<Fs...> F;
struct on_match { template <typename T, typename Fx, bool is_index, bool is_variable>
template <typename Fx, std::size_t I, typename... R, typename... Args> struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<std::is_void<Fx>::value>> {
int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) { typedef sol::destructor_wrapper<Fx> F;
auto& f = std::get<I>(fx.set);
return lua_call_wrapper<T, Fx, is_index, is_variable>{}.call(L, f); static int call(lua_State* L, F&) {
return destruct<T>(L);
} }
}; };
static int call(lua_State* L, F& fx) { template <typename T, typename Fx, bool is_index, bool is_variable>
return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx); struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<!std::is_void<Fx>::value>> {
typedef sol::destructor_wrapper<Fx> F;
static int call(lua_State* L, F& f) {
T* obj = stack::get<non_null<T*>>(L);
f.fx(detail::implicit_wrapper<T>(obj));
return 0;
}
};
template <typename T, typename... Fs, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, C> {
typedef overload_set<Fs...> F;
struct on_match {
template <typename Fx, std::size_t I, typename... R, typename... Args>
int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
auto& f = std::get<I>(fx.set);
return lua_call_wrapper<T, Fx, is_index, is_variable>{}.call(L, f);
}
};
static int call(lua_State* L, F& fx) {
return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx);
}
};
template <typename T, bool is_index, bool is_variable, typename Fx>
int call_wrapped(lua_State* L, Fx&& fx) {
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable>{}.call(L, std::forward<Fx>(fx));
} }
};
template <typename T, bool is_index, bool is_variable, typename Fx> template <typename T, typename = void>
int call_wrapped(lua_State* L, Fx&& fx) { struct is_var_bind : std::false_type {};
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable>{}.call(L, std::forward<Fx>(fx));
}
template <typename T, typename = void> template <typename T>
struct is_var_bind : std::false_type {}; struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {};
template <>
struct is_var_bind<no_prop> : std::true_type {};
template <typename R, typename W>
struct is_var_bind<property_wrapper<R, W>> : std::true_type {};
} // call_detail
template <typename T> template <typename T>
struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {}; struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {};
template <> template <typename T>
struct is_var_bind<no_prop> : std::true_type {}; struct is_function_binding : meta::neg<is_variable_binding<T>> {};
template <typename R, typename W>
struct is_var_bind<property_wrapper<R, W>> : std::true_type {};
} // call_detail
template <typename T>
struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {};
template <typename T>
struct is_function_binding : meta::neg<is_variable_binding<T>> {};
} // sol } // sol

View File

@ -27,9 +27,10 @@
// but has been modified in many places for use with Sol and luajit, // but has been modified in many places for use with Sol and luajit,
// though the core abstractions remain the same // though the core abstractions remain the same
#include "compatibility/version.hpp"
#ifndef SOL_NO_COMPAT #ifndef SOL_NO_COMPAT
#include "compatibility/version.hpp"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -28,88 +28,89 @@
#include "thread.hpp" #include "thread.hpp"
namespace sol { namespace sol {
class coroutine : public reference { class coroutine : public reference {
private: private:
call_status stats = call_status::yielded; call_status stats = call_status::yielded;
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) { void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) {
#if SOL_LUA_VERSION < 502 #if SOL_LUA_VERSION < 502
stats = static_cast<call_status>(lua_resume(lua_state(), static_cast<int>(argcount))); stats = static_cast<call_status>(lua_resume(lua_state(), static_cast<int>(argcount)));
#else #else
stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount))); stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount)));
#endif // Lua 5.1 compat #endif // Lua 5.1 compat
} }
template<std::size_t... I, typename... Ret> template<std::size_t... I, typename... Ret>
auto invoke( types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n ) { auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) {
luacall(n, sizeof...(Ret)); luacall(n, sizeof...(Ret));
return stack::pop<std::tuple<Ret...>>(lua_state()); return stack::pop<std::tuple<Ret...>>(lua_state());
} }
template<std::size_t I, typename Ret> template<std::size_t I, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) { Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) {
luacall(n, 1); luacall(n, 1);
return stack::pop<Ret>(lua_state()); return stack::pop<Ret>(lua_state());
} }
template <std::size_t I> template <std::size_t I>
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) { void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) {
luacall(n, 0); luacall(n, 0);
} }
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
int stacksize = lua_gettop( lua_state() ); int stacksize = lua_gettop(lua_state());
int firstreturn = (std::max)( 1, stacksize - static_cast<int>( n ) ); int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
luacall(n, LUA_MULTRET); luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop(lua_state()); int poststacksize = lua_gettop(lua_state());
int returncount = poststacksize - (firstreturn - 1); int returncount = poststacksize - (firstreturn - 1);
return protected_function_result( lua_state( ), firstreturn, returncount, returncount, status() ); return protected_function_result(lua_state(), firstreturn, returncount, returncount, status());
} }
public: public:
coroutine() noexcept = default; coroutine() noexcept = default;
coroutine(const coroutine&) noexcept = default; coroutine(const coroutine&) noexcept = default;
coroutine& operator=(const coroutine&) noexcept = default; coroutine& operator=(const coroutine&) noexcept = default;
coroutine(lua_State* L, int index = -1) : reference(L, index) { coroutine(lua_State* L, int index = -1) : reference(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<coroutine>(L, index, type_panic); stack::check<coroutine>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
call_status status() const noexcept { call_status status() const noexcept {
return stats; return stats;
} }
bool error() const noexcept { bool error() const noexcept {
call_status cs = status(); call_status cs = status();
return cs != call_status::ok && cs != call_status::yielded; return cs != call_status::ok && cs != call_status::yielded;
} }
bool runnable () const noexcept { bool runnable() const noexcept {
return valid() return valid()
&& (status() == call_status::yielded); && (status() == call_status::yielded);
} }
explicit operator bool() const noexcept { explicit operator bool() const noexcept {
return runnable(); return runnable();
} }
template<typename... Args> template<typename... Args>
protected_function_result operator()( Args&&... args ) { protected_function_result operator()(Args&&... args) {
return call<>( std::forward<Args>( args )... ); return call<>(std::forward<Args>(args)...);
} }
template<typename... Ret, typename... Args> template<typename... Ret, typename... Args>
decltype(auto) operator()( types<Ret...>, Args&&... args ) { decltype(auto) operator()(types<Ret...>, Args&&... args) {
return call<Ret...>( std::forward<Args>( args )... ); return call<Ret...>(std::forward<Args>(args)...);
} }
template<typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
push();
int pushcount = stack::multi_push(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
}
};
} // sol
template<typename... Ret, typename... Args>
decltype(auto) call( Args&&... args ) {
push();
int pushcount = stack::multi_push( lua_state(), std::forward<Args>( args )... );
return invoke( types<Ret...>( ), std::make_index_sequence<sizeof...(Ret)>(), pushcount );
}
};
}
#endif // SOL_COUROUTINE_HPP #endif // SOL_COUROUTINE_HPP

View File

@ -26,29 +26,29 @@
#include <iostream> #include <iostream>
namespace sol { namespace sol {
namespace detail { namespace detail {
namespace debug { namespace debug {
inline std::string dump_types(lua_State* L) { inline std::string dump_types(lua_State* L) {
std::string visual; std::string visual;
std::size_t size = lua_gettop(L) + 1; std::size_t size = lua_gettop(L) + 1;
for(std::size_t i = 1; i < size; ++i) { for (std::size_t i = 1; i < size; ++i) {
if(i != 1) { if (i != 1) {
visual += " | "; visual += " | ";
} }
visual += type_name(L, stack::get<type>(L, static_cast<int>(i))); visual += type_name(L, stack::get<type>(L, static_cast<int>(i)));
} }
return visual; return visual;
} }
inline void print_stack(lua_State* L) { inline void print_stack(lua_State* L) {
std::cout << dump_types(L) << std::endl; std::cout << dump_types(L) << std::endl;
} }
inline void print_section(const std::string& message, lua_State* L) { inline void print_section(const std::string& message, lua_State* L) {
std::cout << "-- " << message << " -- [ " << dump_types(L) << " ]" << std::endl; std::cout << "-- " << message << " -- [ " << dump_types(L) << " ]" << std::endl;
} }
} // detail } // detail
} // debug } // debug
} // sol } // sol
#endif // SOL_DEBUG_HPP #endif // SOL_DEBUG_HPP

View File

@ -32,121 +32,121 @@
#endif #endif
namespace sol { namespace sol {
namespace detail { namespace detail {
#ifdef _MSC_VER #ifdef _MSC_VER
#ifndef SOL_NO_RTTI #ifndef SOL_NO_RTTI
inline std::string get_type_name(const std::type_info& id) { inline std::string get_type_name(const std::type_info& id) {
std::string realname = id.name(); std::string realname = id.name();
const static std::array<std::string, 2> removals = { { "struct ", "class " } }; const static std::array<std::string, 2> removals = { { "struct ", "class " } };
for (std::size_t r = 0; r < removals.size(); ++r) { for (std::size_t r = 0; r < removals.size(); ++r) {
auto found = realname.find(removals[r]); auto found = realname.find(removals[r]);
while (found != std::string::npos) { while (found != std::string::npos) {
realname.erase(found, removals[r].size()); realname.erase(found, removals[r].size());
found = realname.find(removals[r]); found = realname.find(removals[r]);
} }
} }
return realname; return realname;
} }
#endif // No RTII #endif // No RTII
template <typename T> template <typename T>
inline std::string ctti_get_type_name() { inline std::string ctti_get_type_name() {
std::string name = __FUNCSIG__; std::string name = __FUNCSIG__;
std::size_t start = name.find("get_type_name"); std::size_t start = name.find("get_type_name");
if (start == std::string::npos) if (start == std::string::npos)
start = 0; start = 0;
else else
start += 13; start += 13;
if (start < name.size() - 1) if (start < name.size() - 1)
start += 1; start += 1;
std::size_t end = name.find_last_of('>'); std::size_t end = name.find_last_of('>');
if (end == std::string::npos) if (end == std::string::npos)
end = name.size(); end = name.size();
name = name.substr(start, end - start); name = name.substr(start, end - start);
if (name.find("struct", 0) == 0) if (name.find("struct", 0) == 0)
name.replace(0, 6, "", 0); name.replace(0, 6, "", 0);
if (name.find("class", 0) == 0) if (name.find("class", 0) == 0)
name.replace(0, 5, "", 0); name.replace(0, 5, "", 0);
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin()); while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin());
while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end()); while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end());
return name; return name;
} }
#elif defined(__GNUC__) || defined(__clang__) #elif defined(__GNUC__) || defined(__clang__)
template <typename T> template <typename T>
inline std::string ctti_get_type_name() { inline std::string ctti_get_type_name() {
std::string name = __PRETTY_FUNCTION__; std::string name = __PRETTY_FUNCTION__;
std::size_t start = name.find_last_of('['); std::size_t start = name.find_last_of('[');
start = name.find_first_of('=', start); start = name.find_first_of('=', start);
std::size_t end = name.find_last_of(']'); std::size_t end = name.find_last_of(']');
if (end == std::string::npos) if (end == std::string::npos)
end = name.size(); end = name.size();
if (start == std::string::npos) if (start == std::string::npos)
start = 0; start = 0;
if (start < name.size() - 1) if (start < name.size() - 1)
start += 1; start += 1;
name = name.substr(start, end - start); name = name.substr(start, end - start);
start = name.find(";"); start = name.find(";");
if (start != std::string::npos) { if (start != std::string::npos) {
name.erase(start, name.length()); name.erase(start, name.length());
} }
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin()); while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin());
while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end()); while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end());
return name; return name;
} }
#ifndef SOL_NO_RTTI #ifndef SOL_NO_RTTI
#if defined(__clang__) #if defined(__clang__)
inline std::string get_type_name(const std::type_info& id) { inline std::string get_type_name(const std::type_info& id) {
int status; int status;
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status); char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
std::string realname = unmangled; std::string realname = unmangled;
std::free(unmangled); std::free(unmangled);
return realname; return realname;
} }
#elif defined(__GNUC__) #elif defined(__GNUC__)
inline std::string get_type_name(const std::type_info& id) { inline std::string get_type_name(const std::type_info& id) {
int status; int status;
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status); char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
std::string realname = unmangled; std::string realname = unmangled;
std::free(unmangled); std::free(unmangled);
return realname; return realname;
} }
#endif // g++ || clang++ #endif // g++ || clang++
#endif // No RTII #endif // No RTII
#else #else
#error Compiler not supported for demangling #error Compiler not supported for demangling
#endif // compilers #endif // compilers
template <typename T> template <typename T>
inline std::string demangle_once() { inline std::string demangle_once() {
#ifndef SOL_NO_RTTI #ifndef SOL_NO_RTTI
std::string realname = get_type_name(typeid(T)); std::string realname = get_type_name(typeid(T));
#else #else
std::string realname = ctti_get_type_name<T>(); std::string realname = ctti_get_type_name<T>();
#endif // No Runtime Type Information #endif // No Runtime Type Information
return realname; return realname;
} }
template <typename T> template <typename T>
inline std::string short_demangle_once() { inline std::string short_demangle_once() {
std::string realname = ctti_get_type_name<T>(); std::string realname = ctti_get_type_name<T>();
std::size_t idx = realname.find_last_of(":`'\"{}[]|-)(*^&!@#$%`~", std::string::npos, 23); std::size_t idx = realname.find_last_of(":`'\"{}[]|-)(*^&!@#$%`~", std::string::npos, 23);
if (idx != std::string::npos) { if (idx != std::string::npos) {
realname.erase(0, realname.length() < idx ? realname.length() : idx + 1); realname.erase(0, realname.length() < idx ? realname.length() : idx + 1);
} }
return realname; return realname;
} }
template <typename T> template <typename T>
inline std::string demangle() { inline std::string demangle() {
static const std::string d = demangle_once<T>(); static const std::string d = demangle_once<T>();
return d; return d;
} }
template <typename T> template <typename T>
inline std::string short_demangle() { inline std::string short_demangle() {
static const std::string d = short_demangle_once<T>(); static const std::string d = short_demangle_once<T>();
return d; return d;
} }
} // detail } // detail
} // sol } // sol
#endif // SOL_DEMANGLE_HPP #endif // SOL_DEMANGLE_HPP

View File

@ -33,12 +33,15 @@
#endif // SOL_DEPRECATED #endif // SOL_DEPRECATED
namespace sol { namespace sol {
namespace detail { namespace detail {
template <typename T> template <typename T>
struct SOL_DEPRECATED deprecate_type { struct SOL_DEPRECATED deprecate_type {
using type = T; using type = T;
}; };
} // detail
template <typename T>
using deprecate_type_t = typename deprecate_type<T>::type;
} // detail
} // sol } // sol
#endif // SOL_DEPRECATE_HPP #endif // SOL_DEPRECATE_HPP

View File

@ -26,28 +26,30 @@
#include <string> #include <string>
namespace sol { namespace sol {
namespace detail { namespace detail {
struct direct_error_tag {}; struct direct_error_tag {};
const auto direct_error = direct_error_tag{}; const auto direct_error = direct_error_tag{};
} // detail } // detail
class error : public std::runtime_error {
private: class error : public std::runtime_error {
// Because VC++ is a fuccboi private:
std::string w; // Because VC++ is a fuccboi
public: std::string w;
error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {} public:
error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), w(str) {} error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {}
error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), w(std::move(str)) {} error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), w(str) {}
error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), w(std::move(str)) {}
error(const error& e) = default; error(const error& e) = default;
error(error&& e) = default; error(error&& e) = default;
error& operator=(const error& e) = default; error& operator=(const error& e) = default;
error& operator=(error&& e) = default; error& operator=(error&& e) = default;
virtual const char* what() const noexcept override {
return w.c_str();
}
};
virtual const char* what() const noexcept override {
return w.c_str();
}
};
} // sol } // sol
#endif // SOL_ERROR_HPP #endif // SOL_ERROR_HPP

View File

@ -31,106 +31,106 @@
#include <memory> #include <memory>
namespace sol { namespace sol {
template <typename base_t> template <typename base_t>
class basic_function : public base_t { class basic_function : public base_t {
private: private:
void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const { void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const {
lua_callk( base_t::lua_state( ), static_cast<int>( argcount ), static_cast<int>( resultcount ), 0, nullptr ); lua_callk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
} }
template<std::size_t... I, typename... Ret> template<std::size_t... I, typename... Ret>
auto invoke( types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n ) const { auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {
luacall( n, sizeof...( Ret ) ); luacall(n, sizeof...(Ret));
return stack::pop<std::tuple<Ret...>>( base_t::lua_state( ) ); return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
} }
template<std::size_t I, typename Ret> template<std::size_t I, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n ) const { Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {
luacall( n, 1 ); luacall(n, 1);
return stack::pop<Ret>( base_t::lua_state( ) ); return stack::pop<Ret>(base_t::lua_state());
} }
template <std::size_t I> template <std::size_t I>
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const { void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const {
luacall( n, 0 ); luacall(n, 0);
} }
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n ) const { function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const {
int stacksize = lua_gettop( base_t::lua_state( ) ); int stacksize = lua_gettop(base_t::lua_state());
int firstreturn = (std::max)( 1, stacksize - static_cast<int>( n ) ); int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
luacall(n, LUA_MULTRET); luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop( base_t::lua_state( ) ); int poststacksize = lua_gettop(base_t::lua_state());
int returncount = poststacksize - (firstreturn - 1); int returncount = poststacksize - (firstreturn - 1);
return function_result( base_t::lua_state( ), firstreturn, returncount ); return function_result(base_t::lua_state(), firstreturn, returncount);
} }
public: public:
basic_function() = default; basic_function() = default;
basic_function(const basic_function&) = default; basic_function(const basic_function&) = default;
basic_function& operator=(const basic_function&) = default; basic_function& operator=(const basic_function&) = default;
basic_function(basic_function&&) = default; basic_function(basic_function&&) = default;
basic_function& operator=(basic_function&&) = default; basic_function& operator=(basic_function&&) = default;
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {} basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {} basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(lua_State* L, int index = -1): base_t(L, index) { basic_function(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_function>(L, index, type_panic); stack::check<basic_function>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
template<typename... Args>
function_result operator()( Args&&... args ) const {
return call<>( std::forward<Args>( args )... );
}
template<typename... Ret, typename... Args> template<typename... Args>
decltype(auto) operator()( types<Ret...>, Args&&... args ) const { function_result operator()(Args&&... args) const {
return call<Ret...>( std::forward<Args>( args )... ); return call<>(std::forward<Args>(args)...);
} }
template<typename... Ret, typename... Args> template<typename... Ret, typename... Args>
decltype(auto) call( Args&&... args ) const { decltype(auto) operator()(types<Ret...>, Args&&... args) const {
base_t::push( ); return call<Ret...>(std::forward<Args>(args)...);
int pushcount = stack::multi_push_reference( base_t::lua_state( ), std::forward<Args>( args )... ); }
return invoke( types<Ret...>( ), std::make_index_sequence<sizeof...(Ret)>(), pushcount );
}
};
namespace stack { template<typename... Ret, typename... Args>
template<typename Signature> decltype(auto) call(Args&&... args) const {
struct getter<std::function<Signature>> { base_t::push();
typedef meta::bind_traits<Signature> fx_t; int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
typedef typename fx_t::args_list args_lists; return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
typedef meta::tuple_types<typename fx_t::return_type> return_types; }
};
template<typename... Args, typename... Ret> namespace stack {
static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index = -1) { template<typename Signature>
sol::function f(L, index); struct getter<std::function<Signature>> {
auto fx = [f, L, index](Args&&... args) -> meta::return_type_t<Ret...> { typedef meta::bind_traits<Signature> fx_t;
return f.call<Ret...>(std::forward<Args>(args)...); typedef typename fx_t::args_list args_lists;
}; typedef meta::tuple_types<typename fx_t::return_type> return_types;
return std::move(fx);
}
template<typename... FxArgs> template<typename... Args, typename... Ret>
static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index = -1) { static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index = -1) {
sol::function f(L, index); sol::function f(L, index);
auto fx = [f, L, index](FxArgs&&... args) -> void { auto fx = [f, L, index](Args&&... args) -> meta::return_type_t<Ret...> {
f(std::forward<FxArgs>(args)...); return f.call<Ret...>(std::forward<Args>(args)...);
}; };
return std::move(fx); return std::move(fx);
} }
template<typename... FxArgs> template<typename... FxArgs>
static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index = -1) { static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index = -1) {
return get_std_func(types<void>(), t, L, index); sol::function f(L, index);
} auto fx = [f, L, index](FxArgs&&... args) -> void {
f(std::forward<FxArgs>(args)...);
};
return std::move(fx);
}
static std::function<Signature> get(lua_State* L, int index) { template<typename... FxArgs>
return get_std_func(return_types(), args_lists(), L, index); static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index = -1) {
} return get_std_func(types<void>(), t, L, index);
}; }
} // stack
static std::function<Signature> get(lua_State* L, int index) {
return get_std_func(return_types(), args_lists(), L, index);
}
};
} // stack
} // sol } // sol
#endif // SOL_FUNCTION_HPP #endif // SOL_FUNCTION_HPP

View File

@ -29,52 +29,52 @@
#include <cstdint> #include <cstdint>
namespace sol { namespace sol {
struct function_result : public proxy_base<function_result> { struct function_result : public proxy_base<function_result> {
private: private:
lua_State* L; lua_State* L;
int index; int index;
int returncount; int returncount;
public: public:
function_result() = default; function_result() = default;
function_result(lua_State* L, int index = -1, int returncount = 0): L(L), index(index), returncount(returncount) { function_result(lua_State* L, int index = -1, int returncount = 0) : L(L), index(index), returncount(returncount) {
}
function_result(const function_result&) = default;
function_result& operator=(const function_result&) = default;
function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount) {
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
}
function_result& operator=(function_result&& o) {
L = o.L;
index = o.index;
returncount = o.returncount;
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
return *this;
}
template<typename T> }
decltype(auto) get() const { function_result(const function_result&) = default;
return stack::get<T>(L, index); function_result& operator=(const function_result&) = default;
} function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount) {
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
}
function_result& operator=(function_result&& o) {
L = o.L;
index = o.index;
returncount = o.returncount;
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
o.L = nullptr;
o.index = 0;
o.returncount = 0;
return *this;
}
lua_State* lua_state() const { return L; }; template<typename T>
int stack_index() const { return index; }; decltype(auto) get() const {
return stack::get<T>(L, index);
}
~function_result() { lua_State* lua_state() const { return L; };
lua_pop(L, returncount); int stack_index() const { return index; };
}
}; ~function_result() {
lua_pop(L, returncount);
}
};
} // sol } // sol
#endif // SOL_FUNCTION_RESULT_HPP #endif // SOL_FUNCTION_RESULT_HPP

View File

@ -31,217 +31,217 @@
#include "call.hpp" #include "call.hpp"
namespace sol { namespace sol {
template <typename Sig, typename... Ps> template <typename Sig, typename... Ps>
struct function_arguments { struct function_arguments {
std::tuple<Ps...> params; std::tuple<Ps...> params;
template <typename... Args> template <typename... Args>
function_arguments(Args&&... args) : params(std::forward<Args>(args)...) {} function_arguments(Args&&... args) : params(std::forward<Args>(args)...) {}
}; };
template <typename Sig = function_sig<>, typename... Args> template <typename Sig = function_sig<>, typename... Args>
function_arguments<Sig, Args...> function_args( Args&&... args ) { function_arguments<Sig, Args...> function_args(Args&&... args) {
return function_arguments<Sig, Args...>(std::forward<Args>(args)...); return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
} }
namespace stack { namespace stack {
template<typename... Sigs> template<typename... Sigs>
struct pusher<function_sig<Sigs...>> { struct pusher<function_sig<Sigs...>> {
template <typename... Sig, typename Fx, typename... Args> template <typename... Sig, typename Fx, typename... Args>
static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::functor_function<clean_fx>>(std::forward<Fx>(fx), std::forward<Args>(args)...); std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::functor_function<clean_fx>>(std::forward<Fx>(fx), std::forward<Args>(args)...);
set_fx(L, std::move(sptr)); set_fx(L, std::move(sptr));
} }
template <typename R, typename... A, typename Fx, typename... Args> template <typename R, typename... A, typename Fx, typename... Args>
static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
using fx_ptr_t = R(*)(A...); using fx_ptr_t = R(*)(A...);
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx)); fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...); select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...);
} }
template <typename R, typename... A, typename Fx, typename... Args> template <typename R, typename... A, typename Fx, typename... Args>
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
typedef std::decay_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> raw_fx_t; typedef std::decay_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> raw_fx_t;
typedef R(* fx_ptr_t)(A...); typedef R(*fx_ptr_t)(A...);
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible; typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
typedef meta::function_signature_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> Sig; typedef meta::function_signature_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> Sig;
select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args> template <typename Fx, typename T, typename... Args>
static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_variable<meta::unqualified_t<T>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)... ); std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_variable<meta::unqualified_t<T>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
set_fx(L, std::move(sptr)); set_fx(L, std::move(sptr));
} }
template <typename Fx, typename T, typename... Args> template <typename Fx, typename T, typename... Args>
static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> dFx; typedef std::decay_t<Fx> dFx;
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_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call; lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); int upvalues = stack::stack_detail::push_as_upvalues(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));
} }
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args> template <typename Fx, typename T, typename... Args>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference; typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
} }
template <typename Fx> template <typename Fx>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { static void select_member_variable(std::true_type, lua_State* L, Fx&& 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_variable<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, fx); int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx, typename T, typename... Args> template <typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_function<meta::unwrapped_t<meta::unqualified_t<T>>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)... ); std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_function<meta::unwrapped_t<meta::unqualified_t<T>>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
set_fx(L, std::move(sptr)); set_fx(L, std::move(sptr));
} }
template <typename Fx, typename T, typename... Args> template <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; typedef std::decay_t<Fx> dFx;
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>>::call; lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); int upvalues = stack::stack_detail::push_as_upvalues(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));
} }
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_member_variable(std::is_member_object_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_member_variable(std::is_member_object_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename T, typename... Args> template <typename Fx, typename T, typename... Args>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference; typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
} }
template <typename Fx> template <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) {
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>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, fx); int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_member_function(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_member_function(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...); std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, target); int upvalues = stack::stack_detail::push_as_upvalues(L, target);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
static void select_function(std::true_type, lua_State* L, lua_CFunction f) { static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
stack::push(L, f); stack::push(L, f);
} }
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static void select(lua_State* L, Fx&& fx, Args&&... args) { static void select(lua_State* L, Fx&& fx, Args&&... args) {
select_function(std::is_function<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_function(std::is_function<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) { static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) {
function_detail::base_function* target = luafunc.release(); function_detail::base_function* target = luafunc.release();
void* targetdata = static_cast<void*>(target); void* targetdata = static_cast<void*>(target);
lua_CFunction freefunc = function_detail::call; lua_CFunction freefunc = function_detail::call;
stack::push(L, userdata_value(targetdata)); stack::push(L, userdata_value(targetdata));
function_detail::free_function_cleanup(L); function_detail::free_function_cleanup(L);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
stack::push(L, c_closure(freefunc, 1)); stack::push(L, c_closure(freefunc, 1));
} }
template<typename... Args> template<typename... Args>
static int push(lua_State* L, Args&&... args) { static int push(lua_State* L, Args&&... args) {
// Set will always place one thing (function) on the stack // Set will always place one thing (function) on the stack
select(L, std::forward<Args>(args)...); select(L, std::forward<Args>(args)...);
return 1; return 1;
} }
}; };
template<typename T, typename... Args> template<typename T, typename... Args>
struct pusher<function_arguments<T, Args...>> { struct pusher<function_arguments<T, Args...>> {
template <std::size_t... I, typename FP> template <std::size_t... I, typename FP>
static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) { static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {
return stack::push<T>(L, detail::forward_get<I>(fp.params)...); return stack::push<T>(L, detail::forward_get<I>(fp.params)...);
} }
template <typename FP> template <typename FP>
static int push(lua_State* L, FP&& fp) { static int push(lua_State* L, FP&& fp) {
return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<FP>(fp)); return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<FP>(fp));
} }
}; };
template<typename Signature> template<typename Signature>
struct pusher<std::function<Signature>> { struct pusher<std::function<Signature>> {
static int push(lua_State* L, std::function<Signature> fx) { static int push(lua_State* L, std::function<Signature> fx) {
return pusher<function_sig<Signature>>{}.push(L, std::move(fx)); return pusher<function_sig<Signature>>{}.push(L, std::move(fx));
} }
}; };
template<typename Signature> template<typename Signature>
struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> { struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
template <typename F> template <typename F>
static int push(lua_State* L, F&& f) { static int push(lua_State* L, F&& f) {
return pusher<function_sig<>>{}.push(L, std::forward<F>(f)); return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
} }
}; };
template<typename Signature> template<typename Signature>
struct pusher<Signature, std::enable_if_t<meta::all<std::is_function<Signature>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>>::value>> { struct pusher<Signature, std::enable_if_t<meta::all<std::is_function<Signature>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>>::value>> {
template <typename F> template <typename F>
static int push(lua_State* L, F&& f) { static int push(lua_State* L, F&& f) {
return pusher<function_sig<>>{}.push(L, std::forward<F>(f)); return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
} }
}; };
template<typename... Functions> template<typename... Functions>
struct pusher<overload_set<Functions...>> { struct pusher<overload_set<Functions...>> {
static int push(lua_State* L, overload_set<Functions...>&& set) { static int push(lua_State* L, overload_set<Functions...>&& set) {
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(std::move(set.set))); pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(std::move(set.set)));
return 1; return 1;
} }
static int push(lua_State* L, const overload_set<Functions...>& set) { static int push(lua_State* L, const overload_set<Functions...>& set) {
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(set.set)); pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(set.set));
return 1; return 1;
} }
}; };
} // stack } // stack
} // sol } // sol
#endif // SOL_FUNCTION_TYPES_HPP #endif // SOL_FUNCTION_TYPES_HPP

View File

@ -25,178 +25,178 @@
#include "stack.hpp" #include "stack.hpp"
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template<typename Function> template<typename Function>
struct upvalue_free_function { struct upvalue_free_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
static int real_call(lua_State* L) { static int real_call(lua_State* L) {
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L); auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
function_type* fx = udata.first; function_type* fx = udata.first;
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx); int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
return r; return r;
} }
static int call (lua_State* L) { static int call(lua_State* L) {
return detail::static_trampoline<(&real_call)>(L); return detail::static_trampoline<(&real_call)>(L);
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
return call(L); return call(L);
} }
}; };
template<typename T, typename Function> template<typename T, typename Function>
struct upvalue_member_function { struct upvalue_member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
static int real_call(lua_State* L) { static int real_call(lua_State* L) {
// Layout: // Layout:
// idx 1...n: verbatim data of member function pointer // idx 1...n: verbatim data of member function pointer
// 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, 1); auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
function_type& memfx = memberdata.first; function_type& memfx = memberdata.first;
auto& item = *objdata.first; auto& item = *objdata.first;
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type { auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type {
return (item.*memfx)(std::forward<decltype(args)>(args)...); return (item.*memfx)(std::forward<decltype(args)>(args)...);
}; };
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx); return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
} }
static int call (lua_State* L) { static int call(lua_State* L) {
return detail::static_trampoline<(&real_call)>(L); return detail::static_trampoline<(&real_call)>(L);
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
return call(L); return call(L);
} }
}; };
template <int N, typename R, typename M, typename V> template <int N, typename R, typename M, typename V>
int set_assignable(std::false_type, lua_State* L, M&, V&) { int set_assignable(std::false_type, lua_State* L, M&, V&) {
lua_pop(L, N); lua_pop(L, N);
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available"); return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
} }
template <int N, typename R, typename M, typename V> template <int N, typename R, typename M, typename V>
int set_assignable(std::true_type, lua_State* L, M& mem, V& var) { int set_assignable(std::true_type, lua_State* L, M& mem, V& var) {
(mem.*var) = stack::get<R>(L, N); (mem.*var) = stack::get<R>(L, N);
lua_pop(L, N); lua_pop(L, N);
return 0; return 0;
} }
template <int N, typename R, typename M, typename V> template <int N, typename R, typename M, typename V>
int set_variable(std::true_type, lua_State* L, M& mem, V& var) { int set_variable(std::true_type, lua_State* L, M& mem, V& var) {
return set_assignable<N, R>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, mem, var); return set_assignable<N, R>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, mem, var);
} }
template <int N, typename R, typename M, typename V> template <int N, typename R, typename M, typename V>
int set_variable(std::false_type, lua_State* L, M&, V&) { int set_variable(std::false_type, lua_State* L, M&, V&) {
lua_pop(L, N); lua_pop(L, N);
return luaL_error(L, "sol: cannot write to a const variable"); return luaL_error(L, "sol: cannot write to a const variable");
} }
template<typename T, typename Function> template<typename T, typename Function>
struct upvalue_member_variable { struct upvalue_member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
static int real_call(lua_State* L) { static int real_call(lua_State* L) {
// Layout: // Layout:
// idx 1...n: verbatim data of member variable pointer // idx 1...n: verbatim data of member variable pointer
// 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, 1); auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
auto& mem = *objdata.first; auto& mem = *objdata.first;
function_type& var = memberdata.first; function_type& var = memberdata.first;
switch (lua_gettop(L)) { switch (lua_gettop(L)) {
case 0: case 0:
stack::push(L, (mem.*var)); stack::push(L, (mem.*var));
return 1; return 1;
case 1: case 1:
set_variable<1, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var); set_variable<1, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
return 0; return 0;
default: default:
return luaL_error(L, "sol: incorrect number of arguments to member variable function"); return luaL_error(L, "sol: incorrect number of arguments to member variable function");
} }
} }
static int call (lua_State* L) { static int call(lua_State* L) {
return detail::static_trampoline<(&real_call)>(L); return detail::static_trampoline<(&real_call)>(L);
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
return call(L); return call(L);
} }
}; };
template<typename T, typename Function> template<typename T, typename Function>
struct upvalue_this_member_function { struct upvalue_this_member_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
static int real_call(lua_State* L) { static int real_call(lua_State* L) {
// 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, 1); auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
function_type& memfx = memberdata.first; function_type& memfx = memberdata.first;
auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type { auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type {
auto& item = stack::get<T>(L, 1); auto& item = stack::get<T>(L, 1);
return (item.*memfx)(std::forward<decltype(args)>(args)...); return (item.*memfx)(std::forward<decltype(args)>(args)...);
}; };
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 2, fx); int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 2, fx);
return n; return n;
} }
static int call (lua_State* L) { static int call(lua_State* L) {
return detail::static_trampoline<(&real_call)>(L); return detail::static_trampoline<(&real_call)>(L);
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
return call(L); return call(L);
} }
}; };
template<typename T, typename Function> template<typename T, typename Function>
struct upvalue_this_member_variable { struct upvalue_this_member_variable {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type; typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef lua_bind_traits<function_type> traits_type; typedef lua_bind_traits<function_type> traits_type;
static int real_call(lua_State* L) { static int real_call(lua_State* L) {
// 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, 1); auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
auto& mem = stack::get<T>(L, 1); auto& mem = stack::get<T>(L, 1);
function_type& var = memberdata.first; function_type& var = memberdata.first;
switch (lua_gettop(L)) { switch (lua_gettop(L)) {
case 1: case 1:
lua_pop(L, 1); lua_pop(L, 1);
stack::push(L, (mem.*var)); stack::push(L, (mem.*var));
return 1; return 1;
case 2: case 2:
set_variable<2, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var); set_variable<2, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
return 0; return 0;
default: default:
return luaL_error(L, "sol: incorrect number of arguments to member variable function"); return luaL_error(L, "sol: incorrect number of arguments to member variable function");
} }
} }
static int call (lua_State* L) { static int call(lua_State* L) {
return detail::static_trampoline<(&real_call)>(L); return detail::static_trampoline<(&real_call)>(L);
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
return call(L); return call(L);
} }
}; };
} // function_detail } // function_detail
} // sol } // sol
#endif // SOL_FUNCTION_TYPES_BASIC_HPP #endif // SOL_FUNCTION_TYPES_BASIC_HPP

View File

@ -27,91 +27,91 @@
#include <memory> #include <memory>
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
inline decltype(auto) cleanup_key() { inline decltype(auto) cleanup_key() {
const auto& name = u8"sol.ƒ.♲.🗑.(/¯◡ ‿ ◡)/¯ ~ ┻━┻ (ノ◕ヮ◕)ノ*:・゚✧"; const auto& name = u8"sol.ƒ.♲.🗑.(/¯◡ ‿ ◡)/¯ ~ ┻━┻ (ノ◕ヮ◕)ノ*:・゚✧";
return name; return name;
} }
struct base_function { struct base_function {
virtual int operator()(lua_State* L) { virtual int operator()(lua_State* L) {
return luaL_error(L, "sol: failure to call specialized wrapped C++ function from Lua"); return luaL_error(L, "sol: failure to call specialized wrapped C++ function from Lua");
} }
virtual ~base_function() {} virtual ~base_function() {}
}; };
static int base_call(lua_State* L, void* inheritancedata) { static int base_call(lua_State* L, void* inheritancedata) {
if (inheritancedata == nullptr) { if (inheritancedata == nullptr) {
return luaL_error(L, "sol: call from Lua to C++ function has null data"); return luaL_error(L, "sol: call from Lua to C++ function has null data");
} }
base_function* pfx = static_cast<base_function*>(inheritancedata); base_function* pfx = static_cast<base_function*>(inheritancedata);
base_function& fx = *pfx; base_function& fx = *pfx;
return detail::trampoline(L, fx); return detail::trampoline(L, fx);
} }
static int base_gc(lua_State* L, void* udata) { static int base_gc(lua_State* L, void* udata) {
if (udata == nullptr) { if (udata == nullptr) {
return luaL_error(L, "sol: call from lua to C++ gc function with null data"); return luaL_error(L, "sol: call from lua to C++ gc function with null data");
} }
base_function* ptr = static_cast<base_function*>(udata); base_function* ptr = static_cast<base_function*>(udata);
std::default_delete<base_function> dx{}; std::default_delete<base_function> dx{};
dx(ptr); dx(ptr);
return 0; return 0;
} }
template <std::size_t limit> template <std::size_t limit>
static void func_gc(std::true_type, lua_State*) { static void func_gc(std::true_type, lua_State*) {
} }
template <std::size_t limit> template <std::size_t limit>
static void func_gc(std::false_type, lua_State* L) { static void func_gc(std::false_type, lua_State* L) {
for (std::size_t i = 0; i < limit; ++i) { for (std::size_t i = 0; i < limit; ++i) {
void* value = stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(i + 1))); void* value = stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(i + 1)));
if (value == nullptr) if (value == nullptr)
continue; continue;
base_function* obj = static_cast<base_function*>(value); base_function* obj = static_cast<base_function*>(value);
std::allocator<base_function> alloc{}; std::allocator<base_function> alloc{};
alloc.destroy(obj); alloc.destroy(obj);
alloc.deallocate(obj, 1); alloc.deallocate(obj, 1);
} }
} }
inline int call(lua_State* L) { inline int call(lua_State* L) {
void* ludata = stack::get<lightuserdata_value>(L, up_value_index(1)); void* ludata = stack::get<lightuserdata_value>(L, up_value_index(1));
void** pinheritancedata = static_cast<void**>(ludata); void** pinheritancedata = static_cast<void**>(ludata);
return base_call(L, *pinheritancedata); return base_call(L, *pinheritancedata);
} }
inline int gc(lua_State* L) { inline int gc(lua_State* L) {
void* udata = stack::get<userdata_value>(L, 1); void* udata = stack::get<userdata_value>(L, 1);
void** pudata = static_cast<void**>(udata); void** pudata = static_cast<void**>(udata);
return base_gc(L, *pudata); return base_gc(L, *pudata);
} }
template<std::size_t I> template<std::size_t I>
inline int usertype_call(lua_State* L) { inline int usertype_call(lua_State* L) {
// Zero-based template parameter, but upvalues start at 1 // Zero-based template parameter, but upvalues start at 1
return base_call(L, stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(I + 1)))); return base_call(L, stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(I + 1))));
} }
template<std::size_t I> template<std::size_t I>
inline int usertype_gc(lua_State* L) { inline int usertype_gc(lua_State* L) {
func_gc<I>(meta::boolean<(I < 1)>(), L); func_gc<I>(meta::boolean<(I < 1)>(), L);
return 0; return 0;
} }
inline void free_function_cleanup(lua_State* L) { inline void free_function_cleanup(lua_State* L) {
const static char* metatablename = &cleanup_key()[0]; const static char* metatablename = &cleanup_key()[0];
int metapushed = luaL_newmetatable(L, metatablename); int metapushed = luaL_newmetatable(L, metatablename);
if (metapushed == 1) { if (metapushed == 1) {
stack::set_field(L, "__gc", function_detail::gc); stack::set_field(L, "__gc", function_detail::gc);
} }
} }
} // function_detail } // function_detail
} // sol } // sol
#endif // SOL_FUNCTION_TYPES_CORE_HPP #endif // SOL_FUNCTION_TYPES_CORE_HPP

View File

@ -27,33 +27,33 @@
#include "function_types_core.hpp" #include "function_types_core.hpp"
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <typename... Functions> template <typename... Functions>
struct overloaded_function : base_function { struct overloaded_function : base_function {
typedef std::tuple<Functions...> overload_list; typedef std::tuple<Functions...> overload_list;
typedef std::make_index_sequence<sizeof...(Functions)> indices; typedef std::make_index_sequence<sizeof...(Functions)> indices;
overload_list overloads; overload_list overloads;
overloaded_function(overload_list set) overloaded_function(overload_list set)
: overloads(std::move(set)) {} : overloads(std::move(set)) {}
overloaded_function(Functions... fxs) overloaded_function(Functions... fxs)
: overloads(fxs...) { : overloads(fxs...) {
} }
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>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) { int call(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
auto& func = std::get<I>(overloads); auto& func = std::get<I>(overloads);
return stack::call_into_lua<0, false>(r, a, L, start, func); return stack::call_into_lua<0, false>(r, a, L, start, func);
} }
virtual int operator()(lua_State* L) override { virtual int operator()(lua_State* L) override {
auto mfx = [&](auto&&... args){ return this->call(std::forward<decltype(args)>(args)...); }; auto mfx = [&](auto&&... args) { return this->call(std::forward<decltype(args)>(args)...); };
return call_detail::overload_match<Functions...>(mfx, L, 1); return call_detail::overload_match<Functions...>(mfx, L, 1);
} }
}; };
} // function_detail } // function_detail
} // sol } // sol
#endif // SOL_FUNCTION_TYPES_OVERLOAD_HPP #endif // SOL_FUNCTION_TYPES_OVERLOAD_HPP

View File

@ -142,13 +142,13 @@ namespace sol {
int make_regs(regs_t& l, int index, sol::call_construction, F&&, Args&&... args) { int make_regs(regs_t& l, int index, sol::call_construction, F&&, Args&&... args) {
callconstructfunc = call<I + 1>; callconstructfunc = call<I + 1>;
secondarymeta = true; secondarymeta = true;
int endindex = make_regs<I + 2>(l, index + 1, std::forward<Args>(args)...); int endindex = make_regs<I + 2>(l, index, std::forward<Args>(args)...);
return endindex; return endindex;
} }
template <std::size_t I = 0, typename... Bases, typename... Args> template <std::size_t I = 0, typename... Bases, typename... Args>
int make_regs(regs_t& l, int index, base_classes_tag, bases<Bases...>, Args&&... args) { int make_regs(regs_t& l, int index, base_classes_tag, bases<Bases...>, Args&&... args) {
int endindex = make_regs<I + 2>(l, index + 1, std::forward<Args>(args)...); int endindex = make_regs<I + 2>(l, index, std::forward<Args>(args)...);
if (sizeof...(Bases) < 1) { if (sizeof...(Bases) < 1) {
(void)detail::swallow{ 0, ((detail::has_derived<Bases>::value = false), 0)... }; (void)detail::swallow{ 0, ((detail::has_derived<Bases>::value = false), 0)... };
return endindex; return endindex;

View File

@ -4,6 +4,10 @@
#include <sol.hpp> #include <sol.hpp>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <vector>
#include "test_stack_guard.hpp" #include "test_stack_guard.hpp"
std::string free_function() { std::string free_function() {
@ -530,4 +534,22 @@ TEST_CASE("tables/operator[]-optional", "Test if proxies on tables can lazily ev
REQUIRE(present); REQUIRE(present);
REQUIRE(non_nope3.value() == 35); REQUIRE(non_nope3.value() == 35);
REQUIRE(non_nope4.value() == 35); REQUIRE(non_nope4.value() == 35);
} }
TEST_CASE("tables/add", "Basic test to make sure the 'add' feature works") {
static const int sz = 120;
sol::state lua;
sol::table t = lua.create_table(sz, 0);
std::vector<int> bigvec( sz );
std::iota(bigvec.begin(), bigvec.end(), 1);
for (std::size_t i = 0; i < bigvec.size(); ++i) {
t.add(bigvec[i]);
}
for (std::size_t i = 0; i < bigvec.size(); ++i) {
int val = t[i + 1];
REQUIRE(val == bigvec[i]);
}
}