diff --git a/.gitignore b/.gitignore index 39dc9054..9ca6142f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,19 @@ -obj/* -bin/* -*.ninja* -demacro.txt -Shinobi2 -dev.* -main.cpp +obj/* +bin/* +*.ninja* +demacro.txt +Shinobi2 +dev.* +main.cpp +sol.scratch.cpp +lua-5.2.2/ +Debug/ +Release/ +x64/ +*.vcxproj +*.vcxproj.filters +*.tlog +*.lastbuildstate +*.idb +*.sln +*.gitattributes diff --git a/sol.hpp b/sol.hpp index fb2fdf67..fbf44a8f 100644 --- a/sol.hpp +++ b/sol.hpp @@ -1,28 +1,29 @@ -// 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_HPP -#define SOL_HPP - -#include "sol/state.hpp" -#include "sol/object.hpp" - +// 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_HPP +#define SOL_HPP + +#include "sol/state.hpp" +#include "sol/object.hpp" +#include "sol/function.hpp" + #endif // SOL_HPP \ No newline at end of file diff --git a/sol/function.hpp b/sol/function.hpp new file mode 100644 index 00000000..f3d87485 --- /dev/null +++ b/sol/function.hpp @@ -0,0 +1,68 @@ +// 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 + std::tuple call( types, std::size_t n ) { + lua_pcall( state( ), n, sizeof...( Ret ), 0 ); + return stack::pop_call( state( ), std::make_tuple, types( ) ); + } + + template + Ret call( types, std::size_t n ) { + lua_pcall( state( ), n, 1, 0 ); + return stack::pop( state( ) ); + } + + void call( types, std::size_t n ) { + lua_pcall( state( ), n, 0, 0 ); + } + + void call( types<>, std::size_t n ) { + lua_pcall( state( ), n, 0, 0 ); + } + +public: + function() : reference() {} + function(lua_State* L, int index = -1) : reference(L, index) { + type_assert(L, index, type::function); + } + + template + auto invoke(Args&&... args) -> decltype(call(types( ), sizeof...( Args ))) { + push( ); + stack::push_args( state( ), std::forward( args )... ); + return call( types( ), sizeof...( Args ) ); + } +}; +} // sol + +#endif // SOL_FUNCTION_HPP diff --git a/sol/functional.hpp b/sol/functional.hpp new file mode 100644 index 00000000..3fe6ae18 --- /dev/null +++ b/sol/functional.hpp @@ -0,0 +1,122 @@ +// 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...(Args); + static const bool is_member_function = true; + typedef std::tuple arg_tuple_type; + typedef types args_type; + typedef R(T::* func_pointer_type)(Args...); + typedef typename std::remove_pointer::type func_type; + typedef R return_type; + template + using arg_n = std::tuple_element; +}; + +template +struct function_traits { + static const std::size_t arity = sizeof...(Args); + static const bool is_member_function = true; + typedef std::tuple arg_tuple_type; + typedef types args_type; + typedef R(T::* func_type)(Args...); + typedef R(T::* func_pointer_type)(Args...); + typedef R return_type; + template + using arg_n = std::tuple_element; +}; + +template +struct function_traits { + static const std::size_t arity = sizeof...(Args); + static const bool is_member_function = false; + typedef std::tuple arg_tuple_type; + typedef types args_type; + typedef R(func_type)(Args...); + typedef R(*func_pointer_type)(Args...); + typedef R return_type; + template + using arg_n = std::tuple_element; +}; + +template +struct function_traits { + static const std::size_t arity = sizeof...(Args); + static const bool is_member_function = false; + typedef std::tuple arg_tuple_type; + typedef types args_type; + typedef R(func_type)(Args...); + typedef R(*func_pointer_type)(Args...); + typedef R return_type; + 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 +struct lua_return_type { + typedef std::tuple type; +}; + +template +struct lua_return_type { + typedef Ret type; +}; + +template <> +struct lua_return_type<> { + typedef void type; +}; + +template <> +struct lua_return_type { + typedef void type; +}; + +template +inline auto call(Function&& f, const std::tuple& t) -> decltype(detail::call(std::forward(f), t, build_indices{})) { + return call(std::forward(f), t, 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..225fda71 --- /dev/null +++ b/sol/lua_function.hpp @@ -0,0 +1,155 @@ +// 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*) { + 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(FxArgs&&... fxargs) : fx(std::forward(fxargs)...) { + + } + + virtual int operator () (lua_State* L) override { + return ( *this )( tuple_types( ), typename fx_traits::args_type( ), L ); + } + + template + int operator()(types, types t, lua_State* L) { + 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(FxArgs&&... fxargs) : fx(std::forward(fxargs)...) { + + } + + virtual int operator () (lua_State* L) override { + return ( *this )( tuple_types( ), typename fx_traits::args_type( ), L ); + } + + template + int operator () (types, types t, lua_State* L) { + 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; + struct lambda { + T* member; + TFx invocation; + + template + lambda(T* m, FxArgs&&... fxargs) : member(m), invocation(std::forward(fxargs)...) { + + } + + template + typename fx_traits::return_type operator () (Args&&... args) { + return ((*member).*invocation)(std::forward(args)...); + } + } fx; + + template + explicit_lua_func(T* m, FxArgs&&... fxargs) : fx(m, std::forward(fxargs)...) { + + } + + template + explicit_lua_func(T& m, FxArgs&&... fxargs) : fx(std::addressof(m), std::forward(fxargs)...) { + + } + + virtual int operator () (lua_State* L) override { + return ( *this )( tuple_types( ), typename fx_traits::args_type( ), L ); + } + + template + int operator () (types, types t, lua_State* L) { + 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..16b019fc 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 @@ -150,6 +151,48 @@ 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{ '\0', (sol::stack::push(L, std::get(tuplen)), '\0')... }); +} + +template +auto ltr_pop( lua_State*, F&& f, types<>, Vs&&... vs ) +-> decltype( f( std::forward( vs )... ) ) { + return f( std::forward( vs )... ); +} +template +auto ltr_pop( lua_State* L, F&& f, types, Vs&&... vs ) +-> decltype( ltr_pop( L, std::forward( f ), types<>( ), std::forward( vs )..., pop( L ) ) ) { + return ltr_pop( L, std::forward( f ), types<>( ), std::forward( vs )..., pop( L ) ); +} +template +auto ltr_pop( lua_State* L, F&& f, types, Vs&&... vs ) +-> decltype( ltr_pop( L, std::forward( f ), types( ), std::forward( vs )..., pop( L ) ) ) { + return ltr_pop( L, std::forward( f ), types( ), std::forward( vs )..., pop( L ) ); +} + +} // detail + +template +inline void push(lua_State* L, const std::tuple& tuplen) { + detail::push(L, build_indices(), tuplen); +} + +template +inline auto pop_call( lua_State* L, TFx&& fx, types )->decltype( detail::ltr_pop( L, std::forward( fx ), types() ) ) { + return detail::ltr_pop( L, std::forward( fx ), types()); +} + +template +void push_args( lua_State* L, Args&&... args ) { + using swallow = char []; + void( swallow{ '\0', ( stack::push( L, std::forward( args ) ), '\0' )... } ); +} + } // stack } // sol diff --git a/sol/state.hpp b/sol/state.hpp index 985b5c19..f49bf499 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -32,7 +32,7 @@ template struct are_same : std::true_type {}; template -struct are_same : std::integral_constant{} && are_same{}> {}; +struct are_same : std::integral_constant::value && are_same::value> {}; int atpanic(lua_State* L) { throw sol_error(lua_tostring(L, -1)); @@ -58,6 +58,8 @@ private: std::unique_ptr L; table reg; table global; + std::unordered_map> funcs; + public: state(): L(luaL_newstate(), lua_close), @@ -145,6 +147,18 @@ public: return *this; } + template + state& set_function(T&& key, TFx&& fx) { + global.set_function(std::forward(key), std::forward(fx)); + return *this; + } + + template + state& set_function(T&& key, TFx&& fx, TM& mem) { + global.set_function(std::forward(key), std::forward(fx), mem); + return *this; + } + template table create_table(T&& key, int narr = 0, int nrec = 0) { if(narr == 0 && nrec == 0) { diff --git a/sol/table.hpp b/sol/table.hpp index 215ea5a7..679a817b 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,60 @@ 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_fx(std::integral_constant(), + std::forward(key), std::forward(fx)); + } + + template + table& set_function(T&& key, TFx&& fx, TM& mem) { + typedef typename std::remove_pointer::type>::type clean_fx; + std::unique_ptr sptr(new detail::explicit_lua_func(mem, std::forward(fx))); + return set_fx(std::forward(key), std::move(sptr)); + } + size_t size() const { push(); return lua_rawlen(state(), -1); } + +private: + + template + table& set_fx(std::true_type, T&& key, TFx&& fx) { + typedef typename std::remove_pointer::type>::type clean_fx; + std::unique_ptr sptr(new detail::lambda_lua_func(std::forward(fx))); + return set_fx(std::forward(key), std::move(sptr)); + } + + template + table& set_fx(std::false_type, T&& key, TFx&& fx) { + typedef typename std::decay::type ptr_fx; + std::unique_ptr sptr(new detail::explicit_lua_func(std::forward(fx))); + return set_fx(std::forward(key), std::move(sptr)); + } + + template + table& set_fx(T&& key, std::unique_ptr funcptr) { + std::string fkey(key); + auto hint = funcs.find(fkey); + if (hint == funcs.end()) { + std::shared_ptr sptr(funcptr.release()); + hint = funcs.emplace_hint(hint, fkey, std::move(sptr)); + } + else { + hint->second.reset(funcptr.release()); + } + detail::lua_func* target = hint->second.get(); + lua_CFunction freefunc = &detail::lua_cfun; + lua_pushlightuserdata(state(), static_cast(target)); + lua_pushcclosure(state(), freefunc, 1); + lua_setglobal(state(), fkey.c_str()); + return *this; + } }; } // sol diff --git a/sol/tuple.hpp b/sol/tuple.hpp index 60be0bbe..df119139 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,