Heavy optimizations to stateless and lvalue member functions allow us to make many of the general use cases of lambdas and member function pointers work out.

This will be useful. The next fix has tobe in table.hpp in the std::false_type ... specialization of the private `set_fx` function.
This commit is contained in:
ThePhD 2013-12-08 23:05:03 -05:00
parent 6d6dd3db5c
commit 49c73c4725
4 changed files with 242 additions and 53 deletions

View File

@ -38,6 +38,7 @@ struct function_traits<R(T::*)(Args...)> {
typedef types<Args...> args_type; typedef types<Args...> args_type;
typedef R(T::* function_pointer_type)(Args...); typedef R(T::* function_pointer_type)(Args...);
typedef typename std::remove_pointer<function_pointer_type>::type function_type; typedef typename std::remove_pointer<function_pointer_type>::type function_type;
typedef R(* free_function_pointer_type)(Args...);
typedef R return_type; typedef R return_type;
template<std::size_t i> template<std::size_t i>
using arg = typename std::tuple_element<i, arg_tuple_type>::type; using arg = typename std::tuple_element<i, arg_tuple_type>::type;
@ -49,8 +50,9 @@ struct function_traits<R(T::*)(Args...) const> {
static const bool is_member_function = true; static const bool is_member_function = true;
typedef std::tuple<Args...> arg_tuple_type; typedef std::tuple<Args...> arg_tuple_type;
typedef types<Args...> args_type; typedef types<Args...> args_type;
typedef R(T::* function_type)(Args...);
typedef R(T::* function_pointer_type)(Args...); typedef R(T::* function_pointer_type)(Args...);
typedef typename std::remove_pointer<function_pointer_type>::type function_type;
typedef R(* free_function_pointer_type)(Args...);
typedef R return_type; typedef R return_type;
template<std::size_t i> template<std::size_t i>
using arg = typename std::tuple_element<i, arg_tuple_type>::type; using arg = typename std::tuple_element<i, arg_tuple_type>::type;
@ -64,6 +66,7 @@ struct function_traits<R(Args...)> {
typedef types<Args...> args_type; typedef types<Args...> args_type;
typedef R(function_type)(Args...); typedef R(function_type)(Args...);
typedef R(*function_pointer_type)(Args...); typedef R(*function_pointer_type)(Args...);
typedef R(* free_function_pointer_type)(Args...);
typedef R return_type; typedef R return_type;
template<std::size_t i> template<std::size_t i>
using arg = typename std::tuple_element<i, arg_tuple_type>::type; using arg = typename std::tuple_element<i, arg_tuple_type>::type;
@ -77,6 +80,7 @@ struct function_traits<R(*)(Args...)> {
typedef types<Args...> args_type; typedef types<Args...> args_type;
typedef R(function_type)(Args...); typedef R(function_type)(Args...);
typedef R(*function_pointer_type)(Args...); typedef R(*function_pointer_type)(Args...);
typedef R(* free_function_pointer_type)(Args...);
typedef R return_type; typedef R return_type;
template<std::size_t i> template<std::size_t i>
using arg = typename std::tuple_element<i, arg_tuple_type>::type; using arg = typename std::tuple_element<i, arg_tuple_type>::type;

View File

@ -26,10 +26,101 @@
#include "stack.hpp" #include "stack.hpp"
namespace sol { namespace sol {
namespace detail {
template<typename TFx>
struct static_lua_func {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t;
typedef detail::function_traits<fx_t> fx_traits;
template<typename... Args>
static int typed_call( types<void>, types<Args...> t, fx_t* fx, lua_State* L ) {
stack::pop_call( L, fx, t );
return 0;
}
template<typename... TRn, typename... Args>
static int typed_call( types<TRn...>, types<Args...> t, fx_t* fx, lua_State* L ) {
auto r = stack::pop_call( L, fx, t );
stack::push( L, std::move( r ) );
return sizeof...( TRn );
}
static int call( lua_State* L ) {
void* functiondata = lua_touserdata( L, lua_upvalueindex( 1 ) );
//if ( functiondata == nullptr )
// throw sol_error( "call from lua to c++ function has null function pointer data" );
fx_t* fx = *static_cast<fx_t*>( functiondata );
int r = typed_call( tuple_types<typename fx_traits::return_type>( ), typename fx_traits::args_type( ), fx, L );
return r;
}
int operator()( lua_State* L ) {
return call( L );
}
};
template<typename T, typename TFx>
struct static_object_lua_func {
typedef typename std::decay<TFx>::type fx_t;
typedef detail::function_traits<fx_t> fx_traits;
template<typename... Args>
static int typed_call( types<void>, types<Args...>, T& item, fx_t& ifx, lua_State* L ) {
auto fx = [ &item, &ifx ] ( Args&&... args ) { ( item.*ifx )( std::forward<Args>( args )... ); };
stack::pop_call( L, fx, types<Args...>( ) );
return 0;
}
template<typename TR, typename... Args>
static int typed_call( types<TR>, types<Args...>, T& item, fx_t& ifx, lua_State* L ) {
auto fx = [ &item, &ifx ] ( Args&&... args ) -> TR { return ( item.*ifx )( std::forward<Args>( args )... ); };
auto r = stack::pop_call( L, fx, types<Args...>( ) );
stack::push( L, std::move( r ) );
return 1;
}
template<typename... TRn, typename... Args>
static int typed_call( types<TRn...>, types<Args...>, T& item, fx_t& ifx, lua_State* L ) {
auto fx = [ &item, &ifx ] ( Args&&... args ) -> std::tuple<TRn...> { return ( item.*ifx )( std::forward<Args>( args )... ); };
auto r = stack::pop_call( L, fx, types<Args...>( ) );
stack::push( L, std::move( r ) );
return sizeof...( TRn );
}
static int call( lua_State* L ) {
const static std::size_t data_t_count = ( sizeof(fx_t)+( sizeof(void*)-1 ) ) / sizeof( void* );
typedef std::array<void*, data_t_count> data_t;
data_t fxptrdata;
int upvalue = 1;
for ( std::size_t i = 0; i < fxptrdata.size( ); ++i ) {
fxptrdata[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) );
}
void* objectdata = lua_touserdata( L, lua_upvalueindex( upvalue++ ) );
//if ( objectdata == nullptr )
// throw sol_error( "call from lua to c++ function has null object data" );
fx_t* fxptr = reinterpret_cast<fx_t*>( static_cast<void*>( fxptrdata.data( ) ) );
fx_t& mem_ptr = *fxptr;
T& obj = *static_cast<T*>( objectdata );
int r = typed_call( tuple_types<typename fx_traits::return_type>( ), typename fx_traits::args_type( ), obj, mem_ptr, L );
return r;
}
int operator()( lua_State* L ) {
return call( L );
}
};
struct lua_func { struct lua_func {
virtual int operator()(lua_State*) { static int call( lua_State* L ) {
void* inheritancedata = lua_touserdata( L, lua_upvalueindex( 1 ) );
if ( inheritancedata == nullptr )
throw sol_error( "call from lua to c++ function has null data" );
lua_func& fx = *static_cast<lua_func*>( inheritancedata );
int r = fx( L );
return r;
}
virtual int operator()(lua_State*) {
throw sol_error("Failure to call specialized wrapped C++ function from lua"); throw sol_error("Failure to call specialized wrapped C++ function from lua");
} }
@ -39,7 +130,7 @@ struct lua_func {
template<typename TFx> template<typename TFx>
struct lambda_lua_func : public lua_func { struct lambda_lua_func : public lua_func {
typedef decltype(&TFx::operator()) fx_t; typedef decltype(&TFx::operator()) fx_t;
typedef function_traits<fx_t> fx_traits; typedef detail::function_traits<fx_t> fx_traits;
TFx fx; TFx fx;
template<typename... FxArgs> template<typename... FxArgs>
@ -66,7 +157,7 @@ struct lambda_lua_func : public lua_func {
template<typename TFx, typename T = TFx, bool is_member_pointer = std::is_member_function_pointer<TFx>::value> template<typename TFx, typename T = TFx, bool is_member_pointer = std::is_member_function_pointer<TFx>::value>
struct explicit_lua_func : public lua_func { struct explicit_lua_func : public lua_func {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t; typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t;
typedef function_traits<fx_t> fx_traits; typedef detail::function_traits<fx_t> fx_traits;
TFx fx; TFx fx;
template<typename... FxArgs> template<typename... FxArgs>
@ -93,7 +184,7 @@ struct explicit_lua_func : public lua_func {
template<typename TFx, typename T> template<typename TFx, typename T>
struct explicit_lua_func<TFx, T, true> : public lua_func { struct explicit_lua_func<TFx, T, true> : public lua_func {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t; typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type fx_t;
typedef function_traits<fx_t> fx_traits; typedef detail::function_traits<fx_t> fx_traits;
struct lambda { struct lambda {
T* member; T* member;
TFx invocation; TFx invocation;
@ -131,14 +222,6 @@ struct explicit_lua_func<TFx, T, true> : public lua_func {
} }
}; };
int lua_cfun(lua_State* L) {
void* bridgedata = lua_touserdata(L, lua_upvalueindex(1));
auto* fx = static_cast<lua_func*>(bridgedata);
int r = fx->operator()(L);
return r;
}
} // detail
} // sol } // sol
#endif // SOL_LUA_FUNC_HPP #endif // SOL_LUA_FUNC_HPP

View File

@ -26,6 +26,7 @@
#include "tuple.hpp" #include "tuple.hpp"
#include <utility> #include <utility>
#include <type_traits> #include <type_traits>
#include <array>
namespace sol { namespace sol {
template<typename T, typename R = void> template<typename T, typename R = void>
@ -156,10 +157,21 @@ inline void push(lua_State* L, const char (&str)[N]) {
lua_pushlstring(L, str, N - 1); lua_pushlstring(L, str, N - 1);
} }
inline void push(lua_State* L, const char* str) {
lua_pushlstring(L, str, std::char_traits<char>::length( str ));
}
inline void push(lua_State* L, const std::string& str) { inline void push(lua_State* L, const std::string& str) {
lua_pushlstring(L, str.c_str(), str.size()); lua_pushlstring(L, str.c_str(), str.size());
} }
template<typename T, size_t N>
inline void push( lua_State* L, const std::array<T, N>& data ) {
for ( std::size_t i = 0; i < data.size( ); ++i ) {
push( L, data[ i ] );
}
}
namespace detail { namespace detail {
template<typename T, std::size_t... I> template<typename T, std::size_t... I>
inline void push(lua_State* L, indices<I...>, const T& tuplen) { inline void push(lua_State* L, indices<I...>, const T& tuplen) {

View File

@ -25,12 +25,25 @@
#include "stack.hpp" #include "stack.hpp"
#include "lua_function.hpp" #include "lua_function.hpp"
#include <unordered_map> #include <unordered_map>
#include <array>
#include <memory> #include <memory>
namespace sol { namespace sol {
namespace detail {
template <typename T>
T* get_ptr( T& val ) {
return std::addressof( val );
}
template <typename T>
T* get_ptr( T* val ) {
return val;
}
}
class table : virtual public reference { class table : virtual public reference {
private: private:
std::unordered_map<std::string, std::shared_ptr<detail::lua_func>> funcs; std::unordered_map<std::string, std::shared_ptr<lua_func>> funcs;
public: public:
table() noexcept: reference(), funcs() {} table() noexcept: reference(), funcs() {}
table(lua_State* L, int index = -1): reference(L, index), funcs() { table(lua_State* L, int index = -1): reference(L, index), funcs() {
@ -61,15 +74,13 @@ public:
template<typename T, typename TFx> template<typename T, typename TFx>
table& set_function(T&& key, TFx&& fx) { table& set_function(T&& key, TFx&& fx) {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx; typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx;
const static bool isfunction = std::is_function<clean_fx>::value; return set_isfunction_fx( std::is_function<clean_fx>( ), std::forward<T>( key ), std::forward<TFx>( fx ) );
return set_fx(std::integral_constant<bool, !isfunction>(), std::forward<T>(key), std::forward<TFx>(fx));
} }
template<typename T, typename TFx, typename TM> template<typename T, typename TFx, typename TObj>
table& set_function(T&& key, TFx&& fx, TM& mem) { table& set_function(T&& key, TFx&& fx, TObj&& obj) {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx; return set_lvalue_fx( std::integral_constant<bool, std::is_lvalue_reference<TObj>::value || std::is_pointer<TObj>::value>( ),
std::unique_ptr<detail::lua_func> sptr(new detail::explicit_lua_func<clean_fx, TM>(mem, std::forward<TFx>(fx))); std::forward<T>( key ), std::forward<TFx>( fx ), std::forward<TObj>( obj ) );
return set_fx(std::forward<T>(key), std::move(sptr));
} }
size_t size() const { size_t size() const {
@ -77,54 +88,133 @@ public:
return lua_rawlen(state(), -1); return lua_rawlen(state(), -1);
} }
private: private:
template<typename T, typename TFx>
table& set_isfunction_fx( std::true_type, T&& key, TFx&& fx ) {
return set_fx( std::false_type( ), std::forward<T>( key ), std::forward<TFx>( fx ) );
}
template<typename T, typename TFx> template<typename T, typename TFx>
table& set_fx(std::true_type, T&& key, TFx&& fx) { table& set_isfunction_fx(std::false_type, T&& key, TFx&& fx) {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx; typedef typename std::decay<TFx>::type clean_lambda;
std::unique_ptr<detail::lua_func> sptr(new detail::lambda_lua_func<clean_fx>(std::forward<TFx>(fx))); typedef typename detail::function_traits<decltype( &clean_lambda::operator() )>::free_function_pointer_type raw_func_t;
return set_fx(std::forward<T>(key), std::move(sptr)); typedef std::is_convertible<clean_lambda, raw_func_t> isconvertible;
return set_isconvertible_fx( isconvertible( ), std::forward<T>( key ), std::forward<TFx>( fx ) );
}
template<typename T, typename TFx>
table& set_isconvertible_fx( std::true_type, T&& key, TFx&& fx ) {
typedef typename std::decay<TFx>::type clean_lambda;
typedef typename detail::function_traits<decltype( &clean_lambda::operator() )>::free_function_pointer_type raw_func_t;
return set_isfunction_fx( std::true_type( ), std::forward<T>( key ), raw_func_t( std::forward<TFx>( fx ) ) );
}
template<typename T, typename TFx>
table& set_isconvertible_fx( std::false_type, T&& key, TFx&& fx ) {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx;
std::unique_ptr<lua_func> sptr( new lambda_lua_func<clean_fx>( std::forward<TFx>( fx ) ) );
return set_fx( std::forward<T>( key ), std::move( sptr ) );
}
template<typename T, typename TFx, typename TObj>
table& set_lvalue_fx( std::true_type, T&& key, TFx&& fx, TObj&& obj ) {
return set_fx( std::true_type(), std::forward<T>( key ), std::forward<TFx>( fx ), std::forward<TObj>( obj ) );
}
template<typename T, typename TFx, typename TM>
table& set_lvalue_fx( std::false_type, T&& key, TFx&& fx, TM& mem ) {
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx;
std::unique_ptr<lua_func> sptr( new explicit_lua_func<clean_fx, TM>( mem, std::forward<TFx>( fx ) ) );
return set_fx( std::forward<T>( key ), std::move( sptr ) );
}
template<typename T, typename TFx, typename TObj>
table& set_fx( std::true_type, T&& key, TFx&& fx, TObj&& obj ) {
typedef typename std::decay<TObj>::type decay_of_to;
typedef typename std::decay<TFx>::type decay_of_tfx;
const static std::size_t data_t_count = ( sizeof(decay_of_tfx)+( sizeof(void*)-1 ) ) / sizeof( void* );
typedef std::array<void*, data_t_count> data_t;
std::string fkey( key );
// Layout:
// idx 1...n: verbatim data of member function pointer
// idx n + 1: is the object's void pointer
// We don't need to store the size, because the other side is templated
// with the same member function pointer type
decay_of_tfx fxptr( std::forward<TFx>( fx ) );
data_t fxptrdata;
std::size_t fxptrsize = sizeof( fxptr );
std::memcpy( std::addressof( fxptrdata[ 0 ] ), std::addressof( fxptr ), fxptrsize );
void* userobjdata = static_cast<void*>( detail::get_ptr( obj ) );
lua_CFunction freefunc = &static_object_lua_func<decay_of_to, TFx>::call;
const char* freefuncname = fkey.c_str( );
const luaL_Reg funcreg[ 2 ] = {
{ freefuncname, freefunc },
{ }
};
push( );
stack::push( state( ), fxptrdata );
stack::push( state( ), userobjdata );
luaL_setfuncs( state( ), funcreg, fxptrdata.size() + 1 );
lua_pop( state( ), 1 );
return *this;
} }
template<typename T, typename TFx> template<typename T, typename TFx>
table& set_fx(std::false_type, T&& key, TFx&& fx) { table& set_fx(std::false_type, T&& key, TFx&& fx) {
typedef typename std::decay<TFx>::type ptr_fx; typedef typename std::decay<TFx>::type ptr_fx;
std::unique_ptr<detail::lua_func> sptr(new detail::explicit_lua_func<ptr_fx>(std::forward<TFx>(fx))); std::string fkey( key );
return set_fx(std::forward<T>(key), std::move(sptr)); ptr_fx target( std::forward<TFx>( fx ) );
}
template<typename T>
table& set_fx(T&& key, std::unique_ptr<detail::lua_func> luafunc) {
std::string fkey(key);
auto hint = funcs.find(fkey);
if (hint == funcs.end()) {
std::shared_ptr<detail::lua_func> sptr(luafunc.release());
hint = funcs.emplace_hint(hint, fkey, std::move(sptr));
}
else {
hint->second.reset(luafunc.release());
}
detail::lua_func* target = hint->second.get();
void* userdata = static_cast<void*>( target ); void* userdata = static_cast<void*>( target );
lua_CFunction freefunc = &detail::lua_cfun; lua_CFunction freefunc = &static_lua_func<TFx>::call;
const char* freefuncname = hint->first.c_str( ); const char* freefuncname = fkey.c_str( );
const luaL_Reg funcreg[ 2 ] = { const luaL_Reg funcreg[ 2 ] = {
{ freefuncname, freefunc }, { freefuncname, freefunc },
{ } { }
}; };
push( ); push( );
/*//lua_pushlightuserdata( state(), userdata ); stack::push( state( ), target );
lua_pushstring( state(), freefuncname ); // push key onto stack
lua_pushcclosure( state(), freefunc, 1 ); // push value onto stack
lua_settable( state(), -3 );
*/
lua_pushlightuserdata( state( ), userdata );
luaL_setfuncs( state( ), funcreg, 1 ); luaL_setfuncs( state( ), funcreg, 1 );
lua_pop( state( ), 1 ); lua_pop( state( ), 1 );
return *this; return *this;
} }
template<typename T>
table& set_fx( T&& key, std::unique_ptr<lua_func> luafunc ) {
std::string fkey( key );
auto hint = funcs.find( fkey );
if ( hint == funcs.end( ) ) {
std::shared_ptr<lua_func> sptr( luafunc.release( ) );
hint = funcs.emplace_hint( hint, fkey, std::move( sptr ) );
}
else {
hint->second.reset( luafunc.release( ) );
}
lua_func* target = hint->second.get( );
void* userdata = static_cast<void*>( target );
lua_CFunction freefunc = &lua_func::call;
const char* freefuncname = hint->first.c_str( );
const luaL_Reg funcreg[ 2 ] = {
{ freefuncname, freefunc },
{ }
};
push( );
stack::push( state( ), userdata );
luaL_setfuncs( state( ), funcreg, 1 );
lua_pop( state( ), 1 );
return *this;
}
}; };
} // sol } // sol