From e35fe6be85021143329697ed565c06387666e86c Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 3 Jun 2016 21:40:23 -0400 Subject: [PATCH] This mega-commit implements the new `usertype_metatable` while keeping everything else still intact. Blurgh, managing API versions suck... --- Optional | 2 +- sol/bind_traits.hpp | 218 +++++++++++++++++++++++ sol/call.hpp | 282 ++++++++++++++++++++++++++++++ sol/coroutine.hpp | 2 +- sol/function.hpp | 8 +- sol/function_types.hpp | 8 +- sol/function_types_basic.hpp | 6 +- sol/function_types_core.hpp | 14 +- sol/function_types_member.hpp | 14 +- sol/function_types_overload.hpp | 10 +- sol/function_types_templated.hpp | 8 +- sol/function_types_usertype.hpp | 10 +- sol/inheritance.hpp | 16 +- sol/property.hpp | 85 +++++++++ sol/protected_function.hpp | 3 +- sol/protected_function_result.hpp | 8 +- sol/stack.hpp | 8 + sol/stack_check.hpp | 131 +++++++------- sol/stack_check_get.hpp | 54 +++--- sol/stack_core.hpp | 8 + sol/stack_get.hpp | 54 +++++- sol/stack_push.hpp | 142 +++++++++++---- sol/string_shim.hpp | 48 +++++ sol/traits.hpp | 159 +---------------- sol/tuple.hpp | 18 +- sol/types.hpp | 101 +++++++++-- sol/usertype.hpp | 10 +- sol/usertype_metatable.hpp | 187 ++++++++++++++++++++ sol/variadic_args.hpp | 6 +- sol/wrapper.hpp | 209 ++++++++++++++++++++++ test_strings.cpp | 5 +- tests.cpp | 2 +- 32 files changed, 1481 insertions(+), 355 deletions(-) create mode 100644 sol/bind_traits.hpp create mode 100644 sol/call.hpp create mode 100644 sol/property.hpp create mode 100644 sol/string_shim.hpp create mode 100644 sol/usertype_metatable.hpp create mode 100644 sol/wrapper.hpp diff --git a/Optional b/Optional index e62740b3..f11b4f00 160000 --- a/Optional +++ b/Optional @@ -1 +1 @@ -Subproject commit e62740b328e100ac76821e151cb3cfe7412bd98a +Subproject commit f11b4f00eb029862dd2a4d7e3497324aba8a020f diff --git a/sol/bind_traits.hpp b/sol/bind_traits.hpp new file mode 100644 index 00000000..0a30e932 --- /dev/null +++ b/sol/bind_traits.hpp @@ -0,0 +1,218 @@ +#pragma once + +#include "tuple.hpp" + +namespace sol { +namespace meta { +namespace meta_detail { + +template +struct check_deducible_signature { + struct nat {}; + template + static auto test(int) -> decltype(&G::operator(), void()); + template + static auto test(...) -> nat; + + using type = std::is_void(0))>; +}; +} // meta_detail + +template +struct has_deducible_signature : meta_detail::check_deducible_signature::type { }; + +namespace meta_detail { + +template +struct void_tuple_element : meta::tuple_element {}; + +template +struct void_tuple_element> { typedef void type; }; + +template +using void_tuple_element_t = typename void_tuple_element::type; + +template +struct basic_traits { +private: + typedef std::conditional_t::value, int, T>& first_type; + +public: + static const bool is_member_function = std::is_void::value; + static const bool has_c_var_arg = has_c_variadic; + static const std::size_t arity = sizeof...(Args); + static const std::size_t free_arity = sizeof...(Args) + static_cast(!std::is_void::value); + typedef types args_list; + typedef std::tuple args_tuple; + typedef T object_type; + typedef R return_type; + typedef tuple_types returns_list; + typedef R(function_type)(Args...); + typedef std::conditional_t::value, args_list, types> free_args_list; + typedef std::conditional_t::value, R(Args...), R(first_type, Args...)> free_function_type; + typedef std::conditional_t::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type; + typedef std::remove_pointer_t signature_type; + template + using arg_at = void_tuple_element_t; +}; + +template::value> +struct fx_traits : basic_traits {}; + +// Free Functions +template +struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args...); +}; + +template +struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args...); +}; + +template +struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args..., ...); +}; + +template +struct fx_traits : basic_traits { + typedef R(*function_pointer_type)(Args..., ...); +}; + +// Member Functions +/* C-Style Variadics */ +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...); +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...); +}; + +/* Const Volatile */ +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const volatile; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const volatile; +}; + +/* Member Function Qualifiers */ +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) &; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) &; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const &; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const &; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const volatile &; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const volatile &; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) &&; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) &&; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const &&; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const &&; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args...) const volatile &&; +}; + +template +struct fx_traits : basic_traits { + typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&; +}; + +template +struct fx_traits : fx_traits::function_type, false> {}; + +template::value> +struct callable_traits : fx_traits> { + +}; + +template +struct callable_traits { + typedef R Arg; + typedef T object_type; + using signature_type = R(T::*); + static const bool is_member_function = false; + static const std::size_t arity = 1; + static const std::size_t free_arity = 2; + typedef std::tuple args_tuple; + typedef R return_type; + typedef types args_list; + typedef meta::tuple_types returns_list; + typedef R(function_type)(T&, R); + typedef R(*function_pointer_type)(T&, R); + typedef R(*free_function_pointer_type)(T&, R); + template + using arg_at = void_tuple_element_t; +}; +} // meta_detail + +template +struct bind_traits : meta_detail::callable_traits {}; + +template +using function_args_t = typename bind_traits::args_list; + +template +using function_signature_t = typename bind_traits::signature_type; + +template +using function_return_t = typename bind_traits::return_type; + +} // meta +} // sol \ No newline at end of file diff --git a/sol/call.hpp b/sol/call.hpp new file mode 100644 index 00000000..440c8108 --- /dev/null +++ b/sol/call.hpp @@ -0,0 +1,282 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rappt1101010z, 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_CALL_HPP +#define SOL_CALL_HPP + +#include "wrapper.hpp" +#include "property.hpp" +#include "stack.hpp" + +namespace sol { +namespace call_detail { + + template + inline decltype(auto) pick(std::integral_constant, F&& f) { + return std::forward(f); + } + + template + inline auto& pick(std::true_type, property_wrapper& f) { + return f.read; + } + + template + inline auto& pick(std::false_type, property_wrapper& f) { + return f.write; + } + + namespace overload_detail { + template + inline int overload_match_arity(sol::types<>, std::index_sequence<>, std::index_sequence, Match&&, lua_State* L, int, int, Args&&...) { + return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types"); + } + + template + inline int overload_match_arity(sol::types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + typedef lua_bind_traits> traits; + typedef meta::tuple_types return_types; + typedef typename traits::free_args_list args_list; + typedef typename args_list::indices args_indices; + int farity = traits::free_arity; + // 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)...); + } + 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)...); + } + 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)...); + } + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); + } + } // overload_detail + + template + inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + return overload_detail::overload_match_arity(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + + template + inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) { + int fxarity = lua_gettop(L) - (start - 1); + return overload_match_arity(std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + + 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; + return stack::call_into_lua(returns_list(), args_list(), L, is_index ? 2 : 3, wrap::caller(), f); + } + + static int var_call(std::false_type, lua_State* L, F f) { + typedef wrapper> wrap; + typedef typename wrap::free_args_list args_list; + typedef typename wrap::returns_list returns_list; + return stack::call_into_lua(returns_list(), args_list(), L, 1, wrap::caller(), f); + } + + static int call(lua_State* L, F f) { + return var_call(std::integral_constant(), L, f); + } + }; + + template + struct agnostic_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; +#ifdef SOL_SAFE_USERTYPE + typedef typename wrap::object_type object_type; + object_type* o = 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, wrap::caller(), f, *o); +#else + object_type& o = stack::get(L, 1); + return stack::call_into_lua(returns_list(), args_list(), L, is_variable ? 3 : 2, wrap::caller(), f); +#endif // Safety + } + }; + + template + struct agnostic_lua_call_wrapper { + static int call(lua_State* L, 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::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; +#ifdef SOL_SAFE_USERTYPE + object_type* o = stack::get(L, 1); + if (o == nullptr) { + if (is_variable) { + return luaL_error(L, "sol: received null for 'self' argument (bad '.' access?)"); + } + return luaL_error(L, "sol: received null for 'self' argument (pass 'self' as first argument)"); + } + return stack::call_into_lua(types(), args_list(), L, is_variable ? 3 : 2, wrap::caller(), f, *o); +#else + object_type& o = stack::get(L, 1); + return stack::call_into_lua(types(), args_list(), L, is_variable ? 3 : 2, wrap::caller(), f, o); +#endif // Safety + } + + static int call_assign(std::false_type, lua_State* L, F f) { + return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); + } + + static int call_const(std::false_type, lua_State* L, F f) { + typedef typename traits_type::return_type R; + return call_assign(std::is_assignable>, R>(), L, f); + } + + static int call_const(std::true_type, lua_State* L, F f) { + return luaL_error(L, "sol: cannot write to a readonly (const) variable"); + } + + static int call(lua_State* L, F f) { + return call_const(std::is_const(), L, f); + } + }; + + template + struct agnostic_lua_call_wrapper::value>> { + typedef sol::lua_bind_traits traits_type; + + static int call(lua_State* L, F f) { + typedef wrapper> wrap; + typedef typename wrap::object_type object_type; + typedef typename wrap::returns_list returns_list; +#ifdef SOL_SAFE_USERTYPE + object_type* o = stack::get(L, 1); + if (o == nullptr) { + if (is_variable) { + return luaL_error(L, "sol: 'self' argument is nullptr (bad '.' access?)"); + } + return luaL_error(L, "sol: 'self' argument is nullptr (pass 'self' as first argument)"); + } + return stack::call_into_lua(returns_list(), types<>(), L, is_variable ? 3 : 2, wrap::caller(), f, *o); +#else + object_type& o = stack::get(L, 1); + return stack::call_into_lua(returns_list(), types<>(), L, is_variable ? 3 : 2, wrap::caller(), f, o); +#endif // Safety + } + }; + + template + struct agnostic_lua_call_wrapper, is_index, is_variable, C> { + typedef sol::overload_set F; + + template + static int select_call(sol::types, sol::index_value, sol::types r, sol::types a, lua_State* L, int, int start, F& fx) { + auto& f = std::get(fx.set); + return agnostic_lua_call_wrapper{}.call(L, f); + } + + static int call(lua_State* L, F& fx) { + auto mfx = [&](auto&&... args) { return select_call(std::forward(args)...); }; + return overload_match_arity(mfx, L, lua_gettop(L), 1, fx); + } + }; + + template + struct agnostic_lua_call_wrapper { + static int call(lua_State* L, sol::no_construction&) { + return luaL_error(L, "cannot call something tagged with 'no construction'"); + } + }; + + template + struct lua_call_wrapper : agnostic_lua_call_wrapper {}; + + template + struct lua_call_wrapper, is_index, is_variable, C> { + typedef sol::constructor_list F; + + static int call(lua_State* L, F&) { + static const auto& meta = usertype_traits::metatable; + int argcount = lua_gettop(L); + call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, meta, 1) : call_syntax::dot; + argcount -= static_cast(syntax); + + T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); + T*& referencepointer = *pointerpointer; + T* obj = reinterpret_cast(pointerpointer + 1); + referencepointer = obj; + reference userdataref(L, -1); + userdataref.pop(); + + function_detail::construct(detail::constructor_match(obj), L, argcount, 1 + static_cast(syntax)); + + userdataref.push(); + luaL_getmetatable(L, &meta[0]); + if (stack::get(L) == type::nil) { + lua_pop(L, 1); + return luaL_error(L, "sol: unable to get usertype metatable"); + } + + lua_setmetatable(L, -2); + return 1; + } + }; + + template + int call_wrapped(lua_State* L, Fx&& fx) { + return lua_call_wrapper, is_index, is_variable>{}.call(L, std::forward(fx)); + } + + template + struct is_var_bind : std::false_type {}; + + template + struct is_var_bind::value>> : std::true_type {}; + + template <> + struct is_var_bind : std::true_type {}; + + template + struct is_var_bind> : std::true_type {}; + +} // call_detail + +template +struct is_variable_binding : call_detail::is_var_bind> {}; + +template +struct is_function_binding : meta::neg> {}; + +} // sol + +#endif // SOL_CALL_HPP \ No newline at end of file diff --git a/sol/coroutine.hpp b/sol/coroutine.hpp index 65bcbd59..5d442bdc 100644 --- a/sol/coroutine.hpp +++ b/sol/coroutine.hpp @@ -59,7 +59,7 @@ private: protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { int stacksize = lua_gettop( lua_state() ); - int firstreturn = std::max( 1, stacksize - static_cast( n ) ); + int firstreturn = (std::max)( 1, stacksize - static_cast( n ) ); luacall(n, LUA_MULTRET); int poststacksize = lua_gettop(lua_state()); int returncount = poststacksize - (firstreturn - 1); diff --git a/sol/function.hpp b/sol/function.hpp index 14cc5a33..5fdbb37a 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -57,7 +57,7 @@ private: function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n ) const { int stacksize = lua_gettop( base_t::lua_state( ) ); - int firstreturn = std::max( 1, stacksize - static_cast( n ) ); + int firstreturn = (std::max)( 1, stacksize - static_cast( n ) ); luacall(n, LUA_MULTRET); int poststacksize = lua_gettop( base_t::lua_state( ) ); int returncount = poststacksize - (firstreturn - 1); @@ -70,7 +70,7 @@ public: basic_function& operator=(const basic_function&) = default; basic_function(basic_function&&) = default; basic_function& operator=(basic_function&&) = default; - basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {} + basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {} basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {} basic_function(lua_State* L, int index = -1): base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS @@ -100,7 +100,7 @@ namespace stack { template struct getter> { typedef meta::bind_traits fx_t; - typedef typename fx_t::args_type args_types; + typedef typename fx_t::args_list args_lists; typedef meta::tuple_types return_types; template @@ -127,7 +127,7 @@ struct getter> { } static std::function get(lua_State* L, int index) { - return get_std_func(return_types(), args_types(), L, index); + return get_std_func(return_types(), args_lists(), L, index); } }; } // stack diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 489a2029..37338540 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -31,6 +31,7 @@ #include "function_types_overload.hpp" #include "function_types_allocator.hpp" #include "resolve.hpp" +#include "call.hpp" namespace sol { template @@ -45,13 +46,6 @@ function_arguments function_args( Args&&... args ) { return function_arguments(std::forward(args)...); } -// Allow someone to make a member variable readonly (const) -template -auto readonly( R T::* v ) { - typedef const R C; - return static_cast( v ); -} - namespace stack { template struct pusher> { diff --git a/sol/function_types_basic.hpp b/sol/function_types_basic.hpp index cead6ee9..5489458c 100644 --- a/sol/function_types_basic.hpp +++ b/sol/function_types_basic.hpp @@ -34,7 +34,7 @@ struct upvalue_free_function { static int real_call(lua_State* L) { auto udata = stack::stack_detail::get_as_upvalues(L); function_type* fx = udata.first; - int r = stack::call_into_lua(meta::tuple_types(), typename traits_type::args_type(), L, 1, fx); + int r = stack::call_into_lua(meta::tuple_types(), typename traits_type::args_list(), L, 1, fx); return r; } @@ -65,7 +65,7 @@ struct upvalue_member_function { auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type { return (item.*memfx)(std::forward(args)...); }; - return stack::call_into_lua(meta::tuple_types(), typename traits_type::args_type(), L, 1, fx); + return stack::call_into_lua(meta::tuple_types(), typename traits_type::args_list(), L, 1, fx); } static int call (lua_State* L) { @@ -151,7 +151,7 @@ struct upvalue_this_member_function { 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_type(), L, 2, fx); + int n = stack::call_into_lua<1>(meta::tuple_types(), typename traits_type::args_list(), L, 2, fx); return n; } diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index 01ca1fdc..3ea1c2eb 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -23,9 +23,13 @@ #define SOL_FUNCTION_TYPES_CORE_HPP #include "stack.hpp" +#include "wrapper.hpp" #include namespace sol { +namespace detail { +struct empty {}; +} template struct member_property { typedef std::conditional_t::value, detail::empty, RSig> R; @@ -150,7 +154,7 @@ 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::args_list args_list; 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; @@ -179,7 +183,7 @@ struct functor { 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 meta::pop_front_type_t args_list; 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 - 1; @@ -211,7 +215,7 @@ struct functor::value && template struct functor, C> { typedef meta::bind_traits::value, RSig, WSig>> traits_type; - typedef meta::pop_front_type_t args_type; + typedef meta::pop_front_type_t args_list; typedef std::conditional_t::value, typename traits_type::template arg_at<0>, typename traits_type::return_type> return_type; typedef member_property function_type; typedef meta::neg> can_read; @@ -244,7 +248,7 @@ struct functor, C> { template struct functor::value>> { typedef meta::bind_traits traits_type; - typedef typename traits_type::args_type args_type; + typedef typename traits_type::args_list args_list; typedef typename traits_type::return_type return_type; static const std::size_t arity = traits_type::arity; typedef std::true_type can_read; @@ -277,7 +281,7 @@ struct functor::va template struct functor::value>> { typedef meta::bind_traits traits_type; - typedef typename traits_type::args_type args_type; + typedef typename traits_type::args_list args_list; typedef typename traits_type::return_type return_type; static const std::size_t arity = traits_type::arity; static const bool is_free = false; diff --git a/sol/function_types_member.hpp b/sol/function_types_member.hpp index 7d436a69..27f85a36 100644 --- a/sol/function_types_member.hpp +++ b/sol/function_types_member.hpp @@ -30,14 +30,14 @@ 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_types; + 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_types(), L, 1, fx); + return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); } virtual int operator()(lua_State* L) override { @@ -51,14 +51,14 @@ 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_types; + 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_types(), L, 1, fx); + return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); } virtual int operator()(lua_State* L) override { @@ -71,7 +71,7 @@ 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_types; + typedef meta::function_args_t args_lists; struct functor { function_type invocation; T member; @@ -90,7 +90,7 @@ struct member_function : public base_function { 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_types(), L, 1, fx); + return stack::call_into_lua(meta::tuple_types(), args_lists(), L, 1, fx); } virtual int operator()(lua_State* L) override { @@ -103,7 +103,7 @@ 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_type args_types; + typedef typename meta::bind_traits::args_list args_lists; function_type var; T member; typedef std::add_lvalue_reference_t>> M; diff --git a/sol/function_types_overload.hpp b/sol/function_types_overload.hpp index 429100f5..c6ea7e05 100644 --- a/sol/function_types_overload.hpp +++ b/sol/function_types_overload.hpp @@ -36,7 +36,7 @@ struct overload_traits : lua_bind_traits { template struct overload_traits> { - typedef typename functor::args_type args_type; + typedef typename functor::args_list args_list; 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); @@ -51,8 +51,8 @@ template , 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; - typedef typename args_type::indices args_indices; + typedef typename traits::args_list args_list; + typedef typename args_list::indices args_indices; 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) { @@ -61,10 +61,10 @@ inline int overload_match_arity(types, std::index_sequence if (traits::arity != fxarity) { 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 - traits::boost, no_panic)) { + if (!stack::stack_detail::check_types().check(args_list(), 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)...); + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } } // internals diff --git a/sol/function_types_templated.hpp b/sol/function_types_templated.hpp index 389c942e..b1fb363e 100644 --- a/sol/function_types_templated.hpp +++ b/sol/function_types_templated.hpp @@ -29,9 +29,9 @@ namespace function_detail { template inline int call_wrapper_variable(std::false_type, lua_State* L) { typedef meta::bind_traits> traits_type; - typedef typename traits_type::args_type args_type; + typedef typename traits_type::args_list args_list; typedef meta::tuple_types return_type; - return stack::call_into_lua(return_type(), args_type(), L, 1, fx); + return stack::call_into_lua(return_type(), args_list(), L, 1, fx); } template @@ -86,14 +86,14 @@ namespace function_detail { inline int call_wrapper_function(std::true_type, lua_State* L) { typedef meta::bind_traits> traits_type; typedef typename traits_type::object_type T; - typedef typename traits_type::args_type args_type; + typedef typename traits_type::args_list args_list; typedef typename traits_type::return_type return_type; typedef meta::tuple_types return_type_list; auto mfx = [&](auto&&... args) -> typename traits_type::return_type { auto& member = stack::get(L, 1); return (member.*fx)(std::forward(args)...); }; - int n = stack::call_into_lua<1>(return_type_list(), args_type(), L, 2, mfx); + int n = stack::call_into_lua<1>(return_type_list(), args_list(), L, 2, mfx); return n; } diff --git a/sol/function_types_usertype.hpp b/sol/function_types_usertype.hpp index 1b1d62ce..8deba90c 100644 --- a/sol/function_types_usertype.hpp +++ b/sol/function_types_usertype.hpp @@ -34,7 +34,7 @@ struct usertype_function_core : public base_function { typedef std::remove_pointer_t> function_type; typedef functor fx_t; typedef typename fx_t::traits_type traits_type; - typedef typename fx_t::args_type args_type; + typedef typename fx_t::args_list args_list; typedef typename fx_t::return_type return_type; fx_t fx; @@ -53,7 +53,7 @@ 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::args_list args_list; typedef typename base_t::return_type return_type; template @@ -66,7 +66,7 @@ struct usertype_function : public usertype_function_core { return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)"); } #endif // Safety - return static_cast(*this)(meta::tuple_types(), args_type(), index_value<2>(), L); + return static_cast(*this)(meta::tuple_types(), args_list(), index_value<2>(), L); } virtual int operator()(lua_State* L) override { @@ -80,7 +80,7 @@ struct usertype_variable_function : public usertype_function_core typedef std::remove_pointer_t T; typedef typename base_t::fx_t fx_t; typedef typename base_t::traits_type traits_type; - typedef typename base_t::args_type args_type; + typedef typename base_t::args_list args_list; typedef typename base_t::return_type return_type; typedef typename fx_t::can_read can_read; typedef typename fx_t::can_write can_write; @@ -103,7 +103,7 @@ struct usertype_variable_function : public usertype_function_core } int set_writable(std::true_type, lua_State* L) { - return static_cast(*this)(meta::tuple_types(), args_type(), index_value<3>(), L); + return static_cast(*this)(meta::tuple_types(), args_list(), index_value<3>(), L); } int set_variable(std::false_type, lua_State* L) { diff --git a/sol/inheritance.hpp b/sol/inheritance.hpp index a78abc40..caa99a28 100644 --- a/sol/inheritance.hpp +++ b/sol/inheritance.hpp @@ -111,7 +111,7 @@ struct inheritance { return ti != typeid(Base) || type_check(types(), ti); } - static bool check(const std::type_info& ti) { + static bool type_check(const std::type_info& ti) { return ti != typeid(T) || type_check(types(), ti); } @@ -125,14 +125,14 @@ struct inheritance { return ti != typeid(Base) ? type_cast(types(), data, ti) : static_cast(dynamic_cast(static_cast(data))); } - static void* cast(void* voiddata, const std::type_info& ti) { + static void* type_cast(void* voiddata, const std::type_info& ti) { T* data = static_cast(voiddata); return static_cast(ti != typeid(T) ? type_cast(types(), data, ti) : data); } }; -using inheritance_check_function = decltype(&inheritance::check); -using inheritance_cast_function = decltype(&inheritance::cast); +using inheritance_check_function = decltype(&inheritance::type_check); +using inheritance_cast_function = decltype(&inheritance::type_cast); #else template struct inheritance { @@ -145,7 +145,7 @@ struct inheritance { return ti != id_for::value || type_check(types(), ti); } - static bool check(std::size_t ti) { + static bool type_check(std::size_t ti) { return ti != id_for::value || type_check(types(), ti); } @@ -159,14 +159,14 @@ struct inheritance { return ti != id_for::value ? type_cast(types(), data, ti) : static_cast(static_cast(data)); } - static void* cast(void* voiddata, std::size_t ti) { + static void* type_cast(void* voiddata, std::size_t ti) { T* data = static_cast(voiddata); return static_cast(ti != id_for::value ? type_cast(types(), data, ti) : data); } }; -using inheritance_check_function = decltype(&inheritance::check); -using inheritance_cast_function = decltype(&inheritance::cast); +using inheritance_check_function = decltype(&inheritance::type_check); +using inheritance_cast_function = decltype(&inheritance::type_cast); #endif // No Exceptions and/or No Runtime Type Information } // detail diff --git a/sol/property.hpp b/sol/property.hpp new file mode 100644 index 00000000..55feb8ca --- /dev/null +++ b/sol/property.hpp @@ -0,0 +1,85 @@ +// 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_PROPERTY_HPP +#define SOL_PROPERTY_HPP + +namespace sol { + + struct no_prop { }; + + template + struct property_wrapper { + typedef std::integral_constant::value> can_read; + typedef std::integral_constant::value> can_write; + typedef std::conditional_t Read; + typedef std::conditional_t Write; + Read read; + Write write; + + template + property_wrapper(Rx&& r, Wx&& w) : read(std::forward(r)), write(std::forward(w)) {} + }; + + namespace property_detail { + template + inline decltype(auto) property(std::true_type, R&& read, W&& write) { + return property_wrapper, std::decay_t>(std::forward(read), std::forward(write)); + } + template + inline decltype(auto) property(std::false_type, W&& write, R&& read) { + return property_wrapper, std::decay_t>(std::forward(read), std::forward(write)); + } + template + inline decltype(auto) property(std::true_type, R&& read) { + return property_wrapper, void>(std::forward(read), no_prop()); + } + template + inline decltype(auto) property(std::false_type, W&& write) { + return property_wrapper>(no_prop(), std::forward(write)); + } + } // property_detail + + template + inline decltype(auto) property(F&& f, G&& g) { + using namespace sol; + typedef lua_bind_traits> left_traits; + typedef lua_bind_traits> right_traits; + return property_detail::property(meta::boolean<(left_traits::arity < right_traits::arity)>(), std::forward(f), std::forward(g)); + } + + template + inline decltype(auto) property(F&& f) { + using namespace sol; + typedef lua_bind_traits> left_traits; + return property_detail::property(meta::boolean<(left_traits::arity == 0)>(), std::forward(f)); + } + + // Allow someone to make a member variable readonly (const) + template + auto readonly(R T::* v) { + typedef const R C; + return static_cast(v); + } + +} // sol + +#endif // SOL_PROPERTY_HPP diff --git a/sol/protected_function.hpp b/sol/protected_function.hpp index 79cb0cf4..321e57a2 100644 --- a/sol/protected_function.hpp +++ b/sol/protected_function.hpp @@ -26,6 +26,7 @@ #include "stack.hpp" #include "protected_function_result.hpp" #include +#include namespace sol { template @@ -86,7 +87,7 @@ private: protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, handler& h) const { int stacksize = lua_gettop(base_t::lua_state()); - int firstreturn = std::max(1, stacksize - static_cast(n) - 1); + int firstreturn = (std::max)(1, stacksize - static_cast(n) - 1); int returncount = 0; call_status code = call_status::ok; #ifndef SOL_NO_EXCEPTIONS diff --git a/sol/protected_function_result.hpp b/sol/protected_function_result.hpp index f3bfdc90..90c76fcd 100644 --- a/sol/protected_function_result.hpp +++ b/sol/protected_function_result.hpp @@ -55,20 +55,20 @@ private: return stack::get(L, index); } - sol::optional tagged_get( types> ) const { + optional tagged_get( types> ) const { if (valid()) { return nullopt; } - return sol::error(detail::direct_error, stack::get(L, index)); + return error(detail::direct_error, stack::get(L, index)); } - sol::error tagged_get( types ) const { + error tagged_get( types ) const { #ifdef SOL_CHECK_ARGUMENTS 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 error(detail::direct_error, stack::get(L, index)); } public: diff --git a/sol/stack.hpp b/sol/stack.hpp index 03682a18..56405140 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -162,6 +162,14 @@ inline int call_into_lua(types, types ta, lua_State* L, i return push_reference(L, std::forward(r)); } +template +inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + typedef lua_bind_traits> traits_type; + typedef typename traits_type::args_list args_list; + typedef typename traits_type::returns_list returns_list; + return call_into_lua(returns_list(), args_list(), start, std::forward(fx), std::forward(fxargs)...) +} + inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index = -2) { luaL_getmetatable(L, key.c_str()); if (lua_compare(L, -1, index, LUA_OPEQ) == 1) { diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index e78f4756..a048dc49 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -164,6 +164,23 @@ struct checker { } }; +template +struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler) { + type t = type_of(L, index); + bool success = t == type::userdata; + if (!success) { + // expected type, actual type + handler(L, index, type::userdata, t); + } + return success; + } +}; + +template +struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; + template struct checker, type::userdata, C> : checker::value, C> {}; @@ -235,77 +252,63 @@ struct checker { } }; -template -struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler) { - type t = type_of(L, index); - bool success = t == type::userdata || t == type::lightuserdata; - if (!success) { - // expected type, actual type - handler(L, index, type::lightuserdata, t); - } - return success; - } -}; - template struct checker { - template - static bool check (types, lua_State* L, type indextype, int index, Handler&& handler) { - if (indextype != type::userdata) { - handler(L, index, type::userdata, indextype); - return false; - } - if (meta::any, std::is_same, std::is_same, std::is_same>::value) - return true; - if (lua_getmetatable(L, index) == 0) { - return true; - } - if (stack_detail::check_metatable(L)) - return true; - if (stack_detail::check_metatable(L)) - return true; - if (stack_detail::check_metatable>(L)) - return true; + template + static bool check(types, lua_State* L, type indextype, int index, Handler&& handler) { + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype); + return false; + } + if (meta::any, std::is_same, std::is_same, std::is_same>::value) + return true; + if (lua_getmetatable(L, index) == 0) { + return true; + } + if (stack_detail::check_metatable(L)) + return true; + if (stack_detail::check_metatable(L)) + return true; + if (stack_detail::check_metatable>(L)) + return true; #ifndef SOL_NO_EXCEPTIONS - lua_getfield(L, -1, &detail::base_class_check_key()[0]); - void* basecastdata = lua_touserdata(L, -1); - detail::throw_cast basecast = (detail::throw_cast)basecastdata; - bool success = detail::catch_check(basecast); + lua_getfield(L, -1, &detail::base_class_check_key()[0]); + void* basecastdata = lua_touserdata(L, -1); + detail::throw_cast basecast = (detail::throw_cast)basecastdata; + bool success = detail::catch_check(basecast); #elif !defined(SOL_NO_RTTI) - lua_getfield(L, -1, &detail::base_class_check_key()[0]); - if (stack::get(L) == type::nil) { - lua_pop(L, 2); - return false; - } - void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; - bool success = ic(typeid(T)); + lua_getfield(L, -1, &detail::base_class_check_key()[0]); + if (stack::get(L) == type::nil) { + lua_pop(L, 2); + return false; + } + void* basecastdata = lua_touserdata(L, -1); + detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; + bool success = ic(typeid(T)); #else - // Topkek - lua_getfield(L, -1, &detail::base_class_check_key()[0]); - if (stack::get(L) == type::nil) { - lua_pop(L, 2); - return false; - } - void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; - bool success = ic(detail::id_for::value); + // Topkek + lua_getfield(L, -1, &detail::base_class_check_key()[0]); + if (stack::get(L) == type::nil) { + lua_pop(L, 2); + return false; + } + void* basecastdata = lua_touserdata(L, -1); + detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; + bool success = ic(detail::id_for::value); #endif // No Runtime Type Information || Exceptions - lua_pop(L, 2); - if (!success) { - handler(L, index, type::userdata, indextype); - return false; - } - return true; - } + lua_pop(L, 2); + if (!success) { + handler(L, index, type::userdata, indextype); + return false; + } + return true; + } - template - static bool check (lua_State* L, int index, Handler&& handler) { - const type indextype = type_of(L, index); - return check(types(), L, indextype, index, std::forward(handler)); - } + template + static bool check(lua_State* L, int index, Handler&& handler) { + const type indextype = type_of(L, index); + return check(types(), L, indextype, index, std::forward(handler)); + } }; template diff --git a/sol/stack_check_get.hpp b/sol/stack_check_get.hpp index 9175399c..4711fa0e 100644 --- a/sol/stack_check_get.hpp +++ b/sol/stack_check_get.hpp @@ -52,30 +52,44 @@ struct check_getter> { template struct check_getter::value && lua_type_of::value == type::number>> { - template - static optional get( lua_State* L, int index, Handler&& handler) { - int isnum = 0; - lua_Integer value = lua_tointegerx(L, index, &isnum); - if (isnum == 0) { - handler(L, index, type::number, type_of(L, index)); - return nullopt; - } - return static_cast(value); - } + template + static optional get(lua_State* L, int index, Handler&& handler) { + int isnum = 0; + lua_Integer value = lua_tointegerx(L, index, &isnum); + if (isnum == 0) { + handler(L, index, type::number, type_of(L, index)); + return nullopt; + } + return static_cast(value); + } +}; + +template +struct check_getter::value>> { + template + static optional get(lua_State* L, int index, Handler&& handler) { + int isnum = 0; + lua_Integer value = lua_tointegerx(L, index, &isnum); + if (isnum == 0) { + handler(L, index, type::number, type_of(L, index)); + return nullopt; + } + return static_cast(value); + } }; template struct check_getter::value>> { - template - static optional get( lua_State* L, int index, Handler&& handler) { - int isnum = 0; - lua_Number value = lua_tonumberx(L, index, &isnum); - if (isnum == 0) { - handler(L, index, type::number, type_of(L, index)); - return nullopt; - } - return static_cast(value); - } + template + static optional get(lua_State* L, int index, Handler&& handler) { + int isnum = 0; + lua_Number value = lua_tonumberx(L, index, &isnum); + if (isnum == 0) { + handler(L, index, type::number, type_of(L, index)); + return nullopt; + } + return static_cast(value); + } }; template diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index db9d93ab..5bebf811 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -202,6 +202,14 @@ inline decltype(auto) tagged_get(types>, lua_State* L, int index = - return stack_detail::unchecked_get>(L, index); } +template +inline int alloc_destroy(lua_State* L) { + void* rawdata = lua_touserdata(L, up_value_index(1)); + T* data = static_cast(rawdata); + std::allocator alloc; + alloc.destroy(data); +} + } // stack_detail template diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index f1cb078c..dfc6299b 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -62,6 +62,13 @@ struct getter, std::is_unsigne } }; +template +struct getter::value>> { + static T get(lua_State* L, int index = -1) { + return static_cast(lua_tointegerx(L, index, nullptr)); + } +}; + template struct getter::value || std::is_base_of::value>> { static T get(lua_State* L, int index = -1) { @@ -83,6 +90,27 @@ struct getter { } }; +template +struct getter> { + static light get(lua_State* L, int index = -1) { + return light( static_cast(lua_touserdata(L, index)) ); + } +}; + +template +struct getter> { + static T& get(lua_State* L, int index = -1) { + return *static_cast(lua_touserdata(L, index)); + } +}; + +template +struct getter> { + static T* get(lua_State* L, int index = -1) { + return static_cast(lua_touserdata(L, index)); + } +}; + template<> struct getter { static type get(lua_State *L, int index){ @@ -106,6 +134,15 @@ struct getter { } }; +template <> +struct getter { + string_detail::string_shim get(lua_State* L, int index) { + size_t len; + const char* p = lua_tolstring(L, index, &len); + return string_detail::string_shim(p, len); + } +}; + template<> struct getter { static const char* get(lua_State* L, int index = -1) { @@ -113,6 +150,17 @@ struct getter { } }; +template<> +struct getter { + static meta_function get(lua_State *L, int index) { + const char* name = getter{}.get(L, index); + for (std::size_t i = 0; i < meta_function_names.size(); ++i) + if (meta_function_names[i] == name) + return static_cast(i); + return meta_function::construct; + } +}; + template<> struct getter { static char get(lua_State* L, int index = -1) { @@ -208,9 +256,9 @@ struct getter { template<> struct getter { - static c_closure get(lua_State* L, int index = -1) { - return c_closure(lua_tocfunction(L, index), -1); - } + static c_closure get(lua_State* L, int index = -1) { + return c_closure(lua_tocfunction(L, index), -1); + } }; template<> diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 521b6673..2634770a 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -31,44 +31,54 @@ namespace sol { namespace stack { template struct pusher { - template - static int push(lua_State* L, Args&&... args) { - // Basically, we store all user-data like this: - // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new - // data in the first sizeof(T*) bytes, and then however many bytes it takes to - // do the actual object. Things that are std::ref or plain T* are stored as - // just the sizeof(T*), and nothing else. - T** pointerpointer = static_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); - T*& referencereference = *pointerpointer; - T* allocationtarget = reinterpret_cast(pointerpointer + 1); - referencereference = allocationtarget; - std::allocator alloc{}; - alloc.construct(allocationtarget, std::forward(args)...); - luaL_newmetatable(L, &usertype_traits::metatable[0]); - lua_setmetatable(L, -2); - return 1; - } -}; + template + static int push_keyed(lua_State* L, metatable_registry_key k, Args&&... args) { + // Basically, we store all user-data like this: + // If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new + // data in the first sizeof(T*) bytes, and then however many bytes it takes to + // do the actual object. Things that are std::ref or plain T* are stored as + // just the sizeof(T*), and nothing else. + T** pointerpointer = static_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); + T*& referencereference = *pointerpointer; + T* allocationtarget = reinterpret_cast(pointerpointer + 1); + referencereference = allocationtarget; + std::allocator alloc{}; + alloc.construct(allocationtarget, std::forward(args)...); + luaL_newmetatable(L, &k.key[0]); + lua_setmetatable(L, -2); + return 1; + } -template <> -struct pusher { - template - static int push(lua_State* L, T&& obj) { - return stack::push(L, detail::ptr(obj)); - } + template + static int push(lua_State* L, Args&&... args) { + return push_keyed(L, meta_registry_key(&usertype_traits::metatable[0]), std::forward(args)...); + } }; template struct pusher { - static int push(lua_State* L, T* obj) { - if (obj == nullptr) - return stack::push(L, nil); - T** pref = static_cast(lua_newuserdata(L, sizeof(T*))); - *pref = obj; - luaL_getmetatable(L, &usertype_traits::metatable[0]); - lua_setmetatable(L, -2); - return 1; - } + template + static int push_keyed(lua_State* L, metatable_registry_key k, T* obj) { + if (obj == nullptr) + return stack::push(L, nil); + T** pref = static_cast(lua_newuserdata(L, sizeof(T*))); + *pref = obj; + luaL_getmetatable(L, &k.key[0]); + lua_setmetatable(L, -2); + return 1; + } + + static int push(lua_State* L, T* obj) { + return push_keyed(L, meta_registry_key(&usertype_traits::metatable[0]), obj); + } +}; + +template <> +struct pusher { + template + static int push(lua_State* L, T&& obj) { + return stack::push(L, detail::ptr(obj)); + } }; template @@ -127,6 +137,16 @@ struct pusher, std::is_signed< } }; +template +struct pusher::value>> { + static int push(lua_State* L, const T& value) { + if (std::is_same::value) { + return stack::push(L, static_cast(value)); + } + return stack::push(L, static_cast>(value)); + } +}; + template struct pusher, std::is_unsigned>::value>> { static int push(lua_State* L, const T& value) { @@ -136,7 +156,7 @@ struct pusher, std::is_unsigne }; template -struct pusher, meta::neg>, meta::neg>>::value>> { +struct pusher, meta::neg>, meta::neg, std::is_base_of>>>::value>> { static int push(lua_State* L, const T& cont) { lua_createtable(L, static_cast(cont.size()), 0); int tableindex = lua_gettop(L); @@ -149,7 +169,7 @@ struct pusher, meta::neg -struct pusher, meta::has_key_value_pair, meta::neg>>::value>> { +struct pusher, meta::has_key_value_pair, meta::neg, std::is_base_of>>>::value>> { static int push(lua_State* L, const T& cont) { lua_createtable(L, static_cast(cont.size()), 0); int tableindex = lua_gettop(L); @@ -213,12 +233,26 @@ struct pusher { template<> struct pusher { - static int push(lua_State* L, c_closure closure) { - lua_pushcclosure(L, closure.c_function, closure.upvalues); + static int push(lua_State* L, c_closure cc) { + lua_pushcclosure(L, cc.c_function, cc.upvalues); return 1; } }; +template +struct pusher> { + template + static int push(std::index_sequence, lua_State* L, T&& c) { + int pushcount = multi_push(L, detail::forward_get(c.upvalues)...); + return stack::push(L, c_closure(c.c_function, pushcount)); + } + + template + static int push(lua_State* L, T&& c) { + return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward(c)); + } +}; + template<> struct pusher { static int push(lua_State* L, void* userdata) { @@ -235,6 +269,31 @@ struct pusher { } }; +template +struct pusher> { + static int push(lua_State* L, light l) { + lua_pushlightuserdata(L, static_cast(l.value)); + return 1; + } +}; + +template +struct pusher> { + template + static int push(lua_State* L, Args&&... args ) { + // A dumb pusher + void* rawdata = lua_newuserdata(L, sizeof(T)); + std::allocator alloc; + alloc.construct(static_cast(rawdata), std::forward(args)...); + lua_CFunction cdel = stack_detail::alloc_destroy; + // Make sure we have a plain GC set for this data + lua_pushlightuserdata(L, rawdata); + lua_pushcclosure(L, cdel, 1); + lua_setfield(L, -2, "__gc"); + return 1; + } +}; + template<> struct pusher { static int push(lua_State* L, userdata_value data) { @@ -276,6 +335,15 @@ struct pusher { } }; +template<> +struct pusher { + static int push(lua_State* L, meta_function m) { + const std::string& str = name_of(m); + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } +}; + #if 0 diff --git a/sol/string_shim.hpp b/sol/string_shim.hpp new file mode 100644 index 00000000..cda7d9ab --- /dev/null +++ b/sol/string_shim.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +namespace sol { + namespace string_detail { + struct string_shim { + std::size_t s; + const char* p; + + string_shim(std::string& r) : string_shim(r.data(), r.size()) {} + string_shim(const char* p) : string_shim(p, std::char_traits::length(p)) {} + string_shim(const char* p, std::size_t s) : s(s), p(p) {} + + static int compare(const char* lhs_p, std::size_t lhs_sz, const char* rhs_p, std::size_t rhs_sz) { + int result = std::char_traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); + if (result != 0) + return result; + if (lhs_sz < rhs_sz) + return -1; + if (lhs_sz > rhs_sz) + return 1; + return 0; + } + + const char* data() const { + return p; + } + + std::size_t size() const { + return s; + } + + bool operator==(const string_shim& r) const { + return compare(p, s, r.data(), r.size()) == 0; + } + + bool operator==(const char* r) const { + return compare(r, std::char_traits::length(r), p, s) == 0; + } + + bool operator==(const std::string& r) const { + return compare(r.data(), r.size(), p, s) == 0; + } + }; + } +} \ No newline at end of file diff --git a/sol/traits.hpp b/sol/traits.hpp index abf162c2..07d7c709 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -23,6 +23,7 @@ #define SOL_TRAITS_HPP #include "tuple.hpp" +#include "bind_traits.hpp" #include #include #include @@ -54,6 +55,9 @@ struct unwrapped> { typedef T type; }; +template +using unwrapped_t = typename unwrapped::type; + template struct remove_member_pointer; @@ -117,21 +121,6 @@ using enable = std::enable_if_t::value, enable_t>; template using disable = std::enable_if_t>::value, enable_t>; -template -using unqualified = std::remove_cv>; - -template -using unqualified_t = typename unqualified::type; - -template -using unwrapped_t = typename unwrapped::type; - -template -using tuple_element = std::tuple_element>; - -template -using tuple_element_t = std::tuple_element_t>; - template struct find_in_pack_v : boolean { }; @@ -252,151 +241,11 @@ struct is_callable { static const bool value = sizeof(test(0)) == sizeof(yes); }; -template -struct check_deducible_signature { - struct nat {}; - template - static auto test(int) -> decltype(&G::operator(), void()); - template - static auto test(...) -> nat; - - using type = std::is_void(0))>; -}; } // meta_detail -template -struct has_deducible_signature : meta_detail::check_deducible_signature::type { }; - template struct is_callable : boolean::value> {}; -namespace meta_detail { - -template -struct void_tuple_element : meta::tuple_element {}; - -template -struct void_tuple_element> { typedef void type; }; - -template -using void_tuple_element_t = typename void_tuple_element::type; - -template::value> -struct fx_traits { - static const bool is_member_function = false; - static const std::size_t arity = 0; - typedef types<> args_type; - typedef std::tuple<> args_tuple_type; - typedef void object_type; - typedef void function_pointer_type; - typedef void function_type; - typedef void free_function_pointer_type; - typedef void signature_type; - typedef void return_type; - template - using arg_at = void_tuple_element_t; -}; - -template -struct fx_traits : fx_traits {}; - -template -struct fx_traits { - static const std::size_t arity = sizeof...(Args); - static const bool is_member_function = true; - typedef T object_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; - typedef R(*free_function_pointer_type)(Args...); - typedef R return_type; - typedef std::remove_pointer_t signature_type; - template - using arg_at = void_tuple_element_t; -}; - -template -struct fx_traits { - static const std::size_t arity = sizeof...(Args); - static const bool is_member_function = true; - typedef T object_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; - typedef R(*free_function_pointer_type)(Args...); - typedef R return_type; - typedef std::remove_pointer_t signature_type; - template - using arg_at = void_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 args_tuple_type; - typedef types args_type; - typedef R(function_type)(Args...); - typedef R(*function_pointer_type)(Args...); - typedef R(*free_function_pointer_type)(Args...); - typedef R return_type; - typedef std::remove_pointer_t signature_type; - template - using arg_at = void_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 args_tuple_type; - typedef types args_type; - typedef R(function_type)(Args...); - typedef R(*function_pointer_type)(Args...); - typedef R(*free_function_pointer_type)(Args...); - typedef R return_type; - typedef std::remove_pointer_t signature_type; - template - using arg_at = void_tuple_element_t; -}; - -template::value> -struct callable_traits : fx_traits> { - -}; - -template -struct callable_traits { - typedef R Arg; - typedef T object_type; - using signature_type = R(T::*); - static const bool is_member_function = false; - static const std::size_t arity = 1; - 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_at = void_tuple_element_t; -}; -} // meta_detail - -template -struct bind_traits : meta_detail::callable_traits> {}; - -template -using function_args_t = typename bind_traits::args_type; - -template -using function_signature_t = typename bind_traits::signature_type; - -template -using function_return_t = typename bind_traits::return_type; - struct has_begin_end_impl { template, typename B = decltype(std::declval().begin()), diff --git a/sol/tuple.hpp b/sol/tuple.hpp index e91c2599..267f0752 100644 --- a/sol/tuple.hpp +++ b/sol/tuple.hpp @@ -41,6 +41,12 @@ template struct tuple_types_> { typedef types type; }; } // detail +template +using unqualified = std::remove_cv>; + +template +using unqualified_t = typename unqualified::type; + template using tuple_types = typename detail::tuple_types_::type; @@ -50,8 +56,18 @@ struct pop_front_type; template using pop_front_type_t = typename pop_front_type::type; +template +struct pop_front_type> { typedef void front_type; typedef types type; }; + template -struct pop_front_type> { typedef types type; }; +struct pop_front_type> { typedef Arg front_type; typedef types type; }; + +template +using tuple_element = std::tuple_element>; + +template +using tuple_element_t = std::tuple_element_t>; + } // meta } // sol diff --git a/sol/types.hpp b/sol/types.hpp index e3bf9eba..9e90e50c 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -22,9 +22,10 @@ #ifndef SOL_TYPES_HPP #define SOL_TYPES_HPP +#include "optional.hpp" #include "compatibility.hpp" #include "traits.hpp" -#include "optional.hpp" +#include "string_shim.hpp" #include #include @@ -83,8 +84,6 @@ inline int c_trampoline(lua_State* L, lua_CFunction f) { return trampoline(L, f); } #endif // Exceptions vs. No Exceptions -struct empty { void operator()() {} }; - template struct unique_usertype {}; } // detail @@ -174,12 +173,72 @@ struct userdata_value { operator void*() const { return value; } }; -struct c_closure { - lua_CFunction c_function; - int upvalues; - c_closure(lua_CFunction f, int upvalues = 0) : c_function(f), upvalues(upvalues) {} +template +struct light { + L* value; + + light(L& x) : value(std::addressof(x)) {} + light(L* x) : value(x) {} + light(void* x) : value(static_cast(x)) {} + operator L* () const { return value; } + operator L& () const { return *value; } }; +template +auto make_light(T& l) { + typedef meta::unwrapped_t>> L; + return light(l); +} + +template +struct user { + U value; + + user(U x) : value(std::forward(x)) {} + operator U* () const { return std::addressof(value); } + operator U& () const { return value; } +}; + +template +auto make_user(T&& u) { + typedef meta::unwrapped_t> U; + return user(std::forward(u)); +} + +template +struct metatable_registry_key { + T key; + + metatable_registry_key(T key) : key(std::forward(key)) {} +}; + +template +auto meta_registry_key(T&& key) { + typedef meta::unqualified_t K; + return metatable_registry_key(std::forward(key)); +} + +template +struct closure { + lua_CFunction c_function; + std::tuple upvalues; + closure(lua_CFunction f, Upvalues... upvalues) : c_function(f), upvalues(std::forward(upvalues)...) {} +}; + +template <> +struct closure<> { + lua_CFunction c_function; + int upvalues; + closure(lua_CFunction f, int upvalues = 0) : c_function(f), upvalues(upvalues) {} +}; + +typedef closure<> c_closure; + +template +closure make_closure(lua_CFunction f, Args&&... args) { + return closure(f, std::forward(args)...); +} + struct this_state { lua_State* L; operator lua_State* () const { @@ -262,6 +321,8 @@ enum class meta_function { call_function = call, }; +typedef meta_function meta_method; + const std::array meta_variable_names = { { "__index", "__newindex", @@ -320,7 +381,7 @@ inline void type_error(lua_State* L, type expected, type actual) { inline void type_assert(lua_State* L, int index, type expected, type actual) { if (expected != type::poly && expected != actual) { - type_panic(L, index, expected, actual); + type_panic(L, index, expected, actual); } } @@ -373,6 +434,7 @@ class thread; struct variadic_args; struct this_state; +namespace detail { template struct lua_type_of : std::integral_constant {}; @@ -421,6 +483,9 @@ struct lua_type_of : std::integral_constant template <> struct lua_type_of : std::integral_constant {}; +template <> +struct lua_type_of : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; @@ -457,6 +522,12 @@ struct lua_type_of : std::integral_constant struct lua_type_of : std::integral_constant {}; +template +struct lua_type_of> : std::integral_constant {}; + +template +struct lua_type_of> : std::integral_constant {}; + template struct lua_type_of> : std::integral_constant {}; @@ -499,8 +570,15 @@ struct lua_type_of::value>> : std::int template struct lua_type_of::value>> : std::integral_constant {}; +template <> +struct lua_type_of : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; +} // detail + +template +struct lua_type_of : detail::lua_type_of {}; template struct is_lua_primitive : std::integral_constant { private: typedef meta::bind_traits base_t; public: - static const std::size_t arity = base_t::arity - meta::count_for::value; + static const std::size_t true_arity = base_t::arity; + static const std::size_t arity = base_t::arity - meta::count_for::value; + static const std::size_t true_free_arity = base_t::free_arity; + static const std::size_t free_arity = base_t::free_arity - meta::count_for::value; }; template @@ -555,7 +636,7 @@ struct is_table> : std::true_type {}; template inline type type_of() { - return lua_type_of>::value; + return lua_type_of>::value; } } // sol diff --git a/sol/usertype.hpp b/sol/usertype.hpp index 3907f277..e89ba916 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -28,6 +28,8 @@ #include "inheritance.hpp" #include "raii.hpp" #include "deprecate.hpp" +#include "usertype_metatable.hpp" +#include "stack.hpp" #include #include #include @@ -422,13 +424,13 @@ private: #elif !defined(SOL_NO_RTTI) static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = (void*)&detail::inheritance::check; - baseclasscast = (void*)&detail::inheritance::cast; + baseclasscheck = (void*)&detail::inheritance::type_check; + baseclasscast = (void*)&detail::inheritance::type_cast; #else static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = (void*)&detail::inheritance::check; - baseclasscast = (void*)&detail::inheritance::cast; + baseclasscheck = (void*)&detail::inheritance::type_check; + baseclasscast = (void*)&detail::inheritance::type_cast; #endif // No Runtime Type Information vs. Throw-Style Inheritance } diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp new file mode 100644 index 00000000..3945fbe2 --- /dev/null +++ b/sol/usertype_metatable.hpp @@ -0,0 +1,187 @@ +// 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_USERTYPE_METATABLE_HPP +#define SOL_USERTYPE_METATABLE_HPP + +#include "wrapper.hpp" +#include "call.hpp" +#include "stack.hpp" +#include "types.hpp" + +namespace sol { + + namespace usertype_detail { + inline bool is_index(string_detail::string_shim s) { + return s == name_of(meta_function::index) || s == name_of(meta_function::new_index); + } + + inline bool is_index(meta_function mf) { + return mf == meta_function::index || mf == meta_function::new_index; + } + } + + template + struct usertype_metatable { + typedef std::make_index_sequence::value> indices; + typedef std::make_index_sequence::value / 2> half_indices; + template + struct check_binding : is_variable_binding> {}; + Tuple functions; + bool must_index; + + template + static bool contains_variable(std::index_sequence) { + typedef meta::any...> has_variables; + return has_variables::value; + } + + template + bool contains_index(std::index_sequence) const { + bool idx = false; + detail::swallow{ 0, ((idx &= usertype_detail::is_index(std::get(functions))), 0) ... }; + return idx; + } + + usertype_metatable(Tuple t) : functions(std::move(t)), must_index(contains_variable(half_indices()) || contains_index(half_indices())) {} + + template + int find_call(std::integral_constant, std::index_sequence<>, lua_State* L, const sol::string_detail::string_shim& accessor) { + return luaL_error(L, "sol: attempt to index nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data()); + } + + template + int find_call(std::integral_constant idx, std::index_sequence, lua_State* L, const sol::string_detail::string_shim& accessor) { + string_detail::string_shim name(std::get(functions)); + if (accessor == name) { + if (is_variable_binding(functions))>::value) { + return call_with(L, *this); + } + return stack::push(L, c_closure(call, stack::push(L, light(*this)))); + } + return find_call(idx, std::index_sequence(), L, accessor); + } + + template + static int call(lua_State* L) { + usertype_metatable& f = stack::get>(L, up_value_index(1)); + return call_with(L, f); + } + + template + static int call_with(lua_State* L, usertype_metatable& um) { + auto& f = call_detail::pick(std::integral_constant(), std::get(um.functions)); + return call_detail::call_wrapped(L, f); + } + + static int index_call(lua_State* L) { + usertype_metatable& f = stack::get>(L, up_value_index(1)); + string_detail::string_shim accessor = stack::get(L, -1); + return f.find_call(std::true_type(), std::make_index_sequence::value>(), L, accessor); + } + + static int new_index_call(lua_State* L) { + usertype_metatable& f = stack::get>(L, up_value_index(1)); + string_detail::string_shim accessor = stack::get(L, -2); + return f.find_call(std::false_type(), std::make_index_sequence::value>(), L, accessor); + } + + static int gc_call(lua_State* L) { + stack_object o(L, 1); + type x = o.get_type(); + usertype_metatable& f = stack::get>(L, up_value_index(1)); + f.~usertype_metatable(); + return 0; + } + }; + + namespace stack { + + template + struct pusher> { + typedef usertype_metatable umt_t; + + static void cleanup(lua_State* L, int metaidx, usertype_metatable&& um) { + const char* metakey = &usertype_traits::gc_table[0]; + lua_createtable(L, 1, 0); + stack_table t(L, -1); + t[meta_function::garbage_collect] = umt_t::gc_call; + stack::set_field(L, metakey, t, metaidx); + } + + template + static int push(std::index_sequence, lua_State* L, usertype_metatable&& um) { + // Basic index pushing: specialize + // index and newindex to give variables and stuff + // make sure to return final T metatable table + const bool mustindex = um.must_index; + 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_table t(L, -1); + stack::push(L, make_light(um)); + luaL_Reg l[] = { + { &std::get(um.functions)[0], umt_t::call<(I * 2) + 1> }..., + { nullptr, nullptr } + }; + luaL_setfuncs(L, l, 1); + + if (mustindex) { + t[meta_function::index] = make_closure(umt_t::index_call, make_light(um)); + t[meta_function::new_index] = make_closure(umt_t::new_index_call, make_light(um)); + } + else { + t[meta_function::index] = t; + } + if (i < 2) { + // We want to just leave the table + // in the registry only, otherwise we return it + t.pop(); + } + } + int metaidx = lua_gettop(L); + cleanup(L, metaidx, std::move(um)); + return 1; + } + + static int push(lua_State* L, usertype_metatable&& um) { + return push(std::make_index_sequence::value / 2>(), L, std::move(um)); + } + }; + + } // stack + +} // sol + +#endif // SOL_USERTYPE_METATABLE_HPP \ No newline at end of file diff --git a/sol/variadic_args.hpp b/sol/variadic_args.hpp index 4fa0373c..3844e8dc 100644 --- a/sol/variadic_args.hpp +++ b/sol/variadic_args.hpp @@ -41,7 +41,7 @@ namespace sol { int stacktop; stack_proxy sp; - va_iterator() : L(nullptr), index(std::numeric_limits::max()), stacktop(std::numeric_limits::max()) {} + va_iterator() : L(nullptr), index((std::numeric_limits::max)()), stacktop((std::numeric_limits::max)()) {} va_iterator(lua_State* L, int index, int stacktop) : L(L), index(index), stacktop(stacktop), sp(L, index) {} reference operator*() { @@ -100,10 +100,10 @@ namespace sol { } bool operator==(const va_iterator& r) const { - if (stacktop == std::numeric_limits::max()) { + if (stacktop == (std::numeric_limits::max)()) { return r.index == r.stacktop; } - else if (r.stacktop == std::numeric_limits::max()) { + else if (r.stacktop == (std::numeric_limits::max)()) { return index == stacktop; } return index == r.index; diff --git a/sol/wrapper.hpp b/sol/wrapper.hpp new file mode 100644 index 00000000..55a70be4 --- /dev/null +++ b/sol/wrapper.hpp @@ -0,0 +1,209 @@ +// 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_WRAPPER_HPP +#define SOL_WRAPPER_HPP + +#include "types.hpp" + +namespace sol { + + template + struct wrapper { + typedef lua_bind_traits traits_type; + typedef typename traits_type::args_list args_list; + typedef typename traits_type::args_list free_args_list; + typedef typename traits_type::returns_list returns_list; + + template + static decltype(auto) call(Fx&& fx, Args&&... args) { + return fx(std::forward(args)...); + } + + struct caller { + template + decltype(auto) operator()(Fx&& fx, Args&&... args) const { + return call(std::forward(fx), std::forward(args)...); + } + }; + }; + + template + struct wrapper>>::value>> { + typedef lua_bind_traits traits_type; + typedef typename traits_type::args_list args_list; + typedef typename traits_type::args_list free_args_list; + typedef typename traits_type::returns_list returns_list; + + template + static decltype(auto) invoke(Args&&... args) { + return fx(std::forward(args)...); + } + + template + static decltype(auto) call(Fx&& fx, Args&&... args) { + return fx(std::forward(args)...); + } + + struct caller { + template + decltype(auto) operator()(Fx&& fx, Args&&... args) const { + return call(std::forward(fx), std::forward(args)...); + } + }; + }; + + template + struct wrapper>::value>> { + typedef lua_bind_traits traits_type; + typedef typename traits_type::object_type object_type; + typedef typename traits_type::return_type return_type; + typedef typename traits_type::args_list args_list; + typedef types free_args_list; + typedef typename traits_type::returns_list returns_list; + + template + static decltype(auto) invoke(object_type& mem, Args&&... args) { + return (mem.*fx)(std::forward(args)...); + } + + template + static decltype(auto) call(Fx&& fx, object_type& mem) { + return (mem.*fx); + } + + template + static void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&... args) { + (mem.*fx) = std::forward(arg); + } + + struct caller { + template + decltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const { + return call(std::forward(fx), mem, std::forward(args)...); + } + }; + }; + + template + struct member_function_wrapper { + typedef O object_type; + typedef lua_bind_traits traits_type; + typedef typename traits_type::args_list args_list; + typedef types free_args_list; + typedef meta::tuple_types returns_list; + + template + static R invoke(O& mem, Args... args) { + return (mem.*fx)(std::forward(args)...); + } + + template + static R call(Fx&& fx, O& mem, Args... args) { + return (mem.*fx)(std::forward(args)...); + } + + struct caller { + template + decltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const { + return call(std::forward(fx), mem, std::forward(args)...); + } + }; + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + + template + struct wrapper : public member_function_wrapper { + + }; + +} // sol + +#endif // SOL_WRAPPER_HPP diff --git a/test_strings.cpp b/test_strings.cpp index 4241aa9e..6c72ce7b 100644 --- a/test_strings.cpp +++ b/test_strings.cpp @@ -4,7 +4,6 @@ #include // There isn't a single library roundtripping with codecvt works on. We'll do the nitty-gritty of it later... -#if 0 TEST_CASE("stack/strings", "test that strings can be roundtripped") { sol::state lua; @@ -12,7 +11,9 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") { static const char16_t utf16str[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 }; static const char32_t utf32str[] = { 0x1F34C, 0x0020, 0x6665, 0x0020, 0x0046, 0x006F, 0x006F, 0x0020, 0x00A9, 0x0020, 0x0062, 0x0061, 0x0072, 0x0020, 0x1D306, 0x0020, 0x0062, 0x0061, 0x007A, 0x0020, 0x2603, 0x0020, 0x0071, 0x0075, 0x0078, 0x00 }; static const wchar_t widestr[] = L"Fuck these shitty compilers"; + static const char32_t utf32str2[] = U"🕴"; +#if 0 lua["utf8"] = utf8str; lua["utf16"] = utf16str; lua["utf32"] = utf32str; @@ -67,5 +68,5 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") { REQUIRE(utf16_to_char32 == utf32str[0]); REQUIRE(utf32_to_char32 == utf32str[0]); REQUIRE(wide_to_char32 == utf32str[0]); -} #endif // Shit C++ +} diff --git a/tests.cpp b/tests.cpp index aac5b779..f51fc80b 100644 --- a/tests.cpp +++ b/tests.cpp @@ -359,7 +359,7 @@ TEST_CASE("state/multi-require", "make sure that requires transfers across hand- int val1 = thingy1["modfunc"](); int val2 = thingy2["modfunc"](); - int val3 = thingy2["modfunc"](); + int val3 = thingy3["modfunc"](); REQUIRE(val1 == 221); REQUIRE(val2 == 221); REQUIRE(val3 == 221);