diff options
author | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-11-18 20:07:42 +0000 |
---|---|---|
committer | dshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-11-18 20:07:42 +0000 |
commit | a06523dd0f46c2536e070e58c9288419bbcbf22e (patch) | |
tree | 1c49523bf609b18ee5e6a529e18e34438b62bfad /crawl-ref | |
parent | ff00ffd9da330a94bd282bcc127157672e589a9a (diff) | |
download | crawl-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.cc | 84 | ||||
-rw-r--r-- | crawl-ref/source/clua.h | 35 | ||||
-rw-r--r-- | crawl-ref/source/mapmark.cc | 28 | ||||
-rw-r--r-- | crawl-ref/source/mapmark.h | 3 |
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; |