From 77901bb654b47375097df82f9ba81290ecbe7c02 Mon Sep 17 00:00:00 2001 From: PrincessNyanara Date: Fri, 6 Jun 2014 22:54:45 -0400 Subject: [PATCH] massive rework of stack get turned into getter, matches pusher and uses same semantics as std::allocator and other things used throughout the codebase ----- userdata has its traits defined outside in new file of userdata to prevent errors when trying to use those typetraits in places before userdata.hpp gets included userdata was changed to support returning itself via pointers or references. rework of stack changes semantics based on T&, T*, and T&& (the last one tries to create a new userdata and move in data) solves problems maybe presented in https://github.com/Rapptz/sol/issues/25 ----- container.hpp is attempt at solving original problem before going on wild tangent with userdata, stack, and get is going to attempt to use userdata to allow transporation of containers losslessly, perhaps without copying need ----- found out trying to return a std::function does not work -- not sure what do exactly? perhaps should push c closure as last thing, but right now it is tied to a key value (code comes from table.hpp and set_function) will just have to think over how stack arranges itself and learn what to do --- sol.hpp | 1 + sol/container.hpp | 89 +++++++++++ sol/function.hpp | 186 ++++++++++++++++++---- sol/function_types.hpp | 85 ++++++---- sol/stack.hpp | 343 +++++++++++++++++++++------------------- sol/table.hpp | 35 +--- sol/traits.hpp | 6 + sol/types.hpp | 1 + sol/userdata.hpp | 88 ++++++++--- sol/userdata_traits.hpp | 43 +++++ 10 files changed, 609 insertions(+), 268 deletions(-) create mode 100644 sol/container.hpp create mode 100644 sol/userdata_traits.hpp diff --git a/sol.hpp b/sol.hpp index ce093f66..ad511394 100644 --- a/sol.hpp +++ b/sol.hpp @@ -25,5 +25,6 @@ #include "sol/state.hpp" #include "sol/object.hpp" #include "sol/function.hpp" +#include "sol/container.hpp" #endif // SOL_HPP diff --git a/sol/container.hpp b/sol/container.hpp new file mode 100644 index 00000000..a11703ea --- /dev/null +++ b/sol/container.hpp @@ -0,0 +1,89 @@ +#ifndef SOL_CONTAINER_HPP +#define SOL_CONTAINER_HPP + +#include "userdata.hpp" + +namespace sol { + +template +struct container { + typedef typename std::conditional::value, Tc, Decay>::type T; + typedef Decay().begin()))> value_type; + T cont; + + template + container (Args&&... args) : cont(std::forward(args)...){ + + } + + operator T& () const { + return cont; + } + + void set( std::ptrdiff_t i, const value_type& value ) { + cont[ i ] = value; + } + + value_type& get( std::ptrdiff_t i ) { + return cont[ i ]; + } + + std::size_t size( ) const { + return cont.size(); + } + +}; + +namespace stack { +template +struct pusher::value>::type> { + template + static void push(lua_State *L, U&& t){ + typedef container container_t; + // todo: NEED to find a different way of handling this... + static std::vector> classes{}; + userdata classdata(default_constructor, + "__index", &container_t::get, + "__newindex", &container_t::set, + "__len", &container_t::size); + classes.emplace_back(std::make_shared>(std::move(classdata))); + auto&& ptr = classes.back(); + auto udata = std::static_pointer_cast>(ptr); + stack::push(L, *udata); + + container_t* c = static_cast(lua_newuserdata(L, sizeof(container_t))); + std::allocator alloc{}; + alloc.construct(c, std::forward(t)); + + auto&& meta = userdata_traits::metatable; + luaL_getmetatable(L, std::addressof(meta[0])); + lua_setmetatable(L, -2); + } + + template>> = 0> + static void push(lua_State* L, const T& cont) { + lua_createtable(L, cont.size(), 0); + unsigned index = 1; + for(auto&& i : cont) { + // push the index + pusher::push(L, index++); + // push the value + pusher>::push(L, i); + // set the table + lua_settable(L, -3); + } + } + + template> = 0> + static void push(lua_State* L, const T& cont) { + lua_createtable(L, cont.size(), 0); + for(auto&& pair : cont) { + pusher>::push(L, pair.first); + pusher>::push(L, pair.second); + lua_settable(L, -3); + } + } +}; +} // stack +} // sol +#endif // SOL_CONTAINER_HPP diff --git a/sol/function.hpp b/sol/function.hpp index a3affe0a..184c8dc5 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -76,45 +76,177 @@ public: template typename return_type::type call(Args&&... args) const { push(); - stack::push_args(state(), std::forward(args)...); + stack::push(state(), std::forward(args)...); return invoke(types(), sizeof...(Args)); } }; namespace stack { -namespace detail { -template -inline std::function get_std_func(types, types, lua_State* L, int index = -1) { - typedef typename function_traits::return_type return_t; - sol::function f(L, index); - auto fx = [ f, L, index ] (FxArgs&&... args) -> return_t { - return f(types(), std::forward(args)...); - }; - return std::move(fx); -} +template <> +struct pusher { + template + void set_isfunction_fx(lua_State* L, std::true_type, T&& key, TFx&& fx) { + set_fx(std::false_type(), std::forward(key), std::forward(fx)); + } -template -inline std::function get_std_func(types, types, lua_State* L, int index = -1) { - sol::function f(L, index); - auto fx = [ f, L, index ] (FxArgs&&... args) -> void { - f(std::forward(args)...); - }; - return std::move(fx); -} + template + void set_isfunction_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) { + typedef Decay clean_lambda; + typedef typename function_traits::free_function_pointer_type raw_func_t; + typedef std::is_convertible isconvertible; + set_isconvertible_fx(isconvertible(), std::forward(key), std::forward(fx)); + } -template -inline std::function get_std_func(types t, types<>, lua_State* L, int index = -1) { - return get_std_func(std::move(t), types(), L, index); -} + template + void set_isconvertible_fx(lua_State* L, std::true_type, T&& key, TFx&& fx) { + typedef Decay clean_lambda; + typedef typename function_traits::free_function_pointer_type raw_func_t; + set_isfunction_fx(std::true_type(), std::forward(key), raw_func_t(std::forward(fx))); + } + + template + void set_isconvertible_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) { + typedef typename std::remove_pointer>::type clean_fx; + std::unique_ptr sptr(new functor_function(std::forward(fx))); + set_fx(std::forward(key), std::move(sptr)); + } + + template + void set_lvalue_fx(lua_State* L, std::true_type, T&& key, TFx&& fx, TObj&& obj) { + set_fx(std::true_type(), std::forward(key), std::forward(fx), std::forward(obj)); + } + + template + void set_lvalue_fx(lua_State* L, std::false_type, T&& key, TFx&& fx, TObj&& obj) { + typedef typename std::remove_pointer>::type clean_fx; + std::unique_ptr sptr(new member_function(std::forward(obj), std::forward(fx))); + return set_fx(std::forward(key), std::move(sptr)); + } + + template + void set_fx(lua_State* L, std::true_type, T&& key, TFx&& fx, TObj&& obj) { + std::string fkey(key); + + // Layout: + // idx 1...n: verbatim data of member function pointer + // idx n + 1: is the object's void pointer + // We don't need to store the size, because the other side is templated + // with the same member function pointer type + Decay fxptr(std::forward(fx)); + void* userobjdata = static_cast(detail::get_ptr(obj)); + lua_CFunction freefunc = &static_member_function, TFx>::call; + const char* freefuncname = fkey.c_str(); + const luaL_Reg funcreg[2] = { + { freefuncname, freefunc }, + { nullptr, nullptr } + }; + + + int upvalues = stack::detail::push_as_upvalues(L, fxptr); + stack::push(L, userobjdata); + luaL_setfuncs(L, funcreg, upvalues + 1); + + } + + template + void set_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) { + std::string fkey(key); + Decay target(std::forward(fx)); + lua_CFunction freefunc = &static_function::call; + const char* freefuncname = fkey.c_str(); + const luaL_Reg funcreg[2] = { + { freefuncname, freefunc }, + { nullptr, nullptr } + }; + + int upvalues = stack::detail::push_as_upvalues(L, target); + luaL_setfuncs(L, funcreg, upvalues); + + } + + template + void set_fx(lua_State* L, T&& key, std::unique_ptr luafunc) { + std::string fkey(key); + std::string metakey("sol.stateful."); + metakey += fkey; + metakey += ".meta"; + base_function* target = luafunc.release(); + void* userdata = reinterpret_cast(target); + lua_CFunction freefunc = &base_function::call; + const char* freefuncname = fkey.c_str(); + const char* metatablename = metakey.c_str(); + const luaL_Reg funcreg[2] = { + { freefuncname, freefunc }, + { nullptr, nullptr } + }; + + if (luaL_newmetatable(L, metatablename) == 1) { + lua_pushstring(L, "__gc"); + lua_pushcclosure(L, &base_function::gc, 0); + lua_settable(L, -3); + } + + stack::detail::push_userdata(L, userdata, metatablename); + luaL_setfuncs(L, funcreg, 1); + } + + template + void set_function(T&& key, TFx&& fx) { + typedef typename std::remove_pointer>::type clean_fx; + set_isfunction_fx(std::is_function(), std::forward(key), std::forward(fx)); + } + + template + void set_function(T&& key, TFx&& fx, TObj&& obj) { + set_lvalue_fx(Bool::value || std::is_pointer::value>(), + std::forward(key), std::forward(fx), std::forward(obj)); + } + + template + void push(lua_State* L, Key&& key, Args&&... args) { + set_function(L, std::forward(key), std::forward(args)...); + } + +}; +template +struct pusher> { + +}; template -inline std::function get(types>, lua_State* L, int index) { +struct getter> { typedef function_traits fx_t; typedef typename fx_t::args_type args_t; typedef typename tuple_types::type ret_t; - return get_std_func(args_t(), ret_t(), L, index); -} -} // detail + + template + static std::function get_std_func(types, types, lua_State* L, int index = -1) { + typedef typename function_traits::return_type return_t; + sol::function f(L, index); + auto fx = [ f, L, index ] (FxArgs&&... args) -> return_t { + return f(types(), std::forward(args)...); + }; + return std::move(fx); + } + + template + static std::function get_std_func(types, types, lua_State* L, int index = -1) { + sol::function f(L, index); + auto fx = [ f, L, index ] (FxArgs&&... args) -> void { + f(std::forward(args)...); + }; + return std::move(fx); + } + + template + static std::function get_std_func(types t, types<>, lua_State* L, int index = -1) { + return get_std_func(std::move(t), types(), L, index); + } + + static std::function get(lua_State* L, int index) { + return get_std_func(args_t(), ret_t(), L, index); + } +}; } // stack } // sol diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 0a90866c..bb9c326d 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -26,6 +26,38 @@ #include namespace sol { +namespace detail { +template +struct functor { + T* item; + Func invocation; + + template + functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} + + template + R operator()(Args&&... args) { + T& member = *item; + return (member.*invocation)(std::forward(args)...); + } +}; + +template +struct functor { + T* item; + Func invocation; + + template + functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} + + template + void operator()(Args&&... args) { + T& member = *item; + (member.*invocation)(std::forward(args)...); + } +}; +} // detail + template struct static_function { @@ -56,7 +88,7 @@ struct static_function { } static int call(lua_State* L) { - auto udata = stack::get_user(L); + auto udata = stack::detail::get_as_upvalues(L); function_type* fx = udata.first; int r = typed_call(tuple_types(), typename traits_type::args_type(), fx, L); return r; @@ -98,8 +130,8 @@ struct static_member_function { } static int call(lua_State* L) { - auto memberdata = stack::get_user(L, 1); - auto objdata = stack::get_user(L, memberdata.second); + auto memberdata = stack::detail::get_as_upvalues(L, 1); + auto objdata = stack::detail::get_as_upvalues(L, memberdata.second); function_type& memfx = memberdata.first; T& obj = *objdata.first; int r = typed_call(tuple_types(), typename traits_type::args_type(), obj, memfx, L); @@ -242,41 +274,36 @@ struct member_function : public base_function { } }; -template +template struct userdata_function : public base_function { + typedef typename std::remove_pointer::type T; typedef typename std::remove_pointer::type>::type function_type; typedef function_traits traits_type; - struct functor { - T* item; - function_type invocation; + typedef typename traits_type::return_type return_type; - template - functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} - - void prepare(lua_State* L) { - void* udata = stack::get(L, 1); - if (udata == nullptr) - throw error("must use the syntax [object]:[function] to call member functions bound to C++"); - item = static_cast(udata); - } - - template - typename traits_type::return_type operator()(Args&&... args) { - T& member = *item; - return (member.*invocation)(std::forward(args)...); - } - } fx; + detail::functor fx; template userdata_function(FxArgs&&... fxargs): fx(std::forward(fxargs)...) {} template> - typename std::enable_if::value, void>::type special_push(lua_State*, Return&&) { - // push nothing + typename std::enable_if::value, void>::type push(lua_State* L, Return&& r) { + if ( detail::get_ptr(r) == fx.item ) { + // push nothing + // note that pushing nothing with the ':' + // syntax means we leave the instance of what + // was pushed onto the stack by lua to do the + // function call alone, + // and naturally lua returns that. + // It's an "easy" way to return *this, + // without allocating an extra userdata, apparently! + return; + } + stack::push(L, std::forward(r)); } template> - typename std::enable_if::value, void>::type special_push(lua_State* L, Return&& r) { + typename std::enable_if::value, void>::type push(lua_State* L, Return&& r) { stack::push(L, std::forward(r)); } @@ -290,12 +317,10 @@ struct userdata_function : public base_function { template int operator()(types, types t, lua_State* L) { - typedef typename return_type::type return_type; return_type r = stack::get_call(L, 2, fx, t); std::ptrdiff_t nargs = sizeof...(Args); lua_pop(L, nargs); - // stack::push(L, std::move(r)); - special_push(L, r); + push(L, std::forward(r)); return sizeof...(Ret); } @@ -305,7 +330,7 @@ struct userdata_function : public base_function { } virtual int operator()(lua_State* L) override { - fx.prepare(L); + fx.item = detail::get_ptr(stack::get(L, 1)); return (*this)(tuple_types(), typename traits_type::args_type(), L); } }; diff --git a/sol/stack.hpp b/sol/stack.hpp index e6dbfdde..afbfae3e 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -26,129 +26,141 @@ #include "reference.hpp" #include "tuple.hpp" #include "traits.hpp" +#include "userdata_traits.hpp" #include #include #include #include namespace sol { -namespace stack { namespace detail { -inline nil_t get(types, lua_State* L, int index = -1) { - if (lua_isnil(L, index) == 0) - throw sol::error("not nil"); - return nil_t{ }; -} - -inline lightuserdata_t get(types, lua_State* L, int index = -1) { - return{ lua_touserdata(L, lua_upvalueindex(index)) }; -} - -inline userdata_t get(types, lua_State* L, int index = -1) { - return{ lua_touserdata(L, index) }; -} - -inline std::string get(types, lua_State* L, int index = -1) { - std::string::size_type len; - auto str = lua_tolstring(L, index, &len); - return{ str, len }; -} - -inline const char* get(types, lua_State* L, int index = -1) { - return lua_tostring(L, index); -} - -inline type get(types, lua_State* L, int index = -1) { - return static_cast(lua_type(L, index)); -} - -template ::type> -inline U get_sol_type(std::true_type, types, lua_State* L, int index = -1) { - return U(L, index); -} - -template -inline T& get_sol_type(std::false_type, types, lua_State* L, int index = -1) { - userdata_t udata = get(types{}, L, index); - T* obj = static_cast(udata.value); - return *obj; -} - -template > -inline auto get(types t, lua_State* L, int index = -1) -> decltype(get_sol_type(std::is_base_of(), t, L, index)) { - return get_sol_type(std::is_base_of(), t, L, index); -} - -template -inline std::function get(types>, lua_State* L, int index = -1); - template -inline T get_unsigned(std::true_type, lua_State* L, int index = -1) { - return lua_tounsigned(L, index); +T* get_ptr(T& val) { + return std::addressof(val); } template -inline T get_unsigned(std::false_type, lua_State* L, int index = -1) { - return static_cast(lua_tointeger(L, index)); -} - -template -inline T get_arithmetic(std::false_type, lua_State* L, int index = -1) { - // T is a floating point - return static_cast(lua_tonumber(L, index)); -} - -template -inline T get_arithmetic(std::true_type, lua_State* L, int index = -1) { - // T is an integral - return get_unsigned(std::is_unsigned{}, L, index); -} - -template -inline T get_helper(std::true_type, lua_State* L, int index = -1) { - // T is a fundamental type - return get_arithmetic(std::is_integral{}, L, index); -} - -template<> -inline bool get_helper(std::true_type, lua_State* L, int index) { - return lua_toboolean(L, index) != 0; -} - -template -inline auto get_helper(std::false_type, lua_State* L, int index = -1) -> decltype(get(types(), L, index)) { - // T is a class - return get(types(), L, index); +T* get_ptr(T* val) { + return val; } } // detail -template> -inline auto get(lua_State* L, int index = -1) -> decltype(detail::get_helper(std::is_arithmetic{}, L, index)) { - return detail::get_helper(std::is_arithmetic{}, L, index); +namespace stack { +namespace detail { +template +inline void push_userdata(lua_State* L, T&& userdata, Key&& metatablekey) { + T* pdatum = static_cast(lua_newuserdata(L, sizeof(T))); + T& datum = *pdatum; + datum = std::forward(userdata); + luaL_getmetatable(L, std::addressof(metatablekey[0])); + lua_setmetatable(L, -2); } - -template -inline std::pair get_user(lua_State* L, int index = 1) { - const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*); - typedef std::array data_t; - data_t voiddata{ {} }; - for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { - voiddata[ i ] = stack::get(L, index++); - } - return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); -} - -template -auto pop(lua_State* L) -> decltype(get(L)) { - auto&& r = get(L); - lua_pop(L, 1); - return r; -} - -template +} // detail +template +struct getter; +template struct pusher; -template +template +struct getter { + template> = 0> + static U get(lua_State* L, int index = -1) { + return lua_tonumber(L, index); + } + + template, std::is_signed> = 0> + static U get(lua_State* L, int index = -1) { + return lua_tounsigned(L, index); + } + + template, std::is_unsigned> = 0> + static U get(lua_State* L, int index = -1) { + return static_cast(lua_tointeger(L, index)); + } + + template> = 0> + static U get(lua_State* L, int index = -1) { + return T(L, index); + } + + template>, Not>, Not>> = 0> + static U& get(lua_State* L, int index = -1) { + void* udata = lua_touserdata(L, index); + T* obj = static_cast(udata); + return *obj; + } +}; + +template +struct getter { + static T* get(lua_State* L, int index = -1) { + void* udata = lua_touserdata(L, index); + T** obj = static_cast(udata); + return *obj; + } +}; + +template <> +struct getter { + type get(lua_State *L, int index){ + return static_cast(lua_type(L, index)); + } +}; + +template <> +struct getter { + static bool get(lua_State* L, int index) { + return lua_toboolean(L, index) != 0; + } +}; + +template <> +struct getter { + static std::string get(lua_State* L, int index = -1) { + std::string::size_type len; + auto str = lua_tolstring(L, index, &len); + return{ str, len }; + } +}; + +template <> +struct getter { + const char* get(lua_State* L, int index = -1) { + return lua_tostring(L, index); + } +}; + +template <> +struct getter { + nil_t get(lua_State* L, int index = -1) { + if (lua_isnil(L, index) == 0) + throw sol::error("not nil"); + return nil_t{ }; + } +}; + +template <> +struct getter { + userdata_t get(lua_State* L, int index = -1) { + return{ lua_touserdata(L, index) }; + } +}; + +template <> +struct getter { + lightuserdata_t get(lua_State* L, int index = 1) { + return{ lua_touserdata(L, lua_upvalueindex(index)) }; + } +}; + +template <> +struct getter { + void* get(lua_State* L, int index = 1) { + return lua_touserdata(L, index); + } +}; + +template struct pusher { template> = 0> static void push(lua_State* L, const T& value) { @@ -165,34 +177,27 @@ struct pusher { lua_pushunsigned(L, value); } - template, Not>> = 0> - static void push(lua_State* L, const T& cont) { - lua_createtable(L, cont.size(), 0); - unsigned index = 1; - for(auto&& i : cont) { - // push the index - pusher::push(L, index++); - // push the value - pusher>::push(L, i); - // set the table - lua_settable(L, -3); - } - } - - template, has_key_value_pair> = 0> - static void push(lua_State* L, const T& cont) { - lua_createtable(L, cont.size(), 0); - for(auto&& pair : cont) { - pusher>::push(L, pair.first); - pusher>::push(L, pair.second); - lua_settable(L, -3); - } - } - template> = 0> static void push(lua_State*, T& ref) { ref.push(); } + + template>, Not>, Not>> = 0> + static void push(lua_State* L, T& t) { + pusher{}.push(L, std::addressof(t)); + } + + template>, Not>, Not>> = 0> + static void push(lua_State* L, T&& t) { + detail::push_userdata(L, std::move(t), userdata_traits::metatable); + } +}; + +template +struct pusher { + static void push(lua_State* L, T* obj) { + detail::push_userdata(L, obj, userdata_traits::metatable); + } }; template<> @@ -223,6 +228,13 @@ struct pusher { } }; +template<> +struct pusher { + static void push(lua_State* L, lightuserdata_t userdata) { + lua_pushlightuserdata(L, userdata); + } +}; + template<> struct pusher { static void push(lua_State* L, const char* str) { @@ -244,31 +256,33 @@ struct pusher { } }; -template -inline void push(lua_State* L, T&& t) { - pusher>::push(L, std::forward(t)); +inline void push(lua_State*) { + +} + +template +inline void push(lua_State* L, T&& t, Args&&... args) { + using swallow = char[]; + pusher>{}.push(L, std::forward(t)); + void(swallow{'\0', (pusher>{}.push(L, std::forward(args)), '\0')... }); +} + +template> +inline auto get(lua_State* L, int index = -1) -> decltype(getter{}.get(L, index)) { + return getter{}.get(L, index); } template -inline void push_user(lua_State* L, T& userdata, const char* metatablekey) { - T* pdatum = static_cast(lua_newuserdata(L, sizeof(T))); - T& datum = *pdatum; - datum = userdata; - if (metatablekey != nullptr) { - lua_getfield(L, LUA_REGISTRYINDEX, metatablekey); - lua_setmetatable(L, -2); - } -} - -template -inline void push_as_upvalues(lua_State* L, const std::array& data) { - for(auto&& i : data) { - push(L, i); - } +auto pop(lua_State* L) -> decltype(get(L)) { + typedef decltype(get(L)) ret_t; + ret_t r = get(L); + lua_pop(L, 1); + return r; } +namespace detail { template -inline int push_user(lua_State* L, T& item) { +inline int push_as_upvalues(lua_State* L, T& item) { typedef typename std::decay::type TValue; const static std::size_t itemsize = sizeof(TValue); const static std::size_t voidsize = sizeof(void*); @@ -278,11 +292,23 @@ inline int push_user(lua_State* L, T& item) { data_t data{{}}; std::memcpy(std::addressof(data[0]), std::addressof(item), itemsize); - push_as_upvalues(L, data); + for (auto&& v : data) { + push(L, v); + } return data_t_count; } -namespace detail { +template +inline std::pair get_as_upvalues(lua_State* L, int index = 1) { + const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*); + typedef std::array data_t; + data_t voiddata{ {} }; + for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { + voiddata[ i ] = get(L, index++); + } + return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); +} + template inline void push_tuple(lua_State* L, indices, T&& tuplen) { using swallow = char[1 + sizeof...(I)]; @@ -349,8 +375,8 @@ inline auto get_call(lua_State* L, int index, TFx&& fx, types t) -> dec } template -inline auto get_call(lua_State* L, TFx&& fx, types t) -> decltype(detail::ltr_get(L, 1, std::forward(fx), t, t)) { - return detail::ltr_get(L, 1, std::forward(fx), t, t); +inline auto get_call(lua_State* L, TFx&& fx, types t) -> decltype(get_call(L, 1, std::forward(fx), t)) { + return get_call(L, 1, std::forward(fx), t); } template @@ -363,17 +389,6 @@ inline auto pop_reverse_call(lua_State* L, TFx&& fx, types t) -> declty return detail::rtl_pop(L, std::forward(fx), t, reversed()); } -inline void push_args(lua_State*) { - -} - -template -inline void push_args(lua_State* L, Arg&& arg, Args&&... args) { - using swallow = char[]; - stack::push(L, std::forward(arg)); - void(swallow{'\0', (stack::push(L, std::forward(args)), '\0')... }); -} - inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) { if (get(L, 1) == type::table) { if (luaL_newmetatable(L, meta.c_str()) == 0) { diff --git a/sol/table.hpp b/sol/table.hpp index cd885bc8..ddd7026a 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -28,18 +28,6 @@ #include "userdata.hpp" namespace sol { -namespace detail { -template -T* get_ptr(T& val) { - return std::addressof(val); -} - -template -T* get_ptr(T* val) { - return val; -} -} // detail - class table : public reference { friend class state; template @@ -108,18 +96,9 @@ public: } template - table& set_userdata(userdata& user) { - auto&& meta = userdata_traits::metatable; - luaL_newmetatable(state(), meta.c_str()); - for (std::size_t upvalues = 0; upvalues < user.functions.size(); ++upvalues) { - stack::push(state(), static_cast(user.functions[ upvalues ].get())); - } - luaL_setfuncs(state(), user.functiontable.data(), static_cast(user.functions.size())); - - lua_pushvalue(state(), -1); - lua_setfield(state(), -1, "__index"); - - lua_setglobal(state(), user.luaname.c_str()); + table& set_userdata(userdata& user) { + stack::push(state(), user); + lua_setglobal(state(), user.name().c_str()); return *this; } @@ -203,7 +182,7 @@ private: push(); - int upvalues = stack::push_user(state(), fxptr); + int upvalues = stack::detail::push_as_upvalues(state(), fxptr); stack::push(state(), userobjdata); luaL_setfuncs(state(), funcreg, upvalues + 1); @@ -223,7 +202,7 @@ private: }; push(); - int upvalues = stack::push_user(state(), target); + int upvalues = stack::detail::push_as_upvalues(state(), target); luaL_setfuncs(state(), funcreg, upvalues); pop(); @@ -253,7 +232,7 @@ private: } push(); - stack::push_user(state(), userdata, metatablename); + stack::detail::push_userdata(state(), userdata, metatablename); luaL_setfuncs(state(), funcreg, 1); pop(); return *this; @@ -261,4 +240,4 @@ private: }; } // sol -#endif // SOL_TABLE_HPP +#endif // SOL_TABLE_HPP diff --git a/sol/traits.hpp b/sol/traits.hpp index f4bbc29a..6d987af9 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -47,6 +47,12 @@ struct And : Bool {}; template struct And : If, Bool> {}; +template +struct Or : Bool {}; + +template +struct Or : If, Or, Bool> {}; + template using EnableIf = typename std::enable_if::value, int>::type; diff --git a/sol/types.hpp b/sol/types.hpp index 348a17fd..51185ac6 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -31,6 +31,7 @@ struct nil_t {}; const nil_t nil {}; struct void_type {}; const void_type Void {}; +struct function_t {}; struct lightuserdata_t { void* value; lightuserdata_t(void* data) : value(data) {} diff --git a/sol/userdata.hpp b/sol/userdata.hpp index d6c8af02..d0fb300c 100644 --- a/sol/userdata.hpp +++ b/sol/userdata.hpp @@ -24,7 +24,7 @@ #include "state.hpp" #include "function_types.hpp" -#include "demangle.hpp" +#include "userdata_traits.hpp" #include namespace sol { @@ -35,26 +35,15 @@ inline std::unique_ptr make_unique(Args&&... args) { } } // detail -template -struct userdata_traits { - static const std::string name; - static const std::string metatable; -}; - -template -const std::string userdata_traits::name = detail::demangle(typeid(T)); - -template -const std::string userdata_traits::metatable = std::string("sol.stateful.").append(name); - template class userdata { private: - friend table; std::string luaname; std::vector functionnames; - std::vector> functions; + std::vector> funcs; + std::vector> ptrfuncs; std::vector functiontable; + std::vector ptrfunctiontable; template struct constructor { @@ -89,7 +78,7 @@ private: T* obj = static_cast(udata); match_constructor(L, obj, syntax, argcount - static_cast(syntax), typename std::common_type::type()...); - luaL_getmetatable(L, meta.c_str()); + luaL_getmetatable(L, std::addressof(meta[0])); lua_setmetatable(L, -2); return 1; @@ -115,8 +104,10 @@ private: static_assert(std::is_base_of::value, "Any registered function must be part of the class"); typedef typename std::decay::type function_type; functionnames.push_back(std::move(name)); - functions.emplace_back(detail::make_unique>(std::move(func))); + funcs.emplace_back(detail::make_unique>(std::move(func))); + ptrfuncs.emplace_back(detail::make_unique::type>>(std::move(func))); functiontable.push_back({ functionnames.back().c_str(), &base_function::userdata::call }); + ptrfunctiontable.push_back({ functionnames.back().c_str(), &base_function::userdata::call }); build_function_tables(std::forward(args)...); } @@ -130,22 +121,81 @@ public: template userdata(std::string name, constructors, Args&&... args): luaname(std::move(name)) { functionnames.reserve(sizeof...(args) + 2); - functiontable.reserve(sizeof...(args) + 3); - functions.reserve(sizeof...(args) + 2); + functiontable.reserve(sizeof...(args) + 2); + ptrfunctiontable.reserve(sizeof...(args) + 2); + funcs.reserve(sizeof...(args) + 2); + ptrfuncs.reserve(sizeof...(args) + 2); build_function_tables<0>(std::forward(args)...); functionnames.push_back("new"); functiontable.push_back({ functionnames.back().c_str(), &constructor::construct }); functionnames.push_back("__gc"); functiontable.push_back({ functionnames.back().c_str(), &destructor::destruct }); + // ptr_functions does not participate in garbage collection/new, + // as all pointered types are considered + // to be references. This makes returns of + // `std::vector&` and `std::vector*` work functiontable.push_back({ nullptr, nullptr }); + ptrfunctiontable.push_back({ nullptr, nullptr }); } template userdata(const char* name, constructors c, Args&&... args) : userdata(std::string(name), std::move(c), std::forward(args)...) {} + + const std::vector& function_names () const { + return functionnames; + } + + const std::vector>& functions () const { + return funcs; + } + + const std::vector>& reference_functions () const { + return ptrfuncs; + } + + const std::vector& function_table () const { + return functiontable; + } + + const std::vector& reference_function_table () const { + return ptrfunctiontable; + } + + const std::string& name () const { + return luaname; + } }; + +namespace stack { +template +struct pusher> { + static void push ( lua_State* L, userdata& user ) { + auto&& ptrmeta = userdata_traits::type>::metatable; + luaL_newmetatable(L, ptrmeta.c_str()); + for (std::size_t upvalues = 0; upvalues < user.reference_functions().size(); ++upvalues) { + stack::push(L, static_cast(user.reference_functions()[ upvalues ].get())); + } + luaL_setfuncs(L, user.reference_function_table().data(), static_cast(user.reference_functions().size())); + + lua_pushvalue(L, -1); + lua_setfield(L, -1, "__index"); + + auto&& meta = userdata_traits::metatable; + luaL_newmetatable(L, meta.c_str()); + for (std::size_t upvalues = 0; upvalues < user.functions().size(); ++upvalues) { + stack::push(L, static_cast(user.functions()[ upvalues ].get())); + } + luaL_setfuncs(L, user.function_table().data(), static_cast(user.functions().size())); + + lua_pushvalue(L, -1); + lua_setfield(L, -1, "__index"); + } +}; +} // stack + } // sol #endif // SOL_USERDATA_HPP diff --git a/sol/userdata_traits.hpp b/sol/userdata_traits.hpp new file mode 100644 index 00000000..77dabcd5 --- /dev/null +++ b/sol/userdata_traits.hpp @@ -0,0 +1,43 @@ +// The MIT License (MIT) + +// Copyright (c) 2013 Danny Y., Rapptz + +// 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_USERDATA_TRAITS_HPP +#define SOL_USERDATA_TRAITS_HPP + +#include "demangle.hpp" + +namespace sol { + +template +struct userdata_traits { + static const std::string name; + static const std::string metatable; +}; + +template +const std::string userdata_traits::name = detail::demangle(typeid(T)); + +template +const std::string userdata_traits::metatable = std::string("sol.stateful.").append(detail::demangle(typeid(T))); + +} + +#endif // SOL_USERDATA_TRAITS_HPP