mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
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:
parent
556be8da98
commit
b6928b4b4e
|
@ -7,6 +7,8 @@ This is a detail header used to maintain compatability with the 5.2 and 5.3 APIs
|
||||||
|
|
||||||
It is not fully documented as this header's only purpose is for internal use to make sure Sol compiles across all platforms / distributions with no errors or missing Lua functionality. If you think there's some compatibility features we are missing or if you are running into redefinition errors, please make an `issue in the issue tracker`_.
|
It is not fully documented as this header's only purpose is for internal use to make sure Sol compiles across all platforms / distributions with no errors or missing Lua functionality. If you think there's some compatibility features we are missing or if you are running into redefinition errors, please make an `issue in the issue tracker`_.
|
||||||
|
|
||||||
|
If you have this already in your project or you have your own compatibility layer, then please ``#define SOL_NO_COMPAT 1`` before including ``sol.hpp`` or pass this flag on the command line to turn off the compatibility wrapper.
|
||||||
|
|
||||||
For the licenses, see :doc:`here<../licenses>`
|
For the licenses, see :doc:`here<../licenses>`
|
||||||
|
|
||||||
.. _issue in the issue tracker: https://github.com/ThePhD/sol2/issues/
|
.. _issue in the issue tracker: https://github.com/ThePhD/sol2/issues/
|
||||||
|
|
|
@ -1,218 +1,242 @@
|
||||||
#pragma once
|
// The MIT License (MIT)
|
||||||
|
|
||||||
|
// Copyright (c) 2013-2016 Rappt1101010z, ThePhD and contributors
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
// the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
// subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef SOL_BIND_TRAITS_HPP
|
||||||
|
#define SOL_BIND_TRAITS_HPP
|
||||||
|
|
||||||
#include "tuple.hpp"
|
#include "tuple.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace meta {
|
namespace meta {
|
||||||
namespace meta_detail {
|
namespace meta_detail {
|
||||||
|
|
||||||
template<class F>
|
template<class F>
|
||||||
struct check_deducible_signature {
|
struct check_deducible_signature {
|
||||||
struct nat {};
|
struct nat {};
|
||||||
template<class G>
|
template<class G>
|
||||||
static auto test(int) -> decltype(&G::operator(), void());
|
static auto test(int) -> decltype(&G::operator(), void());
|
||||||
template<class>
|
template<class>
|
||||||
static auto test(...) -> nat;
|
static auto test(...)->nat;
|
||||||
|
|
||||||
using type = std::is_void<decltype(test<F>(0))>;
|
using type = std::is_void<decltype(test<F>(0))>;
|
||||||
};
|
};
|
||||||
} // meta_detail
|
} // meta_detail
|
||||||
|
|
||||||
template<class F>
|
template<class F>
|
||||||
struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { };
|
struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { };
|
||||||
|
|
||||||
namespace meta_detail {
|
namespace meta_detail {
|
||||||
|
|
||||||
template <std::size_t I, typename T>
|
template <std::size_t I, typename T>
|
||||||
struct void_tuple_element : meta::tuple_element<I, T> {};
|
struct void_tuple_element : meta::tuple_element<I, T> {};
|
||||||
|
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
struct void_tuple_element<I, std::tuple<>> { typedef void type; };
|
struct void_tuple_element<I, std::tuple<>> { typedef void type; };
|
||||||
|
|
||||||
template <std::size_t I, typename T>
|
template <std::size_t I, typename T>
|
||||||
using void_tuple_element_t = typename void_tuple_element<I, T>::type;
|
using void_tuple_element_t = typename void_tuple_element<I, T>::type;
|
||||||
|
|
||||||
template <bool has_c_variadic, typename T, typename R, typename... Args>
|
template <bool has_c_variadic, typename T, typename R, typename... Args>
|
||||||
struct basic_traits {
|
struct basic_traits {
|
||||||
private:
|
private:
|
||||||
typedef std::conditional_t<std::is_void<T>::value, int, T>& first_type;
|
typedef std::conditional_t<std::is_void<T>::value, int, T>& first_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const bool is_member_function = std::is_void<T>::value;
|
static const bool is_member_function = std::is_void<T>::value;
|
||||||
static const bool has_c_var_arg = has_c_variadic;
|
static const bool has_c_var_arg = has_c_variadic;
|
||||||
static const std::size_t arity = sizeof...(Args);
|
static const std::size_t arity = sizeof...(Args);
|
||||||
static const std::size_t free_arity = sizeof...(Args) + static_cast<std::size_t>(!std::is_void<T>::value);
|
static const std::size_t free_arity = sizeof...(Args)+static_cast<std::size_t>(!std::is_void<T>::value);
|
||||||
typedef types<Args...> args_list;
|
typedef types<Args...> args_list;
|
||||||
typedef std::tuple<Args...> args_tuple;
|
typedef std::tuple<Args...> args_tuple;
|
||||||
typedef T object_type;
|
typedef T object_type;
|
||||||
typedef R return_type;
|
typedef R return_type;
|
||||||
typedef tuple_types<R> returns_list;
|
typedef tuple_types<R> returns_list;
|
||||||
typedef R(function_type)(Args...);
|
typedef R(function_type)(Args...);
|
||||||
typedef std::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list;
|
typedef std::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list;
|
||||||
typedef std::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type;
|
typedef std::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type;
|
||||||
typedef std::conditional_t<std::is_void<T>::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type;
|
typedef std::conditional_t<std::is_void<T>::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type;
|
||||||
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
|
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
|
||||||
template<std::size_t i>
|
template<std::size_t i>
|
||||||
using arg_at = void_tuple_element_t<i, args_tuple>;
|
using arg_at = void_tuple_element_t<i, args_tuple>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Signature, bool b = has_deducible_signature<Signature>::value>
|
template<typename Signature, bool b = has_deducible_signature<Signature>::value>
|
||||||
struct fx_traits : basic_traits<false, void, void> {};
|
struct fx_traits : basic_traits<false, void, void> {};
|
||||||
|
|
||||||
// Free Functions
|
// Free Functions
|
||||||
template<typename R, typename... Args>
|
template<typename R, typename... Args>
|
||||||
struct fx_traits<R(Args...), false> : basic_traits<false, void, R, Args...> {
|
struct fx_traits<R(Args...), false> : basic_traits<false, void, R, Args...> {
|
||||||
typedef R(*function_pointer_type)(Args...);
|
typedef R(*function_pointer_type)(Args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename... Args>
|
template<typename R, typename... Args>
|
||||||
struct fx_traits<R(*)(Args...), false> : basic_traits<false, void, R, Args...> {
|
struct fx_traits<R(*)(Args...), false> : basic_traits<false, void, R, Args...> {
|
||||||
typedef R(*function_pointer_type)(Args...);
|
typedef R(*function_pointer_type)(Args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename... Args>
|
template<typename R, typename... Args>
|
||||||
struct fx_traits<R(Args..., ...), false> : basic_traits<true, void, R, Args...> {
|
struct fx_traits<R(Args..., ...), false> : basic_traits<true, void, R, Args...> {
|
||||||
typedef R(*function_pointer_type)(Args..., ...);
|
typedef R(*function_pointer_type)(Args..., ...);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename... Args>
|
template<typename R, typename... Args>
|
||||||
struct fx_traits<R(*)(Args..., ...), false> : basic_traits<true, void, R, Args...> {
|
struct fx_traits<R(*)(Args..., ...), false> : basic_traits<true, void, R, Args...> {
|
||||||
typedef R(*function_pointer_type)(Args..., ...);
|
typedef R(*function_pointer_type)(Args..., ...);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Member Functions
|
// Member Functions
|
||||||
/* C-Style Variadics */
|
/* C-Style Variadics */
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...), false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...), false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...);
|
typedef R(T::* function_pointer_type)(Args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...), false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...), false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...);
|
typedef R(T::* function_pointer_type)(Args..., ...);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Const Volatile */
|
/* Const Volatile */
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) const, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) const, false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) const;
|
typedef R(T::* function_pointer_type)(Args...) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) const, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) const, false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) const;
|
typedef R(T::* function_pointer_type)(Args..., ...) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) const volatile, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) const volatile, false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) const volatile;
|
typedef R(T::* function_pointer_type)(Args...) const volatile;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) const volatile, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) const volatile, false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) const volatile;
|
typedef R(T::* function_pointer_type)(Args..., ...) const volatile;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Member Function Qualifiers */
|
/* Member Function Qualifiers */
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) &, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) &, false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) &;
|
typedef R(T::* function_pointer_type)(Args...) &;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) &, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) &, false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) &;
|
typedef R(T::* function_pointer_type)(Args..., ...) &;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) const &, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) const &, false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) const &;
|
typedef R(T::* function_pointer_type)(Args...) const &;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) const &, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) const &, false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) const &;
|
typedef R(T::* function_pointer_type)(Args..., ...) const &;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) const volatile &, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) const volatile &, false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) const volatile &;
|
typedef R(T::* function_pointer_type)(Args...) const volatile &;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) const volatile &, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) const volatile &, false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &;
|
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) &&, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) && , false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) &&;
|
typedef R(T::* function_pointer_type)(Args...) && ;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) &&, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) && , false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) &&;
|
typedef R(T::* function_pointer_type)(Args..., ...) && ;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) const &&, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) const &&, false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) const &&;
|
typedef R(T::* function_pointer_type)(Args...) const &&;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) const &&, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) const &&, false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) const &&;
|
typedef R(T::* function_pointer_type)(Args..., ...) const &&;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args...) const volatile &&, false> : basic_traits<false, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args...) const volatile &&, false> : basic_traits<false, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args...) const volatile &&;
|
typedef R(T::* function_pointer_type)(Args...) const volatile &&;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct fx_traits<R(T::*)(Args..., ...) const volatile &&, false> : basic_traits<true, T, R, Args...> {
|
struct fx_traits<R(T::*)(Args..., ...) const volatile &&, false> : basic_traits<true, T, R, Args...> {
|
||||||
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&;
|
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {};
|
struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {};
|
||||||
|
|
||||||
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
|
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
|
||||||
struct callable_traits : fx_traits<std::decay_t<Signature>> {
|
struct callable_traits : fx_traits<std::decay_t<Signature>> {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
struct callable_traits<R(T::*), true> {
|
struct callable_traits<R(T::*), true> {
|
||||||
typedef R Arg;
|
typedef R Arg;
|
||||||
typedef T object_type;
|
typedef T object_type;
|
||||||
using signature_type = R(T::*);
|
using signature_type = R(T::*);
|
||||||
static const bool is_member_function = false;
|
static const bool is_member_function = false;
|
||||||
static const std::size_t arity = 1;
|
static const std::size_t arity = 1;
|
||||||
static const std::size_t free_arity = 2;
|
static const std::size_t free_arity = 2;
|
||||||
typedef std::tuple<Arg> args_tuple;
|
typedef std::tuple<Arg> args_tuple;
|
||||||
typedef R return_type;
|
typedef R return_type;
|
||||||
typedef types<Arg> args_list;
|
typedef types<Arg> args_list;
|
||||||
typedef meta::tuple_types<R> returns_list;
|
typedef meta::tuple_types<R> returns_list;
|
||||||
typedef R(function_type)(T&, R);
|
typedef R(function_type)(T&, R);
|
||||||
typedef R(*function_pointer_type)(T&, R);
|
typedef R(*function_pointer_type)(T&, R);
|
||||||
typedef R(*free_function_pointer_type)(T&, R);
|
typedef R(*free_function_pointer_type)(T&, R);
|
||||||
template<std::size_t i>
|
template<std::size_t i>
|
||||||
using arg_at = void_tuple_element_t<i, args_tuple>;
|
using arg_at = void_tuple_element_t<i, args_tuple>;
|
||||||
};
|
};
|
||||||
} // meta_detail
|
} // meta_detail
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct bind_traits : meta_detail::callable_traits<Signature> {};
|
struct bind_traits : meta_detail::callable_traits<Signature> {};
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
using function_args_t = typename bind_traits<Signature>::args_list;
|
using function_args_t = typename bind_traits<Signature>::args_list;
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
using function_signature_t = typename bind_traits<Signature>::signature_type;
|
using function_signature_t = typename bind_traits<Signature>::signature_type;
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
using function_return_t = typename bind_traits<Signature>::return_type;
|
using function_return_t = typename bind_traits<Signature>::return_type;
|
||||||
|
|
||||||
} // meta
|
} // meta
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
|
#endif // SOL_BIND_TRAITS
|
||||||
|
|
676
sol/call.hpp
676
sol/call.hpp
|
@ -1,6 +1,6 @@
|
||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
|
|
||||||
// Copyright (c) 2013-2016 Rappt1101010z, ThePhD and contributors
|
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
|
||||||
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
// this software and associated documentation files (the "Software"), to deal in
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
@ -26,294 +26,114 @@
|
||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
#include "stack.hpp"
|
#include "stack.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace call_detail {
|
namespace call_detail {
|
||||||
|
|
||||||
template <bool b, typename F>
|
|
||||||
inline decltype(auto) pick(std::integral_constant<bool, b>, F&& f) {
|
|
||||||
return std::forward<F>(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename R, typename W>
|
template <bool b, typename F>
|
||||||
inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
|
inline decltype(auto) pick(std::integral_constant<bool, b>, F&& f) {
|
||||||
return f.read;
|
return std::forward<F>(f);
|
||||||
}
|
|
||||||
|
|
||||||
template <typename R, typename W>
|
|
||||||
inline auto& pick(std::false_type, property_wrapper<R, W>& f) {
|
|
||||||
return f.write;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename List>
|
|
||||||
struct void_call;
|
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
|
||||||
struct void_call<T, types<Args...>> {
|
|
||||||
static void call(Args...) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, int additional_pop = 0>
|
|
||||||
struct constructor_match {
|
|
||||||
T* obj;
|
|
||||||
|
|
||||||
constructor_match(T* obj) : obj(obj) {}
|
|
||||||
|
|
||||||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
|
||||||
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
|
|
||||||
detail::default_construct func{};
|
|
||||||
return stack::call_into_lua<additional_pop, false>(r, a, L, start, func, obj);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline int destruct(lua_State* L) {
|
|
||||||
T* obj = stack::get<non_null<T*>>(L, 1);
|
|
||||||
std::allocator<T> alloc{};
|
|
||||||
alloc.destroy(obj);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace overload_detail {
|
|
||||||
template <std::size_t... M, typename Match, typename... Args>
|
|
||||||
inline int overload_match_arity(sol::types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) {
|
|
||||||
return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
|
template <typename R, typename W>
|
||||||
inline int overload_match_arity(sol::types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
|
inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
|
||||||
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
|
return f.read;
|
||||||
typedef meta::tuple_types<typename traits::return_type> return_types;
|
}
|
||||||
typedef typename traits::free_args_list args_list;
|
|
||||||
typedef typename args_list::indices args_indices;
|
template <typename R, typename W>
|
||||||
// compile-time eliminate any functions that we know ahead of time are of improper arity
|
inline auto& pick(std::false_type, property_wrapper<R, W>& f) {
|
||||||
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
|
return f.write;
|
||||||
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
}
|
||||||
|
|
||||||
|
template <typename T, typename List>
|
||||||
|
struct void_call;
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
struct void_call<T, types<Args...>> {
|
||||||
|
static void call(Args...) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, int additional_pop = 0>
|
||||||
|
struct constructor_match {
|
||||||
|
T* obj;
|
||||||
|
|
||||||
|
constructor_match(T* obj) : obj(obj) {}
|
||||||
|
|
||||||
|
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||||
|
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
|
||||||
|
detail::default_construct func{};
|
||||||
|
return stack::call_into_lua<additional_pop, false>(r, a, L, start, func, obj);
|
||||||
}
|
}
|
||||||
if (traits::free_arity != fxarity) {
|
};
|
||||||
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start, no_panic)) {
|
|
||||||
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
} // overload_detail
|
|
||||||
|
|
||||||
template <typename... Functions, typename Match, typename... Args>
|
template <typename T>
|
||||||
inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
|
inline int destruct(lua_State* L) {
|
||||||
return overload_detail::overload_match_arity(types<Functions...>(), std::make_index_sequence<sizeof...(Functions)>(), std::index_sequence<>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
T* obj = stack::get<non_null<T*>>(L, 1);
|
||||||
}
|
std::allocator<T> alloc{};
|
||||||
|
alloc.destroy(obj);
|
||||||
template <typename... Functions, typename Match, typename... Args>
|
|
||||||
inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {
|
|
||||||
int fxarity = lua_gettop(L) - (start - 1);
|
|
||||||
return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... TypeLists, typename Match, typename... Args>
|
|
||||||
inline int construct(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
|
|
||||||
// use same overload resolution matching as all other parts of the framework
|
|
||||||
return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... TypeLists>
|
|
||||||
inline int construct(lua_State* L) {
|
|
||||||
static const auto& meta = usertype_traits<T>::metatable;
|
|
||||||
int argcount = lua_gettop(L);
|
|
||||||
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, meta, 1) : call_syntax::dot;
|
|
||||||
argcount -= static_cast<int>(syntax);
|
|
||||||
|
|
||||||
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
|
|
||||||
T*& referencepointer = *pointerpointer;
|
|
||||||
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
|
|
||||||
referencepointer = obj;
|
|
||||||
reference userdataref(L, -1);
|
|
||||||
userdataref.pop();
|
|
||||||
|
|
||||||
construct<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
|
|
||||||
|
|
||||||
userdataref.push();
|
|
||||||
luaL_getmetatable(L, &meta[0]);
|
|
||||||
if (type_of(L, -1) == type::nil) {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return luaL_error(L, "sol: unable to get usertype metatable");
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F, bool is_index, bool is_variable, typename = void>
|
|
||||||
struct agnostic_lua_call_wrapper {
|
|
||||||
static int var_call(std::true_type, lua_State* L, F& f) {
|
|
||||||
typedef wrapper<meta::unqualified_t<F>> wrap;
|
|
||||||
typedef typename wrap::returns_list returns_list;
|
|
||||||
typedef typename wrap::free_args_list args_list;
|
|
||||||
typedef typename wrap::caller caller;
|
|
||||||
return stack::call_into_lua<is_index ? 1 : 2>(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int var_call(std::false_type, lua_State* L, F& f) {
|
|
||||||
typedef wrapper<meta::unqualified_t<F>> wrap;
|
|
||||||
typedef typename wrap::free_args_list args_list;
|
|
||||||
typedef typename wrap::returns_list returns_list;
|
|
||||||
typedef typename wrap::caller caller;
|
|
||||||
return stack::call_into_lua(returns_list(), args_list(), L, 1, caller(), f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int call(lua_State* L, F& f) {
|
|
||||||
return var_call(std::integral_constant<bool, is_variable>(), L, f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename F, bool is_index, bool is_variable>
|
|
||||||
struct agnostic_lua_call_wrapper<F, is_index, is_variable, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
|
|
||||||
static int call(lua_State* L, F& f) {
|
|
||||||
typedef wrapper<meta::unqualified_t<F>> wrap;
|
|
||||||
typedef typename wrap::returns_list returns_list;
|
|
||||||
typedef typename wrap::args_list args_list;
|
|
||||||
typedef typename wrap::caller caller;
|
|
||||||
typedef typename wrap::object_type object_type;
|
|
||||||
|
|
||||||
#ifdef SOL_SAFE_USERTYPE
|
|
||||||
object_type* o = stack::get<object_type*>(L, 1);
|
|
||||||
if (o == nullptr) {
|
|
||||||
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
|
|
||||||
}
|
|
||||||
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
|
|
||||||
#else
|
|
||||||
object_type& o = stack::get<object_type&>(L, 1);
|
|
||||||
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
|
|
||||||
#endif // Safety
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool is_index, bool is_variable, typename C>
|
|
||||||
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, C> {
|
|
||||||
static int call(lua_State* L, lua_r_CFunction f) {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool is_index, bool is_variable, typename C>
|
|
||||||
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, C> {
|
|
||||||
static int call(lua_State* L, lua_CFunction f) {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool is_index, bool is_variable, typename C>
|
|
||||||
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, C> {
|
|
||||||
static int call(lua_State* L, no_prop&) {
|
|
||||||
return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename F, bool is_variable>
|
|
||||||
struct agnostic_lua_call_wrapper<F, false, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
|
|
||||||
typedef sol::lua_bind_traits<F> traits_type;
|
|
||||||
|
|
||||||
static int call_assign(std::true_type, lua_State* L, F& f) {
|
|
||||||
typedef wrapper<meta::unqualified_t<F>> wrap;
|
|
||||||
typedef typename wrap::args_list args_list;
|
|
||||||
typedef typename wrap::object_type object_type;
|
|
||||||
typedef typename wrap::caller caller;
|
|
||||||
#ifdef SOL_SAFE_USERTYPE
|
|
||||||
object_type* o = stack::get<object_type*>(L, 1);
|
|
||||||
if (o == nullptr) {
|
|
||||||
if (is_variable) {
|
|
||||||
return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)");
|
|
||||||
}
|
|
||||||
return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)");
|
|
||||||
}
|
|
||||||
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
|
|
||||||
#else
|
|
||||||
object_type& o = stack::get<object_type&>(L, 1);
|
|
||||||
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
|
|
||||||
#endif // Safety
|
|
||||||
}
|
|
||||||
|
|
||||||
static int call_assign(std::false_type, lua_State* L, F&) {
|
|
||||||
return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int call_const(std::false_type, lua_State* L, F& f) {
|
|
||||||
typedef typename traits_type::return_type R;
|
|
||||||
return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int call_const(std::true_type, lua_State* L, F&) {
|
|
||||||
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int call(lua_State* L, F& f) {
|
|
||||||
return call_const(std::is_const<typename traits_type::return_type>(), L, f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename F, bool is_variable>
|
|
||||||
struct agnostic_lua_call_wrapper<F, true, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
|
|
||||||
typedef sol::lua_bind_traits<F> traits_type;
|
|
||||||
|
|
||||||
static int call(lua_State* L, F& f) {
|
|
||||||
typedef wrapper<meta::unqualified_t<F>> wrap;
|
|
||||||
typedef typename wrap::object_type object_type;
|
|
||||||
typedef typename wrap::returns_list returns_list;
|
|
||||||
typedef typename wrap::caller caller;
|
|
||||||
#ifdef SOL_SAFE_USERTYPE
|
|
||||||
object_type* o = stack::get<object_type*>(L, 1);
|
|
||||||
if (o == nullptr) {
|
|
||||||
if (is_variable) {
|
|
||||||
return luaL_error(L, "sol: 'self' argument is nil (bad '.' access?)");
|
|
||||||
}
|
|
||||||
return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)");
|
|
||||||
}
|
|
||||||
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o);
|
|
||||||
#else
|
|
||||||
object_type& o = stack::get<object_type&>(L, 1);
|
|
||||||
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o);
|
|
||||||
#endif // Safety
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool is_index, bool is_variable, typename C>
|
|
||||||
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, C> {
|
|
||||||
static int call(lua_State* L, no_construction&) {
|
|
||||||
return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Args, bool is_index, bool is_variable, typename C>
|
|
||||||
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, C> {
|
|
||||||
static int call(lua_State*, bases<Args...>&) {
|
|
||||||
// Uh. How did you even call this, lul
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename F, bool is_index, bool is_variable, typename = void>
|
namespace overload_detail {
|
||||||
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable> {};
|
template <std::size_t... M, typename Match, typename... Args>
|
||||||
|
inline int overload_match_arity(sol::types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) {
|
||||||
|
return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types");
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args, bool is_index, bool is_variable, typename C>
|
template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
|
||||||
struct lua_call_wrapper<T, sol::constructor_list<Args...>, is_index, is_variable, C> {
|
inline int overload_match_arity(sol::types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
|
||||||
typedef sol::constructor_list<Args...> F;
|
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
|
||||||
|
typedef meta::tuple_types<typename traits::return_type> return_types;
|
||||||
|
typedef typename traits::free_args_list args_list;
|
||||||
|
typedef typename args_list::indices args_indices;
|
||||||
|
// compile-time eliminate any functions that we know ahead of time are of improper arity
|
||||||
|
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
|
||||||
|
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
if (traits::free_arity != fxarity) {
|
||||||
|
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start, no_panic)) {
|
||||||
|
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
} // overload_detail
|
||||||
|
|
||||||
static int call(lua_State* L, F&) {
|
template <typename... Functions, typename Match, typename... Args>
|
||||||
static const auto& metakey = usertype_traits<T>::metatable;
|
inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
|
||||||
|
return overload_detail::overload_match_arity(types<Functions...>(), std::make_index_sequence<sizeof...(Functions)>(), std::index_sequence<>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Functions, typename Match, typename... Args>
|
||||||
|
inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {
|
||||||
|
int fxarity = lua_gettop(L) - (start - 1);
|
||||||
|
return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... TypeLists, typename Match, typename... Args>
|
||||||
|
inline int construct(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
|
||||||
|
// use same overload resolution matching as all other parts of the framework
|
||||||
|
return overload_match_arity<decltype(void_call<T, TypeLists>::call)...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... TypeLists>
|
||||||
|
inline int construct(lua_State* L) {
|
||||||
|
static const auto& meta = usertype_traits<T>::metatable;
|
||||||
int argcount = lua_gettop(L);
|
int argcount = lua_gettop(L);
|
||||||
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, metakey, 1) : call_syntax::dot;
|
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, meta, 1) : call_syntax::dot;
|
||||||
argcount -= static_cast<int>(syntax);
|
argcount -= static_cast<int>(syntax);
|
||||||
|
|
||||||
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
|
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
|
||||||
reference userdataref(L, -1);
|
|
||||||
T*& referencepointer = *pointerpointer;
|
T*& referencepointer = *pointerpointer;
|
||||||
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
|
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
|
||||||
referencepointer = obj;
|
referencepointer = obj;
|
||||||
|
reference userdataref(L, -1);
|
||||||
construct<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax));
|
userdataref.pop();
|
||||||
|
|
||||||
|
construct<T, TypeLists...>(constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
|
||||||
|
|
||||||
userdataref.push();
|
userdataref.push();
|
||||||
luaL_getmetatable(L, &metakey[0]);
|
luaL_getmetatable(L, &meta[0]);
|
||||||
if (type_of(L, -1) == type::nil) {
|
if (type_of(L, -1) == type::nil) {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return luaL_error(L, "sol: unable to get usertype metatable");
|
return luaL_error(L, "sol: unable to get usertype metatable");
|
||||||
|
@ -322,108 +142,288 @@ namespace call_detail {
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename... Cxs, bool is_index, bool is_variable, typename C>
|
template <typename F, bool is_index, bool is_variable, typename = void>
|
||||||
struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, C> {
|
struct agnostic_lua_call_wrapper {
|
||||||
typedef sol::constructor_wrapper<Cxs...> F;
|
static int var_call(std::true_type, lua_State* L, F& f) {
|
||||||
|
typedef wrapper<meta::unqualified_t<F>> wrap;
|
||||||
|
typedef typename wrap::returns_list returns_list;
|
||||||
|
typedef typename wrap::free_args_list args_list;
|
||||||
|
typedef typename wrap::caller caller;
|
||||||
|
return stack::call_into_lua<is_index ? 1 : 2>(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int var_call(std::false_type, lua_State* L, F& f) {
|
||||||
|
typedef wrapper<meta::unqualified_t<F>> wrap;
|
||||||
|
typedef typename wrap::free_args_list args_list;
|
||||||
|
typedef typename wrap::returns_list returns_list;
|
||||||
|
typedef typename wrap::caller caller;
|
||||||
|
return stack::call_into_lua(returns_list(), args_list(), L, 1, caller(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int call(lua_State* L, F& f) {
|
||||||
|
return var_call(std::integral_constant<bool, is_variable>(), L, f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename F, bool is_index, bool is_variable>
|
||||||
|
struct agnostic_lua_call_wrapper<F, is_index, is_variable, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
|
||||||
|
static int call(lua_State* L, F& f) {
|
||||||
|
typedef wrapper<meta::unqualified_t<F>> wrap;
|
||||||
|
typedef typename wrap::returns_list returns_list;
|
||||||
|
typedef typename wrap::args_list args_list;
|
||||||
|
typedef typename wrap::caller caller;
|
||||||
|
typedef typename wrap::object_type object_type;
|
||||||
|
|
||||||
|
#ifdef SOL_SAFE_USERTYPE
|
||||||
|
object_type* o = stack::get<object_type*>(L, 1);
|
||||||
|
if (o == nullptr) {
|
||||||
|
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
|
||||||
|
}
|
||||||
|
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
|
||||||
|
#else
|
||||||
|
object_type& o = stack::get<object_type&>(L, 1);
|
||||||
|
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
|
||||||
|
#endif // Safety
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool is_index, bool is_variable, typename C>
|
||||||
|
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, C> {
|
||||||
|
static int call(lua_State* L, lua_r_CFunction f) {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool is_index, bool is_variable, typename C>
|
||||||
|
struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, C> {
|
||||||
|
static int call(lua_State* L, lua_CFunction f) {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool is_index, bool is_variable, typename C>
|
||||||
|
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, C> {
|
||||||
|
static int call(lua_State* L, no_prop&) {
|
||||||
|
return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename F, bool is_variable>
|
||||||
|
struct agnostic_lua_call_wrapper<F, false, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
|
||||||
|
typedef sol::lua_bind_traits<F> traits_type;
|
||||||
|
|
||||||
|
static int call_assign(std::true_type, lua_State* L, F& f) {
|
||||||
|
typedef wrapper<meta::unqualified_t<F>> wrap;
|
||||||
|
typedef typename wrap::args_list args_list;
|
||||||
|
typedef typename wrap::object_type object_type;
|
||||||
|
typedef typename wrap::caller caller;
|
||||||
|
#ifdef SOL_SAFE_USERTYPE
|
||||||
|
object_type* o = stack::get<object_type*>(L, 1);
|
||||||
|
if (o == nullptr) {
|
||||||
|
if (is_variable) {
|
||||||
|
return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)");
|
||||||
|
}
|
||||||
|
return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)");
|
||||||
|
}
|
||||||
|
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o);
|
||||||
|
#else
|
||||||
|
object_type& o = stack::get<object_type&>(L, 1);
|
||||||
|
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, caller(), f, o);
|
||||||
|
#endif // Safety
|
||||||
|
}
|
||||||
|
|
||||||
|
static int call_assign(std::false_type, lua_State* L, F&) {
|
||||||
|
return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int call_const(std::false_type, lua_State* L, F& f) {
|
||||||
|
typedef typename traits_type::return_type R;
|
||||||
|
return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int call_const(std::true_type, lua_State* L, F&) {
|
||||||
|
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int call(lua_State* L, F& f) {
|
||||||
|
return call_const(std::is_const<typename traits_type::return_type>(), L, f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename F, bool is_variable>
|
||||||
|
struct agnostic_lua_call_wrapper<F, true, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
|
||||||
|
typedef sol::lua_bind_traits<F> traits_type;
|
||||||
|
|
||||||
|
static int call(lua_State* L, F& f) {
|
||||||
|
typedef wrapper<meta::unqualified_t<F>> wrap;
|
||||||
|
typedef typename wrap::object_type object_type;
|
||||||
|
typedef typename wrap::returns_list returns_list;
|
||||||
|
typedef typename wrap::caller caller;
|
||||||
|
#ifdef SOL_SAFE_USERTYPE
|
||||||
|
object_type* o = stack::get<object_type*>(L, 1);
|
||||||
|
if (o == nullptr) {
|
||||||
|
if (is_variable) {
|
||||||
|
return luaL_error(L, "sol: 'self' argument is nil (bad '.' access?)");
|
||||||
|
}
|
||||||
|
return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)");
|
||||||
|
}
|
||||||
|
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o);
|
||||||
|
#else
|
||||||
|
object_type& o = stack::get<object_type&>(L, 1);
|
||||||
|
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o);
|
||||||
|
#endif // Safety
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool is_index, bool is_variable, typename C>
|
||||||
|
struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, C> {
|
||||||
|
static int call(lua_State* L, no_construction&) {
|
||||||
|
return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Args, bool is_index, bool is_variable, typename C>
|
||||||
|
struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, C> {
|
||||||
|
static int call(lua_State*, bases<Args...>&) {
|
||||||
|
// Uh. How did you even call this, lul
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename F, bool is_index, bool is_variable, typename = void>
|
||||||
|
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable> {};
|
||||||
|
|
||||||
|
template <typename T, typename... Args, bool is_index, bool is_variable, typename C>
|
||||||
|
struct lua_call_wrapper<T, sol::constructor_list<Args...>, is_index, is_variable, C> {
|
||||||
|
typedef sol::constructor_list<Args...> F;
|
||||||
|
|
||||||
|
static int call(lua_State* L, F&) {
|
||||||
|
static const auto& metakey = usertype_traits<T>::metatable;
|
||||||
|
int argcount = lua_gettop(L);
|
||||||
|
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, metakey, 1) : call_syntax::dot;
|
||||||
|
argcount -= static_cast<int>(syntax);
|
||||||
|
|
||||||
struct onmatch {
|
|
||||||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
|
||||||
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {
|
|
||||||
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
|
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
|
||||||
reference userdataref(L, -1);
|
reference userdataref(L, -1);
|
||||||
T*& referencepointer = *pointerpointer;
|
T*& referencepointer = *pointerpointer;
|
||||||
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
|
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
|
||||||
referencepointer = obj;
|
referencepointer = obj;
|
||||||
|
|
||||||
auto& func = std::get<I>(f.set);
|
construct<T, Args...>(constructor_match<T, 1>(obj), L, argcount, 1 + static_cast<int>(syntax));
|
||||||
stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
|
|
||||||
|
|
||||||
userdataref.push();
|
userdataref.push();
|
||||||
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
|
luaL_getmetatable(L, &metakey[0]);
|
||||||
if (type_of(L, -1) == type::nil) {
|
if (type_of(L, -1) == type::nil) {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
std::string err = "sol: unable to get usertype metatable for ";
|
return luaL_error(L, "sol: unable to get usertype metatable");
|
||||||
err += usertype_traits<T>::name;
|
|
||||||
return luaL_error(L, err.c_str());
|
|
||||||
}
|
}
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
|
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int call(lua_State* L, F& f) {
|
template <typename T, typename... Cxs, bool is_index, bool is_variable, typename C>
|
||||||
call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::metatable);
|
struct lua_call_wrapper<T, sol::constructor_wrapper<Cxs...>, is_index, is_variable, C> {
|
||||||
int syntaxval = static_cast<int>(syntax);
|
typedef sol::constructor_wrapper<Cxs...> F;
|
||||||
int argcount = lua_gettop(L) - syntaxval;
|
|
||||||
return construct<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
struct onmatch {
|
||||||
|
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||||
|
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {
|
||||||
|
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
|
||||||
|
reference userdataref(L, -1);
|
||||||
|
T*& referencepointer = *pointerpointer;
|
||||||
|
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
|
||||||
|
referencepointer = obj;
|
||||||
|
|
||||||
template <typename T, typename Fx, bool is_index, bool is_variable>
|
auto& func = std::get<I>(f.set);
|
||||||
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<std::is_void<Fx>::value>> {
|
stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper<T>(obj));
|
||||||
typedef sol::destructor_wrapper<Fx> F;
|
|
||||||
|
|
||||||
static int call(lua_State* L, F&) {
|
userdataref.push();
|
||||||
return destruct<T>(L);
|
luaL_getmetatable(L, &usertype_traits<T>::metatable[0]);
|
||||||
}
|
if (type_of(L, -1) == type::nil) {
|
||||||
};
|
lua_pop(L, 1);
|
||||||
|
std::string err = "sol: unable to get usertype metatable for ";
|
||||||
|
err += usertype_traits<T>::name;
|
||||||
|
return luaL_error(L, err.c_str());
|
||||||
|
}
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
|
||||||
template <typename T, typename Fx, bool is_index, bool is_variable>
|
return 1;
|
||||||
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<!std::is_void<Fx>::value>> {
|
}
|
||||||
typedef sol::destructor_wrapper<Fx> F;
|
};
|
||||||
|
|
||||||
static int call(lua_State* L, F& f) {
|
static int call(lua_State* L, F& f) {
|
||||||
T* obj = stack::get<non_null<T*>>(L);
|
call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::metatable);
|
||||||
f.fx(detail::implicit_wrapper<T>(obj));
|
int syntaxval = static_cast<int>(syntax);
|
||||||
return 0;
|
int argcount = lua_gettop(L) - syntaxval;
|
||||||
}
|
return construct<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
|
||||||
};
|
}
|
||||||
|
|
||||||
template <typename T, typename... Fs, bool is_index, bool is_variable, typename C>
|
};
|
||||||
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, C> {
|
|
||||||
typedef overload_set<Fs...> F;
|
|
||||||
|
|
||||||
struct on_match {
|
template <typename T, typename Fx, bool is_index, bool is_variable>
|
||||||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<std::is_void<Fx>::value>> {
|
||||||
int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
|
typedef sol::destructor_wrapper<Fx> F;
|
||||||
auto& f = std::get<I>(fx.set);
|
|
||||||
return lua_call_wrapper<T, Fx, is_index, is_variable>{}.call(L, f);
|
static int call(lua_State* L, F&) {
|
||||||
|
return destruct<T>(L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int call(lua_State* L, F& fx) {
|
template <typename T, typename Fx, bool is_index, bool is_variable>
|
||||||
return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx);
|
struct lua_call_wrapper<T, sol::destructor_wrapper<Fx>, is_index, is_variable, std::enable_if_t<!std::is_void<Fx>::value>> {
|
||||||
|
typedef sol::destructor_wrapper<Fx> F;
|
||||||
|
|
||||||
|
static int call(lua_State* L, F& f) {
|
||||||
|
T* obj = stack::get<non_null<T*>>(L);
|
||||||
|
f.fx(detail::implicit_wrapper<T>(obj));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename... Fs, bool is_index, bool is_variable, typename C>
|
||||||
|
struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, C> {
|
||||||
|
typedef overload_set<Fs...> F;
|
||||||
|
|
||||||
|
struct on_match {
|
||||||
|
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||||
|
int operator()(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
|
||||||
|
auto& f = std::get<I>(fx.set);
|
||||||
|
return lua_call_wrapper<T, Fx, is_index, is_variable>{}.call(L, f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int call(lua_State* L, F& fx) {
|
||||||
|
return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, bool is_index, bool is_variable, typename Fx>
|
||||||
|
int call_wrapped(lua_State* L, Fx&& fx) {
|
||||||
|
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable>{}.call(L, std::forward<Fx>(fx));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, bool is_index, bool is_variable, typename Fx>
|
template <typename T, typename = void>
|
||||||
int call_wrapped(lua_State* L, Fx&& fx) {
|
struct is_var_bind : std::false_type {};
|
||||||
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable>{}.call(L, std::forward<Fx>(fx));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = void>
|
template <typename T>
|
||||||
struct is_var_bind : std::false_type {};
|
struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct is_var_bind<no_prop> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename R, typename W>
|
||||||
|
struct is_var_bind<property_wrapper<R, W>> : std::true_type {};
|
||||||
|
|
||||||
|
} // call_detail
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {};
|
struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {};
|
||||||
|
|
||||||
template <>
|
template <typename T>
|
||||||
struct is_var_bind<no_prop> : std::true_type {};
|
struct is_function_binding : meta::neg<is_variable_binding<T>> {};
|
||||||
|
|
||||||
template <typename R, typename W>
|
|
||||||
struct is_var_bind<property_wrapper<R, W>> : std::true_type {};
|
|
||||||
|
|
||||||
} // call_detail
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_function_binding : meta::neg<is_variable_binding<T>> {};
|
|
||||||
|
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,10 @@
|
||||||
// but has been modified in many places for use with Sol and luajit,
|
// but has been modified in many places for use with Sol and luajit,
|
||||||
// though the core abstractions remain the same
|
// though the core abstractions remain the same
|
||||||
|
|
||||||
|
#include "compatibility/version.hpp"
|
||||||
|
|
||||||
#ifndef SOL_NO_COMPAT
|
#ifndef SOL_NO_COMPAT
|
||||||
|
|
||||||
#include "compatibility/version.hpp"
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,88 +28,89 @@
|
||||||
#include "thread.hpp"
|
#include "thread.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
class coroutine : public reference {
|
class coroutine : public reference {
|
||||||
private:
|
private:
|
||||||
call_status stats = call_status::yielded;
|
call_status stats = call_status::yielded;
|
||||||
|
|
||||||
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) {
|
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t) {
|
||||||
#if SOL_LUA_VERSION < 502
|
#if SOL_LUA_VERSION < 502
|
||||||
stats = static_cast<call_status>(lua_resume(lua_state(), static_cast<int>(argcount)));
|
stats = static_cast<call_status>(lua_resume(lua_state(), static_cast<int>(argcount)));
|
||||||
#else
|
#else
|
||||||
stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount)));
|
stats = static_cast<call_status>(lua_resume(lua_state(), nullptr, static_cast<int>(argcount)));
|
||||||
#endif // Lua 5.1 compat
|
#endif // Lua 5.1 compat
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t... I, typename... Ret>
|
template<std::size_t... I, typename... Ret>
|
||||||
auto invoke( types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n ) {
|
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) {
|
||||||
luacall(n, sizeof...(Ret));
|
luacall(n, sizeof...(Ret));
|
||||||
return stack::pop<std::tuple<Ret...>>(lua_state());
|
return stack::pop<std::tuple<Ret...>>(lua_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I, typename Ret>
|
template<std::size_t I, typename Ret>
|
||||||
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) {
|
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) {
|
||||||
luacall(n, 1);
|
luacall(n, 1);
|
||||||
return stack::pop<Ret>(lua_state());
|
return stack::pop<Ret>(lua_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) {
|
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) {
|
||||||
luacall(n, 0);
|
luacall(n, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
|
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
|
||||||
int stacksize = lua_gettop( lua_state() );
|
int stacksize = lua_gettop(lua_state());
|
||||||
int firstreturn = (std::max)( 1, stacksize - static_cast<int>( n ) );
|
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
|
||||||
luacall(n, LUA_MULTRET);
|
luacall(n, LUA_MULTRET);
|
||||||
int poststacksize = lua_gettop(lua_state());
|
int poststacksize = lua_gettop(lua_state());
|
||||||
int returncount = poststacksize - (firstreturn - 1);
|
int returncount = poststacksize - (firstreturn - 1);
|
||||||
return protected_function_result( lua_state( ), firstreturn, returncount, returncount, status() );
|
return protected_function_result(lua_state(), firstreturn, returncount, returncount, status());
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
coroutine() noexcept = default;
|
coroutine() noexcept = default;
|
||||||
coroutine(const coroutine&) noexcept = default;
|
coroutine(const coroutine&) noexcept = default;
|
||||||
coroutine& operator=(const coroutine&) noexcept = default;
|
coroutine& operator=(const coroutine&) noexcept = default;
|
||||||
coroutine(lua_State* L, int index = -1) : reference(L, index) {
|
coroutine(lua_State* L, int index = -1) : reference(L, index) {
|
||||||
#ifdef SOL_CHECK_ARGUMENTS
|
#ifdef SOL_CHECK_ARGUMENTS
|
||||||
stack::check<coroutine>(L, index, type_panic);
|
stack::check<coroutine>(L, index, type_panic);
|
||||||
#endif // Safety
|
#endif // Safety
|
||||||
}
|
}
|
||||||
|
|
||||||
call_status status() const noexcept {
|
call_status status() const noexcept {
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool error() const noexcept {
|
bool error() const noexcept {
|
||||||
call_status cs = status();
|
call_status cs = status();
|
||||||
return cs != call_status::ok && cs != call_status::yielded;
|
return cs != call_status::ok && cs != call_status::yielded;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool runnable () const noexcept {
|
bool runnable() const noexcept {
|
||||||
return valid()
|
return valid()
|
||||||
&& (status() == call_status::yielded);
|
&& (status() == call_status::yielded);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const noexcept {
|
explicit operator bool() const noexcept {
|
||||||
return runnable();
|
return runnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
protected_function_result operator()( Args&&... args ) {
|
protected_function_result operator()(Args&&... args) {
|
||||||
return call<>( std::forward<Args>( args )... );
|
return call<>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ret, typename... Args>
|
template<typename... Ret, typename... Args>
|
||||||
decltype(auto) operator()( types<Ret...>, Args&&... args ) {
|
decltype(auto) operator()(types<Ret...>, Args&&... args) {
|
||||||
return call<Ret...>( std::forward<Args>( args )... );
|
return call<Ret...>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Ret, typename... Args>
|
||||||
|
decltype(auto) call(Args&&... args) {
|
||||||
|
push();
|
||||||
|
int pushcount = stack::multi_push(lua_state(), std::forward<Args>(args)...);
|
||||||
|
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // sol
|
||||||
|
|
||||||
template<typename... Ret, typename... Args>
|
|
||||||
decltype(auto) call( Args&&... args ) {
|
|
||||||
push();
|
|
||||||
int pushcount = stack::multi_push( lua_state(), std::forward<Args>( args )... );
|
|
||||||
return invoke( types<Ret...>( ), std::make_index_sequence<sizeof...(Ret)>(), pushcount );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif // SOL_COUROUTINE_HPP
|
#endif // SOL_COUROUTINE_HPP
|
||||||
|
|
|
@ -26,29 +26,29 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace debug {
|
namespace debug {
|
||||||
inline std::string dump_types(lua_State* L) {
|
inline std::string dump_types(lua_State* L) {
|
||||||
std::string visual;
|
std::string visual;
|
||||||
std::size_t size = lua_gettop(L) + 1;
|
std::size_t size = lua_gettop(L) + 1;
|
||||||
for(std::size_t i = 1; i < size; ++i) {
|
for (std::size_t i = 1; i < size; ++i) {
|
||||||
if(i != 1) {
|
if (i != 1) {
|
||||||
visual += " | ";
|
visual += " | ";
|
||||||
}
|
}
|
||||||
visual += type_name(L, stack::get<type>(L, static_cast<int>(i)));
|
visual += type_name(L, stack::get<type>(L, static_cast<int>(i)));
|
||||||
}
|
}
|
||||||
return visual;
|
return visual;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void print_stack(lua_State* L) {
|
inline void print_stack(lua_State* L) {
|
||||||
std::cout << dump_types(L) << std::endl;
|
std::cout << dump_types(L) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void print_section(const std::string& message, lua_State* L) {
|
inline void print_section(const std::string& message, lua_State* L) {
|
||||||
std::cout << "-- " << message << " -- [ " << dump_types(L) << " ]" << std::endl;
|
std::cout << "-- " << message << " -- [ " << dump_types(L) << " ]" << std::endl;
|
||||||
}
|
}
|
||||||
} // detail
|
} // detail
|
||||||
} // debug
|
} // debug
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_DEBUG_HPP
|
#endif // SOL_DEBUG_HPP
|
||||||
|
|
192
sol/demangle.hpp
192
sol/demangle.hpp
|
@ -32,121 +32,121 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#ifndef SOL_NO_RTTI
|
#ifndef SOL_NO_RTTI
|
||||||
inline std::string get_type_name(const std::type_info& id) {
|
inline std::string get_type_name(const std::type_info& id) {
|
||||||
std::string realname = id.name();
|
std::string realname = id.name();
|
||||||
const static std::array<std::string, 2> removals = { { "struct ", "class " } };
|
const static std::array<std::string, 2> removals = { { "struct ", "class " } };
|
||||||
for (std::size_t r = 0; r < removals.size(); ++r) {
|
for (std::size_t r = 0; r < removals.size(); ++r) {
|
||||||
auto found = realname.find(removals[r]);
|
auto found = realname.find(removals[r]);
|
||||||
while (found != std::string::npos) {
|
while (found != std::string::npos) {
|
||||||
realname.erase(found, removals[r].size());
|
realname.erase(found, removals[r].size());
|
||||||
found = realname.find(removals[r]);
|
found = realname.find(removals[r]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return realname;
|
return realname;
|
||||||
}
|
}
|
||||||
#endif // No RTII
|
#endif // No RTII
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline std::string ctti_get_type_name() {
|
inline std::string ctti_get_type_name() {
|
||||||
std::string name = __FUNCSIG__;
|
std::string name = __FUNCSIG__;
|
||||||
std::size_t start = name.find("get_type_name");
|
std::size_t start = name.find("get_type_name");
|
||||||
if (start == std::string::npos)
|
if (start == std::string::npos)
|
||||||
start = 0;
|
start = 0;
|
||||||
else
|
else
|
||||||
start += 13;
|
start += 13;
|
||||||
if (start < name.size() - 1)
|
if (start < name.size() - 1)
|
||||||
start += 1;
|
start += 1;
|
||||||
std::size_t end = name.find_last_of('>');
|
std::size_t end = name.find_last_of('>');
|
||||||
if (end == std::string::npos)
|
if (end == std::string::npos)
|
||||||
end = name.size();
|
end = name.size();
|
||||||
name = name.substr(start, end - start);
|
name = name.substr(start, end - start);
|
||||||
if (name.find("struct", 0) == 0)
|
if (name.find("struct", 0) == 0)
|
||||||
name.replace(0, 6, "", 0);
|
name.replace(0, 6, "", 0);
|
||||||
if (name.find("class", 0) == 0)
|
if (name.find("class", 0) == 0)
|
||||||
name.replace(0, 5, "", 0);
|
name.replace(0, 5, "", 0);
|
||||||
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin());
|
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin());
|
||||||
while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end());
|
while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end());
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
#elif defined(__GNUC__) || defined(__clang__)
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline std::string ctti_get_type_name() {
|
inline std::string ctti_get_type_name() {
|
||||||
std::string name = __PRETTY_FUNCTION__;
|
std::string name = __PRETTY_FUNCTION__;
|
||||||
std::size_t start = name.find_last_of('[');
|
std::size_t start = name.find_last_of('[');
|
||||||
start = name.find_first_of('=', start);
|
start = name.find_first_of('=', start);
|
||||||
std::size_t end = name.find_last_of(']');
|
std::size_t end = name.find_last_of(']');
|
||||||
if (end == std::string::npos)
|
if (end == std::string::npos)
|
||||||
end = name.size();
|
end = name.size();
|
||||||
if (start == std::string::npos)
|
if (start == std::string::npos)
|
||||||
start = 0;
|
start = 0;
|
||||||
if (start < name.size() - 1)
|
if (start < name.size() - 1)
|
||||||
start += 1;
|
start += 1;
|
||||||
name = name.substr(start, end - start);
|
name = name.substr(start, end - start);
|
||||||
start = name.find(";");
|
start = name.find(";");
|
||||||
if (start != std::string::npos) {
|
if (start != std::string::npos) {
|
||||||
name.erase(start, name.length());
|
name.erase(start, name.length());
|
||||||
}
|
}
|
||||||
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin());
|
while (!name.empty() && std::isblank(name.front())) name.erase(name.begin(), ++name.begin());
|
||||||
while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end());
|
while (!name.empty() && std::isblank(name.back())) name.erase(--name.end(), name.end());
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
#ifndef SOL_NO_RTTI
|
#ifndef SOL_NO_RTTI
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
inline std::string get_type_name(const std::type_info& id) {
|
inline std::string get_type_name(const std::type_info& id) {
|
||||||
int status;
|
int status;
|
||||||
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
|
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
|
||||||
std::string realname = unmangled;
|
std::string realname = unmangled;
|
||||||
std::free(unmangled);
|
std::free(unmangled);
|
||||||
return realname;
|
return realname;
|
||||||
}
|
}
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
inline std::string get_type_name(const std::type_info& id) {
|
inline std::string get_type_name(const std::type_info& id) {
|
||||||
int status;
|
int status;
|
||||||
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
|
char* unmangled = abi::__cxa_demangle(id.name(), 0, 0, &status);
|
||||||
std::string realname = unmangled;
|
std::string realname = unmangled;
|
||||||
std::free(unmangled);
|
std::free(unmangled);
|
||||||
return realname;
|
return realname;
|
||||||
}
|
}
|
||||||
#endif // g++ || clang++
|
#endif // g++ || clang++
|
||||||
#endif // No RTII
|
#endif // No RTII
|
||||||
#else
|
#else
|
||||||
#error Compiler not supported for demangling
|
#error Compiler not supported for demangling
|
||||||
#endif // compilers
|
#endif // compilers
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline std::string demangle_once() {
|
inline std::string demangle_once() {
|
||||||
#ifndef SOL_NO_RTTI
|
#ifndef SOL_NO_RTTI
|
||||||
std::string realname = get_type_name(typeid(T));
|
std::string realname = get_type_name(typeid(T));
|
||||||
#else
|
#else
|
||||||
std::string realname = ctti_get_type_name<T>();
|
std::string realname = ctti_get_type_name<T>();
|
||||||
#endif // No Runtime Type Information
|
#endif // No Runtime Type Information
|
||||||
return realname;
|
return realname;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline std::string short_demangle_once() {
|
inline std::string short_demangle_once() {
|
||||||
std::string realname = ctti_get_type_name<T>();
|
std::string realname = ctti_get_type_name<T>();
|
||||||
std::size_t idx = realname.find_last_of(":`'\"{}[]|-)(*^&!@#$%`~", std::string::npos, 23);
|
std::size_t idx = realname.find_last_of(":`'\"{}[]|-)(*^&!@#$%`~", std::string::npos, 23);
|
||||||
if (idx != std::string::npos) {
|
if (idx != std::string::npos) {
|
||||||
realname.erase(0, realname.length() < idx ? realname.length() : idx + 1);
|
realname.erase(0, realname.length() < idx ? realname.length() : idx + 1);
|
||||||
}
|
}
|
||||||
return realname;
|
return realname;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline std::string demangle() {
|
inline std::string demangle() {
|
||||||
static const std::string d = demangle_once<T>();
|
static const std::string d = demangle_once<T>();
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline std::string short_demangle() {
|
inline std::string short_demangle() {
|
||||||
static const std::string d = short_demangle_once<T>();
|
static const std::string d = short_demangle_once<T>();
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
} // detail
|
} // detail
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_DEMANGLE_HPP
|
#endif // SOL_DEMANGLE_HPP
|
||||||
|
|
|
@ -33,12 +33,15 @@
|
||||||
#endif // SOL_DEPRECATED
|
#endif // SOL_DEPRECATED
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct SOL_DEPRECATED deprecate_type {
|
struct SOL_DEPRECATED deprecate_type {
|
||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
} // detail
|
|
||||||
|
template <typename T>
|
||||||
|
using deprecate_type_t = typename deprecate_type<T>::type;
|
||||||
|
} // detail
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_DEPRECATE_HPP
|
#endif // SOL_DEPRECATE_HPP
|
||||||
|
|
|
@ -26,28 +26,30 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
struct direct_error_tag {};
|
struct direct_error_tag {};
|
||||||
const auto direct_error = direct_error_tag{};
|
const auto direct_error = direct_error_tag{};
|
||||||
} // detail
|
} // detail
|
||||||
class error : public std::runtime_error {
|
|
||||||
private:
|
class error : public std::runtime_error {
|
||||||
// Because VC++ is a fuccboi
|
private:
|
||||||
std::string w;
|
// Because VC++ is a fuccboi
|
||||||
public:
|
std::string w;
|
||||||
error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {}
|
public:
|
||||||
error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), w(str) {}
|
error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {}
|
||||||
error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), w(std::move(str)) {}
|
error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), w(str) {}
|
||||||
|
error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), w(std::move(str)) {}
|
||||||
|
|
||||||
error(const error& e) = default;
|
error(const error& e) = default;
|
||||||
error(error&& e) = default;
|
error(error&& e) = default;
|
||||||
error& operator=(const error& e) = default;
|
error& operator=(const error& e) = default;
|
||||||
error& operator=(error&& e) = default;
|
error& operator=(error&& e) = default;
|
||||||
|
|
||||||
|
virtual const char* what() const noexcept override {
|
||||||
|
return w.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
virtual const char* what() const noexcept override {
|
|
||||||
return w.c_str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_ERROR_HPP
|
#endif // SOL_ERROR_HPP
|
||||||
|
|
172
sol/function.hpp
172
sol/function.hpp
|
@ -31,106 +31,106 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
template <typename base_t>
|
template <typename base_t>
|
||||||
class basic_function : public base_t {
|
class basic_function : public base_t {
|
||||||
private:
|
private:
|
||||||
void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const {
|
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const {
|
||||||
lua_callk( base_t::lua_state( ), static_cast<int>( argcount ), static_cast<int>( resultcount ), 0, nullptr );
|
lua_callk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t... I, typename... Ret>
|
template<std::size_t... I, typename... Ret>
|
||||||
auto invoke( types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n ) const {
|
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {
|
||||||
luacall( n, sizeof...( Ret ) );
|
luacall(n, sizeof...(Ret));
|
||||||
return stack::pop<std::tuple<Ret...>>( base_t::lua_state( ) );
|
return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I, typename Ret>
|
template<std::size_t I, typename Ret>
|
||||||
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n ) const {
|
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
||||||
luacall( n, 1 );
|
luacall(n, 1);
|
||||||
return stack::pop<Ret>( base_t::lua_state( ) );
|
return stack::pop<Ret>(base_t::lua_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
||||||
luacall( n, 0 );
|
luacall(n, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n ) const {
|
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const {
|
||||||
int stacksize = lua_gettop( base_t::lua_state( ) );
|
int stacksize = lua_gettop(base_t::lua_state());
|
||||||
int firstreturn = (std::max)( 1, stacksize - static_cast<int>( n ) );
|
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
|
||||||
luacall(n, LUA_MULTRET);
|
luacall(n, LUA_MULTRET);
|
||||||
int poststacksize = lua_gettop( base_t::lua_state( ) );
|
int poststacksize = lua_gettop(base_t::lua_state());
|
||||||
int returncount = poststacksize - (firstreturn - 1);
|
int returncount = poststacksize - (firstreturn - 1);
|
||||||
return function_result( base_t::lua_state( ), firstreturn, returncount );
|
return function_result(base_t::lua_state(), firstreturn, returncount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
basic_function() = default;
|
basic_function() = default;
|
||||||
basic_function(const basic_function&) = default;
|
basic_function(const basic_function&) = default;
|
||||||
basic_function& operator=(const basic_function&) = default;
|
basic_function& operator=(const basic_function&) = default;
|
||||||
basic_function(basic_function&&) = default;
|
basic_function(basic_function&&) = default;
|
||||||
basic_function& operator=(basic_function&&) = default;
|
basic_function& operator=(basic_function&&) = default;
|
||||||
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
||||||
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
||||||
basic_function(lua_State* L, int index = -1): base_t(L, index) {
|
basic_function(lua_State* L, int index = -1) : base_t(L, index) {
|
||||||
#ifdef SOL_CHECK_ARGUMENTS
|
#ifdef SOL_CHECK_ARGUMENTS
|
||||||
stack::check<basic_function>(L, index, type_panic);
|
stack::check<basic_function>(L, index, type_panic);
|
||||||
#endif // Safety
|
#endif // Safety
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
function_result operator()( Args&&... args ) const {
|
|
||||||
return call<>( std::forward<Args>( args )... );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Ret, typename... Args>
|
template<typename... Args>
|
||||||
decltype(auto) operator()( types<Ret...>, Args&&... args ) const {
|
function_result operator()(Args&&... args) const {
|
||||||
return call<Ret...>( std::forward<Args>( args )... );
|
return call<>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ret, typename... Args>
|
template<typename... Ret, typename... Args>
|
||||||
decltype(auto) call( Args&&... args ) const {
|
decltype(auto) operator()(types<Ret...>, Args&&... args) const {
|
||||||
base_t::push( );
|
return call<Ret...>(std::forward<Args>(args)...);
|
||||||
int pushcount = stack::multi_push_reference( base_t::lua_state( ), std::forward<Args>( args )... );
|
}
|
||||||
return invoke( types<Ret...>( ), std::make_index_sequence<sizeof...(Ret)>(), pushcount );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace stack {
|
template<typename... Ret, typename... Args>
|
||||||
template<typename Signature>
|
decltype(auto) call(Args&&... args) const {
|
||||||
struct getter<std::function<Signature>> {
|
base_t::push();
|
||||||
typedef meta::bind_traits<Signature> fx_t;
|
int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
|
||||||
typedef typename fx_t::args_list args_lists;
|
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
|
||||||
typedef meta::tuple_types<typename fx_t::return_type> return_types;
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename... Args, typename... Ret>
|
namespace stack {
|
||||||
static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index = -1) {
|
template<typename Signature>
|
||||||
sol::function f(L, index);
|
struct getter<std::function<Signature>> {
|
||||||
auto fx = [f, L, index](Args&&... args) -> meta::return_type_t<Ret...> {
|
typedef meta::bind_traits<Signature> fx_t;
|
||||||
return f.call<Ret...>(std::forward<Args>(args)...);
|
typedef typename fx_t::args_list args_lists;
|
||||||
};
|
typedef meta::tuple_types<typename fx_t::return_type> return_types;
|
||||||
return std::move(fx);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... FxArgs>
|
template<typename... Args, typename... Ret>
|
||||||
static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index = -1) {
|
static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index = -1) {
|
||||||
sol::function f(L, index);
|
sol::function f(L, index);
|
||||||
auto fx = [f, L, index](FxArgs&&... args) -> void {
|
auto fx = [f, L, index](Args&&... args) -> meta::return_type_t<Ret...> {
|
||||||
f(std::forward<FxArgs>(args)...);
|
return f.call<Ret...>(std::forward<Args>(args)...);
|
||||||
};
|
};
|
||||||
return std::move(fx);
|
return std::move(fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... FxArgs>
|
template<typename... FxArgs>
|
||||||
static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index = -1) {
|
static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index = -1) {
|
||||||
return get_std_func(types<void>(), t, L, index);
|
sol::function f(L, index);
|
||||||
}
|
auto fx = [f, L, index](FxArgs&&... args) -> void {
|
||||||
|
f(std::forward<FxArgs>(args)...);
|
||||||
|
};
|
||||||
|
return std::move(fx);
|
||||||
|
}
|
||||||
|
|
||||||
static std::function<Signature> get(lua_State* L, int index) {
|
template<typename... FxArgs>
|
||||||
return get_std_func(return_types(), args_lists(), L, index);
|
static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index = -1) {
|
||||||
}
|
return get_std_func(types<void>(), t, L, index);
|
||||||
};
|
}
|
||||||
} // stack
|
|
||||||
|
static std::function<Signature> get(lua_State* L, int index) {
|
||||||
|
return get_std_func(return_types(), args_lists(), L, index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // stack
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_FUNCTION_HPP
|
#endif // SOL_FUNCTION_HPP
|
||||||
|
|
|
@ -29,52 +29,52 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
struct function_result : public proxy_base<function_result> {
|
struct function_result : public proxy_base<function_result> {
|
||||||
private:
|
private:
|
||||||
lua_State* L;
|
lua_State* L;
|
||||||
int index;
|
int index;
|
||||||
int returncount;
|
int returncount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
function_result() = default;
|
function_result() = default;
|
||||||
function_result(lua_State* L, int index = -1, int returncount = 0): L(L), index(index), returncount(returncount) {
|
function_result(lua_State* L, int index = -1, int returncount = 0) : L(L), index(index), returncount(returncount) {
|
||||||
|
|
||||||
}
|
|
||||||
function_result(const function_result&) = default;
|
|
||||||
function_result& operator=(const function_result&) = default;
|
|
||||||
function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount) {
|
|
||||||
// Must be manual, otherwise destructor will screw us
|
|
||||||
// return count being 0 is enough to keep things clean
|
|
||||||
// but will be thorough
|
|
||||||
o.L = nullptr;
|
|
||||||
o.index = 0;
|
|
||||||
o.returncount = 0;
|
|
||||||
}
|
|
||||||
function_result& operator=(function_result&& o) {
|
|
||||||
L = o.L;
|
|
||||||
index = o.index;
|
|
||||||
returncount = o.returncount;
|
|
||||||
// Must be manual, otherwise destructor will screw us
|
|
||||||
// return count being 0 is enough to keep things clean
|
|
||||||
// but will be thorough
|
|
||||||
o.L = nullptr;
|
|
||||||
o.index = 0;
|
|
||||||
o.returncount = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
}
|
||||||
decltype(auto) get() const {
|
function_result(const function_result&) = default;
|
||||||
return stack::get<T>(L, index);
|
function_result& operator=(const function_result&) = default;
|
||||||
}
|
function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount) {
|
||||||
|
// Must be manual, otherwise destructor will screw us
|
||||||
|
// return count being 0 is enough to keep things clean
|
||||||
|
// but will be thorough
|
||||||
|
o.L = nullptr;
|
||||||
|
o.index = 0;
|
||||||
|
o.returncount = 0;
|
||||||
|
}
|
||||||
|
function_result& operator=(function_result&& o) {
|
||||||
|
L = o.L;
|
||||||
|
index = o.index;
|
||||||
|
returncount = o.returncount;
|
||||||
|
// Must be manual, otherwise destructor will screw us
|
||||||
|
// return count being 0 is enough to keep things clean
|
||||||
|
// but will be thorough
|
||||||
|
o.L = nullptr;
|
||||||
|
o.index = 0;
|
||||||
|
o.returncount = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
lua_State* lua_state() const { return L; };
|
template<typename T>
|
||||||
int stack_index() const { return index; };
|
decltype(auto) get() const {
|
||||||
|
return stack::get<T>(L, index);
|
||||||
|
}
|
||||||
|
|
||||||
~function_result() {
|
lua_State* lua_state() const { return L; };
|
||||||
lua_pop(L, returncount);
|
int stack_index() const { return index; };
|
||||||
}
|
|
||||||
};
|
~function_result() {
|
||||||
|
lua_pop(L, returncount);
|
||||||
|
}
|
||||||
|
};
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_FUNCTION_RESULT_HPP
|
#endif // SOL_FUNCTION_RESULT_HPP
|
||||||
|
|
|
@ -31,217 +31,217 @@
|
||||||
#include "call.hpp"
|
#include "call.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
template <typename Sig, typename... Ps>
|
template <typename Sig, typename... Ps>
|
||||||
struct function_arguments {
|
struct function_arguments {
|
||||||
std::tuple<Ps...> params;
|
std::tuple<Ps...> params;
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
function_arguments(Args&&... args) : params(std::forward<Args>(args)...) {}
|
function_arguments(Args&&... args) : params(std::forward<Args>(args)...) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Sig = function_sig<>, typename... Args>
|
template <typename Sig = function_sig<>, typename... Args>
|
||||||
function_arguments<Sig, Args...> function_args( Args&&... args ) {
|
function_arguments<Sig, Args...> function_args(Args&&... args) {
|
||||||
return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
|
return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace stack {
|
namespace stack {
|
||||||
template<typename... Sigs>
|
template<typename... Sigs>
|
||||||
struct pusher<function_sig<Sigs...>> {
|
struct pusher<function_sig<Sigs...>> {
|
||||||
template <typename... Sig, typename Fx, typename... Args>
|
template <typename... Sig, typename Fx, typename... Args>
|
||||||
static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
||||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::functor_function<clean_fx>>(std::forward<Fx>(fx), std::forward<Args>(args)...);
|
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::functor_function<clean_fx>>(std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
set_fx(L, std::move(sptr));
|
set_fx(L, std::move(sptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R, typename... A, typename Fx, typename... Args>
|
template <typename R, typename... A, typename Fx, typename... Args>
|
||||||
static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
using fx_ptr_t = R(*)(A...);
|
using fx_ptr_t = R(*)(A...);
|
||||||
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
|
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
|
||||||
select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...);
|
select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R, typename... A, typename Fx, typename... Args>
|
template <typename R, typename... A, typename Fx, typename... Args>
|
||||||
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
typedef std::decay_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> raw_fx_t;
|
typedef std::decay_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> raw_fx_t;
|
||||||
typedef R(* fx_ptr_t)(A...);
|
typedef R(*fx_ptr_t)(A...);
|
||||||
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
|
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
|
||||||
select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
template <typename Fx, typename... Args>
|
||||||
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
typedef meta::function_signature_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> Sig;
|
typedef meta::function_signature_t<meta::unwrapped_t<meta::unqualified_t<Fx>>> Sig;
|
||||||
select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename T, typename... Args>
|
template <typename Fx, typename T, typename... Args>
|
||||||
static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
||||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_variable<meta::unqualified_t<T>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)... );
|
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_variable<meta::unqualified_t<T>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
||||||
set_fx(L, std::move(sptr));
|
set_fx(L, std::move(sptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename T, typename... Args>
|
template <typename Fx, typename T, typename... Args>
|
||||||
static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||||
typedef std::decay_t<Fx> dFx;
|
typedef std::decay_t<Fx> dFx;
|
||||||
dFx memfxptr(std::forward<Fx>(fx));
|
dFx memfxptr(std::forward<Fx>(fx));
|
||||||
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
|
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
|
||||||
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
|
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
|
||||||
|
|
||||||
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
||||||
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
|
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
|
||||||
stack::push(L, c_closure(freefunc, upvalues));
|
stack::push(L, c_closure(freefunc, upvalues));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
template <typename Fx, typename... Args>
|
||||||
static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename T, typename... Args>
|
template <typename Fx, typename T, typename... Args>
|
||||||
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||||
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
|
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
|
||||||
select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx>
|
template <typename Fx>
|
||||||
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
|
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
|
||||||
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
|
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
|
||||||
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
|
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
|
||||||
int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
|
int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
|
||||||
stack::push(L, c_closure(freefunc, upvalues));
|
stack::push(L, c_closure(freefunc, upvalues));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename T, typename... Args>
|
template <typename Fx, typename T, typename... Args>
|
||||||
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
||||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_function<meta::unwrapped_t<meta::unqualified_t<T>>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)... );
|
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_function<meta::unwrapped_t<meta::unqualified_t<T>>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
||||||
set_fx(L, std::move(sptr));
|
set_fx(L, std::move(sptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename T, typename... Args>
|
template <typename Fx, typename T, typename... Args>
|
||||||
static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||||
typedef std::decay_t<Fx> dFx;
|
typedef std::decay_t<Fx> dFx;
|
||||||
dFx memfxptr(std::forward<Fx>(fx));
|
dFx memfxptr(std::forward<Fx>(fx));
|
||||||
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
|
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
|
||||||
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
|
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
|
||||||
|
|
||||||
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
||||||
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
|
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
|
||||||
stack::push(L, c_closure(freefunc, upvalues));
|
stack::push(L, c_closure(freefunc, upvalues));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
template <typename Fx, typename... Args>
|
||||||
static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
select_member_variable(std::is_member_object_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
select_member_variable(std::is_member_object_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename T, typename... Args>
|
template <typename Fx, typename T, typename... Args>
|
||||||
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||||
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
|
typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
|
||||||
select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx>
|
template <typename Fx>
|
||||||
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
|
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
|
||||||
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
|
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
|
||||||
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
|
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
|
||||||
int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
|
int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
|
||||||
stack::push(L, c_closure(freefunc, upvalues));
|
stack::push(L, c_closure(freefunc, upvalues));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
template <typename Fx, typename... Args>
|
||||||
static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
select_member_function(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
select_member_function(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
template <typename Fx, typename... Args>
|
||||||
static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
|
static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
|
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
|
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
|
||||||
|
|
||||||
int upvalues = stack::stack_detail::push_as_upvalues(L, target);
|
int upvalues = stack::stack_detail::push_as_upvalues(L, target);
|
||||||
stack::push(L, c_closure(freefunc, upvalues));
|
stack::push(L, c_closure(freefunc, upvalues));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
|
static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
|
||||||
stack::push(L, f);
|
stack::push(L, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
template <typename Fx, typename... Args>
|
||||||
static void select(lua_State* L, Fx&& fx, Args&&... args) {
|
static void select(lua_State* L, Fx&& fx, Args&&... args) {
|
||||||
select_function(std::is_function<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
select_function(std::is_function<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) {
|
static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) {
|
||||||
function_detail::base_function* target = luafunc.release();
|
function_detail::base_function* target = luafunc.release();
|
||||||
void* targetdata = static_cast<void*>(target);
|
void* targetdata = static_cast<void*>(target);
|
||||||
lua_CFunction freefunc = function_detail::call;
|
lua_CFunction freefunc = function_detail::call;
|
||||||
|
|
||||||
stack::push(L, userdata_value(targetdata));
|
stack::push(L, userdata_value(targetdata));
|
||||||
function_detail::free_function_cleanup(L);
|
function_detail::free_function_cleanup(L);
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
stack::push(L, c_closure(freefunc, 1));
|
stack::push(L, c_closure(freefunc, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static int push(lua_State* L, Args&&... args) {
|
static int push(lua_State* L, Args&&... args) {
|
||||||
// Set will always place one thing (function) on the stack
|
// Set will always place one thing (function) on the stack
|
||||||
select(L, std::forward<Args>(args)...);
|
select(L, std::forward<Args>(args)...);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
struct pusher<function_arguments<T, Args...>> {
|
struct pusher<function_arguments<T, Args...>> {
|
||||||
template <std::size_t... I, typename FP>
|
template <std::size_t... I, typename FP>
|
||||||
static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {
|
static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {
|
||||||
return stack::push<T>(L, detail::forward_get<I>(fp.params)...);
|
return stack::push<T>(L, detail::forward_get<I>(fp.params)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FP>
|
template <typename FP>
|
||||||
static int push(lua_State* L, FP&& fp) {
|
static int push(lua_State* L, FP&& fp) {
|
||||||
return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<FP>(fp));
|
return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<FP>(fp));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct pusher<std::function<Signature>> {
|
struct pusher<std::function<Signature>> {
|
||||||
static int push(lua_State* L, std::function<Signature> fx) {
|
static int push(lua_State* L, std::function<Signature> fx) {
|
||||||
return pusher<function_sig<Signature>>{}.push(L, std::move(fx));
|
return pusher<function_sig<Signature>>{}.push(L, std::move(fx));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
|
struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
|
||||||
template <typename F>
|
template <typename F>
|
||||||
static int push(lua_State* L, F&& f) {
|
static int push(lua_State* L, F&& f) {
|
||||||
return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
|
return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct pusher<Signature, std::enable_if_t<meta::all<std::is_function<Signature>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>>::value>> {
|
struct pusher<Signature, std::enable_if_t<meta::all<std::is_function<Signature>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>>::value>> {
|
||||||
template <typename F>
|
template <typename F>
|
||||||
static int push(lua_State* L, F&& f) {
|
static int push(lua_State* L, F&& f) {
|
||||||
return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
|
return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Functions>
|
template<typename... Functions>
|
||||||
struct pusher<overload_set<Functions...>> {
|
struct pusher<overload_set<Functions...>> {
|
||||||
static int push(lua_State* L, overload_set<Functions...>&& set) {
|
static int push(lua_State* L, overload_set<Functions...>&& set) {
|
||||||
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(std::move(set.set)));
|
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(std::move(set.set)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int push(lua_State* L, const overload_set<Functions...>& set) {
|
static int push(lua_State* L, const overload_set<Functions...>& set) {
|
||||||
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(set.set));
|
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(set.set));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // stack
|
} // stack
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_FUNCTION_TYPES_HPP
|
#endif // SOL_FUNCTION_TYPES_HPP
|
||||||
|
|
|
@ -25,178 +25,178 @@
|
||||||
#include "stack.hpp"
|
#include "stack.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace function_detail {
|
namespace function_detail {
|
||||||
template<typename Function>
|
template<typename Function>
|
||||||
struct upvalue_free_function {
|
struct upvalue_free_function {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||||
typedef lua_bind_traits<function_type> traits_type;
|
typedef lua_bind_traits<function_type> traits_type;
|
||||||
|
|
||||||
static int real_call(lua_State* L) {
|
static int real_call(lua_State* L) {
|
||||||
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
|
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
|
||||||
function_type* fx = udata.first;
|
function_type* fx = udata.first;
|
||||||
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
|
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call (lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
return detail::static_trampoline<(&real_call)>(L);
|
return detail::static_trampoline<(&real_call)>(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()(lua_State* L) {
|
int operator()(lua_State* L) {
|
||||||
return call(L);
|
return call(L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename Function>
|
template<typename T, typename Function>
|
||||||
struct upvalue_member_function {
|
struct upvalue_member_function {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||||
typedef lua_bind_traits<function_type> traits_type;
|
typedef lua_bind_traits<function_type> traits_type;
|
||||||
|
|
||||||
static int real_call(lua_State* L) {
|
static int real_call(lua_State* L) {
|
||||||
// Layout:
|
// Layout:
|
||||||
// idx 1...n: verbatim data of member function pointer
|
// idx 1...n: verbatim data of member function pointer
|
||||||
// idx n + 1: is the object's void pointer
|
// idx n + 1: is the object's void pointer
|
||||||
// We don't need to store the size, because the other side is templated
|
// We don't need to store the size, because the other side is templated
|
||||||
// with the same member function pointer type
|
// with the same member function pointer type
|
||||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||||
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||||
function_type& memfx = memberdata.first;
|
function_type& memfx = memberdata.first;
|
||||||
auto& item = *objdata.first;
|
auto& item = *objdata.first;
|
||||||
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type {
|
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type {
|
||||||
return (item.*memfx)(std::forward<decltype(args)>(args)...);
|
return (item.*memfx)(std::forward<decltype(args)>(args)...);
|
||||||
};
|
};
|
||||||
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
|
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call (lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
return detail::static_trampoline<(&real_call)>(L);
|
return detail::static_trampoline<(&real_call)>(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()(lua_State* L) {
|
int operator()(lua_State* L) {
|
||||||
return call(L);
|
return call(L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int N, typename R, typename M, typename V>
|
template <int N, typename R, typename M, typename V>
|
||||||
int set_assignable(std::false_type, lua_State* L, M&, V&) {
|
int set_assignable(std::false_type, lua_State* L, M&, V&) {
|
||||||
lua_pop(L, N);
|
lua_pop(L, N);
|
||||||
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
|
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N, typename R, typename M, typename V>
|
template <int N, typename R, typename M, typename V>
|
||||||
int set_assignable(std::true_type, lua_State* L, M& mem, V& var) {
|
int set_assignable(std::true_type, lua_State* L, M& mem, V& var) {
|
||||||
(mem.*var) = stack::get<R>(L, N);
|
(mem.*var) = stack::get<R>(L, N);
|
||||||
lua_pop(L, N);
|
lua_pop(L, N);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N, typename R, typename M, typename V>
|
template <int N, typename R, typename M, typename V>
|
||||||
int set_variable(std::true_type, lua_State* L, M& mem, V& var) {
|
int set_variable(std::true_type, lua_State* L, M& mem, V& var) {
|
||||||
return set_assignable<N, R>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, mem, var);
|
return set_assignable<N, R>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, mem, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N, typename R, typename M, typename V>
|
template <int N, typename R, typename M, typename V>
|
||||||
int set_variable(std::false_type, lua_State* L, M&, V&) {
|
int set_variable(std::false_type, lua_State* L, M&, V&) {
|
||||||
lua_pop(L, N);
|
lua_pop(L, N);
|
||||||
return luaL_error(L, "sol: cannot write to a const variable");
|
return luaL_error(L, "sol: cannot write to a const variable");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Function>
|
template<typename T, typename Function>
|
||||||
struct upvalue_member_variable {
|
struct upvalue_member_variable {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||||
typedef lua_bind_traits<function_type> traits_type;
|
typedef lua_bind_traits<function_type> traits_type;
|
||||||
|
|
||||||
static int real_call(lua_State* L) {
|
static int real_call(lua_State* L) {
|
||||||
// Layout:
|
// Layout:
|
||||||
// idx 1...n: verbatim data of member variable pointer
|
// idx 1...n: verbatim data of member variable pointer
|
||||||
// idx n + 1: is the object's void pointer
|
// idx n + 1: is the object's void pointer
|
||||||
// We don't need to store the size, because the other side is templated
|
// We don't need to store the size, because the other side is templated
|
||||||
// with the same member function pointer type
|
// with the same member function pointer type
|
||||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||||
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||||
auto& mem = *objdata.first;
|
auto& mem = *objdata.first;
|
||||||
function_type& var = memberdata.first;
|
function_type& var = memberdata.first;
|
||||||
switch (lua_gettop(L)) {
|
switch (lua_gettop(L)) {
|
||||||
case 0:
|
case 0:
|
||||||
stack::push(L, (mem.*var));
|
stack::push(L, (mem.*var));
|
||||||
return 1;
|
return 1;
|
||||||
case 1:
|
case 1:
|
||||||
set_variable<1, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
|
set_variable<1, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call (lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
return detail::static_trampoline<(&real_call)>(L);
|
return detail::static_trampoline<(&real_call)>(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()(lua_State* L) {
|
int operator()(lua_State* L) {
|
||||||
return call(L);
|
return call(L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename Function>
|
template<typename T, typename Function>
|
||||||
struct upvalue_this_member_function {
|
struct upvalue_this_member_function {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||||
typedef lua_bind_traits<function_type> traits_type;
|
typedef lua_bind_traits<function_type> traits_type;
|
||||||
|
|
||||||
static int real_call(lua_State* L) {
|
static int real_call(lua_State* L) {
|
||||||
// Layout:
|
// Layout:
|
||||||
// idx 1...n: verbatim data of member variable pointer
|
// idx 1...n: verbatim data of member variable pointer
|
||||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||||
function_type& memfx = memberdata.first;
|
function_type& memfx = memberdata.first;
|
||||||
auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type {
|
auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type {
|
||||||
auto& item = stack::get<T>(L, 1);
|
auto& item = stack::get<T>(L, 1);
|
||||||
return (item.*memfx)(std::forward<decltype(args)>(args)...);
|
return (item.*memfx)(std::forward<decltype(args)>(args)...);
|
||||||
};
|
};
|
||||||
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 2, fx);
|
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 2, fx);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call (lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
return detail::static_trampoline<(&real_call)>(L);
|
return detail::static_trampoline<(&real_call)>(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()(lua_State* L) {
|
int operator()(lua_State* L) {
|
||||||
return call(L);
|
return call(L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename Function>
|
template<typename T, typename Function>
|
||||||
struct upvalue_this_member_variable {
|
struct upvalue_this_member_variable {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||||
typedef lua_bind_traits<function_type> traits_type;
|
typedef lua_bind_traits<function_type> traits_type;
|
||||||
|
|
||||||
static int real_call(lua_State* L) {
|
static int real_call(lua_State* L) {
|
||||||
// Layout:
|
// Layout:
|
||||||
// idx 1...n: verbatim data of member variable pointer
|
// idx 1...n: verbatim data of member variable pointer
|
||||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||||
auto& mem = stack::get<T>(L, 1);
|
auto& mem = stack::get<T>(L, 1);
|
||||||
function_type& var = memberdata.first;
|
function_type& var = memberdata.first;
|
||||||
switch (lua_gettop(L)) {
|
switch (lua_gettop(L)) {
|
||||||
case 1:
|
case 1:
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
stack::push(L, (mem.*var));
|
stack::push(L, (mem.*var));
|
||||||
return 1;
|
return 1;
|
||||||
case 2:
|
case 2:
|
||||||
set_variable<2, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
|
set_variable<2, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call (lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
return detail::static_trampoline<(&real_call)>(L);
|
return detail::static_trampoline<(&real_call)>(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()(lua_State* L) {
|
int operator()(lua_State* L) {
|
||||||
return call(L);
|
return call(L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // function_detail
|
} // function_detail
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_FUNCTION_TYPES_BASIC_HPP
|
#endif // SOL_FUNCTION_TYPES_BASIC_HPP
|
||||||
|
|
|
@ -27,91 +27,91 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace function_detail {
|
namespace function_detail {
|
||||||
inline decltype(auto) cleanup_key() {
|
inline decltype(auto) cleanup_key() {
|
||||||
const auto& name = u8"sol.ƒ.♲.🗑.(/¯◡ ‿ ◡)/¯ ~ ┻━┻ (ノ◕ヮ◕)ノ*:・゚✧";
|
const auto& name = u8"sol.ƒ.♲.🗑.(/¯◡ ‿ ◡)/¯ ~ ┻━┻ (ノ◕ヮ◕)ノ*:・゚✧";
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct base_function {
|
struct base_function {
|
||||||
virtual int operator()(lua_State* L) {
|
virtual int operator()(lua_State* L) {
|
||||||
return luaL_error(L, "sol: failure to call specialized wrapped C++ function from Lua");
|
return luaL_error(L, "sol: failure to call specialized wrapped C++ function from Lua");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~base_function() {}
|
virtual ~base_function() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int base_call(lua_State* L, void* inheritancedata) {
|
static int base_call(lua_State* L, void* inheritancedata) {
|
||||||
if (inheritancedata == nullptr) {
|
if (inheritancedata == nullptr) {
|
||||||
return luaL_error(L, "sol: call from Lua to C++ function has null data");
|
return luaL_error(L, "sol: call from Lua to C++ function has null data");
|
||||||
}
|
}
|
||||||
|
|
||||||
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
||||||
base_function& fx = *pfx;
|
base_function& fx = *pfx;
|
||||||
return detail::trampoline(L, fx);
|
return detail::trampoline(L, fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int base_gc(lua_State* L, void* udata) {
|
static int base_gc(lua_State* L, void* udata) {
|
||||||
if (udata == nullptr) {
|
if (udata == nullptr) {
|
||||||
return luaL_error(L, "sol: call from lua to C++ gc function with null data");
|
return luaL_error(L, "sol: call from lua to C++ gc function with null data");
|
||||||
}
|
}
|
||||||
|
|
||||||
base_function* ptr = static_cast<base_function*>(udata);
|
base_function* ptr = static_cast<base_function*>(udata);
|
||||||
std::default_delete<base_function> dx{};
|
std::default_delete<base_function> dx{};
|
||||||
dx(ptr);
|
dx(ptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t limit>
|
template <std::size_t limit>
|
||||||
static void func_gc(std::true_type, lua_State*) {
|
static void func_gc(std::true_type, lua_State*) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t limit>
|
template <std::size_t limit>
|
||||||
static void func_gc(std::false_type, lua_State* L) {
|
static void func_gc(std::false_type, lua_State* L) {
|
||||||
for (std::size_t i = 0; i < limit; ++i) {
|
for (std::size_t i = 0; i < limit; ++i) {
|
||||||
void* value = stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(i + 1)));
|
void* value = stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(i + 1)));
|
||||||
if (value == nullptr)
|
if (value == nullptr)
|
||||||
continue;
|
continue;
|
||||||
base_function* obj = static_cast<base_function*>(value);
|
base_function* obj = static_cast<base_function*>(value);
|
||||||
std::allocator<base_function> alloc{};
|
std::allocator<base_function> alloc{};
|
||||||
alloc.destroy(obj);
|
alloc.destroy(obj);
|
||||||
alloc.deallocate(obj, 1);
|
alloc.deallocate(obj, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int call(lua_State* L) {
|
inline int call(lua_State* L) {
|
||||||
void* ludata = stack::get<lightuserdata_value>(L, up_value_index(1));
|
void* ludata = stack::get<lightuserdata_value>(L, up_value_index(1));
|
||||||
void** pinheritancedata = static_cast<void**>(ludata);
|
void** pinheritancedata = static_cast<void**>(ludata);
|
||||||
return base_call(L, *pinheritancedata);
|
return base_call(L, *pinheritancedata);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int gc(lua_State* L) {
|
inline int gc(lua_State* L) {
|
||||||
void* udata = stack::get<userdata_value>(L, 1);
|
void* udata = stack::get<userdata_value>(L, 1);
|
||||||
void** pudata = static_cast<void**>(udata);
|
void** pudata = static_cast<void**>(udata);
|
||||||
return base_gc(L, *pudata);
|
return base_gc(L, *pudata);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
inline int usertype_call(lua_State* L) {
|
inline int usertype_call(lua_State* L) {
|
||||||
// Zero-based template parameter, but upvalues start at 1
|
// Zero-based template parameter, but upvalues start at 1
|
||||||
return base_call(L, stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(I + 1))));
|
return base_call(L, stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(I + 1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
inline int usertype_gc(lua_State* L) {
|
inline int usertype_gc(lua_State* L) {
|
||||||
func_gc<I>(meta::boolean<(I < 1)>(), L);
|
func_gc<I>(meta::boolean<(I < 1)>(), L);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void free_function_cleanup(lua_State* L) {
|
inline void free_function_cleanup(lua_State* L) {
|
||||||
const static char* metatablename = &cleanup_key()[0];
|
const static char* metatablename = &cleanup_key()[0];
|
||||||
int metapushed = luaL_newmetatable(L, metatablename);
|
int metapushed = luaL_newmetatable(L, metatablename);
|
||||||
if (metapushed == 1) {
|
if (metapushed == 1) {
|
||||||
stack::set_field(L, "__gc", function_detail::gc);
|
stack::set_field(L, "__gc", function_detail::gc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // function_detail
|
} // function_detail
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_FUNCTION_TYPES_CORE_HPP
|
#endif // SOL_FUNCTION_TYPES_CORE_HPP
|
||||||
|
|
|
@ -27,33 +27,33 @@
|
||||||
#include "function_types_core.hpp"
|
#include "function_types_core.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace function_detail {
|
namespace function_detail {
|
||||||
template <typename... Functions>
|
template <typename... Functions>
|
||||||
struct overloaded_function : base_function {
|
struct overloaded_function : base_function {
|
||||||
typedef std::tuple<Functions...> overload_list;
|
typedef std::tuple<Functions...> overload_list;
|
||||||
typedef std::make_index_sequence<sizeof...(Functions)> indices;
|
typedef std::make_index_sequence<sizeof...(Functions)> indices;
|
||||||
overload_list overloads;
|
overload_list overloads;
|
||||||
|
|
||||||
overloaded_function(overload_list set)
|
overloaded_function(overload_list set)
|
||||||
: overloads(std::move(set)) {}
|
: overloads(std::move(set)) {}
|
||||||
|
|
||||||
overloaded_function(Functions... fxs)
|
overloaded_function(Functions... fxs)
|
||||||
: overloads(fxs...) {
|
: overloads(fxs...) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||||
int call(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
|
int call(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
|
||||||
auto& func = std::get<I>(overloads);
|
auto& func = std::get<I>(overloads);
|
||||||
return stack::call_into_lua<0, false>(r, a, L, start, func);
|
return stack::call_into_lua<0, false>(r, a, L, start, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int operator()(lua_State* L) override {
|
virtual int operator()(lua_State* L) override {
|
||||||
auto mfx = [&](auto&&... args){ return this->call(std::forward<decltype(args)>(args)...); };
|
auto mfx = [&](auto&&... args) { return this->call(std::forward<decltype(args)>(args)...); };
|
||||||
return call_detail::overload_match<Functions...>(mfx, L, 1);
|
return call_detail::overload_match<Functions...>(mfx, L, 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // function_detail
|
} // function_detail
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_FUNCTION_TYPES_OVERLOAD_HPP
|
#endif // SOL_FUNCTION_TYPES_OVERLOAD_HPP
|
|
@ -142,13 +142,13 @@ namespace sol {
|
||||||
int make_regs(regs_t& l, int index, sol::call_construction, F&&, Args&&... args) {
|
int make_regs(regs_t& l, int index, sol::call_construction, F&&, Args&&... args) {
|
||||||
callconstructfunc = call<I + 1>;
|
callconstructfunc = call<I + 1>;
|
||||||
secondarymeta = true;
|
secondarymeta = true;
|
||||||
int endindex = make_regs<I + 2>(l, index + 1, std::forward<Args>(args)...);
|
int endindex = make_regs<I + 2>(l, index, std::forward<Args>(args)...);
|
||||||
return endindex;
|
return endindex;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t I = 0, typename... Bases, typename... Args>
|
template <std::size_t I = 0, typename... Bases, typename... Args>
|
||||||
int make_regs(regs_t& l, int index, base_classes_tag, bases<Bases...>, Args&&... args) {
|
int make_regs(regs_t& l, int index, base_classes_tag, bases<Bases...>, Args&&... args) {
|
||||||
int endindex = make_regs<I + 2>(l, index + 1, std::forward<Args>(args)...);
|
int endindex = make_regs<I + 2>(l, index, std::forward<Args>(args)...);
|
||||||
if (sizeof...(Bases) < 1) {
|
if (sizeof...(Bases) < 1) {
|
||||||
(void)detail::swallow{ 0, ((detail::has_derived<Bases>::value = false), 0)... };
|
(void)detail::swallow{ 0, ((detail::has_derived<Bases>::value = false), 0)... };
|
||||||
return endindex;
|
return endindex;
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
#include <sol.hpp>
|
#include <sol.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
#include "test_stack_guard.hpp"
|
#include "test_stack_guard.hpp"
|
||||||
|
|
||||||
std::string free_function() {
|
std::string free_function() {
|
||||||
|
@ -530,4 +534,22 @@ TEST_CASE("tables/operator[]-optional", "Test if proxies on tables can lazily ev
|
||||||
REQUIRE(present);
|
REQUIRE(present);
|
||||||
REQUIRE(non_nope3.value() == 35);
|
REQUIRE(non_nope3.value() == 35);
|
||||||
REQUIRE(non_nope4.value() == 35);
|
REQUIRE(non_nope4.value() == 35);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("tables/add", "Basic test to make sure the 'add' feature works") {
|
||||||
|
static const int sz = 120;
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
sol::table t = lua.create_table(sz, 0);
|
||||||
|
|
||||||
|
std::vector<int> bigvec( sz );
|
||||||
|
std::iota(bigvec.begin(), bigvec.end(), 1);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < bigvec.size(); ++i) {
|
||||||
|
t.add(bigvec[i]);
|
||||||
|
}
|
||||||
|
for (std::size_t i = 0; i < bigvec.size(); ++i) {
|
||||||
|
int val = t[i + 1];
|
||||||
|
REQUIRE(val == bigvec[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user