summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2016-07-07 04:44:36 +0200
committerRobin Gareus <robin@gareus.org>2016-07-07 15:37:11 +0200
commit44a3f042a7a878af45ae893e0361d6a8be315da4 (patch)
treeb7ee5d92f24aca24a7de4084f623dca0ea5eb68a /libs
parent225a8a47a419e5e67a27b604bfd912498e3ad2cc (diff)
prepare sharing C++ class instances across lua-interpreters
in particular: lua-lifefime (!) C++ instances. This allows for dynamic allocation of custom user-data, bound to the lifetime of the allocating lua-context.
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/lua_api.h42
-rw-r--r--libs/ardour/lua_api.cc150
-rw-r--r--libs/ardour/luabindings.cc7
-rw-r--r--libs/lua/LuaBridge/detail/LuaRef.h5
-rw-r--r--libs/lua/LuaBridge/detail/Userdata.h14
5 files changed, 217 insertions, 1 deletions
diff --git a/libs/ardour/ardour/lua_api.h b/libs/ardour/ardour/lua_api.h
index 9ae6bf2ff6..9af9649620 100644
--- a/libs/ardour/ardour/lua_api.h
+++ b/libs/ardour/ardour/lua_api.h
@@ -181,6 +181,46 @@ namespace ARDOUR { namespace LuaOSC {
lo_address _addr;
};
-} } /* namespace */
+}
+
+class LuaTableRef {
+ public:
+ LuaTableRef ();
+ ~LuaTableRef ();
+
+ int get (lua_State* L);
+ int set (lua_State* L);
+
+ private:
+ struct LuaTableEntry {
+ LuaTableEntry (int kt, int vt)
+ : keytype (kt)
+ , valuetype (vt)
+ { }
+
+ int keytype;
+ std::string k_s;
+ unsigned int k_n;
+
+ int valuetype;
+ // LUA_TUSERDATA
+ const void* c;
+ void* p;
+ // LUA_TBOOLEAN
+ bool b;
+ // LUA_TSTRING:
+ std::string s;
+ // LUA_TNUMBER:
+ double n;
+ };
+
+ std::vector<LuaTableEntry> _data;
+
+ static void* findclasskey (lua_State *L, const void* key);
+ template<typename T>
+ static void assign (luabridge::LuaRef* rv, T key, const LuaTableEntry& s);
+};
+
+} /* namespace */
#endif // _ardour_lua_api_h_
diff --git a/libs/ardour/lua_api.cc b/libs/ardour/lua_api.cc
index 94b3f816c3..edee3a34a9 100644
--- a/libs/ardour/lua_api.cc
+++ b/libs/ardour/lua_api.cc
@@ -345,3 +345,153 @@ ARDOUR::LuaAPI::hsla_to_rgba (lua_State *L)
luabridge::Stack<double>::push (L, a);
return 4;
}
+
+luabridge::LuaRef::Proxy&
+luabridge::LuaRef::Proxy::clone_instance (const void* classkey, void* p) {
+ lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef);
+ lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef);
+
+ luabridge::UserdataPtr::push_raw (m_L, p, classkey);
+
+ lua_rawset (m_L, -3);
+ lua_pop (m_L, 1);
+ return *this;
+}
+
+LuaTableRef::LuaTableRef () {}
+LuaTableRef::~LuaTableRef () {}
+
+int
+LuaTableRef::get (lua_State* L)
+{
+ luabridge::LuaRef rv (luabridge::newTable (L));
+ for (std::vector<LuaTableEntry>::const_iterator i = _data.begin (); i != _data.end (); ++i) {
+ switch ((*i).keytype) {
+ case LUA_TSTRING:
+ assign(&rv, i->k_s, *i);
+ break;
+ case LUA_TNUMBER:
+ assign(&rv, i->k_n, *i);
+ break;
+ }
+ }
+ luabridge::push (L, rv);
+ return 1;
+}
+
+int
+LuaTableRef::set (lua_State* L)
+{
+ if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); }
+ _data.clear ();
+
+ lua_pushvalue (L, -1);
+ lua_pushnil (L);
+ while (lua_next (L, -2)) {
+ lua_pushvalue (L, -2);
+
+ LuaTableEntry s (lua_type(L, -1), lua_type(L, -2));
+ switch (lua_type(L, -1)) {
+ case LUA_TSTRING:
+ s.k_s = luabridge::Stack<std::string>::get (L, -1);
+ break;
+ ;
+ case LUA_TNUMBER:
+ s.k_n = luabridge::Stack<unsigned int>::get (L, -1);
+ break;
+ default:
+ // invalid key
+ lua_pop (L, 2);
+ continue;
+ }
+
+ switch(lua_type(L, -2)) {
+ case LUA_TSTRING:
+ s.s = luabridge::Stack<std::string>::get (L, -2);
+ break;
+ case LUA_TBOOLEAN:
+ s.b = lua_toboolean (L, -2);
+ break;
+ case LUA_TNUMBER:
+ s.n = lua_tonumber (L, -2);
+ break;
+ case LUA_TUSERDATA:
+ {
+ bool ok = false;
+ lua_getmetatable (L, -2);
+ lua_rawgetp (L, -1, luabridge::getIdentityKey ());
+ if (lua_isboolean (L, -1)) {
+ lua_pop (L, 1);
+ const void* key = lua_topointer (L, -1);
+ lua_pop (L, 1);
+ void const* classkey = findclasskey (L, key);
+
+ if (classkey) {
+ ok = true;
+ s.c = classkey;
+ s.p = luabridge::Userdata::get_ptr (L, -2);
+ }
+ } else {
+ lua_pop (L, 2);
+ }
+
+ if (ok) {
+ break;
+ }
+ // invalid userdata -- fall through
+ }
+ // no break
+ case LUA_TFUNCTION: // no support -- we could... string.format("%q", string.dump(value, true))
+ case LUA_TTABLE: // no nested tables, sorry.
+ case LUA_TNIL: // fallthrough
+ default:
+ // invalid value
+ lua_pop (L, 2);
+ continue;
+ }
+
+ _data.push_back(s);
+ lua_pop (L, 2);
+ }
+ return 0;
+}
+
+void*
+LuaTableRef::findclasskey (lua_State *L, const void* key)
+{
+ lua_pushvalue(L, LUA_REGISTRYINDEX);
+ lua_pushnil (L);
+ while (lua_next (L, -2)) {
+ lua_pushvalue (L, -2);
+ if (lua_topointer(L, -2) == key) {
+ void* rv = lua_touserdata (L, -1);
+ lua_pop (L, 4);
+ return rv;
+ }
+ lua_pop (L, 2);
+ }
+ lua_pop (L, 1);
+ return NULL;
+}
+
+template<typename T>
+void LuaTableRef::assign (luabridge::LuaRef* rv, T key, const LuaTableEntry& s)
+{
+ switch (s.valuetype) {
+ case LUA_TSTRING:
+ (*rv)[key] = s.s;
+ break;
+ case LUA_TBOOLEAN:
+ (*rv)[key] = s.b;
+ break;
+ case LUA_TNUMBER:
+ (*rv)[key] = s.n;
+ break;
+ case LUA_TUSERDATA:
+ (*rv)[key].clone_instance (s.c, s.p);
+ break;
+ default:
+ assert (0);
+ break;
+ }
+}
diff --git a/libs/ardour/luabindings.cc b/libs/ardour/luabindings.cc
index 393389c5ff..1ff2f39987 100644
--- a/libs/ardour/luabindings.cc
+++ b/libs/ardour/luabindings.cc
@@ -169,6 +169,7 @@ CLASSKEYS(ARDOUR::Session);
CLASSKEYS(ARDOUR::BufferSet);
CLASSKEYS(ARDOUR::ChanMapping);
CLASSKEYS(ARDOUR::DSP::DspShm);
+CLASSKEYS(ARDOUR::LuaTableRef);
CLASSKEYS(PBD::ID);
CLASSKEYS(ARDOUR::Location);
CLASSKEYS(ARDOUR::PluginInfo);
@@ -1373,6 +1374,12 @@ LuaBindings::dsp (lua_State* L)
.endClass ()
.endNamespace () // DSP
+
+ .beginClass <LuaTableRef> ("LuaTableRef")
+ .addCFunction ("get", &LuaTableRef::get)
+ .addCFunction ("set", &LuaTableRef::set)
+ .endClass ()
+
.endNamespace (); // ARDOUR
}
diff --git a/libs/lua/LuaBridge/detail/LuaRef.h b/libs/lua/LuaBridge/detail/LuaRef.h
index 8fae1c038a..46c756445e 100644
--- a/libs/lua/LuaBridge/detail/LuaRef.h
+++ b/libs/lua/LuaBridge/detail/LuaRef.h
@@ -180,6 +180,11 @@ private:
return *this;
}
+ // the implementation needs UserdataPtr, which
+ // is not yet defined here.
+ // -> libs/ardour/lua_api.cc
+ Proxy& clone_instance (const void* key, void* p);
+
//--------------------------------------------------------------------------
/**
Assign a new value to this table key.
diff --git a/libs/lua/LuaBridge/detail/Userdata.h b/libs/lua/LuaBridge/detail/Userdata.h
index e832ef2dc1..feab28f132 100644
--- a/libs/lua/LuaBridge/detail/Userdata.h
+++ b/libs/lua/LuaBridge/detail/Userdata.h
@@ -302,6 +302,11 @@ ud __parent (nil)
public:
virtual ~Userdata () { }
+ static void* get_ptr (lua_State* L, int index) {
+ Userdata* ud = static_cast <Userdata*> (lua_touserdata (L, index));
+ return ud->m_p;
+ }
+
//--------------------------------------------------------------------------
/**
Returns the Userdata* if the class on the Lua stack matches.
@@ -457,6 +462,15 @@ private:
assert (m_p != 0);
}
+ friend class LuaRef;
+ static inline void push_raw (lua_State* const L, void* p, const void* classkey)
+ {
+ new (lua_newuserdata (L, sizeof (UserdataPtr))) UserdataPtr (p);
+ lua_rawgetp (L, LUA_REGISTRYINDEX, classkey);
+ assert (lua_istable (L, -1));
+ lua_setmetatable (L, -2);
+ }
+
public:
/** Push non-const pointer to object.
*/