diff --git a/docs/source/api/api-top.rst b/docs/source/api/api-top.rst index 6ff62d7a..e1595406 100644 --- a/docs/source/api/api-top.rst +++ b/docs/source/api/api-top.rst @@ -31,4 +31,5 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo usertype userdata usertype_memory + unique_usertype_traits variadic_args diff --git a/docs/source/api/types.rst b/docs/source/api/types.rst index 2aa126d3..0cd9a8a4 100644 --- a/docs/source/api/types.rst +++ b/docs/source/api/types.rst @@ -137,16 +137,6 @@ special types A tag type that, when used with :doc:`stack::get\>`, does not perform a ``nil`` check when attempting to retrieve the userdata pointer. -.. code-block:: cpp - :caption: unique_usertype - :name: unique-usertype - - template - struct unique_usertype {}; - -A tag type for alerting the framewok that a certain type is to be pushed as a special userdata with special deletion semantics. Is automatically applied to ``std::unique_ptr`` and ``std::shared_ptr``. - - .. code-block:: cpp :caption: type list :name: type-list diff --git a/docs/source/api/unique_usertype_traits.rst b/docs/source/api/unique_usertype_traits.rst new file mode 100644 index 00000000..e6101160 --- /dev/null +++ b/docs/source/api/unique_usertype_traits.rst @@ -0,0 +1,42 @@ +unique_usertype_traits +========================= +A trait for hooking special handles / pointers +---------------------------------------------- + +.. code-block:: cpp + :caption: unique_usertype + :name: unique-usertype + + template + struct unique_usertype_traits { + typedef T type; + typedef T actual_type; + static const bool value = false; + + static bool is_null(const actual_type&) {...} + + static type* get (const actual_type&) {...} + }; + +A traits type for alerting the library that a certain type is to be pushed as a special userdata with special deletion / destruction semantics. It is already defined for ``std::unique_ptr`` and ``std::shared_ptr``. You can specialize this to get ``unique_usertype_traits`` semantics with your code, for example with ``boost::shared_ptr`` like so: + +.. code-block:: cpp + + namespace sol { + template + struct unique_usertype_traits> { + typedef T type; + typedef boost::shared_ptr actual_type; + static const bool value = true; + + static bool is_null(const actual_type& value) { + return value == nullptr; + } + + static type* get (const actual_type& p) { + return p.get(); + } + } + } + +This will allow the framework to properly handle ``boost::shared_ptr``, with ref-counting and all. The `type` is the type that lua and sol will interact with, and will allow you to pull out a non-owning reference / pointer to the data when you just ask for a plain `T*` or `T&` or `T` using the getter functions and properties of Sol. \ No newline at end of file diff --git a/docs/source/api/usertype_memory.rst b/docs/source/api/usertype_memory.rst index 5f06e897..dc639617 100644 --- a/docs/source/api/usertype_memory.rst +++ b/docs/source/api/usertype_memory.rst @@ -1,6 +1,10 @@ usertype memory =============== +.. note:: + + Sol does not take ownership of raw pointers, returned from functions or set through the ``set`` functions. Return a value, a ``std::unique_ptr``, a ``std::shared_ptr`` of some kind, or hook up the :doc:`unique usertypes traits` to work for some specific handle structure you use (AKA, for ``boost::shared_ptr``). + The userdata generated by Sol has a specific layout, depending on how Sol recognizes userdata passed into it. All of the referred to metatable names are generated from :ref:`usertype_traits\` In general, we always insert a T* in the first `sizeof(T*)` bytes, so the any framework that pulls out those first bytes expecting a pointer will work. The rest of the data has some different alignments and contents based on what it's used for and how it's used. diff --git a/docs/source/tutorial/existing.rst b/docs/source/tutorial/existing.rst index 9b77fb90..14fd8968 100644 --- a/docs/source/tutorial/existing.rst +++ b/docs/source/tutorial/existing.rst @@ -20,4 +20,6 @@ If you're already using lua and you just want to use ``sol`` in some places, you :doc:`sol::state_view<../api/state>` is exactly like ``sol::state``, but it doesn't manage the lifetime of a ``lua_State*``. Therefore, you get all the goodies that come with a ``sol::state`` without any of the ownership implications. Sol has no initialization components that need to deliberately remain alive for the duration of the program. It's entirely self-containing and uses lua's garbage collectors and various implementation techniques to require no state C++-side. After you do that, all of the power of `Sol` is available to you, and then some! -Remember that Sol can be as lightweight as you want it: almost all of Sol's types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture! \ No newline at end of file +Remember that Sol can be as lightweight as you want it: almost all of Sol's types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture. + +Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<../api/unique_usertype_traits>` to see how! \ No newline at end of file diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index 0b0d297d..05da1900 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -149,11 +149,41 @@ inline decltype(auto) cleanup_key() { template struct functor { + typedef meta::bind_traits traits_type; + typedef typename traits_type::args_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; + static const std::size_t arity = traits_type::arity; + static const bool is_free = true; + function_type invocation; + + template + functor(Args&&... args): invocation(std::forward(args)...) {} + + template + void call(types, Args&&... args) { + invocation(std::forward(args)...); + } + + template + Ret call(types, Args&&... args) { + return invocation(std::forward(args)...); + } + + 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_base_of::template arg_at<0>>>::value>> { typedef meta::bind_traits traits_type; typedef meta::pop_front_type_t args_type; typedef typename traits_type::return_type return_type; - typedef meta::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 const std::size_t arity = traits_type::arity - 1; + static const bool is_free = false; T* item; function_type invocation; @@ -186,6 +216,8 @@ struct functor, C> { typedef member_property function_type; typedef meta::Not> can_read; typedef meta::Not> can_write; + static const bool is_free = false; + T* item; function_type invocation; @@ -217,6 +249,7 @@ struct functor::va static const std::size_t arity = traits_type::arity; typedef std::true_type can_read; typedef std::true_type can_write; + static const bool is_free = false; T* item; Func invocation; @@ -247,6 +280,7 @@ struct functor:: typedef typename traits_type::args_type args_type; typedef typename traits_type::return_type return_type; static const std::size_t arity = traits_type::arity; + static const bool is_free = false; T* item; Func invocation; diff --git a/sol/function_types_overload.hpp b/sol/function_types_overload.hpp index 8f394a91..655b79e3 100644 --- a/sol/function_types_overload.hpp +++ b/sol/function_types_overload.hpp @@ -30,13 +30,16 @@ namespace sol { namespace function_detail { namespace internals { template -struct overload_traits : meta::bind_traits {}; +struct overload_traits : meta::bind_traits { + static const std::size_t boost = 0; +}; template struct overload_traits> { typedef typename functor::args_type args_type; typedef typename functor::return_type return_type; static const std::size_t arity = functor::arity; + static const std::size_t boost = static_cast(functor::is_free); }; template @@ -45,7 +48,7 @@ inline int overload_match_arity(types<>, std::index_sequence<>, std::index_seque } template -inline int overload_match_arity(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { +inline int overload_match_arity(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int nfxarity, int start, Args&&... args) { typedef overload_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::args_type args_type; @@ -53,15 +56,16 @@ inline int overload_match_arity(types, std::index_sequence typedef meta::index_in state_index; typedef meta::index_in va_pack_index; static const std::size_t arity = traits::arity - static_cast(state_index::value != SIZE_MAX) - static_cast(va_pack_index::value != SIZE_MAX); + int fxarity = traits::boost + nfxarity; // compile-time eliminate any functions that we know ahead of time are of improper arity if (meta::find_in_pack_v, index_value...>::value) { - 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, nfxarity, start, std::forward(args)...); } if (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, nfxarity, start, std::forward(args)...); } - if (!stack::stack_detail::check_types().check(args_type(), 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)...); + if (!stack::stack_detail::check_types().check(args_type(), args_indices(), L, start - traits::boost, no_panic)) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, nfxarity, start, std::forward(args)...); } return matchfx(types(), index_value(), return_types(), args_type(), L, fxarity, start, std::forward(args)...); } @@ -112,13 +116,19 @@ struct usertype_overloaded_function : base_function { usertype_overloaded_function(std::tuple set) : overloads(std::move(set)) {} - template + template > = 0> int call(types, index_value, types r, types a, lua_State* L, int, int start) { auto& func = std::get(overloads); func.item = detail::ptr(stack::get(L, 1)); return stack::call_into_lua<0, false>(r, a, L, start, func); } + template > = 0> + int call(types, index_value, types r, types a, lua_State* L, int, int start) { + auto& func = std::get(overloads); + return stack::call_into_lua<0, false>(r, a, L, start - 1, func); + } + virtual int operator()(lua_State* L) override { auto mfx = [&](auto&&... args){ return this->call(std::forward(args)...); }; return overload_match>>...>(mfx, L, 2); diff --git a/sol/load_result.hpp b/sol/load_result.hpp index 6cd0c6da..ea495694 100644 --- a/sol/load_result.hpp +++ b/sol/load_result.hpp @@ -28,112 +28,112 @@ #include namespace sol { - struct load_result : public proxy_base { - private: - lua_State* L; - int index; - int returncount; - int popcount; - load_status err; + struct load_result : public proxy_base { + private: + lua_State* L; + int index; + int returncount; + int popcount; + load_status err; - template - decltype(auto) tagged_get(types>) const { - if (!valid()) { - return sol::optional(nullopt); - } - return stack::get>(L, index); - } + template + decltype(auto) tagged_get(types>) const { + if (!valid()) { + return sol::optional(nullopt); + } + return stack::get>(L, index); + } - template - decltype(auto) tagged_get(types) const { + template + decltype(auto) tagged_get(types) const { #ifdef SOL_CHECK_ARGUMENTS - if (!valid()) { - type_panic(L, index, type_of(L, index), type::none); - } + if (!valid()) { + type_panic(L, index, type_of(L, index), type::none); + } #endif // Check Argument Safety - return stack::get(L, index); - } + return stack::get(L, index); + } - sol::optional tagged_get(types>) const { - if (valid()) { - return nullopt; - } - return sol::error(detail::direct_error, stack::get(L, index)); - } + sol::optional tagged_get(types>) const { + if (valid()) { + return nullopt; + } + return sol::error(detail::direct_error, stack::get(L, index)); + } - sol::error tagged_get(types) const { + sol::error tagged_get(types) const { #ifdef SOL_CHECK_ARGUMENTS - if (valid()) { - type_panic(L, index, type_of(L, index), type::none); - } + if (valid()) { + type_panic(L, index, type_of(L, index), type::none); + } #endif // Check Argument Safety - return sol::error(detail::direct_error, stack::get(L, index)); - } + return sol::error(detail::direct_error, stack::get(L, index)); + } - public: - load_result() = default; - load_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, load_status err = load_status::ok) : L(L), index(index), returncount(returncount), popcount(popcount), err(err) { + public: + load_result() = default; + load_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, load_status err = load_status::ok) : L(L), index(index), returncount(returncount), popcount(popcount), err(err) { - } - load_result(const load_result&) = default; - load_result& operator=(const load_result&) = default; - load_result(load_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = load_status::syntax; - } - load_result& operator=(load_result&& o) { - L = o.L; - index = o.index; - returncount = o.returncount; - popcount = o.popcount; - err = o.err; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = load_status::syntax; - return *this; - } + } + load_result(const load_result&) = default; + load_result& operator=(const load_result&) = default; + load_result(load_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.err = load_status::syntax; + } + load_result& operator=(load_result&& o) { + L = o.L; + index = o.index; + returncount = o.returncount; + popcount = o.popcount; + err = o.err; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.err = load_status::syntax; + return *this; + } - load_status error() const { - return err; - } + load_status error() const { + return err; + } - bool valid() const { - return error() == load_status::ok; - } + bool valid() const { + return error() == load_status::ok; + } - template - T get() const { - return tagged_get(types>()); - } + template + T get() const { + return tagged_get(types>()); + } - template - decltype(auto) call(Args&&... args) { - return get().template call(std::forward(args)...); - } + template + decltype(auto) call(Args&&... args) { + return get().template call(std::forward(args)...); + } - template - decltype(auto) operator()(Args&&... args) { - return call<>(std::forward(args)...); - } + template + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward(args)...); + } - lua_State* lua_state() const { return L; }; - int stack_index() const { return index; }; + lua_State* lua_state() const { return L; }; + int stack_index() const { return index; }; - ~load_result() { - stack::remove(L, index, popcount); - } - }; + ~load_result() { + stack::remove(L, index, popcount); + } + }; } // sol #endif // SOL_LOAD_RESULT_HPP diff --git a/sol/overload.hpp b/sol/overload.hpp index 6fd87bfe..bced96ea 100644 --- a/sol/overload.hpp +++ b/sol/overload.hpp @@ -28,8 +28,12 @@ namespace sol { template struct overload_set { std::tuple set; - template - overload_set (Args&&... args) : set(std::forward(args)...) {} + template >> = 0> + overload_set (Arg&& arg, Args&&... args) : set(std::forward(arg), std::forward(args)...) {} + overload_set(const overload_set&) = default; + overload_set(overload_set&&) = default; + overload_set& operator=(const overload_set&) = default; + overload_set& operator=(overload_set&&) = default; }; template diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index b4b3d036..b17f5434 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -266,7 +266,7 @@ struct checker { return true; if (stack_detail::check_metatable(L)) return true; - if (stack_detail::check_metatable>(L)) + if (stack_detail::check_metatable>(L)) return true; #ifndef SOL_NO_EXCEPTIONS lua_getfield(L, -1, &detail::base_class_check_key()[0]); @@ -308,27 +308,11 @@ struct checker { } }; -template -struct checker, type::userdata, C> { +template +struct checker::value>> { template static bool check(lua_State* L, int index, Handler&& handler) { - return checker{}.check(L, index, std::forward(handler)); - } -}; - -template -struct checker, type::userdata, C> { - template - static bool check(lua_State* L, int index, Handler&& handler) { - return checker>, type::userdata, C>{}.check(L, index, std::forward(handler)); - } -}; - -template -struct checker, type::userdata, C> { - template - static bool check(lua_State* L, int index, Handler&& handler) { - return checker>, type::userdata, C>{}.check(L, index, std::forward(handler)); + return checker::type, type::userdata>{}.check(L, index, std::forward(handler)); } }; diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index 08acf0e7..10ee66c9 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -221,16 +221,6 @@ struct getter { } }; -template -struct getter> { - static Real& get(lua_State* L, int index = -1) { - T** pref = static_cast(lua_touserdata(L, index)); - detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); - Real* mem = static_cast(static_cast(fx + 1)); - return *mem; - } -}; - template struct getter> { static T* get(lua_State* L, int index = -1) { @@ -246,16 +236,15 @@ struct getter { }; template -struct getter> { - static std::shared_ptr& get(lua_State* L, int index = -1) { - return getter>>::get(L, index); - } -}; - -template -struct getter> { - static std::unique_ptr& get(lua_State* L, int index = -1) { - return getter>>::get(L, index); +struct getter::value>> { + typedef typename unique_usertype_traits::type P; + typedef typename unique_usertype_traits::actual_type Real; + + static Real& get(lua_State* L, int index = -1) { + P** pref = static_cast(lua_touserdata(L, index)); + detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); + Real* mem = static_cast(static_cast(fx + 1)); + return *mem; } }; diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index e8d2d286..9fcb6cca 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -71,53 +71,39 @@ struct pusher { } }; -template -struct pusher> { +template +struct pusher::value>> { + typedef typename unique_usertype_traits::type P; + typedef typename unique_usertype_traits::actual_type Real; + + template >> = 0> + static int push(lua_State* L, Arg&& arg) { + if (unique_usertype_traits::is_null(arg)) + return stack::push(L, nil); + return push_deep(L, std::forward(arg)); + } + + template + static int push(lua_State* L, Arg0&& arg0, Arg0&& arg1, Args&&... args) { + return push_deep(L, std::forward(arg0), std::forward(arg1), std::forward(args)...); + } + template - static int push(lua_State* L, Args&&... args) { - T** pref = static_cast(lua_newuserdata(L, sizeof(T*) + sizeof(detail::special_destruct_func) + sizeof(Real))); + static int push_deep(lua_State* L, Args&&... args) { + P** pref = static_cast(lua_newuserdata(L, sizeof(P*) + sizeof(detail::special_destruct_func) + sizeof(Real))); detail::special_destruct_func* fx = static_cast(static_cast(pref + 1)); Real* mem = static_cast(static_cast(fx + 1)); - *fx = detail::special_destruct; + *fx = detail::special_destruct; detail::default_construct::construct(mem, std::forward(args)...); - *pref = std::addressof(detail::deref(*mem)); - if (luaL_newmetatable(L, &usertype_traits>::metatable[0]) == 1) { - set_field(L, "__gc", detail::unique_destruct); + *pref = unique_usertype_traits::get(*mem); + if (luaL_newmetatable(L, &usertype_traits>::metatable[0]) == 1) { + set_field(L, "__gc", detail::unique_destruct

); } lua_setmetatable(L, -2); return 1; } }; -template -struct pusher::value>> { - template - static int push(lua_State* L, Args&&... args) { - typedef typename is_unique_usertype::metatable_type meta_type; - return stack::push>(L, std::forward(args)...); - } -}; - -template -struct pusher> { - static int push(lua_State* L, std::unique_ptr obj) { - if (obj == nullptr) - return stack::push(L, nil); - return stack::push>>(L, std::move(obj)); - } -}; - -template -struct pusher> { - template - static int push(lua_State* L, S&& s) { - if (s == nullptr) - return stack::push(L, nil); - return stack::push>>(L, std::forward(s)); - } -}; - - template struct pusher> { static int push(lua_State* L, const std::reference_wrapper& t) { diff --git a/sol/traits.hpp b/sol/traits.hpp index 792ee0ae..5abe61fd 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -267,12 +267,16 @@ template using void_tuple_element_t = typename void_tuple_element::type; template::value> -struct fx_traits; +struct fx_traits { + static const bool is_member_function = false; + typedef std::tuple<> args_tuple_type; + typedef types<> args_type; + template + using arg_at = void_tuple_element_t; +}; template -struct fx_traits : fx_traits { - -}; +struct fx_traits : fx_traits {}; template struct fx_traits { diff --git a/sol/types.hpp b/sol/types.hpp index f0ba49e6..8ffa1fd2 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -84,6 +84,9 @@ inline int c_trampoline(lua_State* L, lua_CFunction f) { } #endif // Exceptions vs. No Exceptions struct empty { void operator()() {} }; + +template +struct unique_usertype {}; } // detail struct nil_t {}; const nil_t nil {}; @@ -94,8 +97,52 @@ inline bool operator!=(nil_t, nil_t) { return false; } typedef std::remove_pointer_t lua_r_CFunction; -template -struct unique_usertype {}; +template +struct unique_usertype_traits { + typedef T type; + typedef T actual_type; + static const bool value = false; + + template + static bool is_null(U&&) { + return false; + } + + template + static auto get(U&& value) { + return std::addressof(detail::deref(value)); + } +}; + +template +struct unique_usertype_traits> { + typedef T type; + typedef std::shared_ptr actual_type; + static const bool value = true; + + static bool is_null(const actual_type& value) { + return value == nullptr; + } + + static type* get(const actual_type& p) { + return p.get(); + } +}; + +template +struct unique_usertype_traits> { + typedef T type; + typedef std::unique_ptr actual_type; + static const bool value = true; + + static bool is_null(const actual_type& value) { + return value == nullptr; + } + + static type* get(const actual_type& p) { + return p.get(); + } +}; template struct non_null {}; @@ -442,7 +489,7 @@ template struct is_proxy_primitive : is_lua_primitive { }; template -struct is_unique_usertype : std::false_type {}; +struct is_unique_usertype : std::integral_constant::value> {}; template struct is_transparent_argument : std::false_type {}; diff --git a/sol/usertype.hpp b/sol/usertype.hpp index 320dce43..8a55b6db 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -477,7 +477,7 @@ public: // push pointer tables first, usertype_detail::push_metatable(L, needsindexfunction, functions, functiontable, metafunctiontable, baseclasscheck, baseclasscast); lua_pop(L, 1); - usertype_detail::push_metatable, usertype_detail::stage::uniquemeta>(L, needsindexfunction, functions, functiontable, metafunctiontable, baseclasscheck, baseclasscast); + usertype_detail::push_metatable, usertype_detail::stage::uniquemeta>(L, needsindexfunction, functions, functiontable, metafunctiontable, baseclasscheck, baseclasscast); lua_pop(L, 1); // but leave the regular T table on last // so it can be linked to a type for usage with `.new(...)` or `:new(...)` diff --git a/tests.cpp b/tests.cpp index 042e18fd..cf53ac19 100644 --- a/tests.cpp +++ b/tests.cpp @@ -665,11 +665,13 @@ TEST_CASE("usertype/unique-shared-ptr", "manage the conversion and use of unique lua.set("sharedint", sharedint); std::unique_ptr& uniqueintref = lua["uniqueint"]; std::shared_ptr& sharedintref = lua["sharedint"]; + int64_t* rawuniqueintref = lua["uniqueint"]; + int64_t* rawsharedintref = lua["sharedint"]; int siusecount = sharedintref.use_count(); - REQUIRE(uniqueintref != nullptr); - REQUIRE(sharedintref != nullptr); - REQUIRE(unique_value == *uniqueintref.get()); - REQUIRE(unique_value == *sharedintref.get()); + REQUIRE((uniqueintref.get() == rawuniqueintref && sharedintref.get() == rawsharedintref)); + REQUIRE((uniqueintref != nullptr && sharedintref != nullptr && rawuniqueintref != nullptr && rawsharedintref != nullptr)); + REQUIRE((unique_value == *uniqueintref.get() && unique_value == *sharedintref.get())); + REQUIRE((unique_value == *rawuniqueintref && unique_value == *rawsharedintref)); REQUIRE(siusecount == sharedint.use_count()); std::shared_ptr moreref = sharedint; REQUIRE(unique_value == *moreref.get()); @@ -910,6 +912,12 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c void func() {} + static void oh_boy() {} + + static int oh_boy(std::string name) { + return name.length(); + } + int operator()(int x) { return x; } @@ -923,9 +931,13 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c "something", something, "something2", [](int x, int y) { return x + y; }, "func", &bark::func, + "oh_boy", sol::overload(sol::resolve(&bark::oh_boy), sol::resolve(&bark::oh_boy)), sol::meta_function::call_function, &bark::operator() ); + lua.script("assert(bark.oh_boy('woo') == 3)"); + lua.script("bark.oh_boy()"); + bark b; lua.set("b", &b);