diff --git a/.gitignore b/.gitignore index 77b3dc40..158d2c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ luajit-2.0.4/ *.creator.user.* lua-5.3.1/ main2.cpp +lua-5.3.2/ +lua-5.2.4/ +bench/ diff --git a/bench_cpp_function.hpp b/bench_cpp_function.hpp index 24b18b25..860a856f 100644 --- a/bench_cpp_function.hpp +++ b/bench_cpp_function.hpp @@ -13,11 +13,11 @@ static sol::state prepare_cpp_function_state( ) { return lua; } -struct sol_fast_function_result_cpp_bench { +struct sol_protected_function_result_cpp_bench { void operator () ( nonius::chronometer meter ) const { sol::state lua = prepare_cpp_function_state( ); auto measurement = [ & ] ( int run_index ) { - sol::fast_function r = lua[ "r" ]; + sol::protected_function r = lua[ "r" ]; int value = r( ); return value; }; @@ -25,11 +25,11 @@ struct sol_fast_function_result_cpp_bench { } }; -struct sol_fast_direct_cpp_bench { +struct sol_protected_call_cpp_bench { void operator () ( nonius::chronometer meter ) const { sol::state lua = prepare_cpp_function_state( ); auto measurement = [ & ] ( int run_index ) { - sol::fast_function r = lua[ "r" ]; + sol::protected_function r = lua[ "r" ]; int value = r.call( ); return value; }; @@ -49,7 +49,7 @@ struct sol_function_result_cpp_bench { } }; -struct sol_direct_cpp_bench { +struct sol_call_cpp_bench { void operator () ( nonius::chronometer meter ) const { sol::state lua = prepare_cpp_function_state( ); auto measurement = [ & ] ( int run_index ) { @@ -61,7 +61,7 @@ struct sol_direct_cpp_bench { } }; -struct c_direct_cpp_bench { +struct c_call_cpp_bench { void operator () ( nonius::chronometer meter ) const { sol::state lua = prepare_cpp_function_state( ); lua_State* L = lua.lua_state( ); @@ -82,11 +82,11 @@ void bench_cpp_function( const std::string& dir, std::string& configurationname, cfg.title = "sol::function (C++ source) (" + configurationname + " " + platformname + ")"; cfg.samples = 100; nonius::benchmark benchmarks [] = { - nonius::benchmark( "fast_function - function_result", sol_fast_function_result_cpp_bench( ) ), - nonius::benchmark( "fast_function - call<>", sol_fast_direct_cpp_bench( ) ), + nonius::benchmark( "protected_function - function_result", sol_protected_function_result_cpp_bench( ) ), + nonius::benchmark( "protected_function - call<>", sol_protected_call_cpp_bench( ) ), nonius::benchmark( "function - function_result", sol_function_result_cpp_bench( ) ), - nonius::benchmark( "function - call<>", sol_direct_cpp_bench( ) ), - nonius::benchmark( "plain C", c_direct_cpp_bench( ) ), + nonius::benchmark( "function - call<>", sol_call_cpp_bench( ) ), + nonius::benchmark( "plain C", c_call_cpp_bench( ) ), }; nonius::go( cfg, std::begin( benchmarks ), std::end( benchmarks ), nonius::html_reporter( ) ); } diff --git a/bench_lua_function.hpp b/bench_lua_function.hpp index e8ae4881..06454cc7 100644 --- a/bench_lua_function.hpp +++ b/bench_lua_function.hpp @@ -13,30 +13,6 @@ end return lua; } -struct sol_fast_function_result_lua_bench { - void operator () ( nonius::chronometer meter ) const { - sol::state lua = prepare_lua_function_state( ); - auto measurement = [ & ] ( int run_index ) { - sol::fast_function r = lua[ "r" ]; - int value = r( ); - return value; - }; - meter.measure( measurement ); - } -}; - -struct sol_fast_direct_lua_bench { - void operator () ( nonius::chronometer meter ) const { - sol::state lua = prepare_lua_function_state( ); - auto measurement = [ & ] ( int run_index ) { - sol::fast_function r = lua[ "r" ]; - int value = r.call( ); - return value; - }; - meter.measure( measurement ); - } -}; - struct sol_function_result_lua_bench { void operator () ( nonius::chronometer meter ) const { sol::state lua = prepare_lua_function_state( ); @@ -49,7 +25,7 @@ struct sol_function_result_lua_bench { } }; -struct sol_direct_lua_bench { +struct sol_call_lua_bench { void operator () ( nonius::chronometer meter ) const { sol::state lua = prepare_lua_function_state( ); auto measurement = [ & ] ( int run_index ) { @@ -61,6 +37,30 @@ struct sol_direct_lua_bench { } }; +struct sol_protected_function_result_lua_bench { + void operator () ( nonius::chronometer meter ) const { + sol::state lua = prepare_lua_function_state( ); + auto measurement = [ & ] ( int run_index ) { + sol::protected_function r = lua[ "r" ]; + int value = r( ); + return value; + }; + meter.measure( measurement ); + } +}; + +struct sol_protected_call_lua_bench { + void operator () ( nonius::chronometer meter ) const { + sol::state lua = prepare_lua_function_state( ); + auto measurement = [ & ] ( int run_index ) { + sol::protected_function r = lua[ "r" ]; + int value = r.call( ); + return value; + }; + meter.measure( measurement ); + } +}; + struct c_direct_lua_bench { void operator () ( nonius::chronometer meter ) const { sol::state lua = prepare_lua_function_state( ); @@ -81,11 +81,11 @@ void bench_lua_function( const std::string& dir, std::string& configurationname cfg.output_file = dir + "sol.functions (lua source) - " + configurationname + " " + platformname + ".html"; cfg.title = "sol::function (lua source) (" + configurationname + " " + platformname + ")"; cfg.samples = 100; - nonius::benchmark benchmarks [] = { - nonius::benchmark( "fast_function - function_result", sol_fast_function_result_lua_bench( ) ), - nonius::benchmark( "fast_function - call<>", sol_fast_direct_lua_bench( ) ), - nonius::benchmark( "function - function_result", sol_function_result_lua_bench( ) ), - nonius::benchmark( "function - call<>", sol_direct_lua_bench( ) ), + nonius::benchmark benchmarks[] = { + nonius::benchmark("function - function_result", sol_function_result_lua_bench()), + nonius::benchmark("function - call<>", sol_call_lua_bench()), + nonius::benchmark("protected_function - function_result", sol_protected_function_result_lua_bench()), + nonius::benchmark("protected_function - call<>", sol_protected_call_lua_bench()), nonius::benchmark( "plain C", c_direct_lua_bench( ) ), }; nonius::go( cfg, std::begin( benchmarks ), std::end( benchmarks ), nonius::html_reporter( ) ); diff --git a/sol.hpp b/sol.hpp index ad926d9d..b246d3c9 100644 --- a/sol.hpp +++ b/sol.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Danny Y., Rapptz +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/compatibility.hpp b/sol/compatibility.hpp index c6303944..8d204ebf 100644 --- a/sol/compatibility.hpp +++ b/sol/compatibility.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/compatibility/5.0.0.h b/sol/compatibility/5.0.0.h index 5b8bcac4..dd16ca4c 100644 --- a/sol/compatibility/5.0.0.h +++ b/sol/compatibility/5.0.0.h @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/compatibility/5.1.0.h b/sol/compatibility/5.1.0.h index 054772a9..c3cef8ef 100644 --- a/sol/compatibility/5.1.0.h +++ b/sol/compatibility/5.1.0.h @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/compatibility/5.x.x.h b/sol/compatibility/5.x.x.h index 7de1ff8d..a58b00cb 100644 --- a/sol/compatibility/5.x.x.h +++ b/sol/compatibility/5.x.x.h @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/compatibility/5.x.x.inl b/sol/compatibility/5.x.x.inl index 2ada1572..04f66215 100644 --- a/sol/compatibility/5.x.x.inl +++ b/sol/compatibility/5.x.x.inl @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/compatibility/version.hpp b/sol/compatibility/version.hpp index f69aea85..0880c7a4 100644 --- a/sol/compatibility/version.hpp +++ b/sol/compatibility/version.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/debug.hpp b/sol/debug.hpp index 5ed2d9dc..375b6f4e 100644 --- a/sol/debug.hpp +++ b/sol/debug.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/default_construct.hpp b/sol/default_construct.hpp index 6a6fef91..fd5966be 100644 --- a/sol/default_construct.hpp +++ b/sol/default_construct.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/demangle.hpp b/sol/demangle.hpp index 4a8f6350..7957a1d9 100644 --- a/sol/demangle.hpp +++ b/sol/demangle.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/deprecate.hpp b/sol/deprecate.hpp index 9bea4056..c99954d3 100644 --- a/sol/deprecate.hpp +++ b/sol/deprecate.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/error.hpp b/sol/error.hpp index 1d5e4593..4e619645 100644 --- a/sol/error.hpp +++ b/sol/error.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/function.hpp b/sol/function.hpp index 5c66dfbb..4c93be9e 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -28,88 +28,13 @@ #include "function_types.hpp" #include "usertype_traits.hpp" #include "resolve.hpp" +#include "function_result.hpp" #include #include #include namespace sol { -class function_result { -private: - lua_State* L; - int index; - int returncount; - int popcount; - call_error error; - - template - stack::get_return get(types, indices) const { - return stack::get(L, index); - } - - template - stack::get_return get(types, indices) const { - auto r = std::make_tuple(stack::get(L, index + I)...); - return r; - } - -public: - function_result() = default; - function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_error error = call_error::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) { - - } - function_result(const function_result&) = default; - function_result& operator=(const function_result&) = default; - function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), error(o.error) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.error = call_error::runtime; - } - function_result& operator=(function_result&& o) { - L = o.L; - index = o.index; - returncount = o.returncount; - error = o.error; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.error = call_error::runtime; - return *this; - } - - bool valid() const { - return error == call_error::ok; - } - - template - T get() const { - tuple_types> tr; - return get(tr, tr); - } - - operator std::string() const { - return get(); - } - - template, const char*>>, Not, char>>, Not, std::string>>, Not, std::initializer_list>>> = 0> - operator T () const { - return get(); - } - - ~function_result() { - stack::remove(L, index, popcount); - } -}; - -class fast_function : public reference { +class function : public reference { private: void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const { lua_callk( lua_state( ), static_cast( argcount ), static_cast( resultcount ), 0, nullptr ); @@ -117,7 +42,7 @@ private: template std::tuple invoke( indices, types, std::ptrdiff_t n ) const { - luacall( n, sizeof...( Ret ), h ); + luacall( n, sizeof...( Ret ) ); int nreturns = static_cast( sizeof...( Ret ) ); int stacksize = lua_gettop( lua_state( ) ); int firstreturn = std::max( 0, stacksize - nreturns ) + 1; @@ -139,35 +64,22 @@ private: function_result invoke( indices<>, types<>, std::ptrdiff_t n ) const { int stacksize = lua_gettop( lua_state( ) ); - int firstreturn = std::max( 0, stacksize - static_cast( n ) - 1 ); - int poststacksize = 0; - int returncount = 0; - try { - luacall( n, LUA_MULTRET ); - poststacksize = lua_gettop( lua_state( ) ); - returncount = poststacksize - firstreturn; - } - // Handle C++ errors thrown from C++ functions bound inside of lua - catch ( const std::exception& error ) { - stack::push( lua_state( ), error.what( ) ); - return function_result( lua_state( ), firstreturn, 0, 1, call_error::runtime ); - } - catch ( ... ) { - throw; - } - + int firstreturn = std::max( 1, stacksize - static_cast( n ) ); + luacall( n, LUA_MULTRET ); + int poststacksize = lua_gettop( lua_state( ) ); + int returncount = poststacksize - firstreturn; return function_result( lua_state( ), firstreturn, returncount, returncount, call_error::ok ); } public: - fast_function( ) = default; - fast_function( lua_State* L, int index = -1 ) : reference( L, index ) { + function( ) = default; + function( lua_State* L, int index = -1 ) : reference( L, index ) { type_assert( L, index, type::function ); } - fast_function( const fast_function& ) = default; - fast_function& operator=( const fast_function& ) = default; - fast_function( fast_function&& ) = default; - fast_function& operator=( fast_function&& ) = default; + function( const function& ) = default; + function& operator=( const function& ) = default; + function( function&& ) = default; + function& operator=( function&& ) = default; template function_result operator()( Args&&... args ) const { @@ -176,7 +88,7 @@ public: template auto operator()( types, Args&&... args ) const - -> decltype( invoke( types( ), types( ), 0, std::declval( ) ) ) { + -> decltype( invoke( types( ), types( ), 0 ) ) { return call( std::forward( args )... ); } @@ -190,7 +102,7 @@ public: } }; -class safe_function : public reference { +class protected_function : public reference { private: static reference& handler_storage() { static sol::reference h; @@ -252,21 +164,21 @@ private: function_result invoke(indices<>, types<>, std::ptrdiff_t n, handler& h) const { bool handlerpushed = error_handler.valid(); int stacksize = lua_gettop(lua_state()); - int firstreturn = std::max(0, stacksize - static_cast(n) - 1); + int firstreturn = std::max(1, stacksize - static_cast(n) - 1); int returncount = 0; call_error code = call_error::ok; try { code = static_cast(luacall(n, LUA_MULTRET, h)); - int poststacksize = lua_gettop( lua_state( ) ); + int poststacksize = lua_gettop(lua_state()); returncount = poststacksize - firstreturn; } // Handle C++ errors thrown from C++ functions bound inside of lua catch (const std::exception& error) { - code = call_error::runtime; h.stackindex = 0; stack::push(lua_state(), error.what()); - return function_result( lua_state( ), firstreturn, 0, 1, call_error::runtime ); + firstreturn = lua_gettop(lua_state()); + return function_result(lua_state(), firstreturn, 0, 1, call_error::runtime); } catch (...) { throw; @@ -277,14 +189,14 @@ private: public: sol::reference error_handler; - safe_function() = default; - safe_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) { + protected_function() = default; + protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) { type_assert(L, index, type::function); } - safe_function(const safe_function&) = default; - safe_function& operator=(const safe_function&) = default; - safe_function( safe_function&& ) = default; - safe_function& operator=( safe_function&& ) = default; + protected_function(const protected_function&) = default; + protected_function& operator=(const protected_function&) = default; + protected_function( protected_function&& ) = default; + protected_function& operator=( protected_function&& ) = default; template function_result operator()(Args&&... args) const { diff --git a/sol/function_result.hpp b/sol/function_result.hpp new file mode 100644 index 00000000..43f15870 --- /dev/null +++ b/sol/function_result.hpp @@ -0,0 +1,103 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz 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_FUNCTION_RESULT_HPP +#define SOL_FUNCTION_RESULT_HPP + +#include "reference.hpp" +#include "tuple.hpp" +#include "stack.hpp" +#include "proxy_base.hpp" + +namespace sol { +struct function_result : public proxy_base { +private: + lua_State* L; + int index; + int returncount; + int popcount; + call_error error; + + template + stack::get_return get(types, indices) const { + return stack::get(L, index); + } + + template + stack::get_return get(types, indices) const { + return stack::get_return(stack::get(L, index + I)...); + } + +public: + function_result() = default; + function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_error error = call_error::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) { + + } + function_result(const function_result&) = default; + function_result& operator=(const function_result&) = default; + function_result(function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), error(o.error) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.error = call_error::runtime; + } + function_result& operator=(function_result&& o) { + L = o.L; + index = o.index; + returncount = o.returncount; + error = o.error; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.error = call_error::runtime; + return *this; + } + + bool valid() const { + return error == call_error::ok; + } + + template + T get() const { + tuple_types> tr; + return get(tr, tr); + } + + template + decltype(auto) operator[](K&& key) const { + return get()[std::forward(key)]; + } + + ~function_result() { + stack::remove(L, index, popcount); + } +}; +} // sol + +#endif // SOL_FUNCTION_RESULT_HPP diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 51799bf5..f9b6a69c 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/object.hpp b/sol/object.hpp index deeebb82..4eec3100 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/proxy.hpp b/sol/proxy.hpp index c233900b..80def0f0 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -25,10 +25,11 @@ #include "traits.hpp" #include "object.hpp" #include "function.hpp" +#include "proxy_base.hpp" namespace sol { template -struct proxy { +struct proxy : public proxy_base> { private: Table tbl; If>, Key&, Unqualified> key; @@ -67,20 +68,6 @@ public: return tbl.template get( key ); } - operator std::string() const { - return get(); - } - - template>, is_lua_primitive> = 0> - operator T ( ) const { - return get( ); - } - - template>, Not>> = 0> - operator T& ( ) const { - return get( ); - } - template decltype(auto) operator[](K&& key) const { return get
()[std::forward(key)]; diff --git a/sol/proxy_base.hpp b/sol/proxy_base.hpp new file mode 100644 index 00000000..9b59ee3f --- /dev/null +++ b/sol/proxy_base.hpp @@ -0,0 +1,51 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz 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_PROXY_BASE_HPP +#define SOL_PROXY_BASE_HPP + +#include "reference.hpp" +#include "tuple.hpp" +#include "stack.hpp" + +namespace sol { +template +struct proxy_base { + operator std::string() const { + const Super& super = *static_cast(static_cast(this)); + return super.template get(); + } + + template>, is_proxy_primitive>> = 0> + operator T ( ) const { + const Super& super = *static_cast(static_cast(this)); + return super.template get( ); + } + + template>, Not>>> = 0> + operator T& ( ) const { + const Super& super = *static_cast(static_cast(this)); + return super.template get( ); + } +}; +} // sol + +#endif // SOL_PROXY_BASE_HPP diff --git a/sol/reference.hpp b/sol/reference.hpp index 5748c746..bd311aaa 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -25,14 +25,18 @@ #include "types.hpp" namespace sol { -namespace detail { +namespace stack { template struct push_pop { T t; push_pop (T x) : t(x) { t.push(); } ~push_pop() { t.pop(); } }; -} // detail +template +push_pop push_popper(T&& x) { + return push_pop(std::forward(x)); +}; +} // stack class reference { private: diff --git a/sol/resolve.hpp b/sol/resolve.hpp index 9a6d501f..4299a85b 100644 --- a/sol/resolve.hpp +++ b/sol/resolve.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/stack.hpp b/sol/stack.hpp index 35afc608..c4bca4b6 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -150,7 +150,7 @@ inline void lua_setglobali(lua_State* L, lua_Integer n) { #else lua_pushglobaltable(L); lua_pushinteger(L, n); - lua_pushvalue(L, -3) + lua_pushvalue(L, -3); lua_settable(L, -3); lua_pop(L, 2); // remove table, and the copy of the value #endif diff --git a/sol/state_view.hpp b/sol/state_view.hpp index beaa0c30..0a6827e6 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -150,19 +150,19 @@ public: return globals.get(std::forward(keys)...); } - template - state_view& set(T&& key, U&& value) { - globals.set(std::forward(key), std::forward(value)); + template + state_view& set(Tn&&... argn) { + globals.set(std::forward(argn)...); return *this; } template - SOL_DEPRECATED table& set_userdata(usertype& user) { + SOL_DEPRECATED state_view& set_userdata(usertype& user) { return set_usertype(user); } template - SOL_DEPRECATED table& set_userdata(Key&& key, usertype& user) { + SOL_DEPRECATED state_view& set_userdata(Key&& key, usertype& user) { return set_usertype(std::forward(key), user); } diff --git a/sol/table.hpp b/sol/table.hpp index 43a91a39..a8c32fb3 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/table_core.hpp b/sol/table_core.hpp index 78e6cb40..da0bd50b 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -49,8 +49,9 @@ class table_core : public reference { return stack::pop(lua_state()); } - template>, Bool> = 0> + template, Not>> = 0> decltype(auto) single_get( Key&& key ) const { + auto pp = stack::push_popper(*this); stack::push( lua_state( ), std::forward( key ) ); lua_gettable( lua_state( ), -2 ); return stack::pop( lua_state( ) ); @@ -78,8 +79,9 @@ class table_core : public reference { lua_setglobal( lua_state( ), &key[0] ); } - template>, Bool> = 0> + template, Not>> = 0> void single_set(Key&& key, Value&& value) { + auto pp = stack::push_popper(*this); stack::push(lua_state(), std::forward(key)); stack::push(lua_state(), std::forward(value)); lua_settable(lua_state(), -3); @@ -87,8 +89,8 @@ class table_core : public reference { template void tuple_set( indices, Pairs&& pairs ) { - using swallow = int[]; - swallow{ 0, ( single_set(std::get(pairs), std::get(pairs)) , 0)..., 0 }; + using swallow = int[]; + swallow{ 0, ( single_set(std::get(pairs), std::get(pairs)) , 0)..., 0 }; } #if SOL_LUA_VERSION < 502 @@ -105,14 +107,12 @@ public: template decltype(auto) get( Keys&&... keys ) const { - auto pp = detail::push_pop(*this); return tuple_get( types( ), build_indices( ), std::forward_as_tuple(std::forward(keys)...)); } template table_core& set( Tn&&... argn ) { - auto pp = detail::push_pop(*this); - tuple_set(build_indices(), std::forward_as_tuple(std::forward(argn)...)); + tuple_set(build_indices(), std::forward_as_tuple(std::forward(argn)...)); return *this; } @@ -136,21 +136,19 @@ public: if ( top_level ) { stack::push( lua_state( ), user ); lua_setglobal( lua_state( ), &key[ 0 ] ); - pop( ); } else { - push( ); + auto pp = stack::push_popper( *this ); stack::push( lua_state( ), std::forward( key ) ); stack::push( lua_state( ), user ); lua_settable( lua_state( ), -3 ); - pop( ); } return *this; } template void for_each( Fx&& fx ) const { - push( ); + auto pp = stack::push_popper( *this ); stack::push( lua_state( ), nil ); while ( lua_next( this->lua_state( ), -2 ) ) { sol::object key( lua_state( ), -2 ); @@ -158,14 +156,11 @@ public: fx( key, value ); lua_pop( lua_state( ), 1 ); } - pop( ); } size_t size( ) const { - push( ); - size_t result = lua_rawlen( lua_state( ), -1 ); - pop( ); - return result; + auto pp = stack::push_popper( *this ); + return lua_rawlen(lua_state(), -1); } template @@ -238,11 +233,10 @@ private: template>>, Bool> = 0> void set_resolved_function( Key&& key, Args&&... args ) { - push( ); + auto pp = stack::push_popper( *this ); int tabletarget = lua_gettop( lua_state( ) ); stack::push>( lua_state( ), std::forward( args )... ); lua_setfield( lua_state( ), tabletarget, &key[ 0 ] ); - pop( ); } }; } // sol diff --git a/sol/traits.hpp b/sol/traits.hpp index c55ded3c..2f76540d 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -44,7 +44,7 @@ struct unwrap { template struct unwrap> { - typedef typename std::add_lvalue_reference::type type; + typedef T type; }; template @@ -321,7 +321,7 @@ auto unwrapper(T&& item) -> decltype(std::forward(item)) { } template -Unwrap unwrapper(std::reference_wrapper arg) { +Arg& unwrapper(std::reference_wrapper arg) { return arg.get(); } diff --git a/sol/tuple.hpp b/sol/tuple.hpp index 9c84d1b6..431c8de6 100644 --- a/sol/tuple.hpp +++ b/sol/tuple.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -93,9 +93,6 @@ struct constructors {}; const auto default_constructor = constructors>{}; -template -using ref = std::reference_wrapper; - } // sol #endif // SOL_TUPLE_HPP diff --git a/sol/types.hpp b/sol/types.hpp index b46ef8ff..a4a6139d 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 @@ -126,9 +126,8 @@ template class table_core; typedef table_core table; typedef table_core global_table; -class fast_function; -class safe_function; -typedef safe_function function; +class function; +class protected_function; class object; template @@ -165,7 +164,7 @@ template <> struct lua_type_of : std::integral_constant {}; template <> -struct lua_type_of : std::integral_constant {}; +struct lua_type_of : std::integral_constant {}; template struct lua_type_of> : std::integral_constant{}; @@ -195,6 +194,14 @@ struct lua_type_of::value>::type> : s template struct is_lua_primitive : std::integral_constant>::value> { }; +template +struct is_proxy_primitive : is_lua_primitive { }; + +template +struct is_proxy_primitive> : std::true_type { }; + +template +struct is_proxy_primitive> : std::true_type { }; } // sol #endif // SOL_TYPES_HPP diff --git a/sol/usertype.hpp b/sol/usertype.hpp index c5d72c9c..b4098ca7 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/sol/usertype_traits.hpp b/sol/usertype_traits.hpp index 5ad05512..4d170204 100644 --- a/sol/usertype_traits.hpp +++ b/sol/usertype_traits.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2015 Rapptz and contributors +// Copyright (c) 2013-2016 Rapptz 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 diff --git a/tests.cpp b/tests.cpp index fe2cd03a..5b46a084 100644 --- a/tests.cpp +++ b/tests.cpp @@ -198,7 +198,7 @@ struct giver { }; -TEST_CASE("simple/set_global", "Check if the set_global works properly.") { +TEST_CASE("simple/set", "Check if the set works properly.") { sol::state lua; lua.set("a", 9); @@ -207,10 +207,8 @@ TEST_CASE("simple/set_global", "Check if the set_global works properly.") { lua.set("d", "hello"); REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end")); - lua.set("e", std::string("hello")); + lua.set("e", std::string("hello"), "f", true); REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end")); - - lua.set("f", true); REQUIRE_NOTHROW(lua.script("if f ~= true then error('wrong value') end")); } @@ -225,11 +223,11 @@ TEST_CASE("simple/get", "Tests if the get function works properly.") { REQUIRE_NOTHROW(lua.get("b")); lua.script("d = 'hello'"); - auto d = lua.get("d"); - REQUIRE(d == "hello"); - lua.script("e = true"); - auto e = lua.get("e"); + std::string d; + bool e; + std::tie( d, e ) = lua.get("d", "e"); + REQUIRE(d == "hello"); REQUIRE(e == true); } @@ -265,7 +263,7 @@ TEST_CASE("simple/call_with_parameters", "Lua function is called with a few para REQUIRE_NOTHROW(fvoid(1, 2, 3)); REQUIRE_NOTHROW(a = f.call(1, 2, 3)); REQUIRE(a == 6); - REQUIRE_THROWS(a = f.call(1, 2, "arf")); + REQUIRE_THROWS(a = f(1, 2, "arf")); } TEST_CASE("simple/call_c++_function", "C++ function is called from lua") { @@ -627,7 +625,7 @@ TEST_CASE("tables/usertype", "Show that we can create classes from usertype and REQUIRE(cresult == 3); } -TEST_CASE("tables/usertype constructors", "Show that we can create classes from usertype and use them with multiple destructors") { +TEST_CASE("tables/usertype constructors", "Show that we can create classes from usertype and use them with multiple constructors") { sol::state lua; @@ -704,19 +702,25 @@ TEST_CASE("tables/usertype utility derived", "usertype classes must play nice wh lua.set_usertype(baseusertype); lua.script("base = Base.new(5)"); - lua.script("print(base:get_num())"); + REQUIRE_NOTHROW(lua.script("print(base:get_num())")); - sol::constructors> derivedctor; - sol::usertype derivedusertype(derivedctor, "get_num", &Derived::get_num, "get_num_10", &Derived::get_num_10); + /*sol::constructors> derivedctor; + sol::usertype derivedusertype(derivedctor, + "get_num_10", &Derived::get_num_10, + "get_num", &Derived::get_num + ); lua.set_usertype(derivedusertype); lua.script("derived = Derived.new(7)"); - lua.script("dgn10 = derived:get_num_10()\nprint(dgn10)"); - lua.script("dgn = derived:get_num()\nprint(dgn)"); + Derived& derived = lua["derived"]; + lua.script("dgn = derived:get_num()\n" + "print(dgn)"); + lua.script("dgn10 = derived:get_num_10()\n" + "print(dgn10)"); REQUIRE((lua.get("dgn10") == 70)); - REQUIRE((lua.get("dgn") == 7)); + REQUIRE((lua.get("dgn") == 7));*/ } TEST_CASE("tables/self-referential usertype", "usertype classes must play nice when C++ object types are requested for C++ code") { @@ -856,24 +860,11 @@ TEST_CASE("tables/issue-number-twenty-five", "Using pointers and references from } TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") { - struct Line { - Vec p1, p2; - Line() : p1{0, 0, 0}, p2{0, 0, 0} {} - Line(float x) : p1{x, x, x}, p2{x, x, x} {} - Line(const Vec& p1) : p1{p1}, p2{p1} {} - Line(Vec p1, Vec p2) : p1{p1}, p2{p2} {} - }; - sol::state lua; lua.open_libraries(sol::lib::base); - sol::constructors, sol::types, sol::types> lctor; - sol::usertype ludata(lctor); - lua.set_usertype("Line", ludata); - sol::constructors> ctor; sol::usertype udata(ctor, "normalized", &Vec::normalized, "length", &Vec::length); - lua.set_usertype(udata); REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n" @@ -971,20 +962,26 @@ TEST_CASE("references/get-set", "properly get and set with std::ref semantics. N lua.new_usertype("vars", "boop", &vars::boop); - vars var{}; vars rvar{}; lua.set("beep", var); lua.set("rbeep", std::ref(rvar)); auto& my_var = lua.get("beep"); - auto& ref_var = lua.get>("rbeep"); - + auto& ref_var = lua.get>("rbeep"); + vars& proxy_my_var = lua["beep"]; + std::reference_wrapper proxy_ref_var = lua["rbeep"]; var.boop = 2; rvar.boop = 5; + // Was return as a value: var must be diferent from "beep" + REQUIRE_FALSE(std::addressof(var) == std::addressof(my_var)); + REQUIRE_FALSE(std::addressof(proxy_my_var) == std::addressof(var)); REQUIRE((my_var.boop == 0)); REQUIRE(var.boop != my_var.boop); - // Reference should point back to the same type. + + REQUIRE(std::addressof(ref_var) == std::addressof(rvar)); + //REQUIRE(std::addressof(proxy_ref_var.get()) == std::addressof(rvar)); + REQUIRE(rvar.boop == 5); REQUIRE(rvar.boop == ref_var.boop); } @@ -1003,7 +1000,7 @@ TEST_CASE("interop/null-to-nil-and-back", "nil should be the given type when a p "assert(x == nil)")); } -TEST_CASE( "functions/sol::function_result", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers" ) { +TEST_CASE( "functions/function_result-protected_function", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers" ) { sol::state lua; lua.open_libraries( sol::lib::base, sol::lib::debug ); @@ -1032,8 +1029,8 @@ TEST_CASE( "functions/sol::function_result", "Function result should be the beef + "end" ); - sol::function func = lua[ "doom" ]; - sol::function luafunc = lua[ "luadoom" ]; + sol::protected_function func = lua[ "doom" ]; + sol::protected_function luafunc = lua[ "luadoom" ]; sol::function luahandler = lua[ "handler" ]; sol::function cpphandler = lua[ "cpphandler" ]; func.error_handler = luahandler; @@ -1049,5 +1046,110 @@ TEST_CASE( "functions/sol::function_result", "Function result should be the beef REQUIRE(!result2.valid()); errorstring = result2; REQUIRE(errorstring == errormessage2); - +} + +TEST_CASE("functions/destructor-tests", "Show that proper copies / destruction happens") { + static int created = 0; + static int destroyed = 0; + static void* last_call = nullptr; + static void* static_call = reinterpret_cast(0x01); + typedef void(* fptr)(); + struct x { + x() {++created;} + x(const x&) {++created;} + x(x&&) {++created;} + x& operator=(const x&) {++created; return *this;} + x& operator=(x&&) {++created; return *this;} + void func() {last_call = static_cast(this);}; + ~x () {++destroyed;} + }; + struct y { + y() {++created;} + y(const x&) {++created;} + y(x&&) {++created;} + y& operator=(const x&) {return *this;} + y& operator=(x&&) {return *this;} + static void func() {last_call = static_call;}; + void operator()() {func();} + operator fptr () { return func; } + ~y () {++destroyed;} + }; + + // stateful functors/member functions should always copy unless specified + { + created = 0; + destroyed = 0; + last_call = nullptr; + { + sol::state lua; + x x1; + lua.set_function("x1copy", &x::func, x1); + lua.script("x1copy()"); + REQUIRE(created == 2); + REQUIRE(destroyed == 0); + REQUIRE_FALSE(last_call == &x1); + + lua.set_function("x1ref", &x::func, std::ref(x1)); + lua.script("x1ref()"); + REQUIRE(created == 2); + REQUIRE(destroyed == 0); + REQUIRE(last_call == &x1); + } + REQUIRE(created == 2); + REQUIRE(destroyed == 2); + REQUIRE(created == destroyed); + } + + // things convertible to a static function should _never_ be forced to make copies + // therefore, pass through untouched + { + created = 0; + destroyed = 0; + last_call = nullptr; + { + sol::state lua; + y y1; + lua.set_function("y1copy", y1); + lua.script("y1copy()"); + REQUIRE(created == 1); + REQUIRE(destroyed == 0); + REQUIRE(last_call == static_call); + + last_call = nullptr; + lua.set_function("y1ref", std::ref(y1)); + lua.script("y1ref()"); + REQUIRE(created == 1); + REQUIRE(destroyed == 0); + REQUIRE(last_call == static_call); + } + REQUIRE(created == 1); + REQUIRE(destroyed == 1); + REQUIRE(created == destroyed); + } +} + +TEST_CASE("usertype/destructor-tests", "Show that proper copies / destruction happens") { + static int created = 0; + static int destroyed = 0; + static void* last_call = nullptr; + struct x { + x() {++created;} + ~x () {++destroyed;} + }; + { + sol::state lua; + x x1; + x x2; + lua.set("x1copy", x1, "x2copy", x2, "x1ref", std::ref(x1)); + x& x1copyref = lua["x1copy"]; + x& x2copyref = lua["x2copy"]; + x& x1ref = lua["x1ref"]; + REQUIRE(created == 4); + REQUIRE(destroyed == 0); + REQUIRE_FALSE(last_call == &x1); + REQUIRE(std::addressof(x1) == std::addressof(x1ref)); + } + REQUIRE(created == 4); + REQUIRE(destroyed == 4); + REQUIRE(created == destroyed); }