From a06523dd0f46c2536e070e58c9288419bbcbf22e Mon Sep 17 00:00:00 2001 From: dshaligram Date: Tue, 18 Nov 2008 20:07:42 +0000 Subject: Added lua_datum to wrap the common task of retaining references to Lua objects in the Lua registry. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7477 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/clua.cc | 84 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) (limited to 'crawl-ref/source/clua.cc') diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc index 477d772a40..9fa1a79a9a 100644 --- a/crawl-ref/source/clua.cc +++ b/crawl-ref/source/clua.cc @@ -84,12 +84,17 @@ CLua::CLua(bool managed) CLua::~CLua() { + // Copy the listener vector, because listeners may remove + // themselves from the listener list when we notify them of a + // shutdown. + const std::vector slisteners = shutdown_listeners; + for (int i = 0, size = slisteners.size(); i < size; ++i) + slisteners[i]->shutdown(*this); shutting_down = true; if (_state) lua_close(_state); } -// This has the disadvantage of repeatedly trying init_lua if it fails. lua_State *CLua::state() { if (!_state) @@ -597,7 +602,7 @@ void CLua::init_lua() _state = managed_vm? lua_newstate(_clua_allocator, this) : luaL_newstate(); if (!_state) - return; + end(1, false, "Unable to create Lua state."); lua_stack_cleaner clean(_state); @@ -658,6 +663,22 @@ void CLua::load_cmacro() execfile("clua/macro.lua", true, true); } +void CLua::add_shutdown_listener(lua_shutdown_listener *listener) +{ + if (std::find(shutdown_listeners.begin(), shutdown_listeners.end(), + listener) == shutdown_listeners.end()) + shutdown_listeners.push_back(listener); +} + +void CLua::remove_shutdown_listener(lua_shutdown_listener *listener) +{ + std::vector::iterator i = + std::find(shutdown_listeners.begin(), shutdown_listeners.end(), + listener); + if (i != shutdown_listeners.end()) + shutdown_listeners.erase(i); +} + ///////////////////////////////////////////////////////////////////// static void _clua_register_metatable(lua_State *ls, const char *tn, @@ -2849,3 +2870,62 @@ std::string quote_lua_string(const std::string &s) { return replace_all_of(replace_all_of(s, "\\", "\\\\"), "\"", "\\\""); } + +///////////////////////////////////////////////////////////////////// + +lua_datum::lua_datum(CLua &_lua, int stackpos, bool pop) + : need_cleanup(true), lua(_lua) +{ + // Store the datum in the registry indexed by "this". + lua_pushvalue(lua, stackpos); + lua_pushlightuserdata(lua, this); + // Move the key (this) before the value. + lua_insert(lua, -2); + lua_settable(lua, LUA_REGISTRYINDEX); + + if (pop && stackpos < 0) + lua_pop(lua, -stackpos); + + lua.add_shutdown_listener(this); +} + +lua_datum::lua_datum(const lua_datum &o) + : need_cleanup(true), lua(o.lua) +{ + lua_pushlightuserdata(lua, this); + o.push(); + lua_settable(lua, LUA_REGISTRYINDEX); + + lua.add_shutdown_listener(this); +} + +void lua_datum::push() const +{ + lua_pushlightuserdata(lua, const_cast(this)); + lua_gettable(lua, LUA_REGISTRYINDEX); + + // The value we saved is now on top of the Lua stack. +} + +lua_datum::~lua_datum() +{ + cleanup(); +} + +void lua_datum::shutdown(CLua &) +{ + cleanup(); +} + +void lua_datum::cleanup() +{ + if (need_cleanup) + { + need_cleanup = false; + lua.remove_shutdown_listener(this); + + lua_pushlightuserdata(lua, this); + lua_pushnil(lua); + lua_settable(lua, LUA_REGISTRYINDEX); + } +} -- cgit v1.2.3-54-g00ecf