Skip to content

Instantly share code, notes, and snippets.

@cbeck88
Last active August 27, 2015 14:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cbeck88/f081023f40b844417aac to your computer and use it in GitHub Desktop.
Save cbeck88/f081023f40b844417aac to your computer and use it in GitHub Desktop.
iterations of design for lua state (posted on stack overflow)
////////////////////////////////////////////////////
// First stab, very naively:
//
// Define lua environment
void init_lua(lua_State * L);
struct lua_environment {
data_structure_a a_;
data_structure_b b_;
data_structure_c c_;
...
lua_State * L_;
lua_environment()
: a_()
, b_()
, c_()
...
, L_(lua_newstate())
{
init_lua(L_);
}
};
lua_environment * current_environment;
// Global pointers! Forcing static singleton pattern! Very bad! Evil!
// Implement callbacks
int callback_1(lua_State * L) { current_environment->do_something(); }
int callback_2(lua_State * L) { current_environment->do_somethingelse(); }
int callback_3(lua_State * L) { ... }
// Register callbacks
void init_lua(lua_State * L) {
const luaL_Reg regs[] = {
{ "callback_1", &callback_1 },
{ "callback_1", &callback_2 },
{ "callback_1", &callback_3 },
{ NULL, NULL}
};
luaL_register(L, regs);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Note that the above forces nasty design patterns, and results in every function needing to be registered in 3 separate places.
// If you leave a function out of the callback registration list there is no help from the compiler.
// Once the class gets complicated or you have alot of callbacks it's not a good thing.
//
// Now a little less naively.
void init_lua(lua_State * L);
class lua_environment {
data_structure_a a_;
data_structure_b b_;
data_structure_c c_;
...
lua_State * L_;
public:
// Lua callbacks
int callback_1(lua_State * L) { do_something(); }
int callback_2(lua_State * L) { do_somethingelse(); }
int callback_3(lua_State * L) { ... }
...
lua_environment()
: a_()
, b_()
, c_()
...
, L_(lua_newstate())
{
*static_cast<lua_environment**>(lua_getextraspace(L_)) = this;
init_lua(L_);
}
};
typedef int (lua_environment::*env_mem_func)(lua_State * L);
// This template wraps a member function into a C-style "free" function compatible with lua.
template <env_mem_func func>
int dispatch(lua_State * L) {
lua_environment * env_ptr = *static_cast<lua_environment**>(lua_getextraspace(L));
return ((*env_ptr).*func)(L);
}
void init_lua(lua_State * L) {
const luaL_Reg regs[] = {
{ "callback_1", &dispatch<&lua_environment::callback_1> },
{ "callback_1", &dispatch<&lua_environment::callback_2> },
{ "callback_1", &dispatch<&lua_environment::callback_3> },
{ NULL, NULL }
};
luaL_register(L, regs);
}
///////////////////////////////////////////////////////////
// This try was better, but it still has the drawback that once I have 100 callbacks I end up with these
// gigantic lists which have to be maintained in parallel.
// Everything must be declared, then defined, then registered, in a separate place.
// Final (current?) version looks something like:
class lua_environment : public lua_registrar<lua_environment> {
data_structure_a a_;
data_structure_b b_;
data_structure_c c_;
...
lua_State * L_;
// Lua callbacks
REGISTER_CALLBACK(func1, "This is the help string for func1")(lua_State * L) {
std::cout << "This is the implementation for func1" << std::endl;
do_something();
}
REGISTER_CALLBACK(func2, "This is the help string for func2")(lua_State * L) {
std::cout << "This is the implementation for func2" << std::endl;
do_something();
}
...
public:
lua_environment()
: a_()
, b_()
, c_()
, L_(lua_newstate())
{
*static_cast<lua_environment**>(lua_getextraspace(L_)) = this;
register_all_callbacks(L_); // <-- method exposed by lua_registrar<T>
}
};
// Ah... now there is much less clutter there is in a crucial file for my application that is already very busy!
// I can put all the template glue nonsense in a different file, where the lua_registrar template and the
// relevant macros are defined!
// :D
// SO Question is about implementation for REGISTER_CALLBACK macro above.
// I don't know any way to do that using static initialization, templates seems to be more straightforward. YMMV
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment