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

View File

@ -1,6 +1,6 @@
// 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
// this software and associated documentation files (the "Software"), to deal in
@ -27,293 +27,113 @@
#include "stack.hpp"
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>
inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
return f.read;
}
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 <bool b, typename F>
inline decltype(auto) pick(std::integral_constant<bool, b>, F&& f) {
return std::forward<F>(f);
}
template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
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 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)...);
template <typename R, typename W>
inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
return f.read;
}
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);
}
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>
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);
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
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;
}
};
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> {};
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 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;
template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
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 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&) {
static const auto& metakey = usertype_traits<T>::metatable;
template <typename... Functions, typename Match, typename... Args>
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);
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);
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;
reference userdataref(L, -1);
userdataref.pop();
construct<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax));
construct<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &metakey[0]);
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");
@ -322,108 +142,288 @@ namespace call_detail {
lua_setmetatable(L, -2);
return 1;
}
};
template <typename T, typename... Cxs, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, C> {
typedef sol::constructor_wrapper<Cxs...> F;
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;
}
};
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)));
reference userdataref(L, -1);
T*& referencepointer = *pointerpointer;
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj;
auto& func = std::get<I>(f.set);
stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
construct<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
luaL_getmetatable(L, &metakey[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());
return luaL_error(L, "sol: unable to get usertype metatable");
}
lua_setmetatable(L, -2);
lua_setmetatable(L, -2);
return 1;
}
};
static int call(lua_State* L, F& f) {
call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::metatable);
int syntaxval = static_cast<int>(syntax);
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... Cxs, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, C> {
typedef sol::constructor_wrapper<Cxs...> 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>
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;
auto& func = std::get<I>(f.set);
stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
static int call(lua_State* L, F&) {
return destruct<T>(L);
}
};
userdataref.push();
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>
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;
return 1;
}
};
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;
}
};
static int call(lua_State* L, F& f) {
call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::metatable);
int syntaxval = static_cast<int>(syntax);
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 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);
template <typename T, typename Fx, bool is_index, bool is_variable>
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&) {
return destruct<T>(L);
}
};
static int call(lua_State* L, F& fx) {
return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx);
template <typename T, typename Fx, bool is_index, bool is_variable>
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>
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, typename = void>
struct is_var_bind : std::false_type {};
template <typename T, typename = void>
struct is_var_bind : std::false_type {};
template <typename T>
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>
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 <>
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>
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>> {};
template <typename T>
struct is_function_binding : meta::neg<is_variable_binding<T>> {};
} // sol

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,28 +26,30 @@
#include <string>
namespace sol {
namespace detail {
struct direct_error_tag {};
const auto direct_error = direct_error_tag{};
} // detail
class error : public std::runtime_error {
private:
// Because VC++ is a fuccboi
std::string w;
public:
error(const std::string& str) : error(detail::direct_error, "lua: error: " + 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)) {}
namespace detail {
struct direct_error_tag {};
const auto direct_error = direct_error_tag{};
} // detail
error(const error& e) = default;
error(error&& e) = default;
error& operator=(const error& e) = default;
error& operator=(error&& e) = default;
class error : public std::runtime_error {
private:
// Because VC++ is a fuccboi
std::string w;
public:
error(const std::string& str) : error(detail::direct_error, "lua: error: " + 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(error&& e) = default;
error& operator=(const 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
#endif // SOL_ERROR_HPP

View File

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

View File

@ -29,52 +29,52 @@
#include <cstdint>
namespace sol {
struct function_result : public proxy_base<function_result> {
private:
lua_State* L;
int index;
int returncount;
struct function_result : public proxy_base<function_result> {
private:
lua_State* L;
int index;
int returncount;
public:
function_result() = default;
function_result(lua_State* L, int index = -1, int returncount = 0): L(L), index(index), returncount(returncount) {
public:
function_result() = default;
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;
}
}
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 {
return stack::get<T>(L, index);
}
template<typename T>
decltype(auto) get() const {
return stack::get<T>(L, index);
}
lua_State* lua_state() const { return L; };
int stack_index() const { return index; };
lua_State* lua_state() const { return L; };
int stack_index() const { return index; };
~function_result() {
lua_pop(L, returncount);
}
};
~function_result() {
lua_pop(L, returncount);
}
};
} // sol
#endif // SOL_FUNCTION_RESULT_HPP

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,10 @@
#include <sol.hpp>
#include <iostream>
#include <map>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <vector>
#include "test_stack_guard.hpp"
std::string free_function() {
@ -531,3 +535,21 @@ TEST_CASE("tables/operator[]-optional", "Test if proxies on tables can lazily ev
REQUIRE(non_nope3.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]);
}
}