summaryrefslogtreecommitdiffstats
path: root/crawl-ref
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
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')
-rw-r--r--crawl-ref/source/clua.cc84
-rw-r--r--crawl-ref/source/clua.h35
-rw-r--r--crawl-ref/source/mapmark.cc28
-rw-r--r--crawl-ref/source/mapmark.h3
4 files changed, 130 insertions, 20 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);
+ }
+}
diff --git a/crawl-ref/source/clua.h b/crawl-ref/source/clua.h
index f5a0050cca..ae465aa3a0 100644
--- a/crawl-ref/source/clua.h
+++ b/crawl-ref/source/clua.h
@@ -57,6 +57,36 @@ private:
static lua_clua_map lua_map;
};
+class lua_shutdown_listener
+{
+public:
+ virtual void shutdown(CLua &lua) = 0;
+};
+
+// A convenience class to keep a reference to a lua object on the stack.
+// This is useful to hang on to things that cannot be directly retrieved by
+// C++ code, such as Lua function references.
+class lua_datum : public lua_shutdown_listener
+{
+public:
+ lua_datum(CLua &lua, int stackpos = -1, bool pop = true);
+ lua_datum(const lua_datum &other);
+
+ void shutdown(CLua &lua);
+
+ ~lua_datum();
+
+ // Push the datum onto the Lua stack.
+ void push() const;
+
+private:
+ bool need_cleanup;
+ CLua &lua;
+
+private:
+ void cleanup();
+};
+
class CLua
{
public:
@@ -95,6 +125,9 @@ public:
void fnreturns(const char *params, ...);
bool runhook(const char *hook, const char *params, ...);
+ void add_shutdown_listener(lua_shutdown_listener *);
+ void remove_shutdown_listener(lua_shutdown_listener *);
+
static int file_write(lua_State *ls);
static int loadfile(lua_State *ls, const char *file,
bool trusted = false, bool die_on_fail = false);
@@ -128,6 +161,8 @@ private:
sfset sourced_files;
unsigned long uniqindex;
+ std::vector<lua_shutdown_listener*> shutdown_listeners;
+
private:
void init_lua();
void set_error(int err, lua_State *ls = NULL);
diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc
index 5f0942ef2e..7fadb6330e 100644
--- a/crawl-ref/source/mapmark.cc
+++ b/crawl-ref/source/mapmark.cc
@@ -188,13 +188,6 @@ map_lua_marker::map_lua_marker(const std::string &s, const std::string &,
map_lua_marker::~map_lua_marker()
{
- // Remove the Lua marker table from the registry.
- if (initialised)
- {
- lua_pushlightuserdata(dlua, this);
- lua_pushnil(dlua);
- lua_settable(dlua, LUA_REGISTRYINDEX);
- }
}
map_marker *map_lua_marker::clone() const
@@ -216,22 +209,21 @@ void map_lua_marker::check_register_table()
}
// Got a table. Save it in the registry.
-
- // Key is this.
- lua_pushlightuserdata(dlua, this);
- // Move key before value.
- lua_insert(dlua, -2);
- lua_settable(dlua, LUA_REGISTRYINDEX);
-
+ marker_table.reset(new lua_datum(dlua));
initialised = true;
}
bool map_lua_marker::get_table() const
{
- // First save the unmarshall Lua function.
- lua_pushlightuserdata(dlua, const_cast<map_lua_marker*>(this));
- lua_gettable(dlua, LUA_REGISTRYINDEX);
- return (lua_istable(dlua, -1));
+ if (marker_table.get())
+ {
+ marker_table->push();
+ return (lua_istable(dlua, -1));
+ }
+ else
+ {
+ return (false);
+ }
}
void map_lua_marker::write(writer &outf) const
diff --git a/crawl-ref/source/mapmark.h b/crawl-ref/source/mapmark.h
index 3efc40e591..07d89331be 100644
--- a/crawl-ref/source/mapmark.h
+++ b/crawl-ref/source/mapmark.h
@@ -16,6 +16,7 @@
#include "luadgn.h"
#include <map>
#include <string>
+#include <memory>
//////////////////////////////////////////////////////////////////////////
// Map markers
@@ -117,6 +118,8 @@ public:
throw (std::string);
private:
bool initialised;
+ std::auto_ptr<lua_datum> marker_table;
+
private:
void check_register_table();
bool get_table() const;