From f67b21b5257291edf3043ac26c29b57bffe528aa Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 2 Dec 2013 14:22:51 -0500 Subject: [PATCH] The solution technically works, but there's some stack corruption going on somewhere that I can quite track down, even when calling a void function with no parameters. I'll have to look into it... --- sol/function.hpp | 125 +++++++++----- sol/functional.hpp | 102 ++++++++++++ sol/lua_function.hpp | 138 ++++++++++++++++ sol/stack.hpp | 33 ++++ sol/state.hpp | 378 ++++++++++++++++++++++--------------------- sol/table.hpp | 50 ++++++ sol/tuple.hpp | 25 ++- sol/types.hpp | 4 +- 8 files changed, 614 insertions(+), 241 deletions(-) create mode 100644 sol/functional.hpp create mode 100644 sol/lua_function.hpp diff --git a/sol/function.hpp b/sol/function.hpp index 5aee99b0..059c204b 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -1,41 +1,84 @@ -#ifndef SOL_FUNCTION_HPP -#define SOL_FUNCTION_HPP - -#include "reference.hpp" -#include "tuple.hpp" -#include "stack.hpp" - -namespace sol { -class function : virtual public reference { -private: - template - void push_args(Args&&... args) { - auto L = state(); - using swallow = char []; - void( swallow{ (stack::push(L, std::forward(args)), '\0')... } ); - } -public: - function() : reference() {} - function(lua_State* L, int index = -1) : reference(L, index) { - type_assert(L, index, type::function); - } - - template - T invoke(Args&&... args) { - push(); - push_args(std::forward(args)...); - lua_pcall(state(), sizeof...(Args), 1, 0); - return stack::pop(state()); - } - - template - void invoke(Args&&... args) { - push(); - push_args(std::forward(args)...); - lua_pcall(state(), sizeof...(Args), 0, 0); - } -}; -} // sol - - -#endif // SOL_FUNCTION_HPP \ No newline at end of file +// 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_FUNCTION_HPP +#define SOL_FUNCTION_HPP + +#include "reference.hpp" +#include "tuple.hpp" +#include "stack.hpp" + +namespace sol { +class function : virtual public reference { +private: + template + void push_args(Args&&... args) const { + auto L = state(); + using swallow = char[ ]; + void(swallow{ (stack::push(L, std::forward(args)), '\0')... }); + } + + template + struct invoker { + template + static std::tuple call( const function& ref, Args&&... args ) { + ref.push( ); + ref.push_args( std::forward( args )... ); + lua_pcall( ref.state( ), sizeof...( Args ), sizeof...( Ret ), 0 ); + return std::make_tuple( stack::pop( ref.state( ) )... ); + } + }; + + template<> + struct invoker<> { + template + static void call( const function& ref, Args&&... args ) { + ref.push( ); + ref.push_args( std::forward( args )... ); + lua_pcall( ref.state( ), sizeof...( Args ), 0, 0 ); + } + }; + + template + struct invoker { + template + static T call( const function& ref, Args&&... args ) { + ref.push( ); + ref.push_args( std::forward( args )... ); + lua_pcall( ref.state( ), sizeof...( Args ), 1, 0 ); + return stack::pop( ref.state( ) ); + } + }; + +public: + function() : reference() {} + function(lua_State* L, int index = -1) : reference(L, index) { + type_assert(L, index, type::function); + } + + template + auto invoke( Args&&... args ) { + return invoker::call( *this, std::forward( args )... ); + } +}; +} // sol + +#endif // SOL_FUNCTION_HPP diff --git a/sol/functional.hpp b/sol/functional.hpp new file mode 100644 index 00000000..349d8d05 --- /dev/null +++ b/sol/functional.hpp @@ -0,0 +1,102 @@ +// 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. + +#include "tuple.hpp" + +#ifndef SOL_FUNCTIONAL_HPP +#define SOL_FUNCTIONAL_HPP + +namespace sol { +namespace detail { + +template +struct function_traits; + +template +struct function_traits { + static const std::size_t arity = sizeof...( Tn ); + static const bool is_member_function = true; + typedef std::tuple arg_tuple_t; + typedef types args_t; + typedef R( T::* func_t )( Tn... ); + typedef R( T::* func_pointer_t )( Tn... ); + typedef R return_t; + template + using arg_n = std::tuple_element; +}; + +template +struct function_traits { + static const std::size_t arity = sizeof...( Tn ); + static const bool is_member_function = true; + typedef std::tuple arg_tuple_t; + typedef types args_t; + typedef R( T::* func_t )( Tn... ); + typedef R( T::* func_pointer_t )( Tn... ); + typedef R return_t; + template + using arg_n = std::tuple_element; +}; + +template +struct function_traits { + static const std::size_t arity = sizeof...( Tn ); + static const bool is_member_function = false; + typedef std::tuple arg_tuple_t; + typedef types args_t; + typedef R( func_t )( Tn... ); + typedef R( *func_pointer_t )( Tn... ); + typedef R return_t; + template + using arg_n = std::tuple_element; +}; + +template +struct function_traits { + static const std::size_t arity = sizeof...( Tn ); + static const bool is_member_function = false; + typedef std::tuple arg_tuple_t; + typedef types args_t; + typedef R( func_t )( Tn... ); + typedef R( *func_pointer_t )( Tn... ); + typedef R return_t; + template + using arg_n = std::tuple_element; +}; + +using std::get; + +template +inline auto call( Function f, const Tuple& t, indices ) -> decltype( f( get( t )... ) ) { + return f( get( t )... ); +} + +} // detail + +template +inline auto call( Function f, const std::tuple& t ) -> decltype( detail::call( f, t, detail::build_indices{} ) ) { + return call( f, t, detail::build_indices{} ); +} + +} // sol + + +#endif // SOL_FUNCTIONAL_HPP \ No newline at end of file diff --git a/sol/lua_function.hpp b/sol/lua_function.hpp new file mode 100644 index 00000000..1d09b0ee --- /dev/null +++ b/sol/lua_function.hpp @@ -0,0 +1,138 @@ +// 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_LUA_FUNC_HPP +#define SOL_LUA_FUNC_HPP + +#include "functional.hpp" +#include "stack.hpp" + +namespace sol { +namespace detail { + + struct lua_func { + virtual int operator () ( lua_State* L ) { + throw sol_error( "Failure to call specialized wrapped C++ function from lua" ); + } + + virtual ~lua_func( ) {}; + }; + + template + struct lambda_lua_func : public lua_func { + typedef decltype( &TFx::operator() ) fx_t; + typedef function_traits fx_traits; + TFx fx; + + template + lambda_lua_func( TFxn&&... fxn ) : fx( std::forward( fxn )... ) { + + } + + virtual int operator () ( lua_State* L ) override { + return ( *this )( tuple_types( ), fx_traits::args_t( ), L ); + } + + template + int operator()( types, types t, lua_State* L ) { + auto r = stack::pop_call( L, fx, t ); + return 0; + } + + template + int operator()( types, types t, lua_State* L ) { + auto r = stack::pop_call( L, fx, t ); + stack::push( L, r ); + return sizeof...( TRn ); + } + }; + + template ::value> + struct explicit_lua_func : public lua_func { + typedef typename std::remove_pointer::type>::type fx_t; + typedef function_traits fx_traits; + TFx fx; + + template + explicit_lua_func( TFxn&&... fxn ) : fx( std::forward( fxn )... ) { + + } + + virtual int operator () ( lua_State* L ) override { + return ( *this )( tuple_types( ), fx_traits::args_t( ), L ); + } + + template + int operator () ( types, types t, lua_State* L ) { + auto r = stack::pop_call( L, fx, t ); + return 0; + } + + template + int operator () ( types, types t, lua_State* L ) { + auto r = stack::pop_call( L, fx, t ); + stack::push( L, r ); + return sizeof...( TRn ); + } + }; + + template + struct explicit_lua_func : public lua_func { + typedef typename std::remove_pointer::type>::type fx_t; + typedef function_traits fx_traits; + T* member; + TFx fx; + + template + explicit_lua_func( T* m, TFxn&&... fxn ) : member(m), fx( std::forward( fxn )... ) { + + } + + virtual int operator () ( lua_State* L ) override { + return ( *this )( tuple_types( ), fx_traits::args_t( ), L ); + } + + template + int operator () ( types, types, lua_State* L ) { + auto r = stack::pop_call( L, fx, t ); + return 0; + } + + template + int operator () ( types, types t, lua_State* L ) { + auto r = stack::pop_call( L, fx, t ); + stack::push( L, r ); + return sizeof...( TRn ); + } + }; + + + int lua_cfun( lua_State* L ) { + void* bridgedata = lua_touserdata( L, lua_upvalueindex( 1 ) ); + auto* fx = static_cast( bridgedata ); + int r = fx->operator()( L ); + return r; + } + +} // detail +} // sol + +#endif // SOL_LUA_FUNC_HPP diff --git a/sol/stack.hpp b/sol/stack.hpp index adba07ec..e2863822 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -23,6 +23,7 @@ #define SOL_STACK_HPP #include "reference.hpp" +#include "tuple.hpp" #include #include @@ -35,6 +36,19 @@ using DisableIf = typename std::enable_if::type; namespace stack { namespace detail { +template +auto ltr_pop( T&& extra, F f, types<>, Vs&&... vs ) + -> decltype( f( std::forward( vs )... ) ) { + return f( std::forward( vs )... ); +} + +// take head, produce value from it, pass after other values +template +auto ltr_pop( lua_State* L, F f, types, Vs&&... vs ) +-> decltype( ltr_pop( L, f, types{}, std::forward( vs )..., stack::pop( L ) ) ) { + return ltr_pop( L, f, types{}, std::forward( vs )..., stack::pop( L ) ); +} + template inline T get_unsigned(lua_State* L, std::true_type, int index = -1) { return lua_tounsigned(L, index); @@ -150,6 +164,25 @@ inline void push(lua_State* L, const char (&str)[N]) { inline void push(lua_State* L, const std::string& str) { lua_pushlstring(L, str.c_str(), str.size()); } + +namespace detail { +template +inline void push( lua_State* L, indices, const T& tuplen ) { + using swallow = char []; + void( swallow{ ( push( L, std::get( tuplen ) ), '\0' )... } ); +} +} // detail + +template +inline void push(lua_State* L, const std::tuple& tuplen) { + detail::push(L, sol::detail::build_indices(), tuplen); +} + +template +inline auto pop_call( lua_State* L, TFx&& fx, types t )->decltype( detail::ltr_pop( L, fx, t ) ) { + return detail::ltr_pop( L, fx, t ); +} + } // stack } // sol diff --git a/sol/state.hpp b/sol/state.hpp index 3489d0cd..a4f154ea 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -1,186 +1,194 @@ -// 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_STATE_HPP -#define SOL_STATE_HPP - -#include "error.hpp" -#include "table.hpp" -#include - -namespace sol { -namespace detail { -template -struct are_same : std::true_type {}; - -template -struct are_same : std::integral_constant::value && are_same::value> {}; - -int atpanic(lua_State* L) { - throw sol_error(lua_tostring(L, -1)); -} -} // detail - -enum class lib : char { - base, - package, - coroutine, - string, - os, - math, - table, - debug, - bit32, - io, - count -}; - -class state { -private: - std::unique_ptr L; - table reg; - table global; -public: - state(): - L(luaL_newstate(), lua_close), - reg(L.get(), LUA_REGISTRYINDEX), - global(reg.get(LUA_RIDX_GLOBALS)) { - lua_atpanic(L.get(), detail::atpanic); - } - - state(const std::string& filename): - L(luaL_newstate(), lua_close), - reg(L.get(), LUA_REGISTRYINDEX), - global(reg.get
(LUA_RIDX_GLOBALS)) { - lua_atpanic(L.get(), detail::atpanic); - open_file(filename); - } - - template - void open_libraries(Args&&... args) { - static_assert(detail::are_same{}, "all types must be libraries"); - if(sizeof...(args) == 0) { - luaL_openlibs(L.get()); - return; - } - - lib libraries[1 + sizeof...(args)] = { lib::count, std::forward(args)... }; - - for(auto&& library : libraries) { - switch(library) { - case lib::base: - luaL_requiref(L.get(), "base", luaopen_base, 1); - break; - case lib::package: - luaL_requiref(L.get(), "package", luaopen_package, 1); - break; - case lib::coroutine: - luaL_requiref(L.get(), "coroutine", luaopen_coroutine, 1); - break; - case lib::string: - luaL_requiref(L.get(), "string", luaopen_string, 1); - break; - case lib::table: - luaL_requiref(L.get(), "table", luaopen_table, 1); - break; - case lib::math: - luaL_requiref(L.get(), "math", luaopen_math, 1); - break; - case lib::bit32: - luaL_requiref(L.get(), "bit32", luaopen_bit32, 1); - break; - case lib::io: - luaL_requiref(L.get(), "io", luaopen_io, 1); - break; - case lib::os: - luaL_requiref(L.get(), "os", luaopen_os, 1); - break; - case lib::debug: - luaL_requiref(L.get(), "debug", luaopen_debug, 1); - break; - case lib::count: - break; - } - } - } - - void script(const std::string& code) { - if(luaL_dostring(L.get(), code.c_str())) { - lua_error(L.get()); - } - } - - void open_file(const std::string& filename) { - if(luaL_dofile(L.get(), filename.c_str())) { - lua_error(L.get()); - } - } - - template - T get(U&& key) const { - return global.get(std::forward(key)); - } - - template - state& set(T&& key, U&& value) { - global.set(std::forward(key), std::forward(value)); - return *this; - } - - template - table create_table(T&& key, int narr = 0, int nrec = 0) { - if(narr == 0 && nrec == 0) { - lua_newtable(L.get()); - } - else { - lua_createtable(L.get(), narr, nrec); - } - - table result(L.get()); - lua_pop(L.get(), 1); - global.set(std::forward(key), result); - return result; - } - - table create_table(int narr = 0, int nrec = 0) { - if(narr == 0 && nrec == 0) { - lua_newtable(L.get()); - } - else { - lua_createtable(L.get(), narr, nrec); - } - - table result(L.get()); - lua_pop(L.get(), 1); - return result; - } - - table global_table() const { - return global; - } - - table registry() const { - return reg; - } -}; -} // sol - +// 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_STATE_HPP +#define SOL_STATE_HPP + +#include "error.hpp" +#include "table.hpp" +#include + +namespace sol { +namespace detail { +template +struct are_same : std::true_type {}; + +template +struct are_same : std::integral_constant::value && are_same::value> {}; + +int atpanic(lua_State* L) { + throw sol_error(lua_tostring(L, -1)); +} +} // detail + +enum class lib : char { + base, + package, + coroutine, + string, + os, + math, + table, + debug, + bit32, + io, + count +}; + +class state { +private: + std::unique_ptr L; + table reg; + table global; + std::unordered_map> funcs; + +public: + state(): + L(luaL_newstate(), lua_close), + reg(L.get(), LUA_REGISTRYINDEX), + global(reg.get
(LUA_RIDX_GLOBALS)) { + lua_atpanic(L.get(), detail::atpanic); + } + + state(const std::string& filename): + L(luaL_newstate(), lua_close), + reg(L.get(), LUA_REGISTRYINDEX), + global(reg.get
(LUA_RIDX_GLOBALS)) { + lua_atpanic(L.get(), detail::atpanic); + open_file(filename); + } + + template + void open_libraries(Args&&... args) { + static_assert(detail::are_same{}, "all types must be libraries"); + if(sizeof...(args) == 0) { + luaL_openlibs(L.get()); + return; + } + + lib libraries[1 + sizeof...(args)] = { lib::count, std::forward(args)... }; + + for(auto&& library : libraries) { + switch(library) { + case lib::base: + luaL_requiref(L.get(), "base", luaopen_base, 1); + break; + case lib::package: + luaL_requiref(L.get(), "package", luaopen_package, 1); + break; + case lib::coroutine: + luaL_requiref(L.get(), "coroutine", luaopen_coroutine, 1); + break; + case lib::string: + luaL_requiref(L.get(), "string", luaopen_string, 1); + break; + case lib::table: + luaL_requiref(L.get(), "table", luaopen_table, 1); + break; + case lib::math: + luaL_requiref(L.get(), "math", luaopen_math, 1); + break; + case lib::bit32: + luaL_requiref(L.get(), "bit32", luaopen_bit32, 1); + break; + case lib::io: + luaL_requiref(L.get(), "io", luaopen_io, 1); + break; + case lib::os: + luaL_requiref(L.get(), "os", luaopen_os, 1); + break; + case lib::debug: + luaL_requiref(L.get(), "debug", luaopen_debug, 1); + break; + case lib::count: + break; + } + } + } + + void script(const std::string& code) { + if(luaL_dostring(L.get(), code.c_str())) { + lua_error(L.get()); + } + } + + void open_file(const std::string& filename) { + if(luaL_dofile(L.get(), filename.c_str())) { + lua_error(L.get()); + } + } + + template + T get(U&& key) const { + return global.get(std::forward(key)); + } + + template + state& set(T&& key, U&& value) { + global.set(std::forward(key), std::forward(value)); + return *this; + } + + template + state& set_function( T&& key, TFx&& fx ) { + global.set_function( std::forward( key ), std::forward( fx ) ); + return *this; + } + + template + table create_table(T&& key, int narr = 0, int nrec = 0) { + if(narr == 0 && nrec == 0) { + lua_newtable(L.get()); + } + else { + lua_createtable(L.get(), narr, nrec); + } + + table result(L.get()); + lua_pop(L.get(), 1); + global.set(std::forward(key), result); + return result; + } + + table create_table(int narr = 0, int nrec = 0) { + if(narr == 0 && nrec == 0) { + lua_newtable(L.get()); + } + else { + lua_createtable(L.get(), narr, nrec); + } + + table result(L.get()); + lua_pop(L.get(), 1); + return result; + } + + table global_table() const { + return global; + } + + table registry() const { + return reg; + } +}; +} // sol + #endif // SOL_STATE_HPP \ No newline at end of file diff --git a/sol/table.hpp b/sol/table.hpp index 215ea5a7..97316824 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -23,9 +23,14 @@ #define SOL_TABLE_HPP #include "stack.hpp" +#include "lua_function.hpp" +#include +#include namespace sol { class table : virtual public reference { +private: + std::unordered_map> funcs; public: table() noexcept: reference{} {} table(lua_State* L, int index = -1): reference(L, index) { @@ -53,10 +58,55 @@ public: return *this; } + template + table& set_function( T&& key, TFx&& fx ) { + typedef typename std::remove_pointer::type>::type clean_fx; + const static bool isfunction = std::is_function::value; + return set_function( std::integral_constant( ), + std::forward( key ), std::forward( fx ) ); + } + + template + table& set_function( std::true_type, T&& key, TFx&& fx ) { + typedef typename std::decay::type clean_fx; + std::string fkey( key ); + lua_CFunction freefunc = &detail::lua_cfun; + auto hint = funcs.find( fkey ); + detail::lua_func* target = nullptr; + if ( hint == funcs.end( ) ) { + std::shared_ptr sptr( new detail::lambda_lua_func( std::forward( fx ) ) ); + hint = funcs.emplace_hint( hint, fkey, std::move( sptr ) ); + } + target = hint->second.get( ); + lua_pushlightuserdata( state( ), static_cast( target ) ); + lua_pushcclosure( state( ), freefunc, 1 ); + lua_setglobal( state( ), fkey.c_str( ) ); + return *this; + } + + template + table& set_function( std::false_type, T&& key, TFx&& fx ) { + typedef typename std::decay::type clean_fx; + std::string fkey( key ); + lua_CFunction freefunc = &detail::lua_cfun; + auto hint = funcs.find( fkey ); + detail::lua_func* target = nullptr; + if ( hint == funcs.end( ) ) { + std::shared_ptr sptr( new detail::explicit_lua_func( std::forward( fx ) ) ); + hint = funcs.emplace_hint( hint, fkey, std::move( sptr ) ); + } + target = hint->second.get( ); + lua_pushlightuserdata( state( ), static_cast( target ) ); + lua_pushcclosure( state( ), freefunc, 1 ); + lua_setglobal( state( ), fkey.c_str( ) ); + return *this; + } + size_t size() const { push(); return lua_rawlen(state(), -1); } + }; } // sol diff --git a/sol/tuple.hpp b/sol/tuple.hpp index 60be0bbe..c91d4a7c 100644 --- a/sol/tuple.hpp +++ b/sol/tuple.hpp @@ -26,28 +26,25 @@ #include namespace sol { -namespace detail { + template -struct indices {}; +struct indices { }; template -struct build_indices : build_indices {}; +struct build_indices : build_indices { }; template -struct build_indices<0, Ns...> : indices {}; +struct build_indices<0, Ns...> : indices{ }; -using std::get; +template +struct types : build_indices { }; -template -inline auto call(Function f, const Tuple& t, indices) -> decltype(f(get(t)...)) { - return f(get(t)...); -} -} // detail +template +struct tuple_types : types, std::false_type { }; + +template +struct tuple_types> : types, std::true_type{ }; -template -inline auto call(Function f, const std::tuple& t) -> decltype(detail::call(f, t, detail::build_indices{})) { - return call(f, t, detail::build_indices{}); -} } // sol #endif // SOL_TUPLE_HPP \ No newline at end of file diff --git a/sol/types.hpp b/sol/types.hpp index cbc947ef..104d86c4 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -28,7 +28,9 @@ namespace sol { struct nil_t {}; -const nil_t nil{}; +const nil_t nil{ }; +struct Void_t { }; +const Void_t Void{}; enum class type : int { none = LUA_TNONE,