mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
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:
parent
6d6dd3db5c
commit
49c73c4725
|
@ -38,6 +38,7 @@ struct function_traits<R(T::*)(Args...)> {
|
|||
typedef types<Args...> args_type;
|
||||
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;
|
||||
template<std::size_t i>
|
||||
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;
|
||||
typedef std::tuple<Args...> arg_tuple_type;
|
||||
typedef types<Args...> args_type;
|
||||
typedef R(T::* function_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;
|
||||
template<std::size_t i>
|
||||
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 R(function_type)(Args...);
|
||||
typedef R(*function_pointer_type)(Args...);
|
||||
typedef R(* free_function_pointer_type)(Args...);
|
||||
typedef R return_type;
|
||||
template<std::size_t i>
|
||||
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 R(function_type)(Args...);
|
||||
typedef R(*function_pointer_type)(Args...);
|
||||
typedef R(* free_function_pointer_type)(Args...);
|
||||
typedef R return_type;
|
||||
template<std::size_t i>
|
||||
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
||||
|
|
|
@ -26,9 +26,100 @@
|
|||
#include "stack.hpp"
|
||||
|
||||
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 {
|
||||
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");
|
||||
}
|
||||
|
@ -39,7 +130,7 @@ struct lua_func {
|
|||
template<typename TFx>
|
||||
struct lambda_lua_func : public lua_func {
|
||||
typedef decltype(&TFx::operator()) fx_t;
|
||||
typedef function_traits<fx_t> fx_traits;
|
||||
typedef detail::function_traits<fx_t> fx_traits;
|
||||
TFx fx;
|
||||
|
||||
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>
|
||||
struct explicit_lua_func : public lua_func {
|
||||
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;
|
||||
|
||||
template<typename... FxArgs>
|
||||
|
@ -93,7 +184,7 @@ struct explicit_lua_func : public lua_func {
|
|||
template<typename TFx, typename T>
|
||||
struct explicit_lua_func<TFx, T, true> : public lua_func {
|
||||
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 {
|
||||
T* member;
|
||||
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
|
||||
|
||||
#endif // SOL_LUA_FUNC_HPP
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "tuple.hpp"
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
|
||||
namespace sol {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
template<typename T, std::size_t... I>
|
||||
inline void push(lua_State* L, indices<I...>, const T& tuplen) {
|
||||
|
|
136
sol/table.hpp
136
sol/table.hpp
|
@ -25,12 +25,25 @@
|
|||
#include "stack.hpp"
|
||||
#include "lua_function.hpp"
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
|
||||
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 {
|
||||
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:
|
||||
table() noexcept: reference(), funcs() {}
|
||||
table(lua_State* L, int index = -1): reference(L, index), funcs() {
|
||||
|
@ -61,15 +74,13 @@ public:
|
|||
template<typename T, typename TFx>
|
||||
table& set_function(T&& key, TFx&& 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_fx(std::integral_constant<bool, !isfunction>(), std::forward<T>(key), std::forward<TFx>(fx));
|
||||
return set_isfunction_fx( std::is_function<clean_fx>( ), std::forward<T>( key ), std::forward<TFx>( fx ) );
|
||||
}
|
||||
|
||||
template<typename T, typename TFx, typename TM>
|
||||
table& set_function(T&& key, TFx&& fx, TM& mem) {
|
||||
typedef typename std::remove_pointer<typename std::decay<TFx>::type>::type clean_fx;
|
||||
std::unique_ptr<detail::lua_func> sptr(new detail::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_function(T&& key, TFx&& fx, TObj&& obj) {
|
||||
return set_lvalue_fx( std::integral_constant<bool, std::is_lvalue_reference<TObj>::value || std::is_pointer<TObj>::value>( ),
|
||||
std::forward<T>( key ), std::forward<TFx>( fx ), std::forward<TObj>( obj ) );
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
|
@ -77,34 +88,119 @@ public:
|
|||
return lua_rawlen(state(), -1);
|
||||
}
|
||||
private:
|
||||
|
||||
template<typename T, typename TFx>
|
||||
table& set_fx(std::true_type, T&& key, TFx&& fx) {
|
||||
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>
|
||||
table& set_isfunction_fx(std::false_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;
|
||||
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<detail::lua_func> sptr(new detail::lambda_lua_func<clean_fx>(std::forward<TFx>(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>
|
||||
table& set_fx(std::false_type, T&& key, TFx&& 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)));
|
||||
return set_fx(std::forward<T>(key), std::move(sptr));
|
||||
std::string fkey( key );
|
||||
ptr_fx target( std::forward<TFx>( fx ) );
|
||||
void* userdata = static_cast<void*>( target );
|
||||
lua_CFunction freefunc = &static_lua_func<TFx>::call;
|
||||
const char* freefuncname = fkey.c_str( );
|
||||
const luaL_Reg funcreg[ 2 ] = {
|
||||
{ freefuncname, freefunc },
|
||||
{ }
|
||||
};
|
||||
|
||||
push( );
|
||||
|
||||
stack::push( state( ), target );
|
||||
luaL_setfuncs( state( ), funcreg, 1 );
|
||||
|
||||
lua_pop( state( ), 1 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
table& set_fx(T&& key, std::unique_ptr<detail::lua_func> luafunc) {
|
||||
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<detail::lua_func> sptr(luafunc.release());
|
||||
std::shared_ptr<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();
|
||||
lua_func* target = hint->second.get( );
|
||||
void* userdata = static_cast<void*>( target );
|
||||
lua_CFunction freefunc = &detail::lua_cfun;
|
||||
lua_CFunction freefunc = &lua_func::call;
|
||||
const char* freefuncname = hint->first.c_str( );
|
||||
const luaL_Reg funcreg[ 2 ] = {
|
||||
{ freefuncname, freefunc },
|
||||
|
@ -113,13 +209,7 @@ private:
|
|||
|
||||
push( );
|
||||
|
||||
/*//lua_pushlightuserdata( state(), userdata );
|
||||
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 );
|
||||
stack::push( state( ), userdata );
|
||||
luaL_setfuncs( state( ), funcreg, 1 );
|
||||
|
||||
lua_pop( state( ), 1 );
|
||||
|
|
Loading…
Reference in New Issue
Block a user