Last active
August 27, 2015 14:47
-
-
Save cbeck88/f081023f40b844417aac to your computer and use it in GitHub Desktop.
iterations of design for lua state (posted on stack overflow)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////////////////////// | |
// 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