From 66ad18979706a6396bc67424e9e35e5262d60061 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 9 Jan 2017 23:25:28 -0500 Subject: [PATCH] add functionality to have functions properly detected and the amount shifted over properly based on being a call constructor or not --- docs/source/api/usertype.rst | 3 ++- single/sol/sol.hpp | 31 +++++++++++++++--------- sol/call.hpp | 2 +- sol/usertype_metatable.hpp | 25 +++++++++++++------- test_usertypes.cpp | 46 ++++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 21 deletions(-) diff --git a/docs/source/api/usertype.rst b/docs/source/api/usertype.rst index 2fa73a32..bd941c52 100644 --- a/docs/source/api/usertype.rst +++ b/docs/source/api/usertype.rst @@ -170,9 +170,10 @@ If you don't specify any constructor options at all and the type is `default_con * ``{anything}, {some_factory_function}`` - Essentially binds whatever the function is to name ``{anything}`` - When used WITH the ``sol::no_constructor`` option above (e.g. ``"new", sol::no_constructor`` and after that having ``"create", &my_creation_func``), one can remove typical constructor avenues and then only provide specific factory functions. Note that this combination is similar to using the ``sol::factories`` method mentioned earlier in this list. To control the destructor as well, see further below -* ``sol::call_constructor, {valid function / constructor / initializer / factory}`` +* ``sol::call_constructor, {valid constructor / initializer / factory}`` - The purpose of this is to enable the syntax ``local v = my_class( 24 )`` and have that call a constructor; it has no other purpose - This is compatible with luabind, kaguya and other Lua library syntaxes and looks similar to C++ syntax, but the general consensus in Programming with Lua and other places is to use a function named ``new`` + - Note that with the ``sol::call_constructor`` key, a construct type above must be specified. A free function without it will pass in the metatable describing this object as the first argument without that distinction, which can cause strange runtime errors. usertype destructor options +++++++++++++++++++++++++++ diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 4d935cc8..01755d5e 100644 --- a/single/sol/sol.hpp +++ b/single/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2017-01-09 21:30:54.823287 UTC -// This header was generated with sol v2.15.7 (revision 969615f) +// Generated 2017-01-10 04:24:27.805667 UTC +// This header was generated with sol v2.15.7 (revision 490194f) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -8071,7 +8071,7 @@ namespace sol { }; static int call(lua_State* L, F& fx) { - return overload_match_arity(on_match(), L, lua_gettop(L), 1, fx); + return overload_match_arity(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx); } }; @@ -10181,20 +10181,23 @@ namespace sol { struct verified_tag {} const verified{}; template - struct is_constructor : std::false_type {}; + struct is_non_factory_constructor : std::false_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; template - struct is_constructor> : std::true_type {}; + struct is_non_factory_constructor> : std::true_type {}; - template - struct is_constructor> : std::true_type {}; + template <> + struct is_non_factory_constructor : std::true_type {}; + + template + struct is_constructor : is_non_factory_constructor {}; template struct is_constructor> : std::true_type {}; - template <> - struct is_constructor : std::true_type {}; - template using has_constructor = meta::any>...>; @@ -10419,8 +10422,14 @@ namespace sol { template static int real_call_with(lua_State* L, usertype_metatable& um) { + typedef meta::unqualified_tuple_element_t K; + typedef meta::unqualified_tuple_element_t F; + static const int boost = + !usertype_detail::is_non_factory_constructor::value + && std::is_same::value ? + 1 : 0; auto& f = std::get(um.functions); - return call_detail::call_wrapped(L, f); + return call_detail::call_wrapped(L, f); } template diff --git a/sol/call.hpp b/sol/call.hpp index 3daaeeb3..d09cc023 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -501,7 +501,7 @@ namespace sol { }; static int call(lua_State* L, F& fx) { - return overload_match_arity(on_match(), L, lua_gettop(L), 1, fx); + return overload_match_arity(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx); } }; diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index c52a545b..37693227 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -187,20 +187,23 @@ namespace sol { struct verified_tag {} const verified{}; template - struct is_constructor : std::false_type {}; + struct is_non_factory_constructor : std::false_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; template - struct is_constructor> : std::true_type {}; + struct is_non_factory_constructor> : std::true_type {}; - template - struct is_constructor> : std::true_type {}; + template <> + struct is_non_factory_constructor : std::true_type {}; + + template + struct is_constructor : is_non_factory_constructor {}; template struct is_constructor> : std::true_type {}; - template <> - struct is_constructor : std::true_type {}; - template using has_constructor = meta::any>...>; @@ -425,8 +428,14 @@ namespace sol { template static int real_call_with(lua_State* L, usertype_metatable& um) { + typedef meta::unqualified_tuple_element_t K; + typedef meta::unqualified_tuple_element_t F; + static const int boost = + !usertype_detail::is_non_factory_constructor::value + && std::is_same::value ? + 1 : 0; auto& f = std::get(um.functions); - return call_detail::call_wrapped(L, f); + return call_detail::call_wrapped(L, f); } template diff --git a/test_usertypes.cpp b/test_usertypes.cpp index d23d45c1..60adc730 100644 --- a/test_usertypes.cpp +++ b/test_usertypes.cpp @@ -235,6 +235,28 @@ void des(T& e) { e.~T(); } +struct matrix_xf { + float a, b; + + static matrix_xf from_lua_table(sol::table t) { + matrix_xf m; + m.a = t[1][1]; + m.b = t[1][2]; + return m; + } +}; + +struct matrix_xi { + int a, b; + + static matrix_xi from_lua_table(sol::table t) { + matrix_xi m; + m.a = t[1][1]; + m.b = t[1][2]; + return m; + } +}; + TEST_CASE("usertype/usertype", "Show that we can create classes from usertype and use them") { sol::state lua; @@ -944,6 +966,30 @@ t = thing(256) REQUIRE(y.v == 256); } +TEST_CASE("usertype/call_constructor-factories", "make sure tables can be passed to factory-based call constructors") { + sol::state lua; + lua.open_libraries(); + + lua.new_usertype("mat", + sol::call_constructor, sol::factories(&matrix_xf::from_lua_table) + ); + + lua.script("m = mat{ {1.1, 2.2} }"); + + lua.new_usertype("mati", + sol::call_constructor, sol::factories(&matrix_xi::from_lua_table) + ); + + lua.script("mi = mati{ {1, 2} }"); + + matrix_xf& m = lua["m"]; + REQUIRE(m.a == 1.1f); + REQUIRE(m.b == 2.2f); + matrix_xi& mi = lua["mi"]; + REQUIRE(mi.a == 1); + REQUIRE(mi.b == 2); +} + TEST_CASE("usertype/call_constructor_2", "prevent metatable regression") { class class01 { public: