diff --git a/Results - Debug.html b/Results - Debug.html new file mode 100644 index 00000000..9b2baac6 --- /dev/null +++ b/Results - Debug.html @@ -0,0 +1,433 @@ + + + + + Sol - Functions (Debug) - nonius report + + + + + + + + + +
+ + + diff --git a/Results - Release.html b/Results - Release.html new file mode 100644 index 00000000..2e1fceea --- /dev/null +++ b/Results - Release.html @@ -0,0 +1,433 @@ + + + + + Sol - Functions (Release) - nonius report + + + + + + + + + +
+ + + diff --git a/bench.cpp b/bench.cpp index 69120430..ed433788 100644 --- a/bench.cpp +++ b/bench.cpp @@ -1,6 +1,60 @@ #define NONIUS_RUNNER #include "nonius/nonius.h++" +#include "sol.hpp" -NONIUS_BENCHMARK( "Function Calls", []() { +struct sol_function_result_bench { + void operator () ( nonius::chronometer meter ) const { + sol::state lua; + lua.script( R"( +function r () + return 1 + 1 +end +)" ); + sol::function r = lua[ "r" ]; + meter.measure( [ & ] ( int run_index ) { + // Measure cost of lua calling and returning a function + return r( ); + } ); + } +}; -} ); \ No newline at end of file +struct sol_direct_bench { + void operator () ( nonius::chronometer meter ) const { + sol::state lua; + lua.script( R"( +function r () + return 1 + 1 +end +)" ); + auto fun = [ & ] ( int run_index ) { + // Measure cost of lua calling and returning a function + sol::function r = lua[ "r" ]; + return r.call( ); + }; + meter.measure( fun ); + } +}; + +struct c_direct_bench { + void operator () ( nonius::chronometer meter ) const { + sol::state lua; + lua.script( R"( +function r () + return 1 + 1 +end +)" ); + + lua_State* L = lua.lua_state( ); + meter.measure( [ & ] ( int run_index ) { + lua_getglobal( L, "r" ); + lua_call( L, 0, 1 ); + int lua_out = (int)lua_tonumber( L, -1 ); + lua_pop( L, 1 ); + return lua_out; + } ); + } +}; + +NONIUS_BENCHMARK( "sol - function_result", sol_function_result_bench() ); +NONIUS_BENCHMARK( "sol - int", sol_direct_bench() ); +NONIUS_BENCHMARK( "C - int", c_direct_bench( ) ); diff --git a/sol/function.hpp b/sol/function.hpp index db6bfc7a..beca7969 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -128,40 +128,40 @@ private: int stack; handler(const reference& target) : target(target), stack(0) { if (target.valid()) { - stack = lua_gettop(target.state()) + 1; + stack = lua_gettop(target.lua_state()) + 1; target.push(); } } ~handler() { if (stack > 0) { - lua_remove(target.state(), stack); + lua_remove(target.lua_state(), stack); } } }; int luacodecall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const { - return lua_pcallk(state(), static_cast(argcount), static_cast(resultcount), h.stack, 0, nullptr); + return lua_pcallk(lua_state(), static_cast(argcount), static_cast(resultcount), h.stack, 0, nullptr); } void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const { - lua_callk(state(), static_cast(argcount), static_cast(resultcount), 0, nullptr); + lua_callk(lua_state(), static_cast(argcount), static_cast(resultcount), 0, nullptr); } template std::tuple invoke(indices, types, std::ptrdiff_t n, handler& h) const { luacall(n, sizeof...(Ret), h); const int nreturns = static_cast(sizeof...(Ret)); - const int stacksize = lua_gettop(state()); + const int stacksize = lua_gettop(lua_state()); const int firstreturn = std::max(0, stacksize - nreturns) + 1; - auto r = std::make_tuple(stack::get(state(), firstreturn + I)...); - lua_pop(state(), nreturns); + auto r = std::make_tuple(stack::get(lua_state(), firstreturn + I)...); + lua_pop(lua_state(), nreturns); return r; } template Ret invoke(indices, types, std::ptrdiff_t n, handler& h) const { luacall(n, 1, h); - return stack::pop(state()); + return stack::pop(lua_state()); } template @@ -171,7 +171,7 @@ private: function_result invoke(indices<>, types<>, std::ptrdiff_t n, handler& h) const { const bool handlerpushed = error_handler.valid(); - const int stacksize = lua_gettop(state()); + const int stacksize = lua_gettop(lua_state()); const int firstreturn = std::max(0, stacksize - static_cast(n) - 1); int code = LUA_OK; try { @@ -181,27 +181,27 @@ private: catch (const std::exception& error) { code = LUA_ERRRUN; h.stack = 0; - stack::push(state(), error.what()); + stack::push(lua_state(), error.what()); } // TODO: handle idiots? /*catch (const char* error) { code = LUA_ERRRUN; - stack::push(state(), error); + stack::push(lua_state(), error); } catch (const std::string& error) { code = LUA_ERRRUN; - stack::push(state(), error); + stack::push(lua_state(), error); } catch (...) { code = LUA_ERRRUN; - stack::push( state(), "[sol] an unknownable runtime exception occurred" ); + stack::push( lua_state(), "[sol] an unknownable runtime exception occurred" ); }*/ catch (...) { throw; } - const int poststacksize = lua_gettop(state()); + const int poststacksize = lua_gettop(lua_state()); const int returncount = poststacksize - firstreturn; - return function_result(state(), firstreturn + ( handlerpushed ? 0 : 1 ), returncount, static_cast(code)); + return function_result(lua_state(), firstreturn + ( handlerpushed ? 0 : 1 ), returncount, static_cast(code)); } public: @@ -232,7 +232,7 @@ public: -> decltype(invoke(types(), types(), 0, std::declval())) { handler h(error_handler); push(); - int pushcount = stack::push_args(state(), std::forward(args)...); + int pushcount = stack::push_args(lua_state(), std::forward(args)...); auto tr = types(); return invoke(tr, tr, pushcount, h); } diff --git a/sol/object.hpp b/sol/object.hpp index 02759208..142060aa 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -33,14 +33,14 @@ public: object() = default; template - auto as() const -> decltype(stack::get(state())) const { + auto as() const -> decltype(stack::get(lua_state())) const { push(); - type actual = stack::get(state()); + type actual = stack::get(lua_state()); // This code is actually present // in almost all of the type-getters, // and it thus insanely redundant - // type_assert(state(), -1, type_of(), actual); - return stack::pop(state()); + // type_assert(lua_state(), -1, type_of(), actual); + return stack::pop(lua_state()); } template diff --git a/sol/reference.hpp b/sol/reference.hpp index 4d44636a..69e41720 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -97,7 +97,7 @@ public: return static_cast(result); } - lua_State* state() const noexcept { + lua_State* lua_state() const noexcept { return L; } }; diff --git a/sol/state.hpp b/sol/state.hpp index 6b83d60a..b4700ef6 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -30,7 +30,7 @@ namespace sol { namespace detail { inline int atpanic(lua_State* L) { const char* message = lua_tostring(L, -1); - std::string err = message ? message : "An unexpected error occured and forced the lua state to call atpanic"; + std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic"; throw error(err); } } // detail @@ -53,18 +53,12 @@ class state { private: std::unique_ptr L; table reg; - table global; + global_table globals; public: state(lua_CFunction panic = detail::atpanic): L(luaL_newstate(), lua_close), reg(L.get(), LUA_REGISTRYINDEX), -#if SOL_LUA_VERSION < 502 - // Global table is just a special index - global(L.get(), LUA_GLOBALSINDEX) { -#else - // Global tables are stored in the environment/registry table - global(reg.get(LUA_RIDX_GLOBALS)) { -#endif // Lua 5.2 + globals(detail::global_overload, reg) { set_panic(panic); } @@ -152,13 +146,13 @@ public: template auto get(Keys&&... keys) const - -> decltype(global.get(std::forward(keys)...)) { - return global.get(std::forward(keys)...); + -> decltype(globals.get(std::forward(keys)...)) { + return globals.get(std::forward(keys)...); } template state& set(T&& key, U&& value) { - global.set(std::forward(key), std::forward(value)); + globals.set(std::forward(key), std::forward(value)); return *this; } @@ -189,7 +183,7 @@ public: template state& set_usertype(Key&& key, usertype& user) { - global.set_usertype(std::forward(key), user); + globals.set_usertype(std::forward(key), user); return *this; } @@ -208,7 +202,7 @@ public: template void for_each(Fx&& fx) { - global.for_each(std::forward(fx)); + globals.for_each(std::forward(fx)); } template @@ -216,7 +210,7 @@ public: lua_createtable(L.get(), narr, nrec); table result(L.get()); lua_pop(L.get(), 1); - global.set(std::forward(key), result); + globals.set(std::forward(key), result); return result; } @@ -227,8 +221,8 @@ public: return result; } - table global_table() const { - return global; + global_table global() const { + return globals; } table registry() const { @@ -240,42 +234,42 @@ public: } template - proxy operator[](T&& key) { - return global[std::forward(key)]; + proxy operator[](T&& key) { + return globals[std::forward(key)]; } template - proxy operator[](T&& key) const { - return global[std::forward(key)]; + proxy operator[](T&& key) const { + return globals[std::forward(key)]; } template state& set_function(Key&& key, R fun_ptr(Args...)){ - global.set_function(std::forward(key), fun_ptr); + globals.set_function(std::forward(key), fun_ptr); return *this; } template state& set_function(Key&& key, Sig* fun_ptr){ - global.set_function(std::forward(key), fun_ptr); + globals.set_function(std::forward(key), fun_ptr); return *this; } template state& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) { - global.set_function(std::forward(key), mem_ptr, std::forward(obj)); + globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); return *this; } template state& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) { - global.set_function(std::forward(key), mem_ptr, std::forward(obj)); + globals.set_function(std::forward(key), mem_ptr, std::forward(obj)); return *this; } template state& set_function(Key&& key, Fx&& fx) { - global.set_function(std::forward(key), std::forward(fx)); + globals.set_function(std::forward(key), std::forward(fx)); return *this; } }; diff --git a/sol/table.hpp b/sol/table.hpp index 174bee83..6bf20226 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -22,167 +22,10 @@ #ifndef SOL_TABLE_HPP #define SOL_TABLE_HPP -#include "proxy.hpp" -#include "stack.hpp" -#include "function_types.hpp" -#include "usertype.hpp" +#include "table_core.hpp" namespace sol { -class table : public reference { - friend class state; - template - stack::get_return single_get(Key&& key) const { - push(); - stack::push(state(), std::forward(key)); - lua_gettable(state(), -2); - stack::get_return result = stack::pop(state()); - pop(); - return result; - } - - template - stack::get_return tuple_get(types, indices, Keys&& keys) const { - return stack::get_return(single_get(std::get(keys))...); - } - - template - stack::get_return tuple_get(types, indices, Keys&& keys) const { - return single_get(std::get(keys)); - } - -public: - table() noexcept : reference() {} - table(lua_State* L, int index = -1) : reference(L, index) { - type_assert(L, index, type::table); - } - - template - stack::get_return get( Keys&&... keys ) const { - return tuple_get(types(), build_indices(), std::tie(keys...)); - } - - template - table& set(T&& key, U&& value) { - push(); - stack::push(state(), std::forward(key)); - stack::push(state(), std::forward(value)); - lua_settable(state(), -3); - lua_pop(state(), 1); - return *this; - } - - template - SOL_DEPRECATED table& set_userdata(usertype& user) { - return set_usertype(user); - } - - template - SOL_DEPRECATED table& set_userdata(Key&& key, usertype& user) { - return set_usertype(std::forward(key), user); - } - - template - table& set_usertype(usertype& user) { - return set_usertype(usertype_traits::name, user); - } - - template - table& set_usertype(Key&& key, usertype& user) { - push(); - stack::push(state(), std::forward(key)); - stack::push(state(), user); - lua_settable(state(), -3); - lua_pop(state(), 1); - return *this; - } - - template - void for_each(Fx&& fx) const { - push(); - stack::push(state(), nil); - while (lua_next(this->state(), -2)) { - sol::object key(state(), -2); - sol::object value(state(), -1); - fx(key, value); - lua_pop(state(), 1); - } - pop(); - } - - size_t size() const { - push(); - size_t result = lua_rawlen(state(), -1); - pop(); - return result; - } - - template - proxy operator[]( T&& key ) { - return proxy( *this, std::forward( key ) ); - } - - template - proxy operator[]( T&& key ) const { - return proxy( *this, std::forward( key ) ); - } - - void pop(int n = 1) const noexcept { - lua_pop(state(), n); - } - - template - table& set_function(Key&& key, R fun_ptr(Args...)){ - set_resolved_function(std::forward(key), fun_ptr); - return *this; - } - - template - table& set_function(Key&& key, Sig* fun_ptr){ - set_resolved_function(std::forward(key), fun_ptr); - return *this; - } - - template - table& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) { - set_resolved_function(std::forward(key), mem_ptr, std::forward(obj)); - return *this; - } - - template - table& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) { - set_resolved_function(std::forward(key), mem_ptr, std::forward(obj)); - return *this; - } - - template - table& set_function(Key&& key, Fx&& fx) { - set_fx(types(), std::forward(key), std::forward(fx)); - return *this; - } - -private: - template::type> - void set_fx(types, Key&& key, Fx&& fx) { - set_resolved_function(std::forward(key), std::forward(fx)); - } - - template - void set_fx(types<>, Key&& key, Fx&& fx) { - typedef Unqualified> fx_t; - typedef decltype(&fx_t::operator()) Sig; - set_fx(types>(), std::forward(key), std::forward(fx)); - } - - template - void set_resolved_function(Key&& key, Args&&... args) { - std::string fkey(std::forward(key)); - push(); - int tabletarget = lua_gettop(state()); - stack::push>(state(), std::forward(args)...); - lua_setfield(state(), tabletarget, fkey.c_str()); - pop(); - } -}; + typedef table_core table; } // sol #endif // SOL_TABLE_HPP diff --git a/sol/table_core.hpp b/sol/table_core.hpp new file mode 100644 index 00000000..0ecd1e85 --- /dev/null +++ b/sol/table_core.hpp @@ -0,0 +1,224 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2015 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_TABLE_CORE_HPP +#define SOL_TABLE_CORE_HPP + +#include "proxy.hpp" +#include "stack.hpp" +#include "function_types.hpp" +#include "usertype.hpp" + +namespace sol { +namespace detail { + struct global_overload_tag { } const global_overload; +} // detail + +template +class table_core : public reference { + friend class state; + template>>, Bool> = 0> + stack::get_return single_get( Key&& key ) const { + lua_getglobal( lua_state( ), &key[ 0 ] ); + stack::get_return result = stack::pop( lua_state( ) ); + return result; + } + + template>>, Bool> = 0> + stack::get_return single_get( Key&& key ) const { + push( ); + stack::push( lua_state( ), std::forward( key ) ); + lua_gettable( lua_state( ), -2 ); + stack::get_return result = stack::pop( lua_state( ) ); + pop( ); + return result; + } + + template + stack::get_return tuple_get( types, indices, Keys&& keys ) const { + return stack::get_return( single_get( std::get( keys ) )... ); + } + + template + stack::get_return tuple_get( types, indices, Keys&& keys ) const { + return single_get( std::get( keys ) ); + } + +#if SOL_LUA_VERSION < 502 + table_core( detail::global_overload_tag, const table_core& reg ) noexcept : reference( reg.lua_state(), LUA_GLOBALSINDEX ) { } +#else + table_core( detail::global_overload_tag, const table& reg ) noexcept : reference( reg.get
( LUA_RIDX_GLOBALS ) ) { } +#endif +public: + table_core( ) noexcept : reference( ) { } + table_core( const table_core& global ) : reference( global ) { } + table_core( lua_State* L, int index = -1 ) : reference( L, index ) { + type_assert( L, index, type::table ); + } + + template + stack::get_return get( Keys&&... keys ) const { + return tuple_get( types( ), build_indices( ), std::tie( keys... ) ); + } + + template + table_core& set( T&& key, U&& value ) { + if ( top_level ) { + stack::push( lua_state( ), std::forward( value ) ); + lua_setglobal( lua_state( ), &key[0] ); + } + else { + push( ); + stack::push( lua_state( ), std::forward( key ) ); + stack::push( lua_state( ), std::forward( value ) ); + lua_settable( lua_state( ), -3 ); + pop( ); + } + return *this; + } + + template + SOL_DEPRECATED table_core& set_userdata( usertype& user ) { + return set_usertype( user ); + } + + template + SOL_DEPRECATED table_core& set_userdata( Key&& key, usertype& user ) { + return set_usertype( std::forward( key ), user ); + } + + template + table_core& set_usertype( usertype& user ) { + return set_usertype( usertype_traits::name, user ); + } + + template + table_core& set_usertype( Key&& key, usertype& user ) { + if ( top_level ) { + stack::push( lua_state( ), user ); + lua_setglobal( lua_state( ), &key[ 0 ] ); + pop( ); + } + else { + push( ); + 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( ); + stack::push( lua_state( ), nil ); + while ( lua_next( this->lua_state( ), -2 ) ) { + sol::object key( lua_state( ), -2 ); + sol::object value( lua_state( ), -1 ); + 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; + } + + template + proxy operator[]( T&& key ) { + return proxy( *this, std::forward( key ) ); + } + + template + proxy operator[]( T&& key ) const { + return proxy( *this, std::forward( key ) ); + } + + void pop( int n = 1 ) const noexcept { + lua_pop( lua_state( ), n ); + } + + template + table_core& set_function( Key&& key, R fun_ptr( Args... ) ) { + set_resolved_function( std::forward( key ), fun_ptr ); + return *this; + } + + template + table_core& set_function( Key&& key, Sig* fun_ptr ) { + set_resolved_function( std::forward( key ), fun_ptr ); + return *this; + } + + template + table_core& set_function( Key&& key, R( C::*mem_ptr )( Args... ), T&& obj ) { + set_resolved_function( std::forward( key ), mem_ptr, std::forward( obj ) ); + return *this; + } + + template + table_core& set_function( Key&& key, Sig C::* mem_ptr, T&& obj ) { + set_resolved_function( std::forward( key ), mem_ptr, std::forward( obj ) ); + return *this; + } + + template + table_core& set_function( Key&& key, Fx&& fx ) { + set_fx( types( ), std::forward( key ), std::forward( fx ) ); + return *this; + } + +private: + template::type> + void set_fx( types, Key&& key, Fx&& fx ) { + set_resolved_function( std::forward( key ), std::forward( fx ) ); + } + + template + void set_fx( types<>, Key&& key, Fx&& fx ) { + typedef Unqualified> fx_t; + typedef decltype( &fx_t::operator() ) Sig; + set_fx( types>( ), std::forward( key ), std::forward( fx ) ); + } + + template>>, Bool> = 0> + void set_resolved_function( Key&& key, Args&&... args ) { + stack::push>( lua_state( ), std::forward( args )... ); + lua_setglobal( lua_state( ), &key[ 0 ] ); + } + + template>>, Bool> = 0> + void set_resolved_function( Key&& key, Args&&... args ) { + push( ); + int tabletarget = lua_gettop( lua_state( ) ); + stack::push>( lua_state( ), std::forward( args )... ); + lua_setfield( lua_state( ), tabletarget, &key[ 0 ] ); + pop( ); + } +}; +} // sol + +#endif // SOL_TABLE_CORE_HPP diff --git a/sol/types.hpp b/sol/types.hpp index 574e134e..8bcf8372 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -121,7 +121,10 @@ inline std::string type_name(lua_State*L, type t) { template class usertype; -class table; +template +class table_core; +typedef table_core table; +typedef table_core global_table; class function; class object; diff --git a/tests.cpp b/tests.cpp index cf791df8..fe2cd03a 100644 --- a/tests.cpp +++ b/tests.cpp @@ -597,7 +597,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works std::cout << a << ',' << b << '\n'; }; - REQUIRE_NOTHROW(assert1(lua.global_table())); + REQUIRE_NOTHROW(assert1(lua.global())); } TEST_CASE("tables/usertype", "Show that we can create classes from usertype and use them") {