Skip to content

Instantly share code, notes, and snippets.

@ThePhD
Last active August 29, 2015 14:00
Show Gist options
  • Save ThePhD/11298310 to your computer and use it in GitHub Desktop.
Save ThePhD/11298310 to your computer and use it in GitHub Desktop.
lua_class.c++
namespace sol {
template <typename... Tn>
struct constructors { };
template <typename T>
class lua_class {
public:
static const std::string classname;
static const std::string meta;
private:
std::string luaname;
std::vector<std::string> functionnames;
std::vector<std::unique_ptr<lua_func>> functions;
std::vector<luaL_Reg> functiontable;
std::vector<luaL_Reg> metatable;
struct maker {
static int construct( lua_State* L ) {
// First argument is now a table that represent the class to instantiate
luaL_checktype( L, 1, LUA_TTABLE );
lua_newtable( L ); // Create table to represent instance
// Set first argument of new to metatable of instance
lua_pushvalue( L, 1 );
lua_setmetatable( L, -2 );
// Do function lookups in metatable
lua_pushvalue( L, 1 );
lua_setfield( L, 1, "__index" );
void* userdata = lua_newuserdata( L, sizeof( T ) );
T* obj = static_cast<T*>( userdata );
std::allocator<T> alloc{ };
alloc.construct( obj );
}
template <std::size_t n>
static int destruct( lua_State* L ) {
for ( std::size_t i = 0; i < n; ++i ) {
stack::pop<light_user_data>( L, i );
}
void* userdata = lua_touserdata( L, 0 );
T* obj = static_cast<T*>( userdata );
std::allocator<T> alloc{ };
alloc.destroy( obj );
}
};
void build_function_tables( ) {
}
template <typename... Args, typename Ret, typename... MArgs>
void build_function_tables( Ret( T::* func )( MArgs... ), std::string name, Args&&... args ) {
typedef typename std::decay<decltype( func )>::type fx_t;
functionnames.push_back( std::move( name ) );
functions.emplace_back( std::make_unique<class_lua_func<fx_t, T>>( std::move( func ) ) );
functiontable.push_back( { functionnames.back().c_str(), &lua_func::call } );
build_function_tables( std::forward<Args>( args )... );
}
public:
template <typename... Args>
lua_class( Args&&... args ) : lua_class( classname, std::forward<Args>( args )... ) {
}
template <typename... Args>
lua_class( std::string name, Args&&... args ) : lua_class( name, constructors<>( ), std::forward<Args>( args )... ) {
}
template <typename... Args, typename... CArgs>
lua_class( constructors<CArgs...> c, Args&&... args ) : lua_class( classname, std::move( c ), std::forward<Args>( args )... ) {
}
template <typename... Args, typename... CArgs>
lua_class( std::string name, constructors<CArgs...> c, Args&&... args ) : luaname( std::move( name ) ) {
functionnames.reserve( sizeof...( args ) );
functiontable.reserve( sizeof...( args ) );
functions.reserve( sizeof...( args ) );
metatable.reserve( sizeof...( args ) );
build_function_tables( std::forward<Args>( args )... );
functionnames.push_back( "new" );
functiontable.push_back( { functionnames.back( ).c_str( ), &maker::construct } );
functiontable.push_back( { nullptr, nullptr } );
// ERROR: error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'lua_CFunction'
metatable.push_back( { "__gc", &maker::destruct<sizeof...( Args ) / 2> } );
metatable.push_back( { nullptr, nullptr } );
}
};
template <typename T>
const std::string lua_class<T>::classname = detail::demangle( typeid( T ) );
template <typename T>
const std::string lua_class<T>::meta = std::string( "sol.stateful." ).append( classname );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment