mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Overloading now works and there are tests to back it up. The codebase now relies on some C++14 features explicitly.
This commit is contained in:
parent
9372b54b02
commit
2788abb34e
|
@ -3,7 +3,7 @@
|
|||
[![Build Status](https://travis-ci.org/Rapptz/sol.svg?branch=master)](https://travis-ci.org/Rapptz/sol)
|
||||
|
||||
Sol is a C++ library binding to Lua. It currently supports all Lua versions 5.1+ (LuaJIT 2.x included). Sol aims to be easy to use and easy to add to a project.
|
||||
At this time, the library is header-only for easy integration with projects.
|
||||
The library is header-only for easy integration with projects.
|
||||
|
||||
## Sneak Peek
|
||||
|
||||
|
|
|
@ -302,7 +302,7 @@ struct pusher<function_sig<Sigs...>> {
|
|||
typedef std::decay_t<Fx> dFx;
|
||||
typedef Unqualified<Fx> uFx;
|
||||
dFx memfxptr(std::forward<Fx>(fx));
|
||||
auto userptr = sol::detail::get_ptr(obj);
|
||||
auto userptr = ptr(obj);
|
||||
void* userobjdata = static_cast<void*>(userptr);
|
||||
lua_CFunction freefunc = &static_member_function<std::decay_t<decltype(*userptr)>, uFx>::call;
|
||||
|
||||
|
@ -369,6 +369,20 @@ struct pusher<std::function<Signature>> {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Functions>
|
||||
struct pusher<overload_set<Functions...>> {
|
||||
template<std::size_t... I, typename Set>
|
||||
static int push(indices<I...>, lua_State* L, Set&& set) {
|
||||
pusher<function_sig<>>{}.set_fx<Set>(L, std::make_unique<overloaded_function<Functions...>>(std::get<I>(set)...));
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename Set>
|
||||
static int push(lua_State* L, Set&& set) {
|
||||
return push(build_indices<sizeof...(Functions)>(), L, std::forward<Set>(set));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct getter<std::function<Signature>> {
|
||||
typedef function_traits<Signature> fx_t;
|
||||
|
|
|
@ -22,546 +22,10 @@
|
|||
#ifndef SOL_FUNCTION_TYPES_HPP
|
||||
#define SOL_FUNCTION_TYPES_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
struct ref_call_t {} const ref_call = ref_call_t{};
|
||||
template <typename T>
|
||||
struct implicit_wrapper {
|
||||
T& item;
|
||||
implicit_wrapper(T& item) : item(item) {}
|
||||
operator T& () {
|
||||
return item;
|
||||
}
|
||||
operator T* () {
|
||||
return std::addressof(item);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Sig, typename... Args>
|
||||
struct function_packer : std::tuple<Args...> { using std::tuple<Args...>::tuple; };
|
||||
|
||||
template <typename Sig, typename... Args>
|
||||
function_packer<Sig, Args...> function_pack( Args&&... args ) {
|
||||
return function_packer<Sig, Args...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T, typename Func, typename = void>
|
||||
struct functor {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
bool check () const {
|
||||
return invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
(member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return (member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
decltype(auto) operator()(Args&&... args) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::value>> {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->fx.invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename Arg>
|
||||
void call(types<return_type>, Arg&& arg) {
|
||||
T& member = *item;
|
||||
(member.*invocation) = std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
return_type call(types<return_type>) {
|
||||
T& member = *item;
|
||||
return (member.*invocation);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, std::enable_if_t<std::is_function<Func>::value || std::is_class<Func>::value>> {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef remove_one_type<typename traits_type::args_type> args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef std::conditional_t<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, std::add_pointer_t<Func>> function_type;
|
||||
T* item;
|
||||
function_type invocation;
|
||||
|
||||
private:
|
||||
bool check(std::false_type) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check(std::true_type) const {
|
||||
return this->invocation != nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename... FxArgs>
|
||||
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->check(std::is_function<Func>());
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
} // detail
|
||||
|
||||
template<typename Function>
|
||||
struct static_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef function_traits<function_type> traits_type;
|
||||
|
||||
template<typename... Args>
|
||||
static int typed_call(types<void> tr, types<Args...> ta, function_type* fx, lua_State* L) {
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
static int typed_call(types<Ret...>, types<Args...> ta, function_type* fx, lua_State* L) {
|
||||
typedef return_type_t<Ret...> return_type;
|
||||
decltype(auto) r = stack::call(L, 0, types<return_type>(), ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
auto udata = stack::detail::get_as_upvalues<function_type*>(L);
|
||||
function_type* fx = udata.first;
|
||||
int r = typed_call(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), fx, L);
|
||||
return r;
|
||||
}
|
||||
|
||||
int operator()(lua_State* L) {
|
||||
return call(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Function>
|
||||
struct static_member_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef function_traits<function_type> traits_type;
|
||||
|
||||
template<typename... Args>
|
||||
static int typed_call(types<void> tr, types<Args...> ta, T& item, function_type& ifx, lua_State* L) {
|
||||
auto fx = [&item, &ifx](Args&&... args) -> void { (item.*ifx)(std::forward<Args>(args)...); };
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
static int typed_call(types<Ret...> tr, types<Args...> ta, T& item, function_type& ifx, lua_State* L) {
|
||||
auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward<Args>(args)...); };
|
||||
decltype(auto) r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
auto memberdata = stack::detail::get_as_upvalues<function_type>(L, 1);
|
||||
auto objdata = stack::detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||
function_type& memfx = memberdata.first;
|
||||
T& obj = *objdata.first;
|
||||
int r = typed_call(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), obj, memfx, L);
|
||||
return r;
|
||||
}
|
||||
|
||||
int operator()(lua_State* L) {
|
||||
return call(L);
|
||||
}
|
||||
};
|
||||
|
||||
struct base_function {
|
||||
static int base_call(lua_State* L, void* inheritancedata) {
|
||||
if(inheritancedata == nullptr) {
|
||||
throw error("call from Lua to C++ function has null data");
|
||||
}
|
||||
|
||||
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
||||
base_function& fx = *pfx;
|
||||
int r = fx(L);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ref_base_call(lua_State* L, void* inheritancedata) {
|
||||
if(inheritancedata == nullptr) {
|
||||
throw error("call from Lua to C++ function has null data");
|
||||
}
|
||||
|
||||
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
||||
base_function& fx = *pfx;
|
||||
int r = fx(L, detail::ref_call);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int base_gc(lua_State*, void* udata) {
|
||||
if(udata == nullptr) {
|
||||
throw error("call from lua to C++ gc function with null data");
|
||||
}
|
||||
|
||||
base_function* ptr = static_cast<base_function*>(udata);
|
||||
std::default_delete<base_function> dx{};
|
||||
dx(ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
void** pinheritancedata = static_cast<void**>(stack::get<upvalue>(L, 1).value);
|
||||
return base_call(L, *pinheritancedata);
|
||||
}
|
||||
|
||||
static int gc(lua_State* L) {
|
||||
void** pudata = static_cast<void**>(stack::get<userdata>(L, 1).value);
|
||||
return base_gc(L, *pudata);
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
struct usertype {
|
||||
static int call(lua_State* L) {
|
||||
// Zero-based template parameter, but upvalues start at 1
|
||||
return ref_base_call(L, stack::get<upvalue>(L, I + 1));
|
||||
}
|
||||
|
||||
static int ref_call(lua_State* L) {
|
||||
return ref_base_call(L, stack::get<upvalue>(L, I + 1));
|
||||
}
|
||||
|
||||
template <std::size_t limit>
|
||||
static void func_gc (std::true_type, lua_State*) {
|
||||
|
||||
}
|
||||
|
||||
template <std::size_t limit>
|
||||
static void func_gc (std::false_type, lua_State* L) {
|
||||
// Shut up clang tautological error without throwing out std::size_t
|
||||
for(std::size_t i = 0; i < limit; ++i) {
|
||||
upvalue up = stack::get<upvalue>(L, static_cast<int>(i + 1));
|
||||
base_function* obj = static_cast<base_function*>(up.value);
|
||||
std::allocator<base_function> alloc{};
|
||||
alloc.destroy(obj);
|
||||
alloc.deallocate(obj, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int gc(lua_State* L) {
|
||||
func_gc<I>(Bool<(I < 1)>(), L);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
virtual int operator()(lua_State*) {
|
||||
throw error("failure to call specialized wrapped C++ function from Lua");
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State*, detail::ref_call_t) {
|
||||
throw error("failure to call reference specialized wrapped C++ function from Lua");
|
||||
}
|
||||
|
||||
virtual ~base_function() {}
|
||||
};
|
||||
|
||||
template<typename Function>
|
||||
struct functor_function : public base_function {
|
||||
typedef decltype(&Function::operator()) function_type;
|
||||
typedef function_return_t<function_type> return_type;
|
||||
typedef function_args_t<function_type> args_type;
|
||||
Function fx;
|
||||
|
||||
template<typename... Args>
|
||||
functor_function(Args&&... args): fx(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void> r, types<Args...> t, lua_State* L) {
|
||||
stack::call(L, 0, r, t, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
return_type r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, r);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return (*this)(types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return (*this)(types<return_type>(), args_type(), L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename T>
|
||||
struct member_function : public base_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef function_return_t<function_type> return_type;
|
||||
typedef function_args_t<function_type> args_type;
|
||||
struct functor {
|
||||
T member;
|
||||
function_type invocation;
|
||||
|
||||
template<typename Tm, typename... Args>
|
||||
functor(Tm&& m, Args&&... args): member(std::forward<Tm>(m)), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
return_type operator()(Args&&... args) {
|
||||
auto& mem = unwrap(deref(member));
|
||||
return (mem.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
} fx;
|
||||
|
||||
template<typename Tm, typename... Args>
|
||||
member_function(Tm&& m, Args&&... args): fx(std::forward<Tm>(m), std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void> tr, types<Args...> ta, lua_State* L) {
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
decltype(auto) r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return (*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return (*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_function_core : public base_function {
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef detail::functor<T, function_type> fx_t;
|
||||
typedef typename fx_t::traits_type traits_type;
|
||||
typedef typename fx_t::args_type args_type;
|
||||
typedef typename fx_t::return_type return_type;
|
||||
|
||||
fx_t fx;
|
||||
|
||||
template<typename... Args>
|
||||
usertype_function_core(Args&&... args): fx(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename Return, typename Raw = Unqualified<Return>>
|
||||
std::enable_if_t<std::is_same<T, Raw>::value, int> push(lua_State* L, Return&& r) {
|
||||
if(ptr(unwrap(r)) == fx.item) {
|
||||
// push nothing
|
||||
// note that pushing nothing with the ':'
|
||||
// syntax means we leave the instance of what
|
||||
// was pushed onto the stack by lua to do the
|
||||
// function call alone,
|
||||
// and naturally lua returns that.
|
||||
// It's an "easy" way to return *this,
|
||||
// without allocating an extra userdata, apparently!
|
||||
return 1;
|
||||
}
|
||||
return stack::push(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename Return, typename Raw = Unqualified<Return>>
|
||||
std::enable_if_t<!std::is_same<T, Raw>::value, int> push(lua_State* L, Return&& r) {
|
||||
return stack::push(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void> tr, types<Args...> ta, lua_State* L) {
|
||||
//static const std::size_t skew = static_cast<std::size_t>(std::is_member_object_pointer<function_type>::value);
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
decltype(auto) r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
int pushcount = push(L, std::forward<decltype(r)>(r));
|
||||
return pushcount;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
template<typename... FxArgs>
|
||||
usertype_function(FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
this->fx.item = ptr(stack::get<T>(L, 1));
|
||||
if(this->fx.item == nullptr) {
|
||||
throw error("userdata for function call is null: are you using the wrong syntax? (use item:function/variable(...) syntax)");
|
||||
}
|
||||
return static_cast<base_t&>(*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return prelude(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return prelude(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_variable_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
template<typename... FxArgs>
|
||||
usertype_variable_function(FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...) {}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
this->fx.item = ptr(stack::get<T>(L, 1));
|
||||
if(this->fx.item == nullptr) {
|
||||
throw error("userdata for member variable is null");
|
||||
}
|
||||
|
||||
int argcount = lua_gettop(L);
|
||||
switch(argcount) {
|
||||
case 2:
|
||||
return static_cast<base_t&>(*this)(tuple_types<return_type>(), types<>(), L);
|
||||
case 3:
|
||||
return static_cast<base_t&>(*this)(tuple_types<void>(), args_type(), L);
|
||||
default:
|
||||
throw error("cannot get/set userdata member variable with inappropriate number of arguments");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return prelude(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return prelude(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_indexing_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
std::string name;
|
||||
std::unordered_map<std::string, std::pair<std::unique_ptr<base_function>, bool>> functions;
|
||||
|
||||
template<typename... FxArgs>
|
||||
usertype_indexing_function(std::string name, FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...), name(std::move(name)) {}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
std::string accessor = stack::get<std::string>(L, 1 - lua_gettop(L));
|
||||
auto function = functions.find(accessor);
|
||||
if(function != functions.end()) {
|
||||
if(function->second.second) {
|
||||
stack::push<upvalue>(L, function->second.first.get());
|
||||
stack::push(L, &base_function::usertype<0>::ref_call, 1);
|
||||
return 1;
|
||||
}
|
||||
return (*function->second.first)(L, detail::ref_call);
|
||||
}
|
||||
if (!this->fx.check()) {
|
||||
throw error("invalid indexing \"" + accessor + "\" on type: " + name);
|
||||
}
|
||||
this->fx.item = ptr(stack::get<T>(L, 1));
|
||||
return static_cast<base_t&>(*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return prelude(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return prelude(L);
|
||||
}
|
||||
};
|
||||
|
||||
} // sol
|
||||
#include "function_types_core.hpp"
|
||||
#include "function_types_static.hpp"
|
||||
#include "function_types_member.hpp"
|
||||
#include "function_types_usertype.hpp"
|
||||
#include "function_types_overload.hpp"
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_HPP
|
||||
|
|
269
sol/function_types_core.hpp
Normal file
269
sol/function_types_core.hpp
Normal file
|
@ -0,0 +1,269 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz 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_FUNCTION_TYPES_CORE_HPP
|
||||
#define SOL_FUNCTION_TYPES_CORE_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
struct ref_call_t {} const ref_call = ref_call_t{};
|
||||
template <typename T>
|
||||
struct implicit_wrapper {
|
||||
T& item;
|
||||
implicit_wrapper(T& item) : item(item) {}
|
||||
operator T& () {
|
||||
return item;
|
||||
}
|
||||
operator T* () {
|
||||
return std::addressof(item);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Sig, typename... Args>
|
||||
struct function_packer : std::tuple<Args...> { using std::tuple<Args...>::tuple; };
|
||||
|
||||
template <typename Sig, typename... Args>
|
||||
function_packer<Sig, Args...> function_pack( Args&&... args ) {
|
||||
return function_packer<Sig, Args...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline bool check_types(types<>, indices<>, lua_State* L, int) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Arg, typename... Args, std::size_t I, std::size_t... In>
|
||||
inline bool check_types(types<Arg, Args...>, indices<I, In...>, lua_State* L, int start = 1) {
|
||||
if (!stack::check<Arg>(L, start + I, no_panic))
|
||||
return false;
|
||||
|
||||
return check_types(types<Args...>(), indices<In...>(), L, start);
|
||||
}
|
||||
|
||||
template<typename T, typename Func, typename = void>
|
||||
struct functor {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
bool check () const {
|
||||
return invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
(member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return (member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
decltype(auto) operator()(Args&&... args) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::value>> {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->fx.invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename Arg>
|
||||
void call(types<return_type>, Arg&& arg) {
|
||||
T& member = *item;
|
||||
(member.*invocation) = std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
return_type call(types<return_type>) {
|
||||
T& member = *item;
|
||||
return (member.*invocation);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, std::enable_if_t<std::is_function<Func>::value || std::is_class<Func>::value>> {
|
||||
typedef member_traits<Func> traits_type;
|
||||
typedef remove_one_type<typename traits_type::args_type> args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef std::tuple_element_t<0, typename traits_type::args_tuple_type> Arg0;
|
||||
typedef std::conditional_t<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, std::add_pointer_t<Func>> function_type;
|
||||
static_assert(std::is_base_of<Unqualified<std::remove_pointer_t<Arg0>>, T>::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type.");
|
||||
T* item;
|
||||
function_type invocation;
|
||||
|
||||
private:
|
||||
bool check(std::false_type) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check(std::true_type) const {
|
||||
return this->invocation != nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->check(std::is_function<Func>());
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>(), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
} // detail
|
||||
|
||||
struct base_function {
|
||||
static int base_call(lua_State* L, void* inheritancedata) {
|
||||
if(inheritancedata == nullptr) {
|
||||
throw error("call from Lua to C++ function has null data");
|
||||
}
|
||||
|
||||
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
||||
base_function& fx = *pfx;
|
||||
int r = fx(L);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ref_base_call(lua_State* L, void* inheritancedata) {
|
||||
if(inheritancedata == nullptr) {
|
||||
throw error("call from Lua to C++ function has null data");
|
||||
}
|
||||
|
||||
base_function* pfx = static_cast<base_function*>(inheritancedata);
|
||||
base_function& fx = *pfx;
|
||||
int r = fx(L, detail::ref_call);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int base_gc(lua_State*, void* udata) {
|
||||
if(udata == nullptr) {
|
||||
throw error("call from lua to C++ gc function with null data");
|
||||
}
|
||||
|
||||
base_function* ptr = static_cast<base_function*>(udata);
|
||||
std::default_delete<base_function> dx{};
|
||||
dx(ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
void** pinheritancedata = static_cast<void**>(stack::get<upvalue>(L, 1).value);
|
||||
return base_call(L, *pinheritancedata);
|
||||
}
|
||||
|
||||
static int gc(lua_State* L) {
|
||||
void** pudata = static_cast<void**>(stack::get<userdata>(L, 1).value);
|
||||
return base_gc(L, *pudata);
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
struct usertype {
|
||||
static int call(lua_State* L) {
|
||||
// Zero-based template parameter, but upvalues start at 1
|
||||
return ref_base_call(L, stack::get<upvalue>(L, I + 1));
|
||||
}
|
||||
|
||||
static int ref_call(lua_State* L) {
|
||||
return ref_base_call(L, stack::get<upvalue>(L, I + 1));
|
||||
}
|
||||
|
||||
template <std::size_t limit>
|
||||
static void func_gc (std::true_type, lua_State*) {
|
||||
|
||||
}
|
||||
|
||||
template <std::size_t limit>
|
||||
static void func_gc (std::false_type, lua_State* L) {
|
||||
// Shut up clang tautological error without throwing out std::size_t
|
||||
for(std::size_t i = 0; i < limit; ++i) {
|
||||
upvalue up = stack::get<upvalue>(L, static_cast<int>(i + 1));
|
||||
base_function* obj = static_cast<base_function*>(up.value);
|
||||
std::allocator<base_function> alloc{};
|
||||
alloc.destroy(obj);
|
||||
alloc.deallocate(obj, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int gc(lua_State* L) {
|
||||
func_gc<I>(Bool<(I < 1)>(), L);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
virtual int operator()(lua_State*) {
|
||||
throw error("failure to call specialized wrapped C++ function from Lua");
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State*, detail::ref_call_t) {
|
||||
throw error("failure to call reference specialized wrapped C++ function from Lua");
|
||||
}
|
||||
|
||||
virtual ~base_function() {}
|
||||
};
|
||||
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_CORE_HPP
|
109
sol/function_types_member.hpp
Normal file
109
sol/function_types_member.hpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz 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_FUNCTION_TYPES_MEMBER_HPP
|
||||
#define SOL_FUNCTION_TYPES_MEMBER_HPP
|
||||
|
||||
#include "function_types_core.hpp"
|
||||
|
||||
namespace sol {
|
||||
template<typename Function>
|
||||
struct functor_function : public base_function {
|
||||
typedef decltype(&Function::operator()) function_type;
|
||||
typedef function_return_t<function_type> return_type;
|
||||
typedef function_args_t<function_type> args_type;
|
||||
Function fx;
|
||||
|
||||
template<typename... Args>
|
||||
functor_function(Args&&... args): fx(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void> r, types<Args...> t, lua_State* L) {
|
||||
stack::call(L, 0, r, t, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
return_type r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, r);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return (*this)(types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return (*this)(types<return_type>(), args_type(), L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename T>
|
||||
struct member_function : public base_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef function_return_t<function_type> return_type;
|
||||
typedef function_args_t<function_type> args_type;
|
||||
struct functor {
|
||||
T member;
|
||||
function_type invocation;
|
||||
|
||||
template<typename Tm, typename... Args>
|
||||
functor(Tm&& m, Args&&... args): member(std::forward<Tm>(m)), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
return_type operator()(Args&&... args) {
|
||||
auto& mem = unwrap(deref(member));
|
||||
return (mem.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
} fx;
|
||||
|
||||
template<typename Tm, typename... Args>
|
||||
member_function(Tm&& m, Args&&... args): fx(std::forward<Tm>(m), std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void> tr, types<Args...> ta, lua_State* L) {
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
decltype(auto) r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return (*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return (*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
};
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_MEMBER_HPP
|
210
sol/function_types_overload.hpp
Normal file
210
sol/function_types_overload.hpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz 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_FUNCTION_TYPES_OVERLOAD_HPP
|
||||
#define SOL_FUNCTION_TYPES_OVERLOAD_HPP
|
||||
|
||||
#include "overload.hpp"
|
||||
#include "function_types_core.hpp"
|
||||
#include "function_types_usertype.hpp"
|
||||
|
||||
namespace sol {
|
||||
template <typename... Functions>
|
||||
struct overloaded_function : base_function {
|
||||
typedef std::tuple<std::pair<int, Functions>...> overloads_t;
|
||||
overloads_t overloads;
|
||||
|
||||
overloaded_function(Functions... fxs)
|
||||
: overloads({ function_traits<Unqualified<Functions>>::arity, fxs }...) {
|
||||
|
||||
}
|
||||
|
||||
int match_arity(lua_State* L, std::ptrdiff_t x, indices<>) {
|
||||
throw error("no matching function call takes this number of arguments");
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t... In>
|
||||
int match_arity(lua_State* L, std::ptrdiff_t x, indices<I, In...>) {
|
||||
// TODO:
|
||||
// when we get proper constexpr, search functions only within the specific
|
||||
// arity range, instead of all of them by using
|
||||
// std::tuple<
|
||||
// std::pair<1 - arity, std::tuple<func_arity_of_1_a, func_arity_of_1_b>>,
|
||||
// std::pair<3 - arity, std::tuple<func_arity_of_3>>,
|
||||
// std::pair<n - arity, std::tuple<func_arity_of_n, ...>>,
|
||||
// ...
|
||||
//>
|
||||
auto& package = std::get<I>(overloads);
|
||||
auto arity = package.first;
|
||||
if (arity != x) {
|
||||
return match_arity(L, x, indices<In...>());
|
||||
}
|
||||
auto& func = package.second;
|
||||
typedef Unqualified<decltype(func)> fx_t;
|
||||
typedef tuple_types<typename function_traits<fx_t>::return_type> return_type;
|
||||
typedef typename function_traits<fx_t>::args_type args_type;
|
||||
if (!detail::check_types(args_type(), args_type(), L)) {
|
||||
return match_arity(L, x, indices<In...>());
|
||||
}
|
||||
return stack::typed_call(return_type(), args_type(), func, L);
|
||||
}
|
||||
|
||||
int match_arity(lua_State* L) {
|
||||
std::ptrdiff_t x = lua_gettop(L);
|
||||
return match_arity(L, x, build_indices<std::tuple_size<overloads_t>::value>());
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return match_arity(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return match_arity(L);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename... Functions>
|
||||
struct usertype_overloaded_function : base_function {
|
||||
typedef std::tuple<std::pair<int, detail::functor<T, Functions>>...> overloads_t;
|
||||
overloads_t overloads;
|
||||
|
||||
usertype_overloaded_function(overload_set<Functions...> set)
|
||||
: usertype_overloaded_function(build_indices<sizeof...(Functions)>(), set) {}
|
||||
|
||||
template<std::size_t... In>
|
||||
usertype_overloaded_function(indices<In...>, overload_set<Functions...> set)
|
||||
: usertype_overloaded_function(std::get<In>(set)...) {}
|
||||
|
||||
|
||||
usertype_overloaded_function(Functions... fxs)
|
||||
: overloads({function_traits<Functions>::arity, fxs}...) {
|
||||
|
||||
}
|
||||
|
||||
int match_arity(lua_State* L, std::ptrdiff_t x, indices<>) {
|
||||
throw error("no matching function call takes this number of arguments");
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t... In>
|
||||
int match_arity(lua_State* L, std::ptrdiff_t x, indices<I, In...>) {
|
||||
// TODO:
|
||||
// propogate changes from above down here too when they get figured out
|
||||
auto& package = std::get<I>(overloads);
|
||||
auto arity = package.first;
|
||||
if (arity != x) {
|
||||
return match_arity(L, x, indices<In...>());
|
||||
}
|
||||
auto& func = package.second;
|
||||
typedef Unqualified<decltype(func)> fx_t;
|
||||
typedef tuple_types<typename fx_t::return_type> return_type;
|
||||
typedef typename fx_t::args_type args_type;
|
||||
if (!detail::check_types(args_type(), args_type(), L, 2)) {
|
||||
return match_arity(L, x, indices<In...>());
|
||||
}
|
||||
func.item = ptr(stack::get<T>(L, 1));
|
||||
return stack::typed_call(return_type(), args_type(), func, L);
|
||||
}
|
||||
|
||||
int match_arity(lua_State* L) {
|
||||
std::ptrdiff_t x = lua_gettop(L) - 1;
|
||||
return match_arity(L, x, build_indices<std::tuple_size<overloads_t>::value>());
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return match_arity(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return match_arity(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Functions, typename T>
|
||||
struct usertype_indexing_function<overload_set<Functions...>, T> : base_function {
|
||||
typedef std::tuple<std::pair<int, detail::functor<T, Functions>>...> overloads_t;
|
||||
overloads_t overloads;
|
||||
std::string name;
|
||||
std::unordered_map<std::string, std::pair<std::unique_ptr<base_function>, bool>> functions;
|
||||
|
||||
usertype_indexing_function(std::string name, overload_set<Functions...> set)
|
||||
: usertype_indexing_function(build_indices<sizeof...(Functions)>(), std::move(name), set) {}
|
||||
|
||||
template <std::size_t... In>
|
||||
usertype_indexing_function(indices<In...>, std::string name, overload_set<Functions...> set)
|
||||
: usertype_indexing_function(std::move(name), std::get<In>(set)...) {}
|
||||
|
||||
usertype_indexing_function(std::string name, Functions... fxs)
|
||||
: overloads({function_traits<Functions>::arity, fxs}...), name(std::move(name)) {}
|
||||
|
||||
int match_arity(lua_State* L, std::ptrdiff_t x, indices<>) {
|
||||
throw error("no matching function call takes this number of arguments");
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t... In>
|
||||
int match_arity(lua_State* L, std::ptrdiff_t x, indices<I, In...>) {
|
||||
// TODO:
|
||||
// propogate changes from above down here too when they get figured out
|
||||
auto& package = std::get<I>(overloads);
|
||||
auto arity = package.first;
|
||||
if (arity != x) {
|
||||
return match_arity(L, x, indices<In...>());
|
||||
}
|
||||
auto& func = package.second;
|
||||
typedef Unqualified<decltype(func)> fx_t;
|
||||
typedef tuple_types<typename fx_t::return_type> return_type;
|
||||
typedef typename fx_t::args_type args_type;
|
||||
if (!detail::check_types(args_type(), args_type(), L, 2)) {
|
||||
return match_arity(L, x, indices<In...>());
|
||||
}
|
||||
func.item = ptr(stack::get<T>(L, 1));
|
||||
return stack::typed_call(return_type(), args_type(), func, L);
|
||||
}
|
||||
|
||||
int match_arity(lua_State* L) {
|
||||
std::ptrdiff_t x = lua_gettop(L) - 1;
|
||||
return match_arity(L, x, build_indices<std::tuple_size<overloads_t>::value>());
|
||||
}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
std::string accessor = stack::get<std::string>(L, 1 - lua_gettop(L));
|
||||
auto function = functions.find(accessor);
|
||||
if(function != functions.end()) {
|
||||
if(function->second.second) {
|
||||
stack::push<upvalue>(L, function->second.first.get());
|
||||
stack::push(L, &base_function::usertype<0>::ref_call, 1);
|
||||
return 1;
|
||||
}
|
||||
return (*function->second.first)(L);
|
||||
}
|
||||
return match_arity(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return prelude(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return prelude(L);
|
||||
}
|
||||
};
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_OVERLOAD_HPP
|
100
sol/function_types_static.hpp
Normal file
100
sol/function_types_static.hpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz 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_FUNCTION_TYPES_STATIC_HPP
|
||||
#define SOL_FUNCTION_TYPES_STATIC_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
|
||||
namespace sol {
|
||||
template<typename Function>
|
||||
struct static_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef function_traits<function_type> traits_type;
|
||||
|
||||
template<typename... Args>
|
||||
static int typed_call(types<void> tr, types<Args...> ta, function_type* fx, lua_State* L) {
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
static int typed_call(types<Ret...>, types<Args...> ta, function_type* fx, lua_State* L) {
|
||||
typedef return_type_t<Ret...> return_type;
|
||||
decltype(auto) r = stack::call(L, 0, types<return_type>(), ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
auto udata = stack::detail::get_as_upvalues<function_type*>(L);
|
||||
function_type* fx = udata.first;
|
||||
int r = typed_call(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), fx, L);
|
||||
return r;
|
||||
}
|
||||
|
||||
int operator()(lua_State* L) {
|
||||
return call(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Function>
|
||||
struct static_member_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef function_traits<function_type> traits_type;
|
||||
|
||||
template<typename... Args>
|
||||
static int typed_call(types<void> tr, types<Args...> ta, T& item, function_type& ifx, lua_State* L) {
|
||||
auto fx = [&item, &ifx](Args&&... args) -> void { (item.*ifx)(std::forward<Args>(args)...); };
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
static int typed_call(types<Ret...> tr, types<Args...> ta, T& item, function_type& ifx, lua_State* L) {
|
||||
auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward<Args>(args)...); };
|
||||
decltype(auto) r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
static int call(lua_State* L) {
|
||||
auto memberdata = stack::detail::get_as_upvalues<function_type>(L, 1);
|
||||
auto objdata = stack::detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||
function_type& memfx = memberdata.first;
|
||||
T& obj = *objdata.first;
|
||||
int r = typed_call(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), obj, memfx, L);
|
||||
return r;
|
||||
}
|
||||
|
||||
int operator()(lua_State* L) {
|
||||
return call(L);
|
||||
}
|
||||
};
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_STATIC_HPP
|
191
sol/function_types_usertype.hpp
Normal file
191
sol/function_types_usertype.hpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz 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_FUNCTION_TYPES_USERTYPE_HPP
|
||||
#define SOL_FUNCTION_TYPES_USERTYPE_HPP
|
||||
|
||||
#include "overload.hpp"
|
||||
#include "function_types_core.hpp"
|
||||
|
||||
namespace sol {
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_function_core : public base_function {
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef detail::functor<T, function_type> fx_t;
|
||||
typedef typename fx_t::traits_type traits_type;
|
||||
typedef typename fx_t::args_type args_type;
|
||||
typedef typename fx_t::return_type return_type;
|
||||
|
||||
fx_t fx;
|
||||
|
||||
template<typename... Args>
|
||||
usertype_function_core(Args&&... args): fx(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename Return, typename Raw = Unqualified<Return>>
|
||||
std::enable_if_t<std::is_same<T, Raw>::value, int> push(lua_State* L, Return&& r) {
|
||||
if(ptr(unwrap(r)) == fx.item) {
|
||||
// push nothing
|
||||
// note that pushing nothing with the ':'
|
||||
// syntax means we leave the instance of what
|
||||
// was pushed onto the stack by lua to do the
|
||||
// function call alone,
|
||||
// and naturally lua returns that.
|
||||
// It's an "easy" way to return *this,
|
||||
// without allocating an extra userdata, apparently!
|
||||
return 1;
|
||||
}
|
||||
return stack::push(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename Return, typename Raw = Unqualified<Return>>
|
||||
std::enable_if_t<!std::is_same<T, Raw>::value, int> push(lua_State* L, Return&& r) {
|
||||
return stack::push(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
int operator()(types<void> tr, types<Args...> ta, lua_State* L) {
|
||||
//static const std::size_t skew = static_cast<std::size_t>(std::is_member_object_pointer<function_type>::value);
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, lua_State* L) {
|
||||
decltype(auto) r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
int pushcount = push(L, std::forward<decltype(r)>(r));
|
||||
return pushcount;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
template<typename... Args>
|
||||
usertype_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
this->fx.item = ptr(stack::get<T>(L, 1));
|
||||
if(this->fx.item == nullptr) {
|
||||
throw error("userdata for function call is null: are you using the wrong syntax? (use item:function/variable(...) syntax)");
|
||||
}
|
||||
return static_cast<base_t&>(*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return prelude(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return prelude(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_variable_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
template<typename... Args>
|
||||
usertype_variable_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
this->fx.item = ptr(stack::get<T>(L, 1));
|
||||
if(this->fx.item == nullptr) {
|
||||
throw error("userdata for member variable is null");
|
||||
}
|
||||
|
||||
int argcount = lua_gettop(L);
|
||||
switch(argcount) {
|
||||
case 2:
|
||||
return static_cast<base_t&>(*this)(tuple_types<return_type>(), types<>(), L);
|
||||
case 3:
|
||||
return static_cast<base_t&>(*this)(tuple_types<void>(), args_type(), L);
|
||||
default:
|
||||
throw error("cannot get/set userdata member variable with inappropriate number of arguments");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return prelude(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return prelude(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_indexing_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
|
||||
std::string name;
|
||||
std::unordered_map<std::string, std::pair<std::unique_ptr<base_function>, bool>> functions;
|
||||
|
||||
template<typename... Args>
|
||||
usertype_indexing_function(std::string name, Args&&... args): base_t(std::forward<Args>(args)...), name(std::move(name)) {}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
std::string accessor = stack::get<std::string>(L, 1 - lua_gettop(L));
|
||||
auto function = functions.find(accessor);
|
||||
if(function != functions.end()) {
|
||||
if(function->second.second) {
|
||||
stack::push<upvalue>(L, function->second.first.get());
|
||||
stack::push(L, &base_function::usertype<0>::ref_call, 1);
|
||||
return 1;
|
||||
}
|
||||
return (*function->second.first)(L);
|
||||
}
|
||||
if (!this->fx.check()) {
|
||||
throw error("invalid indexing \"" + accessor + "\" on type: " + name);
|
||||
}
|
||||
this->fx.item = ptr(stack::get<T>(L, 1));
|
||||
return static_cast<base_t&>(*this)(tuple_types<return_type>(), args_type(), L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
return prelude(L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L, detail::ref_call_t) override {
|
||||
return prelude(L);
|
||||
}
|
||||
};
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_USERTYPE_HPP
|
39
sol/overload.hpp
Normal file
39
sol/overload.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz 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_OVERLOAD_HPP
|
||||
#define SOL_OVERLOAD_HPP
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace sol {
|
||||
template <typename... Functions>
|
||||
struct overload_set : std::tuple<Functions...> {
|
||||
using std::tuple<Functions...>::tuple;
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
decltype(auto) overload(Args&&... args) {
|
||||
return overload_set<Args...>(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SOL_OVERLOAD_HPP
|
|
@ -27,6 +27,7 @@
|
|||
#include "tuple.hpp"
|
||||
#include "traits.hpp"
|
||||
#include "usertype_traits.hpp"
|
||||
#include "overload.hpp"
|
||||
#include <utility>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
@ -627,6 +628,22 @@ inline void call(lua_State* L, types<void> tr, types<Args...> ta, Fx&& fx, FxArg
|
|||
call<checkargs>(L, 0, ta, tr, ta, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args, typename Fx>
|
||||
inline int typed_call(types<void> tr, types<Args...> ta, Fx&& fx, lua_State* L) {
|
||||
stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args, typename Fx>
|
||||
inline int typed_call(types<Ret...> tr, types<Args...> ta, Fx&& fx, lua_State* L) {
|
||||
decltype(auto) r = stack::call(L, 0, tr, ta, fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return stack::push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
|
||||
if (sol::stack::get<type>(L, 1) == type::table) {
|
||||
if (luaL_newmetatable(L, meta.c_str()) == 0) {
|
||||
|
|
|
@ -212,7 +212,12 @@ private:
|
|||
set_resolved_function<R( Args... )>( std::forward<Key>( key ), std::forward<Fx>( fx ) );
|
||||
}
|
||||
|
||||
template<typename Fx, typename Key>
|
||||
template<typename Fx, typename Key, EnableIf<is_specialization_of<Unqualified<Fx>, overload_set>> = 0>
|
||||
void set_fx( types<>, Key&& key, Fx&& fx ) {
|
||||
set(std::forward<Key>(key), std::forward<Fx>(fx));
|
||||
}
|
||||
|
||||
template<typename Fx, typename Key, DisableIf<is_specialization_of<Unqualified<Fx>, overload_set>> = 0>
|
||||
void set_fx( types<>, Key&& key, Fx&& fx ) {
|
||||
typedef Unwrapped<Unqualified<Fx>> fx_t;
|
||||
typedef decltype( &fx_t::operator() ) Sig;
|
||||
|
|
|
@ -197,7 +197,7 @@ template<typename T, typename R, typename... Args>
|
|||
struct fx_traits<R(T::*)(Args...), false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = true;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
typedef std::tuple<Args...> args_tuple_type;
|
||||
typedef types<Args...> args_type;
|
||||
typedef R(T::* function_pointer_type)(Args...);
|
||||
typedef std::remove_pointer_t<function_pointer_type> function_type;
|
||||
|
@ -205,14 +205,14 @@ struct fx_traits<R(T::*)(Args...), false> {
|
|||
typedef R return_type;
|
||||
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
|
||||
template<std::size_t i>
|
||||
using arg = std::tuple_element_t<i, arg_tuple_type>;
|
||||
using arg = std::tuple_element_t<i, args_tuple_type>;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R(T::*)(Args...) const, false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = true;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
typedef std::tuple<Args...> args_tuple_type;
|
||||
typedef types<Args...> args_type;
|
||||
typedef R(T::* function_pointer_type)(Args...);
|
||||
typedef std::remove_pointer_t<function_pointer_type> function_type;
|
||||
|
@ -220,14 +220,14 @@ struct fx_traits<R(T::*)(Args...) const, false> {
|
|||
typedef R return_type;
|
||||
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
|
||||
template<std::size_t i>
|
||||
using arg = std::tuple_element_t<i, arg_tuple_type>;
|
||||
using arg = std::tuple_element_t<i, args_tuple_type>;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R(Args...), false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = false;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
typedef std::tuple<Args...> args_tuple_type;
|
||||
typedef types<Args...> args_type;
|
||||
typedef R(function_type)(Args...);
|
||||
typedef R(*function_pointer_type)(Args...);
|
||||
|
@ -235,14 +235,14 @@ struct fx_traits<R(Args...), false> {
|
|||
typedef R return_type;
|
||||
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
|
||||
template<std::size_t i>
|
||||
using arg = std::tuple_element_t<i, arg_tuple_type>;
|
||||
using arg = std::tuple_element_t<i, args_tuple_type>;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R(*)(Args...), false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = false;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
typedef std::tuple<Args...> args_tuple_type;
|
||||
typedef types<Args...> args_type;
|
||||
typedef R(function_type)(Args...);
|
||||
typedef R(*function_pointer_type)(Args...);
|
||||
|
@ -250,7 +250,7 @@ struct fx_traits<R(*)(Args...), false> {
|
|||
typedef R return_type;
|
||||
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
|
||||
template<std::size_t i>
|
||||
using arg = std::tuple_element_t<i, arg_tuple_type>;
|
||||
using arg = std::tuple_element_t<i, args_tuple_type>;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
@ -280,14 +280,14 @@ struct member_traits<Signature, true> {
|
|||
typedef Signature signature_type;
|
||||
static const bool is_member_function = false;
|
||||
static const std::size_t arity = 1;
|
||||
typedef std::tuple<Arg> arg_tuple_type;
|
||||
typedef std::tuple<Arg> args_tuple_type;
|
||||
typedef types<Arg> args_type;
|
||||
typedef R return_type;
|
||||
typedef R(function_type)(Arg);
|
||||
typedef R(*function_pointer_type)(Arg);
|
||||
typedef R(*free_function_pointer_type)(Arg);
|
||||
template<std::size_t i>
|
||||
using arg = std::tuple_element_t<i, arg_tuple_type>;
|
||||
using arg = std::tuple_element_t<i, args_tuple_type>;
|
||||
};
|
||||
} // detail
|
||||
|
||||
|
|
|
@ -32,13 +32,6 @@
|
|||
#include <algorithm>
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
template<typename T, typename... Args>
|
||||
inline std::unique_ptr<T> make_unique(Args&&... args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
} // detail
|
||||
|
||||
const std::array<std::string, 2> meta_variable_names = {{
|
||||
"__index",
|
||||
"__newindex"
|
||||
|
@ -121,7 +114,7 @@ private:
|
|||
}
|
||||
|
||||
static int construct(lua_State* L) {
|
||||
auto&& meta = usertype_traits<T>::metatable;
|
||||
const auto& meta = usertype_traits<T>::metatable;
|
||||
call_syntax syntax = stack::get_call_syntax(L, meta);
|
||||
int argcount = lua_gettop(L);
|
||||
|
||||
|
@ -164,7 +157,7 @@ private:
|
|||
int extracount = 0;
|
||||
if(!indexmetafunctions.empty()) {
|
||||
if(index == nullptr) {
|
||||
auto idxptr = detail::make_unique<usertype_indexing_function<void (T::*)(), T>>("__index", nullptr);
|
||||
auto idxptr = std::make_unique<usertype_indexing_function<void (T::*)(), T>>("__index", nullptr);
|
||||
index = &(idxptr->functions);
|
||||
functionnames.emplace_back("__index");
|
||||
metafunctions.emplace_back(std::move(idxptr));
|
||||
|
@ -180,7 +173,7 @@ private:
|
|||
}
|
||||
if(!newindexmetafunctions.empty()) {
|
||||
if(newindex == nullptr) {
|
||||
auto idxptr = detail::make_unique<usertype_indexing_function<void (T::*)(), T>>("__newindex", nullptr);
|
||||
auto idxptr = std::make_unique<usertype_indexing_function<void (T::*)(), T>>("__newindex", nullptr);
|
||||
newindex = &(idxptr->functions);
|
||||
functionnames.emplace_back("__newindex");
|
||||
metafunctions.emplace_back(std::move(idxptr));
|
||||
|
@ -218,14 +211,19 @@ private:
|
|||
bool build_function(std::true_type, function_map_t*&, function_map_t*&, std::string funcname, Ret Base::* func) {
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
|
||||
typedef std::decay_t<decltype(func)> function_type;
|
||||
indexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<usertype_variable_function<function_type, T>>(func), false));
|
||||
newindexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<usertype_variable_function<function_type, T>>(func), false));
|
||||
indexmetafunctions.emplace(funcname, std::make_pair(std::make_unique<usertype_variable_function<function_type, T>>(func), false));
|
||||
newindexmetafunctions.emplace(funcname, std::make_pair(std::make_unique<usertype_variable_function<function_type, T>>(func), false));
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename... Functions>
|
||||
std::unique_ptr<base_function> make_function(const std::string&, overload_set<Functions...> func) {
|
||||
return std::make_unique<usertype_overloaded_function<T, Functions...>>(func);
|
||||
}
|
||||
|
||||
template<typename Arg, typename... Args, typename Ret>
|
||||
std::unique_ptr<base_function> make_function(const std::string&, Ret(*func)(Arg, Args...)) {
|
||||
typedef Unqualified<Arg> Argu;
|
||||
typedef Unqualified<std::remove_pointer_t<Arg>> Argu;
|
||||
static_assert(std::is_base_of<Argu, T>::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type.");
|
||||
typedef std::decay_t<decltype(func)> function_type;
|
||||
return std::make_unique<usertype_function<function_type, T>>(func);
|
||||
|
@ -254,8 +252,7 @@ private:
|
|||
template<typename Fx>
|
||||
std::unique_ptr<base_function> make_function(const std::string&, Fx&& func) {
|
||||
typedef Unqualified<Fx> Fxu;
|
||||
typedef std::tuple_element_t<0, typename function_traits<Fxu>::arg_tuple_type> Arg;
|
||||
typedef Unqualified<Arg> Argu;
|
||||
typedef Unqualified<std::remove_pointer_t<function_traits<Fxu>::arg<0>>> Argu;
|
||||
static_assert(std::is_base_of<Argu, T>::value, "Any non-member-function must have a first argument which is covariant with the desired usertype.");
|
||||
typedef std::decay_t<Fxu> function_type;
|
||||
return std::make_unique<usertype_function<function_type, T>>(func);
|
||||
|
@ -269,9 +266,9 @@ private:
|
|||
functionnames.push_back(std::move(funcname));
|
||||
std::string& name = functionnames.back();
|
||||
auto indexmetamethod = std::find(meta_variable_names.begin(), meta_variable_names.end(), name);
|
||||
std::unique_ptr<base_function> ptr(nullptr);
|
||||
std::unique_ptr<base_function> baseptr(nullptr);
|
||||
if(indexmetamethod != meta_variable_names.end()) {
|
||||
auto idxptr = detail::make_unique<usertype_indexing_function<function_type, T>>(name, func);
|
||||
auto idxptr = std::make_unique<usertype_indexing_function<function_type, T>>(name, func);
|
||||
std::ptrdiff_t idxvalue = std::distance(meta_variable_names.begin(), indexmetamethod);
|
||||
switch(idxvalue) {
|
||||
case 0:
|
||||
|
@ -283,12 +280,12 @@ private:
|
|||
default:
|
||||
break;
|
||||
}
|
||||
ptr = std::move(idxptr);
|
||||
baseptr = std::move(idxptr);
|
||||
}
|
||||
else {
|
||||
ptr = make_function(funcname, std::forward<Fx>(func));
|
||||
baseptr = make_function(funcname, std::forward<Fx>(func));
|
||||
}
|
||||
metafunctions.emplace_back(std::move(ptr));
|
||||
metafunctions.emplace_back(std::move(baseptr));
|
||||
metafunctiontable.push_back( { name.c_str(), &base_function::usertype<N>::call } );
|
||||
ptrmetafunctiontable.push_back( { name.c_str(), &base_function::usertype<N>::ref_call } );
|
||||
return true;
|
||||
|
|
78
tests.cpp
78
tests.cpp
|
@ -85,6 +85,22 @@ struct self_test {
|
|||
}
|
||||
};
|
||||
|
||||
int func_1(int a) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string func_1s(std::string a) {
|
||||
return "string: " + a;
|
||||
}
|
||||
|
||||
int func_2(int a, int b) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
void func_3(int a, int b, int c) {
|
||||
|
||||
}
|
||||
|
||||
struct vars {
|
||||
vars () {
|
||||
|
||||
|
@ -1167,3 +1183,65 @@ TEST_CASE("usertype/destructor-tests", "Show that proper copies / destruction ha
|
|||
REQUIRE(destroyed == 4);
|
||||
REQUIRE(created == destroyed);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/overloading", "Check if overloading works properly for regular set function syntax") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("func_1", func_1);
|
||||
lua.set_function("func", sol::overload(func_1, func_1s, func_2, func_3));
|
||||
|
||||
const std::string string_bark = "string: bark";
|
||||
|
||||
REQUIRE_NOTHROW(lua.script(R"(
|
||||
a = func(1)
|
||||
b = func("bark")
|
||||
c = func(1,2)
|
||||
func(1,2,3)
|
||||
)"));
|
||||
|
||||
REQUIRE((lua["a"] == 1));
|
||||
REQUIRE((lua["b"] == string_bark));
|
||||
REQUIRE((lua["c"] == 2));
|
||||
|
||||
REQUIRE_THROWS(lua.script("func(1,2,'meow')"));
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/overloading", "Check if overloading works properly for usertypes") {
|
||||
struct woof {
|
||||
int var;
|
||||
|
||||
int func(int x) {
|
||||
return var + x;
|
||||
}
|
||||
|
||||
double func2(int x, int y) {
|
||||
return var + x + y + 0.5;
|
||||
}
|
||||
|
||||
std::string func2s(int x, std::string y) {
|
||||
return y + " " + std::to_string(x);
|
||||
}
|
||||
};
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<woof>("woof",
|
||||
"var", &woof::var,
|
||||
"func", sol::overload(&woof::func, &woof::func2, &woof::func2s)
|
||||
);
|
||||
|
||||
const std::string bark_58 = "bark 58";
|
||||
|
||||
REQUIRE_NOTHROW(lua.script(R"(
|
||||
r = woof:new()
|
||||
a = r:func(1)
|
||||
b = r:func(1, 2)
|
||||
c = r:func(58, "bark")
|
||||
)"));
|
||||
REQUIRE((lua["a"] == 1));
|
||||
REQUIRE((lua["b"] == 3.5));
|
||||
REQUIRE((lua["c"] == bark_58));
|
||||
|
||||
REQUIRE_THROWS(lua.script("r:func(1,2,'meow')"));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user