summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/clua.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-18 20:07:42 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-18 20:07:42 +0000
commita06523dd0f46c2536e070e58c9288419bbcbf22e (patch)
tree1c49523bf609b18ee5e6a529e18e34438b62bfad /crawl-ref/source/clua.cc
parentff00ffd9da330a94bd282bcc127157672e589a9a (diff)
downloadcrawl-ref-a06523dd0f46c2536e070e58c9288419bbcbf22e.tar.gz
crawl-ref-a06523dd0f46c2536e070e58c9288419bbcbf22e.zip
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
Diffstat (limited to 'crawl-ref/source/clua.cc')
-rw-r--r--crawl-ref/source/clua.cc84
1 files changed, 82 insertions, 2 deletions
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<lua_shutdown_listener*> 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<lua_shutdown_listener*>::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<lua_datum*>(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);
+ }
+}