From 27174aba9c225d69166d40af1d63a71dd10483b5 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Thu, 7 Jul 2016 16:52:39 -0400 Subject: [PATCH] This mega-commit produces `simple_usertype` to allow for faster compile times by avoiding the use of `__index` internally. It sacrifices some speed and some storage optimizations and also does not allow variable syntax, but the produced table is directly modifiable. Adds a `protect()` function to trigger safety for an item. This commit also optimizes away all instances of virtual function calls for function calls and storage. Will need to test speed to see how it works out. Closes #133 Closes #134 Closes #135 Closes #136 --- .gitignore | 1 + sol/call.hpp | 114 +++++++------ sol/function_types.hpp | 77 ++++++--- sol/function_types_core.hpp | 79 +-------- sol/function_types_member.hpp | 155 ------------------ sol/function_types_overloaded.hpp | 8 +- sol/function_types_stateful.hpp | 139 ++++++++++++++++ ...basic.hpp => function_types_stateless.hpp} | 13 +- sol/overload.hpp | 2 +- sol/protect.hpp | 41 +++++ sol/raii.hpp | 5 + sol/simple_usertype_metatable.hpp | 142 ++++++++++++++++ sol/stack.hpp | 2 +- sol/stack_core.hpp | 6 +- sol/stack_push.hpp | 8 +- sol/state_view.hpp | 28 +++- sol/table_core.hpp | 20 +++ sol/types.hpp | 15 +- sol/usertype.hpp | 91 ++++------ sol/usertype_metatable.hpp | 38 ++++- test_functions.cpp | 2 +- test_simple_usertype.cpp | 85 ++++++++++ test_usertypes.cpp | 55 ++++++- 23 files changed, 735 insertions(+), 391 deletions(-) delete mode 100644 sol/function_types_member.hpp create mode 100644 sol/function_types_stateful.hpp rename sol/{function_types_basic.hpp => function_types_stateless.hpp} (93%) create mode 100644 sol/protect.hpp create mode 100644 sol/simple_usertype_metatable.hpp create mode 100644 test_simple_usertype.cpp diff --git a/.gitignore b/.gitignore index 28811ff0..8d1f1545 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,4 @@ single/sol.hpp lua53.dll main.exe main.o +lua-5.3.3/ diff --git a/sol/call.hpp b/sol/call.hpp index 9583ce9d..391abe35 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -22,6 +22,7 @@ #ifndef SOL_CALL_HPP #define SOL_CALL_HPP +#include "protect.hpp" #include "wrapper.hpp" #include "property.hpp" #include "stack.hpp" @@ -90,7 +91,7 @@ namespace sol { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } if (traits::free_arity != fxarity) { - return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } if (!stack::stack_detail::check_types().check(args_list(), args_indices(), L, start, no_panic)) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); @@ -111,7 +112,7 @@ namespace sol { } template - inline int construct(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + inline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { // use same overload resolution matching as all other parts of the framework return overload_match_arity::call)...>(std::forward(matchfx), L, fxarity, start, std::forward(args)...); } @@ -130,7 +131,7 @@ namespace sol { reference userdataref(L, -1); userdataref.pop(); - construct(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); + construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); userdataref.push(); luaL_getmetatable(L, &meta[0]); @@ -143,14 +144,14 @@ namespace sol { return 1; } - template + template struct agnostic_lua_call_wrapper { static int var_call(std::true_type, lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::returns_list returns_list; typedef typename wrap::free_args_list args_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f); + return stack::call_into_lua(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f); } static int var_call(std::false_type, lua_State* L, F& f) { @@ -158,7 +159,7 @@ namespace sol { typedef typename wrap::free_args_list args_list; typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; - return stack::call_into_lua(returns_list(), args_list(), L, 1, caller(), f); + return stack::call_into_lua<0, checked>(returns_list(), args_list(), L, 1, caller(), f); } static int call(lua_State* L, F& f) { @@ -166,78 +167,80 @@ namespace sol { } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_r_CFunction f) { return f(L); } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_CFunction f) { return f(L); } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_prop&) { return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property"); } }; - template - struct agnostic_lua_call_wrapper { + template + struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_construction&) { return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); } }; - template - struct agnostic_lua_call_wrapper, is_index, is_variable, C> { + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, C> { static int call(lua_State*, const bases&) { // Uh. How did you even call this, lul return 0; } }; - template - struct lua_call_wrapper : agnostic_lua_call_wrapper {}; + template + struct lua_call_wrapper : agnostic_lua_call_wrapper {}; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { static int call(lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::returns_list returns_list; typedef typename wrap::args_list args_list; typedef typename wrap::caller caller; typedef typename wrap::object_type object_type; + typedef std::conditional_t::value, object_type, T> Ta; #ifdef SOL_SAFE_USERTYPE - object_type* o = static_cast(stack::get(L, 1)); + object_type* o = static_cast(stack::get(L, 1)); if (o == nullptr) { return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)"); } - return stack::call_into_lua(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o); + return stack::call_into_lua(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o); #else - object_type& o = static_cast(stack::get(L, 1)); - return stack::call_into_lua(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o); + object_type& o = static_cast(stack::get(L, 1)); + return stack::call_into_lua(returns_list(), args_list(), L, is_variable ? 3 : 2, caller(), f, o); #endif // Safety } }; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef sol::lua_bind_traits traits_type; static int call_assign(std::true_type, lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::args_list args_list; typedef typename wrap::object_type object_type; + typedef std::conditional_t::value, object_type, T> Ta; typedef typename wrap::caller caller; #ifdef SOL_SAFE_USERTYPE - object_type* o = static_cast(stack::get(L, 1)); + object_type* o = static_cast(stack::get(L, 1)); if (o == nullptr) { if (is_variable) { return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)"); @@ -246,7 +249,7 @@ namespace sol { } return stack::call_into_lua(types(), args_list(), L, is_variable ? 3 : 2, caller(), f, *o); #else - object_type& o = static_cast(stack::get(L, 1)); + object_type& o = static_cast(stack::get(L, 1)); return stack::call_into_lua(types(), args_list(), L, is_variable ? 3 : 2, caller(), f, o); #endif // Safety } @@ -269,8 +272,8 @@ namespace sol { } }; - template - struct lua_call_wrapper::value>> { + template + struct lua_call_wrapper::value>> { typedef sol::lua_bind_traits traits_type; static int call(lua_State* L, F& f) { @@ -286,16 +289,16 @@ namespace sol { } return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)"); } - return stack::call_into_lua(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o); + return stack::call_into_lua(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, *o); #else object_type& o = static_cast(stack::get(L, 1)); - return stack::call_into_lua(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o); + return stack::call_into_lua(returns_list(), types<>(), L, is_variable ? 3 : 2, caller(), f, o); #endif // Safety } }; - template - struct lua_call_wrapper, is_index, is_variable, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, C> { typedef sol::constructor_list F; static int call(lua_State* L, F&) { @@ -310,7 +313,7 @@ namespace sol { T* obj = reinterpret_cast(pointerpointer + 1); referencepointer = obj; - construct(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); + construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); @@ -324,8 +327,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, C> { typedef sol::constructor_wrapper F; struct onmatch { @@ -339,7 +342,7 @@ namespace sol { referencepointer = obj; auto& func = std::get(f.set); - stack::call_into_lua<1, false>(r, a, L, start, func, detail::implicit_wrapper(obj)); + stack::call_into_lua<1, checked>(r, a, L, start, func, detail::implicit_wrapper(obj)); userdataref.push(); luaL_getmetatable(L, &metakey[0]); @@ -359,13 +362,13 @@ namespace sol { call_syntax syntax = stack::get_call_syntax(L, usertype_traits::metatable); int syntaxval = static_cast(syntax); int argcount = lua_gettop(L) - syntaxval; - return construct>...>(onmatch(), L, argcount, 1 + syntaxval, f); + return construct_match>...>(onmatch(), L, argcount, 1 + syntaxval, f); } }; - template - struct lua_call_wrapper, is_index, is_variable, std::enable_if_t::value>> { + template + struct lua_call_wrapper, is_index, is_variable, checked, std::enable_if_t::value>> { typedef sol::destructor_wrapper F; static int call(lua_State* L, const F&) { @@ -373,8 +376,8 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, std::enable_if_t::value>> { + template + struct lua_call_wrapper, is_index, is_variable, checked, std::enable_if_t::value>> { typedef sol::destructor_wrapper F; static int call(lua_State* L, const F& f) { @@ -384,15 +387,15 @@ namespace sol { } }; - template - struct lua_call_wrapper, is_index, is_variable, C> { + template + struct lua_call_wrapper, is_index, is_variable, checked, C> { typedef overload_set F; struct on_match { template int operator()(types, index_value, types, types, lua_State* L, int, int, F& fx) { auto& f = std::get(fx.set); - return lua_call_wrapper{}.call(L, f); + return lua_call_wrapper{}.call(L, f); } }; @@ -401,11 +404,26 @@ namespace sol { } }; + template + struct lua_call_wrapper, is_index, is_variable, checked, C> { + typedef protect_t F; + + static int call(lua_State* L, F& fx) { + return lua_call_wrapper{}.call(L, fx.value); + } + }; + template - int call_wrapped(lua_State* L, Fx&& fx) { + inline int call_wrapped(lua_State* L, Fx&& fx) { return lua_call_wrapper, is_index, is_variable>{}.call(L, std::forward(fx)); } + template + inline int call_user(lua_State* L) { + auto& fx = stack::get>(L, upvalue_index(1)); + return call_wrapped(L, fx); + } + template struct is_var_bind : std::false_type {}; @@ -428,4 +446,4 @@ namespace sol { } // sol -#endif // SOL_CALL_HPP \ No newline at end of file +#endif // SOL_CALL_HPP diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 767841bc..6927f605 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -24,8 +24,8 @@ #include "function_types_core.hpp" #include "function_types_templated.hpp" -#include "function_types_basic.hpp" -#include "function_types_member.hpp" +#include "function_types_stateless.hpp" +#include "function_types_stateful.hpp" #include "function_types_overloaded.hpp" #include "resolve.hpp" #include "call.hpp" @@ -44,13 +44,51 @@ namespace sol { } namespace stack { + template + struct pusher, std::enable_if_t::value && !std::is_void::value>> { + static int push(lua_State* L, property_wrapper pw) { + return stack::push(L, sol::overload(std::move(pw.read), std::move(pw.write))); + } + }; + + template + struct pusher> { + static int push(lua_State* L, property_wrapper pw) { + return stack::push(L, std::move(pw.read)); + } + }; + + template + struct pusher> { + static int push(lua_State* L, property_wrapper pw) { + return stack::push(L, std::move(pw.write)); + } + }; + + template + struct pusher>> { + static int push(lua_State* L, detail::constructors_for>) { + lua_CFunction cf = call_detail::construct; + return stack::push(L, cf); + } + }; + + template + struct pusher>> { + static int push(lua_State* L, constructor_wrapper c) { + lua_CFunction cf = call_detail::call_user; + int closures = stack::push(L, make_user(std::move(c))); + return stack::push(L, c_closure(cf, 1)); + } + }; + template struct pusher> { template static void select_convertible(std::false_type, types, lua_State* L, Fx&& fx, Args&&... args) { typedef std::remove_pointer_t> clean_fx; - std::unique_ptr sptr = std::make_unique>(std::forward(fx), std::forward(args)...); - set_fx(L, std::move(sptr)); + typedef function_detail::functor_function F; + set_fx(L, std::forward(fx), std::forward(args)...); } template @@ -62,7 +100,7 @@ namespace sol { template static void select_convertible(types t, lua_State* L, Fx&& fx, Args&&... args) { - typedef std::decay_t>> raw_fx_t; + typedef std::decay_t> raw_fx_t; typedef R(*fx_ptr_t)(A...); typedef std::is_convertible is_convertible; select_convertible(is_convertible(), t, L, std::forward(fx), std::forward(args)...); @@ -70,15 +108,15 @@ namespace sol { template static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { - typedef meta::function_signature_t>> Sig; + typedef meta::function_signature_t> Sig; select_convertible(types(), L, std::forward(fx), std::forward(args)...); } template static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::remove_pointer_t> clean_fx; - std::unique_ptr sptr = std::make_unique, clean_fx>>(std::forward(fx), std::forward(obj), std::forward(args)...); - set_fx(L, std::move(sptr)); + typedef function_detail::member_variable, clean_fx> F; + set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); } template @@ -114,9 +152,9 @@ namespace sol { template static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::remove_pointer_t> clean_fx; - std::unique_ptr sptr = std::make_unique>, clean_fx>>(std::forward(fx), std::forward(obj), std::forward(args)...); - set_fx(L, std::move(sptr)); + typedef std::decay_t clean_fx; + typedef function_detail::member_function, clean_fx> F; + set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); } template @@ -173,14 +211,11 @@ namespace sol { select_function(std::is_function>(), L, std::forward(fx), std::forward(args)...); } - static void set_fx(lua_State* L, std::unique_ptr luafunc) { - function_detail::base_function* target = luafunc.release(); - void* targetdata = static_cast(target); - lua_CFunction freefunc = function_detail::call; + template + static void set_fx(lua_State* L, Args&&... args) { + lua_CFunction freefunc = function_detail::call>; - stack::push(L, userdata_value(targetdata)); - function_detail::free_function_cleanup(L); - lua_setmetatable(L, -2); + stack::push>(L, std::forward(args)...); stack::push(L, c_closure(freefunc, 1)); } @@ -231,12 +266,14 @@ namespace sol { template struct pusher> { static int push(lua_State* L, overload_set&& set) { - pusher>{}.set_fx(L, std::make_unique>(std::move(set.set))); + typedef function_detail::overloaded_function F; + pusher>{}.set_fx(L, std::move(set.set)); return 1; } static int push(lua_State* L, const overload_set& set) { - pusher>{}.set_fx(L, std::make_unique>(set.set)); + typedef function_detail::overloaded_function F; + pusher>{}.set_fx(L, set.set); return 1; } }; diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index dcbbfb03..cc7cfbfb 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -33,83 +33,10 @@ namespace sol { return name; } - struct base_function { - virtual int operator()(lua_State* L) { - return luaL_error(L, "sol: failure to call specialized wrapped C++ function from Lua"); - } - - virtual ~base_function() {} - }; - - static int base_call(lua_State* L, void* inheritancedata) { - if (inheritancedata == nullptr) { - return luaL_error(L, "sol: call from Lua to C++ function has null data"); - } - - base_function* pfx = static_cast(inheritancedata); - base_function& fx = *pfx; - return detail::trampoline(L, fx); - } - - static int base_gc(lua_State* L, void* udata) { - if (udata == nullptr) { - return luaL_error(L, "sol: call from lua to C++ gc function with null data"); - } - - base_function* ptr = static_cast(udata); - std::default_delete dx{}; - dx(ptr); - return 0; - } - - template - static void func_gc(std::true_type, lua_State*) { - - } - - template - static void func_gc(std::false_type, lua_State* L) { - for (std::size_t i = 0; i < limit; ++i) { - void* value = stack::get(L, up_value_index(static_cast(i + 1))); - if (value == nullptr) - continue; - base_function* obj = static_cast(value); - std::allocator alloc{}; - alloc.destroy(obj); - alloc.deallocate(obj, 1); - } - } - + template inline int call(lua_State* L) { - void* ludata = stack::get(L, up_value_index(1)); - void** pinheritancedata = static_cast(ludata); - return base_call(L, *pinheritancedata); - } - - inline int gc(lua_State* L) { - void* udata = stack::get(L, 1); - void** pudata = static_cast(udata); - return base_gc(L, *pudata); - } - - template - inline int usertype_call(lua_State* L) { - // Zero-based template parameter, but upvalues start at 1 - return base_call(L, stack::get(L, up_value_index(static_cast(I + 1)))); - } - - template - inline int usertype_gc(lua_State* L) { - func_gc(meta::boolean<(I < 1)>(), L); - return 0; - } - - inline void free_function_cleanup(lua_State* L) { - const static char* metatablename = &cleanup_key()[0]; - int metapushed = luaL_newmetatable(L, metatablename); - if (metapushed == 1) { - stack::set_field(L, "__gc", function_detail::gc); - } + Fx& fx = stack::get>(L, upvalue_index(1)); + return fx(L); } } // function_detail } // sol diff --git a/sol/function_types_member.hpp b/sol/function_types_member.hpp deleted file mode 100644 index 27f85a36..00000000 --- a/sol/function_types_member.hpp +++ /dev/null @@ -1,155 +0,0 @@ -// The MIT License (MIT) - -// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// 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 { -namespace function_detail { -template -struct free_function : public base_function { - typedef meta::unwrapped_t> Function; - typedef meta::function_return_t return_type; - typedef meta::function_args_t args_lists; - Function fx; - - template - free_function(Args&&... args): fx(std::forward(args)...) {} - - int call(lua_State* L) { - return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); - } - - virtual int operator()(lua_State* L) override { - auto f = [&](lua_State* L) -> int { return this->call(L);}; - return detail::trampoline(L, f); - } -}; - -template -struct functor_function : public base_function { - typedef meta::unwrapped_t> Function; - typedef decltype(&Function::operator()) function_type; - typedef meta::function_return_t return_type; - typedef meta::function_args_t args_lists; - Function fx; - - template - functor_function(Args&&... args): fx(std::forward(args)...) {} - - int call(lua_State* L) { - return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); - } - - virtual int operator()(lua_State* L) override { - auto f = [&](lua_State* L) -> int { return this->call(L);}; - return detail::trampoline(L, f); - } -}; - -template -struct member_function : public base_function { - typedef std::remove_pointer_t> function_type; - typedef meta::function_return_t return_type; - typedef meta::function_args_t args_lists; - struct functor { - function_type invocation; - T member; - - template - functor(F&& f, Args&&... args): invocation(std::forward(f)), member(std::forward(args)...) {} - - template - return_type operator()(Args&&... args) { - auto& mem = detail::unwrap(detail::deref(member)); - return (mem.*invocation)(std::forward(args)...); - } - } fx; - - template - member_function(F&& f, Args&&... args) : fx(std::forward(f), std::forward(args)...) {} - - int call(lua_State* L) { - return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); - } - - virtual int operator()(lua_State* L) override { - auto f = [&](lua_State* L) -> int { return this->call(L);}; - return detail::trampoline(L, f); - } -}; - -template -struct member_variable : public base_function { - typedef std::remove_pointer_t> function_type; - typedef typename meta::bind_traits::return_type return_type; - typedef typename meta::bind_traits::args_list args_lists; - function_type var; - T member; - typedef std::add_lvalue_reference_t>> M; - - template - member_variable(V&& v, Args&&... args): var(std::forward(v)), member(std::forward(args)...) {} - - int set_assignable(std::false_type, lua_State* L, M) { - lua_pop(L, 1); - return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available"); - } - - int set_assignable(std::true_type, lua_State* L, M mem) { - (mem.*var) = stack::get(L, 1); - lua_pop(L, 1); - return 0; - } - - int set_variable(std::true_type, lua_State* L, M mem) { - return set_assignable(std::is_assignable, return_type>(), L, mem); - } - - int set_variable(std::false_type, lua_State* L, M) { - lua_pop(L, 1); - return luaL_error(L, "sol: cannot write to a const variable"); - } - - int call(lua_State* L) { - M mem = detail::unwrap(detail::deref(member)); - switch (lua_gettop(L)) { - case 0: - stack::push(L, (mem.*var)); - return 1; - case 1: - return set_variable(meta::neg>(), L, mem); - default: - return luaL_error(L, "sol: incorrect number of arguments to member variable function"); - } - } - - virtual int operator()(lua_State* L) override { - auto f = [&](lua_State* L) -> int { return this->call(L);}; - return detail::trampoline(L, f); - } -}; -} // function_detail -} // sol - -#endif // SOL_FUNCTION_TYPES_MEMBER_HPP diff --git a/sol/function_types_overloaded.hpp b/sol/function_types_overloaded.hpp index 257b4321..f38c4428 100644 --- a/sol/function_types_overloaded.hpp +++ b/sol/function_types_overloaded.hpp @@ -29,7 +29,7 @@ namespace sol { namespace function_detail { template - struct overloaded_function : base_function { + struct overloaded_function { typedef std::tuple overload_list; typedef std::make_index_sequence indices; overload_list overloads; @@ -43,12 +43,12 @@ namespace sol { } template - int call(types, index_value, types r, types a, lua_State* L, int, int start) { + int call(types, index_value, types, types, lua_State* L, int, int) { auto& func = std::get(overloads); - return stack::call_into_lua<0, false>(r, a, L, start, func); + return call_detail::call_wrapped(L, func); } - virtual int operator()(lua_State* L) override { + int operator()(lua_State* L) { auto mfx = [&](auto&&... args) { return this->call(std::forward(args)...); }; return call_detail::overload_match(mfx, L, 1); } diff --git a/sol/function_types_stateful.hpp b/sol/function_types_stateful.hpp new file mode 100644 index 00000000..a5b92a09 --- /dev/null +++ b/sol/function_types_stateful.hpp @@ -0,0 +1,139 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// 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_STATEFUL_HPP +#define SOL_FUNCTION_TYPES_STATEFUL_HPP + +#include "function_types_core.hpp" + +namespace sol { + namespace function_detail { + template + struct functor_function { + typedef meta::unwrapped_t> Function; + typedef decltype(&Function::operator()) function_type; + typedef meta::function_return_t return_type; + typedef meta::function_args_t args_lists; + Function fx; + + template + functor_function(Function f, Args&&... args) : fx(std::move(f), std::forward(args)...) {} + + int call(lua_State* L) { + return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); + } + + int operator()(lua_State* L) { + auto f = [&](lua_State* L) -> int { return this->call(L); }; + return detail::trampoline(L, f); + } + }; + + template + struct member_function { + typedef std::remove_pointer_t> function_type; + typedef meta::function_return_t return_type; + typedef meta::function_args_t args_lists; + struct functor { + function_type invocation; + T member; + + template + functor(function_type f, Args&&... args) : invocation(std::move(f)), member(std::forward(args)...) {} + + template + return_type operator()(Args&&... args) { + auto& mem = detail::unwrap(detail::deref(member)); + return (mem.*invocation)(std::forward(args)...); + } + } fx; + + template + member_function(function_type f, Args&&... args) : fx(std::move(f), std::forward(args)...) {} + + int call(lua_State* L) { + return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); + } + + int operator()(lua_State* L) { + auto f = [&](lua_State* L) -> int { return this->call(L); }; + return detail::trampoline(L, f); + } + + ~member_function() { + + } + }; + + template + struct member_variable { + typedef std::remove_pointer_t> function_type; + typedef typename meta::bind_traits::return_type return_type; + typedef typename meta::bind_traits::args_list args_lists; + function_type var; + T member; + typedef std::add_lvalue_reference_t>> M; + + template + member_variable(function_type v, Args&&... args) : var(std::move(v)), member(std::forward(args)...) {} + + int set_assignable(std::false_type, lua_State* L, M) { + lua_pop(L, 1); + return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available"); + } + + int set_assignable(std::true_type, lua_State* L, M mem) { + (mem.*var) = stack::get(L, 1); + lua_pop(L, 1); + return 0; + } + + int set_variable(std::true_type, lua_State* L, M mem) { + return set_assignable(std::is_assignable, return_type>(), L, mem); + } + + int set_variable(std::false_type, lua_State* L, M) { + lua_pop(L, 1); + return luaL_error(L, "sol: cannot write to a const variable"); + } + + int call(lua_State* L) { + M mem = detail::unwrap(detail::deref(member)); + switch (lua_gettop(L)) { + case 0: + stack::push(L, (mem.*var)); + return 1; + case 1: + return set_variable(meta::neg>(), L, mem); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + int operator()(lua_State* L) { + auto f = [&](lua_State* L) -> int { return this->call(L); }; + return detail::trampoline(L, f); + } + }; + } // function_detail +} // sol + +#endif // SOL_FUNCTION_TYPES_STATEFUL_HPP diff --git a/sol/function_types_basic.hpp b/sol/function_types_stateless.hpp similarity index 93% rename from sol/function_types_basic.hpp rename to sol/function_types_stateless.hpp index 67fd4c05..0b880975 100644 --- a/sol/function_types_basic.hpp +++ b/sol/function_types_stateless.hpp @@ -19,8 +19,8 @@ // 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_BASIC_HPP -#define SOL_FUNCTION_TYPES_BASIC_HPP +#ifndef SOL_FUNCTION_TYPES_STATELESS_HPP +#define SOL_FUNCTION_TYPES_STATELESS_HPP #include "stack.hpp" @@ -147,12 +147,7 @@ namespace sol { // idx 1...n: verbatim data of member variable pointer auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); function_type& memfx = memberdata.first; - auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type { - auto& item = stack::get(L, 1); - return (item.*memfx)(std::forward(args)...); - }; - int n = stack::call_into_lua<1>(meta::tuple_types(), typename traits_type::args_list(), L, 2, fx); - return n; + return call_detail::call_wrapped(L, memfx); } static int call(lua_State* L) { @@ -199,4 +194,4 @@ namespace sol { } // function_detail } // sol -#endif // SOL_FUNCTION_TYPES_BASIC_HPP +#endif // SOL_FUNCTION_TYPES_STATELESS_HPP diff --git a/sol/overload.hpp b/sol/overload.hpp index c0c5289f..54f723da 100644 --- a/sol/overload.hpp +++ b/sol/overload.hpp @@ -38,7 +38,7 @@ namespace sol { template decltype(auto) overload(Args&&... args) { - return overload_set(std::forward(args)...); + return overload_set...>(std::forward(args)...); } } diff --git a/sol/protect.hpp b/sol/protect.hpp new file mode 100644 index 00000000..b0509e7f --- /dev/null +++ b/sol/protect.hpp @@ -0,0 +1,41 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// 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_PROTECT_HPP +#define SOL_PROTECT_HPP + +#include + +namespace sol { + + template + struct protect_t { + T value; + }; + + template + auto protect(T&& value) { + return protect_t>{ std::forward(value) }; + } + +} // sol + +#endif // SOL_PROTECT_HPP diff --git a/sol/raii.hpp b/sol/raii.hpp index 610591f3..c3effa74 100644 --- a/sol/raii.hpp +++ b/sol/raii.hpp @@ -64,6 +64,11 @@ namespace sol { inline std::unique_ptr make_unique_deleter(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } + + template + struct constructors_for { + List l; + }; } // detail template diff --git a/sol/simple_usertype_metatable.hpp b/sol/simple_usertype_metatable.hpp new file mode 100644 index 00000000..1317a77e --- /dev/null +++ b/sol/simple_usertype_metatable.hpp @@ -0,0 +1,142 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// 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_SIMPLE_USERTYPE_METATABLE_HPP +#define SOL_SIMPLE_USERTYPE_METATABLE_HPP + +#include "usertype_metatable.hpp" +#include "object.hpp" +#include +#include + +namespace sol { + + struct simple_tag {} const simple; + + template + struct simple_usertype_metatable : usertype_detail::registrar { + std::vector> registrations; + object callconstructfunc; + + template + void add(lua_State* L, N&& n, F&& f) { + registrations.emplace_back(make_object(L, std::forward(n)), make_object(L, std::forward(f))); + } + + template + void add(lua_State* L, N&& n, constructor_wrapper c) { + registrations.emplace_back(make_object(L, std::forward(n)), make_object(L, detail::constructors_for>{std::move(c)})); + } + + template + void add(lua_State* L, N&& n, constructor_list c) { + registrations.emplace_back(make_object(L, std::forward(n)), make_object(L, detail::constructors_for>{std::move(c)})); + } + + template + void add(lua_State* L, call_construction, F&& f) { + callconstructfunc = make_object(L, std::forward(f)); + } + + template + simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) + : callconstructfunc(nil) { + registrations.reserve(std::tuple_size>::value); + detail::swallow{ 0, + (add(L, detail::forward_get(args), detail::forward_get(args)),0)... + }; + } + + template + simple_usertype_metatable(usertype_detail::verified_tag v, lua_State* L, Args&&... args) : simple_usertype_metatable(v, std::make_index_sequence(), L, std::forward_as_tuple(std::forward(args)...)) {} + + template + simple_usertype_metatable(usertype_detail::add_destructor_tag, lua_State* L, Args&&... args) : simple_usertype_metatable(usertype_detail::verified, L, std::forward(args)..., "__gc", default_destructor) {} + + template + simple_usertype_metatable(usertype_detail::check_destructor_tag, lua_State* L, Args&&... args) : simple_usertype_metatable(meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), L, std::forward(args)...) {} + + public: + + template + simple_usertype_metatable(lua_State* L, Args&&... args) : simple_usertype_metatable(meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), L, std::forward(args)...) {} + + template + simple_usertype_metatable(constructors constructorlist, lua_State* L, Args&&... args) : simple_usertype_metatable(usertype_detail::check_destructor_tag(), L, std::forward(args)..., "new", constructorlist) {} + + template + simple_usertype_metatable(constructor_wrapper constructorlist, lua_State* L, Args&&... args) : simple_usertype_metatable(usertype_detail::check_destructor_tag(), L, std::forward(args)..., "new", constructorlist) {} + + virtual int push_um(lua_State* L) override { + return stack::push(L, std::move(*this)); + } + }; + + namespace stack { + template + struct pusher> { + typedef simple_usertype_metatable umt_t; + + static int push(lua_State* L, umt_t&& umx) { + for (std::size_t i = 0; i < 3; ++i) { + // Pointer types, AKA "references" from C++ + const char* metakey = nullptr; + switch (i) { + case 0: + metakey = &usertype_traits::metatable[0]; + break; + case 1: + metakey = &usertype_traits>::metatable[0]; + break; + case 2: + default: + metakey = &usertype_traits::metatable[0]; + break; + } + luaL_newmetatable(L, metakey); + stack_reference t(L, -1); + for (auto& kvp : umx.registrations) { + stack::set_field(L, kvp.first, kvp.second, t.stack_index()); + } + + // Metatable indexes itself + stack::set_field(L, meta_function::index, t, t.stack_index()); + + // metatable on the metatable + // for call constructor purposes and such + lua_createtable(L, 0, 1); + stack_reference metabehind(L, -1); + if (umx.callconstructfunc.valid()) { + stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); + } + stack::set_field(L, metatable_key, metabehind, t.stack_index()); + metabehind.pop(); + + if (i < 2) + t.pop(); + } + return 1; + } + }; + } // stack +} // sol + +#endif // SOL_SIMPLE_USERTYPE_METATABLE_HPP diff --git a/sol/stack.hpp b/sol/stack.hpp index 92196ccc..c421f7dd 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -61,7 +61,7 @@ namespace sol { typedef std::array data_t; data_t voiddata{ {} }; for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { - voiddata[i] = get(L, up_value_index(index++)); + voiddata[i] = get(L, upvalue_index(index++)); } return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); } diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index ea603b27..76ed4c25 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -92,6 +92,10 @@ namespace sol { typedef T& type; }; template + struct strip> { + typedef T& type; + }; + template struct strip> { typedef T type; }; @@ -207,7 +211,7 @@ namespace sol { template inline int alloc_destroy(lua_State* L) { - void* rawdata = lua_touserdata(L, up_value_index(1)); + void* rawdata = lua_touserdata(L, upvalue_index(1)); T* data = static_cast(rawdata); std::allocator alloc; alloc.destroy(data); diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 84e7f727..d79d3234 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -283,8 +283,9 @@ namespace sol { static int push_with(lua_State* L, Args&&... args) { // A dumb pusher void* rawdata = lua_newuserdata(L, sizeof(T)); + T* data = static_cast(rawdata); std::allocator alloc; - alloc.construct(static_cast(rawdata), std::forward(args)...); + alloc.construct(data, std::forward(args)...); if (with_meta) { lua_CFunction cdel = stack_detail::alloc_destroy; // Make sure we have a plain GC set for this data @@ -297,6 +298,11 @@ namespace sol { return 1; } + template + static int push(lua_State* L, Args&&... args) { + return push_with(L, std::forward(args)...); + } + static int push(lua_State* L, const user& u) { return push_with(L, u.value); } diff --git a/sol/state_view.hpp b/sol/state_view.hpp index 493b38f2..a7110112 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -331,15 +331,33 @@ namespace sol { return *this; } - template - state_view& new_enum(const std::string& name, Args&&... args) { - global.new_enum(name, std::forward(args)...); + template + state_view& new_usertype(const std::string& name, constructors ctor, Args&&... args) { + global.new_usertype(name, ctor, std::forward(args)...); + return *this; + } + + template + state_view& new_simple_usertype(const std::string& name, Args&&... args) { + global.new_simple_usertype(name, std::forward(args)...); + return *this; + } + + template + state_view& new_simple_usertype(const std::string& name, Args&&... args) { + global.new_simple_usertype(name, std::forward(args)...); return *this; } template - state_view& new_usertype(const std::string& name, constructors ctor, Args&&... args) { - global.new_usertype(name, ctor, std::forward(args)...); + state_view& new_simple_usertype(const std::string& name, constructors ctor, Args&&... args) { + global.new_simple_usertype(name, ctor, std::forward(args)...); + return *this; + } + + template + state_view& new_enum(const std::string& name, Args&&... args) { + global.new_enum(name, std::forward(args)...); return *this; } diff --git a/sol/table_core.hpp b/sol/table_core.hpp index fd7a3c30..e4361dc0 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -272,6 +272,26 @@ namespace sol { return *this; } + template + basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { + usertype utype(simple, base_t::lua_state(), std::forward(args)...); + set_usertype(name, utype); + return *this; + } + + template + basic_table_core& new_simple_usertype(const std::string& name, Args&&... args) { + constructors> ctor{}; + return new_simple_usertype(name, ctor, std::forward(args)...); + } + + template + basic_table_core& new_simple_usertype(const std::string& name, constructors ctor, Args&&... args) { + usertype utype(simple, base_t::lua_state(), ctor, std::forward(args)...); + set_usertype(name, utype); + return *this; + } + template basic_table_core& new_enum(const std::string& name, Args&&... args) { if (read_only) { diff --git a/sol/types.hpp b/sol/types.hpp index ba60357f..4bc12d7b 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -168,9 +168,9 @@ namespace sol { template struct function_sig {}; - struct up_value_index { + struct upvalue_index { int index; - up_value_index(int idx) : index(lua_upvalueindex(idx)) {} + upvalue_index(int idx) : index(lua_upvalueindex(idx)) {} operator int() const { return index; } }; @@ -213,9 +213,10 @@ namespace sol { struct user { U value; - user(U x) : value(std::forward(x)) {} + user(U x) : value(std::move(x)) {} operator U* () { return std::addressof(value); } operator U& () { return value; } + operator const U& () const { return value; } }; template @@ -611,12 +612,16 @@ namespace sol { || meta::is_specialization_of>::value > { }; + template + struct is_lua_primitive : std::true_type {}; template struct is_lua_primitive> : std::true_type { }; template - struct is_lua_primitive> : std::true_type {}; + struct is_lua_primitive> : std::true_type { }; template - struct is_lua_primitive : std::true_type {}; + struct is_lua_primitive> : is_lua_primitive { }; + template + struct is_lua_primitive> : std::true_type {}; template <> struct is_lua_primitive : std::true_type {}; template <> diff --git a/sol/usertype.hpp b/sol/usertype.hpp index f052c577..62da01a7 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -22,79 +22,54 @@ #ifndef SOL_USERTYPE_HPP #define SOL_USERTYPE_HPP -#include "usertype_metatable.hpp" #include "stack.hpp" +#include "usertype_metatable.hpp" +#include "simple_usertype_metatable.hpp" #include namespace sol { -namespace usertype_detail { -struct add_destructor_tag {}; -struct check_destructor_tag {}; -struct verified_tag {} const verified {}; -template -struct is_constructor : std::false_type {}; + template + class usertype { + private: + std::unique_ptr metatableregister; -template -struct is_constructor> : std::true_type {}; + template + usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister(detail::make_unique_deleter, Args...>, detail::deleter>(std::forward(args)...)) {} -template -struct is_constructor> : std::true_type {}; + template + usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward(args)..., "__gc", default_destructor) {} -template <> -struct is_constructor : std::true_type {}; + template + usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} -template -using has_constructor = meta::any>...>; + public: -template -struct is_destructor : std::false_type {}; + template + usertype(Args&&... args) : usertype(meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(args)...) {} -template -struct is_destructor> : std::true_type {}; + template + usertype(constructors constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} -template -using has_destructor = meta::any>...>; -} // usertype_detail + template + usertype(constructor_wrapper constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} -template -class usertype { -private: - std::unique_ptr metatableregister; + template + usertype(simple_tag, lua_State* L, Args&&... args) : metatableregister(detail::make_unique_deleter, detail::deleter>(L, std::forward(args)...)) {} - template - usertype(usertype_detail::verified_tag, Args&&... args) : metatableregister( detail::make_unique_deleter, Args...>, detail::deleter>(std::forward(args)...) ) {} + int push(lua_State* L) { + return metatableregister->push_um(L); + } + }; - template - usertype(usertype_detail::add_destructor_tag, Args&&... args) : usertype(usertype_detail::verified, std::forward(args)..., "__gc", default_destructor) {} - - template - usertype(usertype_detail::check_destructor_tag, Args&&... args) : usertype(meta::condition, meta::neg>>, usertype_detail::add_destructor_tag, usertype_detail::verified_tag>(), std::forward(args)...) {} - -public: - - template - usertype(Args&&... args) : usertype(meta::condition, meta::neg>>, decltype(default_constructor), usertype_detail::check_destructor_tag>(), std::forward(args)...) {} - - template - usertype(constructors constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} - - template - usertype(constructor_wrapper constructorlist, Args&&... args) : usertype(usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} - - int push(lua_State* L) { - return metatableregister->push_um(L); - } -}; - -namespace stack { -template -struct pusher> { - static int push(lua_State* L, usertype& user) { - return user.push(L); - } -}; -} // stack + namespace stack { + template + struct pusher> { + static int push(lua_State* L, usertype& user) { + return user.push(L); + } + }; + } // stack } // sol #endif // SOL_USERTYPE_HPP diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index 23bea2dc..6634423e 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -86,6 +86,36 @@ namespace sol { else return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); } + + struct add_destructor_tag {}; + struct check_destructor_tag {}; + struct verified_tag {} const verified{}; + struct simple_tag {} const simple; + + template + struct is_constructor : std::false_type {}; + + template + struct is_constructor> : std::true_type {}; + + template + struct is_constructor> : std::true_type {}; + + template <> + struct is_constructor : std::true_type {}; + + template + using has_constructor = meta::any>...>; + + template + struct is_destructor : std::false_type {}; + + template + struct is_destructor> : std::true_type {}; + + template + using has_destructor = meta::any>...>; + } // usertype_detail template @@ -148,7 +178,7 @@ namespace sol { } template - void make_regs(regs_t&, int&, sol::call_construction, F&&) { + void make_regs(regs_t&, int&, call_construction, F&&) { callconstructfunc = call; secondarymeta = true; } @@ -228,7 +258,7 @@ namespace sol { } static int real_index_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, up_value_index(1)); + usertype_metatable& f = stack::get>(L, upvalue_index(1)); if (stack::get(L, -1) == type::string) { string_detail::string_shim accessor = stack::get(L, -1); bool found = false; @@ -242,7 +272,7 @@ namespace sol { } static int real_new_index_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, up_value_index(1)); + usertype_metatable& f = stack::get>(L, upvalue_index(1)); if (stack::get(L, -2) == type::string) { string_detail::string_shim accessor = stack::get(L, -2); bool found = false; @@ -257,7 +287,7 @@ namespace sol { template static int real_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, up_value_index(1)); + usertype_metatable& f = stack::get>(L, upvalue_index(1)); return real_call_with(L, f); } diff --git a/test_functions.cpp b/test_functions.cpp index 7e1760ec..3131c720 100644 --- a/test_functions.cpp +++ b/test_functions.cpp @@ -827,7 +827,7 @@ TEST_CASE("functions/overloading", "Check if overloading works properly for regu 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)); + lua.set_function("func", sol::overload(func_2, func_3, func_1, func_1s)); const std::string string_bark = "string: bark"; diff --git a/test_simple_usertype.cpp b/test_simple_usertype.cpp new file mode 100644 index 00000000..ca76aa9c --- /dev/null +++ b/test_simple_usertype.cpp @@ -0,0 +1,85 @@ +#define SOL_CHECK_ARGUMENTS + +#include +#include + +#include +#include + +TEST_CASE("usertypes/simple_usertypes", "Ensure that simple usertypes properly work here") { + struct marker { + bool value = false; + }; + struct bark { + int var = 50; + marker mark; + + void fun() { + var = 51; + } + + int get() const { + return var; + } + + int set(int x) { + var = x; + return var; + } + + std::string special() const { + return mark.value ? "woof" : "pantpant"; + } + + const marker& the_marker() const { + return mark; + } + }; + + sol::state lua; + lua.new_simple_usertype("bark", + "fun", &bark::fun, + "get", &bark::get, + "var", &bark::var, + "the_marker", &bark::the_marker, + "x", sol::property(&bark::get), + "y", sol::property(&bark::set), + "z", sol::property(&bark::get, &bark::set) + ); + + lua.script("b = bark.new()"); + bark& b = lua["b"]; + + lua.script("b:fun()"); + int var = b.var; + REQUIRE(var == 51); + + lua.script("b:var(20)"); + lua.script("v = b:var()"); + int v = lua["v"]; + REQUIRE(v == 20); + + lua.script("m = b:the_marker()"); + marker& m = lua["m"]; + REQUIRE_FALSE(b.mark.value); + REQUIRE_FALSE(m.value); + m.value = true; + REQUIRE(&b.mark == &m); + REQUIRE(b.mark.value); + + sol::table barktable = lua["bark"]; + barktable["special"] = &bark::special; + + lua.script("s = b:special()"); + std::string s = lua["s"]; + REQUIRE(s == "woof"); + + lua.script("b:y(24)"); + lua.script("x = b:x()"); + int x = lua["x"]; + REQUIRE(x == 24); + + lua.script("z = b:z(b:z() + 5)"); + int z = lua["z"]; + REQUIRE(z == 29); +} diff --git a/test_usertypes.cpp b/test_usertypes.cpp index 18e18526..12b30d52 100644 --- a/test_usertypes.cpp +++ b/test_usertypes.cpp @@ -664,6 +664,35 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert REQUIRE_THROWS(lua.script("r:func(1,2,'meow')")); } +TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") { + struct overloading_test { + int print(int i) { std::cout << "Integer print: " << i << std::endl; return 500 + i; } + int print() { std::cout << "No param print." << std::endl; return 500; } + }; + + sol::state lua; + lua.new_usertype("overloading_test", sol::constructors<>(), + "print", sol::overload(static_cast(&overloading_test::print), static_cast(&overloading_test::print)), + "print2", sol::overload(static_cast(&overloading_test::print), static_cast(&overloading_test::print)) + ); + lua.set("test", overloading_test()); + + sol::function f0_0 = lua.load("return test:print()"); + sol::function f0_1 = lua.load("return test:print2()"); + sol::function f1_0 = lua.load("return test:print(24)"); + sol::function f1_1 = lua.load("return test:print2(24)"); + int res = f0_0(); + int res2 = f0_1(); + int res3 = f1_0(); + int res4 = f1_1(); + + REQUIRE(res == 500); + REQUIRE(res2 == 500); + + REQUIRE(res3 == 524); + REQUIRE(res4 == 524); +} + TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles properly and errors out at runtime") { struct bark { int var = 50; @@ -1015,8 +1044,7 @@ print(e.bark) } TEST_CASE("usertype/copyability", "make sure user can write to a class variable even if the class itself isn't copy-safe") { - struct NoCopy - { + struct NoCopy { int get() const { return _you_can_copy_me; } void set(int val) { _you_can_copy_me = val; } @@ -1034,3 +1062,26 @@ nocopy.val = 5 )__") ); } + +TEST_CASE("usertype/protect", "users should be allowed to manually protect a function") { + struct protect_me { + int gen(int x) { + return x; + } + }; + + sol::state lua; + lua.open_libraries(sol::lib::base); + lua.new_usertype("protect_me", + "gen", sol::protect( &protect_me::gen ) + ); + + REQUIRE_NOTHROW( + lua.script(R"__( +pm = protect_me.new() +value = pcall(pm.gen,pm) +)__"); + ); + bool value = lua["value"]; + REQUIRE_FALSE(value); +}