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.
This commit is contained in:
parent
225a8a47a4
commit
44a3f042a7
|
@ -181,6 +181,46 @@ namespace ARDOUR { namespace LuaOSC {
|
||||||
lo_address _addr;
|
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_
|
#endif // _ardour_lua_api_h_
|
||||||
|
|
|
@ -345,3 +345,153 @@ ARDOUR::LuaAPI::hsla_to_rgba (lua_State *L)
|
||||||
luabridge::Stack<double>::push (L, a);
|
luabridge::Stack<double>::push (L, a);
|
||||||
return 4;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -169,6 +169,7 @@ CLASSKEYS(ARDOUR::Session);
|
||||||
CLASSKEYS(ARDOUR::BufferSet);
|
CLASSKEYS(ARDOUR::BufferSet);
|
||||||
CLASSKEYS(ARDOUR::ChanMapping);
|
CLASSKEYS(ARDOUR::ChanMapping);
|
||||||
CLASSKEYS(ARDOUR::DSP::DspShm);
|
CLASSKEYS(ARDOUR::DSP::DspShm);
|
||||||
|
CLASSKEYS(ARDOUR::LuaTableRef);
|
||||||
CLASSKEYS(PBD::ID);
|
CLASSKEYS(PBD::ID);
|
||||||
CLASSKEYS(ARDOUR::Location);
|
CLASSKEYS(ARDOUR::Location);
|
||||||
CLASSKEYS(ARDOUR::PluginInfo);
|
CLASSKEYS(ARDOUR::PluginInfo);
|
||||||
|
@ -1373,6 +1374,12 @@ LuaBindings::dsp (lua_State* L)
|
||||||
.endClass ()
|
.endClass ()
|
||||||
|
|
||||||
.endNamespace () // DSP
|
.endNamespace () // DSP
|
||||||
|
|
||||||
|
.beginClass <LuaTableRef> ("LuaTableRef")
|
||||||
|
.addCFunction ("get", &LuaTableRef::get)
|
||||||
|
.addCFunction ("set", &LuaTableRef::set)
|
||||||
|
.endClass ()
|
||||||
|
|
||||||
.endNamespace (); // ARDOUR
|
.endNamespace (); // ARDOUR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,11 @@ private:
|
||||||
return *this;
|
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.
|
Assign a new value to this table key.
|
||||||
|
|
|
@ -302,6 +302,11 @@ ud __parent (nil)
|
||||||
public:
|
public:
|
||||||
virtual ~Userdata () { }
|
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.
|
Returns the Userdata* if the class on the Lua stack matches.
|
||||||
|
@ -457,6 +462,15 @@ private:
|
||||||
assert (m_p != 0);
|
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:
|
public:
|
||||||
/** Push non-const pointer to object.
|
/** Push non-const pointer to object.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user