From 2788abb34e6656034c537f4a54dfbbe78915f158 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Wed, 10 Feb 2016 11:36:00 -0500 Subject: [PATCH] Overloading now works and there are tests to back it up. The codebase now relies on some C++14 features explicitly. --- README.md | 2 +- sol/function.hpp | 16 +- sol/function_types.hpp | 546 +------------------------------- sol/function_types_core.hpp | 269 ++++++++++++++++ sol/function_types_member.hpp | 109 +++++++ sol/function_types_overload.hpp | 210 ++++++++++++ sol/function_types_static.hpp | 100 ++++++ sol/function_types_usertype.hpp | 191 +++++++++++ sol/overload.hpp | 39 +++ sol/stack.hpp | 17 + sol/table_core.hpp | 7 +- sol/traits.hpp | 20 +- sol/usertype.hpp | 37 +-- tests.cpp | 78 +++++ 14 files changed, 1067 insertions(+), 574 deletions(-) create mode 100644 sol/function_types_core.hpp create mode 100644 sol/function_types_member.hpp create mode 100644 sol/function_types_overload.hpp create mode 100644 sol/function_types_static.hpp create mode 100644 sol/function_types_usertype.hpp create mode 100644 sol/overload.hpp diff --git a/README.md b/README.md index 956e4c9c..5f882f3b 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/sol/function.hpp b/sol/function.hpp index 3a2d9aaf..1fa1f765 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -302,7 +302,7 @@ struct pusher> { typedef std::decay_t dFx; typedef Unqualified uFx; dFx memfxptr(std::forward(fx)); - auto userptr = sol::detail::get_ptr(obj); + auto userptr = ptr(obj); void* userobjdata = static_cast(userptr); lua_CFunction freefunc = &static_member_function, uFx>::call; @@ -369,6 +369,20 @@ struct pusher> { } }; +template +struct pusher> { + template + static int push(indices, lua_State* L, Set&& set) { + pusher>{}.set_fx(L, std::make_unique>(std::get(set)...)); + return 1; + } + + template + static int push(lua_State* L, Set&& set) { + return push(build_indices(), L, std::forward(set)); + } +}; + template struct getter> { typedef function_traits fx_t; diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 780719d5..2a914738 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -22,546 +22,10 @@ #ifndef SOL_FUNCTION_TYPES_HPP #define SOL_FUNCTION_TYPES_HPP -#include "stack.hpp" -#include -#include - -namespace sol { -namespace detail { -struct ref_call_t {} const ref_call = ref_call_t{}; -template -struct implicit_wrapper { - T& item; - implicit_wrapper(T& item) : item(item) {} - operator T& () { - return item; - } - operator T* () { - return std::addressof(item); - } -}; - -template -struct function_packer : std::tuple { using std::tuple::tuple; }; - -template -function_packer function_pack( Args&&... args ) { - return function_packer(std::forward(args)...); -} - -template -struct functor { - typedef member_traits traits_type; - typedef typename traits_type::args_type args_type; - typedef typename traits_type::return_type return_type; - - T* item; - Func invocation; - - template - functor(Args&&... args): item(nullptr), invocation(std::forward(args)...) {} - - bool check () const { - return invocation != nullptr; - } - - template - void call(types, Args&&... args) { - T& member = *item; - (member.*invocation)(std::forward(args)...); - } - - template - Ret call(types, Args&&... args) { - T& member = *item; - return (member.*invocation)(std::forward(args)...); - } - - template - decltype(auto) operator()(Args&&... args) { - return this->call(types{}, std::forward(args)...); - } -}; - -template -struct functor::value>> { - typedef member_traits traits_type; - typedef typename traits_type::args_type args_type; - typedef typename traits_type::return_type return_type; - T* item; - Func invocation; - - template - functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} - - bool check () const { - return this->fx.invocation != nullptr; - } - - template - void call(types, Arg&& arg) { - T& member = *item; - (member.*invocation) = std::forward(arg); - } - - return_type call(types) { - T& member = *item; - return (member.*invocation); - } - - template - auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { - return this->call(types{}, std::forward(args)...); - } -}; - -template -struct functor::value || std::is_class::value>> { - typedef member_traits traits_type; - typedef remove_one_type args_type; - typedef typename traits_type::return_type return_type; - typedef std::conditional_t::value || std::is_class::value, Func, std::add_pointer_t> 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 - functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} - - bool check () const { - return this->check(std::is_function()); - } - - template - void call(types, Args&&... args) { - T& member = *item; - invocation(implicit_wrapper(member), std::forward(args)...); - } - - template - Ret call(types, Args&&... args) { - T& member = *item; - return invocation(implicit_wrapper(member), std::forward(args)...); - } - - template - auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { - return this->call(types{}, std::forward(args)...); - } -}; -} // detail - -template -struct static_function { - typedef std::remove_pointer_t> function_type; - typedef function_traits traits_type; - - template - static int typed_call(types tr, types ta, function_type* fx, lua_State* L) { - stack::call(L, 0, tr, ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return 0; - } - - template - static int typed_call(types, types ta, function_type* fx, lua_State* L) { - typedef return_type_t return_type; - decltype(auto) r = stack::call(L, 0, types(), ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return stack::push(L, std::forward(r)); - } - - static int call(lua_State* L) { - auto udata = stack::detail::get_as_upvalues(L); - function_type* fx = udata.first; - int r = typed_call(tuple_types(), typename traits_type::args_type(), fx, L); - return r; - } - - int operator()(lua_State* L) { - return call(L); - } -}; - -template -struct static_member_function { - typedef std::remove_pointer_t> function_type; - typedef function_traits traits_type; - - template - static int typed_call(types tr, types ta, T& item, function_type& ifx, lua_State* L) { - auto fx = [&item, &ifx](Args&&... args) -> void { (item.*ifx)(std::forward(args)...); }; - stack::call(L, 0, tr, ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return 0; - } - - template - static int typed_call(types tr, types ta, T& item, function_type& ifx, lua_State* L) { - auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward(args)...); }; - decltype(auto) r = stack::call(L, 0, tr, ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return stack::push(L, std::forward(r)); - } - - static int call(lua_State* L) { - auto memberdata = stack::detail::get_as_upvalues(L, 1); - auto objdata = stack::detail::get_as_upvalues(L, memberdata.second); - function_type& memfx = memberdata.first; - T& obj = *objdata.first; - int r = typed_call(tuple_types(), 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(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(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(udata); - std::default_delete dx{}; - dx(ptr); - return 0; - } - - static int call(lua_State* L) { - void** pinheritancedata = static_cast(stack::get(L, 1).value); - return base_call(L, *pinheritancedata); - } - - static int gc(lua_State* L) { - void** pudata = static_cast(stack::get(L, 1).value); - return base_gc(L, *pudata); - } - - template - struct usertype { - static int call(lua_State* L) { - // Zero-based template parameter, but upvalues start at 1 - return ref_base_call(L, stack::get(L, I + 1)); - } - - static int ref_call(lua_State* L) { - return ref_base_call(L, stack::get(L, I + 1)); - } - - template - static void func_gc (std::true_type, lua_State*) { - - } - - template - 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(L, static_cast(i + 1)); - base_function* obj = static_cast(up.value); - std::allocator alloc{}; - alloc.destroy(obj); - alloc.deallocate(obj, 1); - } - } - - static int gc(lua_State* L) { - func_gc(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 -struct functor_function : public base_function { - typedef decltype(&Function::operator()) function_type; - typedef function_return_t return_type; - typedef function_args_t args_type; - Function fx; - - template - functor_function(Args&&... args): fx(std::forward(args)...) {} - - template - int operator()(types r, types t, lua_State* L) { - stack::call(L, 0, r, t, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return 0; - } - - template - int operator()(types tr, types ta, lua_State* L) { - return_type r = stack::call(L, 0, tr, ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return stack::push(L, r); - } - - virtual int operator()(lua_State* L) override { - return (*this)(types(), args_type(), L); - } - - virtual int operator()(lua_State* L, detail::ref_call_t) override { - return (*this)(types(), args_type(), L); - } -}; - -template -struct member_function : public base_function { - typedef std::remove_pointer_t> function_type; - typedef function_return_t return_type; - typedef function_args_t args_type; - struct functor { - T member; - function_type invocation; - - template - functor(Tm&& m, Args&&... args): member(std::forward(m)), invocation(std::forward(args)...) {} - - template - return_type operator()(Args&&... args) { - auto& mem = unwrap(deref(member)); - return (mem.*invocation)(std::forward(args)...); - } - } fx; - - template - member_function(Tm&& m, Args&&... args): fx(std::forward(m), std::forward(args)...) {} - - template - int operator()(types tr, types ta, lua_State* L) { - stack::call(L, 0, tr, ta, fx); - return 0; - } - - template - int operator()(types tr, types ta, lua_State* L) { - decltype(auto) r = stack::call(L, 0, tr, ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return stack::push(L, std::forward(r)); - } - - virtual int operator()(lua_State* L) override { - return (*this)(tuple_types(), args_type(), L); - } - - virtual int operator()(lua_State* L, detail::ref_call_t) override { - return (*this)(tuple_types(), args_type(), L); - } -}; - -template -struct usertype_function_core : public base_function { - typedef std::remove_pointer_t T; - typedef std::remove_pointer_t> function_type; - typedef detail::functor 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 - usertype_function_core(Args&&... args): fx(std::forward(args)...) {} - - template> - std::enable_if_t::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(r)); - } - - template> - std::enable_if_t::value, int> push(lua_State* L, Return&& r) { - return stack::push(L, std::forward(r)); - } - - template - int operator()(types tr, types ta, lua_State* L) { - //static const std::size_t skew = static_cast(std::is_member_object_pointer::value); - stack::call(L, 0, tr, ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - return 0; - } - - template - int operator()(types tr, types ta, lua_State* L) { - decltype(auto) r = stack::call(L, 0, tr, ta, fx); - int nargs = static_cast(sizeof...(Args)); - lua_pop(L, nargs); - int pushcount = push(L, std::forward(r)); - return pushcount; - } -}; - -template -struct usertype_function : public usertype_function_core { - typedef usertype_function_core base_t; - typedef std::remove_pointer_t 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 - usertype_function(FxArgs&&... fxargs): base_t(std::forward(fxargs)...) {} - - int prelude(lua_State* L) { - this->fx.item = ptr(stack::get(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(*this)(tuple_types(), 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 -struct usertype_variable_function : public usertype_function_core { - typedef usertype_function_core base_t; - typedef std::remove_pointer_t 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 - usertype_variable_function(FxArgs&&... fxargs): base_t(std::forward(fxargs)...) {} - - int prelude(lua_State* L) { - this->fx.item = ptr(stack::get(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(*this)(tuple_types(), types<>(), L); - case 3: - return static_cast(*this)(tuple_types(), 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 -struct usertype_indexing_function : public usertype_function_core { - typedef usertype_function_core base_t; - typedef std::remove_pointer_t 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, bool>> functions; - - template - usertype_indexing_function(std::string name, FxArgs&&... fxargs): base_t(std::forward(fxargs)...), name(std::move(name)) {} - - int prelude(lua_State* L) { - std::string accessor = stack::get(L, 1 - lua_gettop(L)); - auto function = functions.find(accessor); - if(function != functions.end()) { - if(function->second.second) { - stack::push(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(L, 1)); - return static_cast(*this)(tuple_types(), 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 diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp new file mode 100644 index 00000000..463d3379 --- /dev/null +++ b/sol/function_types_core.hpp @@ -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 +#include + +namespace sol { +namespace detail { +struct ref_call_t {} const ref_call = ref_call_t{}; +template +struct implicit_wrapper { + T& item; + implicit_wrapper(T& item) : item(item) {} + operator T& () { + return item; + } + operator T* () { + return std::addressof(item); + } +}; + +template +struct function_packer : std::tuple { using std::tuple::tuple; }; + +template +function_packer function_pack( Args&&... args ) { + return function_packer(std::forward(args)...); +} + +inline bool check_types(types<>, indices<>, lua_State* L, int) { + return true; +} + +template +inline bool check_types(types, indices, lua_State* L, int start = 1) { + if (!stack::check(L, start + I, no_panic)) + return false; + + return check_types(types(), indices(), L, start); +} + +template +struct functor { + typedef member_traits traits_type; + typedef typename traits_type::args_type args_type; + typedef typename traits_type::return_type return_type; + + T* item; + Func invocation; + + template + functor(Args&&... args): item(nullptr), invocation(std::forward(args)...) {} + + bool check () const { + return invocation != nullptr; + } + + template + void call(types, Args&&... args) { + T& member = *item; + (member.*invocation)(std::forward(args)...); + } + + template + Ret call(types, Args&&... args) { + T& member = *item; + return (member.*invocation)(std::forward(args)...); + } + + template + decltype(auto) operator()(Args&&... args) { + return this->call(types{}, std::forward(args)...); + } +}; + +template +struct functor::value>> { + typedef member_traits traits_type; + typedef typename traits_type::args_type args_type; + typedef typename traits_type::return_type return_type; + T* item; + Func invocation; + + template + functor(Args&&... args): item(nullptr), invocation(std::forward(args)...) {} + + bool check () const { + return this->fx.invocation != nullptr; + } + + template + void call(types, Arg&& arg) { + T& member = *item; + (member.*invocation) = std::forward(arg); + } + + return_type call(types) { + T& member = *item; + return (member.*invocation); + } + + template + auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { + return this->call(types{}, std::forward(args)...); + } +}; + +template +struct functor::value || std::is_class::value>> { + typedef member_traits traits_type; + typedef remove_one_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::value || std::is_class::value, Func, std::add_pointer_t> function_type; + static_assert(std::is_base_of>, 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 + functor(Args&&... args): item(nullptr), invocation(std::forward(args)...) {} + + bool check () const { + return this->check(std::is_function()); + } + + template + void call(types, Args&&... args) { + T& member = *item; + invocation(implicit_wrapper(member), std::forward(args)...); + } + + template + Ret call(types, Args&&... args) { + T& member = *item; + return invocation(implicit_wrapper(member), std::forward(args)...); + } + + template + auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { + return this->call(types(), std::forward(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(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(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(udata); + std::default_delete dx{}; + dx(ptr); + return 0; + } + + static int call(lua_State* L) { + void** pinheritancedata = static_cast(stack::get(L, 1).value); + return base_call(L, *pinheritancedata); + } + + static int gc(lua_State* L) { + void** pudata = static_cast(stack::get(L, 1).value); + return base_gc(L, *pudata); + } + + template + struct usertype { + static int call(lua_State* L) { + // Zero-based template parameter, but upvalues start at 1 + return ref_base_call(L, stack::get(L, I + 1)); + } + + static int ref_call(lua_State* L) { + return ref_base_call(L, stack::get(L, I + 1)); + } + + template + static void func_gc (std::true_type, lua_State*) { + + } + + template + 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(L, static_cast(i + 1)); + base_function* obj = static_cast(up.value); + std::allocator alloc{}; + alloc.destroy(obj); + alloc.deallocate(obj, 1); + } + } + + static int gc(lua_State* L) { + func_gc(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 diff --git a/sol/function_types_member.hpp b/sol/function_types_member.hpp new file mode 100644 index 00000000..3ea8b6a8 --- /dev/null +++ b/sol/function_types_member.hpp @@ -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 +struct functor_function : public base_function { + typedef decltype(&Function::operator()) function_type; + typedef function_return_t return_type; + typedef function_args_t args_type; + Function fx; + + template + functor_function(Args&&... args): fx(std::forward(args)...) {} + + template + int operator()(types r, types t, lua_State* L) { + stack::call(L, 0, r, t, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return 0; + } + + template + int operator()(types tr, types ta, lua_State* L) { + return_type r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return stack::push(L, r); + } + + virtual int operator()(lua_State* L) override { + return (*this)(types(), args_type(), L); + } + + virtual int operator()(lua_State* L, detail::ref_call_t) override { + return (*this)(types(), args_type(), L); + } +}; + +template +struct member_function : public base_function { + typedef std::remove_pointer_t> function_type; + typedef function_return_t return_type; + typedef function_args_t args_type; + struct functor { + T member; + function_type invocation; + + template + functor(Tm&& m, Args&&... args): member(std::forward(m)), invocation(std::forward(args)...) {} + + template + return_type operator()(Args&&... args) { + auto& mem = unwrap(deref(member)); + return (mem.*invocation)(std::forward(args)...); + } + } fx; + + template + member_function(Tm&& m, Args&&... args): fx(std::forward(m), std::forward(args)...) {} + + template + int operator()(types tr, types ta, lua_State* L) { + stack::call(L, 0, tr, ta, fx); + return 0; + } + + template + int operator()(types tr, types ta, lua_State* L) { + decltype(auto) r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return stack::push(L, std::forward(r)); + } + + virtual int operator()(lua_State* L) override { + return (*this)(tuple_types(), args_type(), L); + } + + virtual int operator()(lua_State* L, detail::ref_call_t) override { + return (*this)(tuple_types(), args_type(), L); + } +}; +} // sol + +#endif // SOL_FUNCTION_TYPES_MEMBER_HPP diff --git a/sol/function_types_overload.hpp b/sol/function_types_overload.hpp new file mode 100644 index 00000000..1a07cb1b --- /dev/null +++ b/sol/function_types_overload.hpp @@ -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 +struct overloaded_function : base_function { + typedef std::tuple...> overloads_t; + overloads_t overloads; + + overloaded_function(Functions... fxs) + : overloads({ function_traits>::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 + int match_arity(lua_State* L, std::ptrdiff_t x, indices) { + // 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>, + // std::pair<3 - arity, std::tuple>, + // std::pair>, + // ... + //> + auto& package = std::get(overloads); + auto arity = package.first; + if (arity != x) { + return match_arity(L, x, indices()); + } + auto& func = package.second; + typedef Unqualified fx_t; + typedef tuple_types::return_type> return_type; + typedef typename function_traits::args_type args_type; + if (!detail::check_types(args_type(), args_type(), L)) { + return match_arity(L, x, indices()); + } + 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::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 +struct usertype_overloaded_function : base_function { + typedef std::tuple>...> overloads_t; + overloads_t overloads; + + usertype_overloaded_function(overload_set set) + : usertype_overloaded_function(build_indices(), set) {} + + template + usertype_overloaded_function(indices, overload_set set) + : usertype_overloaded_function(std::get(set)...) {} + + + usertype_overloaded_function(Functions... fxs) + : overloads({function_traits::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 + int match_arity(lua_State* L, std::ptrdiff_t x, indices) { + // TODO: + // propogate changes from above down here too when they get figured out + auto& package = std::get(overloads); + auto arity = package.first; + if (arity != x) { + return match_arity(L, x, indices()); + } + auto& func = package.second; + typedef Unqualified fx_t; + typedef tuple_types 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()); + } + func.item = ptr(stack::get(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::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 +struct usertype_indexing_function, T> : base_function { + typedef std::tuple>...> overloads_t; + overloads_t overloads; + std::string name; + std::unordered_map, bool>> functions; + + usertype_indexing_function(std::string name, overload_set set) + : usertype_indexing_function(build_indices(), std::move(name), set) {} + + template + usertype_indexing_function(indices, std::string name, overload_set set) + : usertype_indexing_function(std::move(name), std::get(set)...) {} + + usertype_indexing_function(std::string name, Functions... fxs) + : overloads({function_traits::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 + int match_arity(lua_State* L, std::ptrdiff_t x, indices) { + // TODO: + // propogate changes from above down here too when they get figured out + auto& package = std::get(overloads); + auto arity = package.first; + if (arity != x) { + return match_arity(L, x, indices()); + } + auto& func = package.second; + typedef Unqualified fx_t; + typedef tuple_types 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()); + } + func.item = ptr(stack::get(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::value>()); + } + + int prelude(lua_State* L) { + std::string accessor = stack::get(L, 1 - lua_gettop(L)); + auto function = functions.find(accessor); + if(function != functions.end()) { + if(function->second.second) { + stack::push(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 diff --git a/sol/function_types_static.hpp b/sol/function_types_static.hpp new file mode 100644 index 00000000..21a12465 --- /dev/null +++ b/sol/function_types_static.hpp @@ -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 +struct static_function { + typedef std::remove_pointer_t> function_type; + typedef function_traits traits_type; + + template + static int typed_call(types tr, types ta, function_type* fx, lua_State* L) { + stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return 0; + } + + template + static int typed_call(types, types ta, function_type* fx, lua_State* L) { + typedef return_type_t return_type; + decltype(auto) r = stack::call(L, 0, types(), ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return stack::push(L, std::forward(r)); + } + + static int call(lua_State* L) { + auto udata = stack::detail::get_as_upvalues(L); + function_type* fx = udata.first; + int r = typed_call(tuple_types(), typename traits_type::args_type(), fx, L); + return r; + } + + int operator()(lua_State* L) { + return call(L); + } +}; + +template +struct static_member_function { + typedef std::remove_pointer_t> function_type; + typedef function_traits traits_type; + + template + static int typed_call(types tr, types ta, T& item, function_type& ifx, lua_State* L) { + auto fx = [&item, &ifx](Args&&... args) -> void { (item.*ifx)(std::forward(args)...); }; + stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return 0; + } + + template + static int typed_call(types tr, types ta, T& item, function_type& ifx, lua_State* L) { + auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward(args)...); }; + decltype(auto) r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return stack::push(L, std::forward(r)); + } + + static int call(lua_State* L) { + auto memberdata = stack::detail::get_as_upvalues(L, 1); + auto objdata = stack::detail::get_as_upvalues(L, memberdata.second); + function_type& memfx = memberdata.first; + T& obj = *objdata.first; + int r = typed_call(tuple_types(), 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 diff --git a/sol/function_types_usertype.hpp b/sol/function_types_usertype.hpp new file mode 100644 index 00000000..5e6cb4f7 --- /dev/null +++ b/sol/function_types_usertype.hpp @@ -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 +struct usertype_function_core : public base_function { + typedef std::remove_pointer_t T; + typedef std::remove_pointer_t> function_type; + typedef detail::functor 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 + usertype_function_core(Args&&... args): fx(std::forward(args)...) {} + + template> + std::enable_if_t::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(r)); + } + + template> + std::enable_if_t::value, int> push(lua_State* L, Return&& r) { + return stack::push(L, std::forward(r)); + } + + template + int operator()(types tr, types ta, lua_State* L) { + //static const std::size_t skew = static_cast(std::is_member_object_pointer::value); + stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return 0; + } + + template + int operator()(types tr, types ta, lua_State* L) { + decltype(auto) r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + int pushcount = push(L, std::forward(r)); + return pushcount; + } +}; + +template +struct usertype_function : public usertype_function_core { + typedef usertype_function_core base_t; + typedef std::remove_pointer_t 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 + usertype_function(Args&&... args): base_t(std::forward(args)...) {} + + int prelude(lua_State* L) { + this->fx.item = ptr(stack::get(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(*this)(tuple_types(), 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 +struct usertype_variable_function : public usertype_function_core { + typedef usertype_function_core base_t; + typedef std::remove_pointer_t 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 + usertype_variable_function(Args&&... args): base_t(std::forward(args)...) {} + + int prelude(lua_State* L) { + this->fx.item = ptr(stack::get(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(*this)(tuple_types(), types<>(), L); + case 3: + return static_cast(*this)(tuple_types(), 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 +struct usertype_indexing_function : public usertype_function_core { + typedef usertype_function_core base_t; + typedef std::remove_pointer_t 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, bool>> functions; + + template + usertype_indexing_function(std::string name, Args&&... args): base_t(std::forward(args)...), name(std::move(name)) {} + + int prelude(lua_State* L) { + std::string accessor = stack::get(L, 1 - lua_gettop(L)); + auto function = functions.find(accessor); + if(function != functions.end()) { + if(function->second.second) { + stack::push(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(L, 1)); + return static_cast(*this)(tuple_types(), 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 diff --git a/sol/overload.hpp b/sol/overload.hpp new file mode 100644 index 00000000..ae2da711 --- /dev/null +++ b/sol/overload.hpp @@ -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 + +namespace sol { + template + struct overload_set : std::tuple { + using std::tuple::tuple; + }; + + template + decltype(auto) overload(Args&&... args) { + return overload_set(std::forward(args)...); + } +} + +#endif // SOL_OVERLOAD_HPP \ No newline at end of file diff --git a/sol/stack.hpp b/sol/stack.hpp index 0f4d8468..fcb3e648 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -27,6 +27,7 @@ #include "tuple.hpp" #include "traits.hpp" #include "usertype_traits.hpp" +#include "overload.hpp" #include #include #include @@ -627,6 +628,22 @@ inline void call(lua_State* L, types tr, types ta, Fx&& fx, FxArg call(L, 0, ta, tr, ta, std::forward(fx), std::forward(args)...); } +template +inline int typed_call(types tr, types ta, Fx&& fx, lua_State* L) { + stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return 0; +} + +template +inline int typed_call(types tr, types ta, Fx&& fx, lua_State* L) { + decltype(auto) r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + return stack::push(L, std::forward(r)); +} + inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) { if (sol::stack::get(L, 1) == type::table) { if (luaL_newmetatable(L, meta.c_str()) == 0) { diff --git a/sol/table_core.hpp b/sol/table_core.hpp index dab706fa..f60b0de4 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -212,7 +212,12 @@ private: set_resolved_function( std::forward( key ), std::forward( fx ) ); } - template + template, overload_set>> = 0> + void set_fx( types<>, Key&& key, Fx&& fx ) { + set(std::forward(key), std::forward(fx)); + } + + template, overload_set>> = 0> void set_fx( types<>, Key&& key, Fx&& fx ) { typedef Unwrapped> fx_t; typedef decltype( &fx_t::operator() ) Sig; diff --git a/sol/traits.hpp b/sol/traits.hpp index c60dd692..c82cedbb 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -197,7 +197,7 @@ template struct fx_traits { static const std::size_t arity = sizeof...(Args); static const bool is_member_function = true; - typedef std::tuple arg_tuple_type; + typedef std::tuple args_tuple_type; typedef types args_type; typedef R(T::* function_pointer_type)(Args...); typedef std::remove_pointer_t function_type; @@ -205,14 +205,14 @@ struct fx_traits { typedef R return_type; typedef std::remove_pointer_t signature_type; template - using arg = std::tuple_element_t; + using arg = std::tuple_element_t; }; template struct fx_traits { static const std::size_t arity = sizeof...(Args); static const bool is_member_function = true; - typedef std::tuple arg_tuple_type; + typedef std::tuple args_tuple_type; typedef types args_type; typedef R(T::* function_pointer_type)(Args...); typedef std::remove_pointer_t function_type; @@ -220,14 +220,14 @@ struct fx_traits { typedef R return_type; typedef std::remove_pointer_t signature_type; template - using arg = std::tuple_element_t; + using arg = std::tuple_element_t; }; template struct fx_traits { static const std::size_t arity = sizeof...(Args); static const bool is_member_function = false; - typedef std::tuple arg_tuple_type; + typedef std::tuple args_tuple_type; typedef types args_type; typedef R(function_type)(Args...); typedef R(*function_pointer_type)(Args...); @@ -235,14 +235,14 @@ struct fx_traits { typedef R return_type; typedef std::remove_pointer_t signature_type; template - using arg = std::tuple_element_t; + using arg = std::tuple_element_t; }; template struct fx_traits { static const std::size_t arity = sizeof...(Args); static const bool is_member_function = false; - typedef std::tuple arg_tuple_type; + typedef std::tuple args_tuple_type; typedef types args_type; typedef R(function_type)(Args...); typedef R(*function_pointer_type)(Args...); @@ -250,7 +250,7 @@ struct fx_traits { typedef R return_type; typedef std::remove_pointer_t signature_type; template - using arg = std::tuple_element_t; + using arg = std::tuple_element_t; }; } // detail @@ -280,14 +280,14 @@ struct member_traits { typedef Signature signature_type; static const bool is_member_function = false; static const std::size_t arity = 1; - typedef std::tuple arg_tuple_type; + typedef std::tuple args_tuple_type; typedef types 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 - using arg = std::tuple_element_t; + using arg = std::tuple_element_t; }; } // detail diff --git a/sol/usertype.hpp b/sol/usertype.hpp index 9c386460..712af3fc 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -32,13 +32,6 @@ #include namespace sol { -namespace detail { -template -inline std::unique_ptr make_unique(Args&&... args) { - return std::unique_ptr(new T(std::forward(args)...)); -} -} // detail - const std::array meta_variable_names = {{ "__index", "__newindex" @@ -121,7 +114,7 @@ private: } static int construct(lua_State* L) { - auto&& meta = usertype_traits::metatable; + const auto& meta = usertype_traits::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>("__index", nullptr); + auto idxptr = std::make_unique>("__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>("__newindex", nullptr); + auto idxptr = std::make_unique>("__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::value, "Any registered function must be part of the class"); typedef std::decay_t function_type; - indexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique>(func), false)); - newindexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique>(func), false)); + indexmetafunctions.emplace(funcname, std::make_pair(std::make_unique>(func), false)); + newindexmetafunctions.emplace(funcname, std::make_pair(std::make_unique>(func), false)); return false; } + template + std::unique_ptr make_function(const std::string&, overload_set func) { + return std::make_unique>(func); + } + template std::unique_ptr make_function(const std::string&, Ret(*func)(Arg, Args...)) { - typedef Unqualified Argu; + typedef Unqualified> Argu; static_assert(std::is_base_of::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type."); typedef std::decay_t function_type; return std::make_unique>(func); @@ -254,8 +252,7 @@ private: template std::unique_ptr make_function(const std::string&, Fx&& func) { typedef Unqualified Fxu; - typedef std::tuple_element_t<0, typename function_traits::arg_tuple_type> Arg; - typedef Unqualified Argu; + typedef Unqualified::arg<0>>> Argu; static_assert(std::is_base_of::value, "Any non-member-function must have a first argument which is covariant with the desired usertype."); typedef std::decay_t function_type; return std::make_unique>(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 ptr(nullptr); + std::unique_ptr baseptr(nullptr); if(indexmetamethod != meta_variable_names.end()) { - auto idxptr = detail::make_unique>(name, func); + auto idxptr = std::make_unique>(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(func)); + baseptr = make_function(funcname, std::forward(func)); } - metafunctions.emplace_back(std::move(ptr)); + metafunctions.emplace_back(std::move(baseptr)); metafunctiontable.push_back( { name.c_str(), &base_function::usertype::call } ); ptrmetafunctiontable.push_back( { name.c_str(), &base_function::usertype::ref_call } ); return true; diff --git a/tests.cpp b/tests.cpp index 570ad6b3..e28db93b 100644 --- a/tests.cpp +++ b/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", + "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')")); +}