From f1558e3a9297c6a4fefa9d399a7c9d067d859aa3 Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Tue, 11 Jan 2005 04:59:27 +0000 Subject: added symbol type fixed incorrect unbinding of instance methods fixes for symbol type little restructuring svn path=/trunk/; revision=2489 --- externals/grill/py/source/bound.cpp | 121 ++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 41 deletions(-) (limited to 'externals/grill/py/source/bound.cpp') diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp index ce17578c..5690e0b1 100644 --- a/externals/grill/py/source/bound.cpp +++ b/externals/grill/py/source/bound.cpp @@ -13,7 +13,45 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include -typedef std::set FuncSet; +class MethodCompare: + public std::less +{ +public: + bool operator()(PyObject *a,PyObject *b) const + { + if(PyMethod_Check(a)) + if(PyMethod_Check(b)) { + // both are methods + PyObject *sa = PyMethod_GET_SELF(a); + PyObject *sb = PyMethod_GET_SELF(b); + if(sa) + if(sb) { + // both have self + if(sa == sb) + return PyMethod_GET_FUNCTION(a) < PyMethod_GET_FUNCTION(b); + else + return sa < sb; + } + else + return false; + else + if(sb) + return true; + else + return PyMethod_GET_FUNCTION(a) < PyMethod_GET_FUNCTION(b); + } + else + return false; + else + if(PyMethod_Check(b)) + return true; + else + // both are functions + return a < b; + } +}; + +typedef std::set FuncSet; struct bounddata { @@ -33,10 +71,10 @@ bool pyext::boundmeth(flext_base *th,t_symbol *sym,int argc,t_atom *argv,void *d // call all functions bound by this symbol for(FuncSet::iterator it = obj->funcs.begin(); it != obj->funcs.end(); ++it) { PyObject *ret = PyObject_CallObject(*it,args); - if(!ret) { + if(!ret) PyErr_Print(); - } - Py_XDECREF(ret); + else + Py_DECREF(ret); } Py_XDECREF(args); @@ -47,41 +85,39 @@ bool pyext::boundmeth(flext_base *th,t_symbol *sym,int argc,t_atom *argv,void *d PyObject *pyext::pyext_bind(PyObject *,PyObject *args) { - PyObject *self,*meth; - char *name; - if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth)) + PyObject *self,*meth,*name; + if(!PyArg_ParseTuple(args, "OOO:pyext_bind", &self,&name,&meth)) // borrowed references post("py/pyext - Wrong arguments!"); else if(!PyInstance_Check(self) || !(PyMethod_Check(meth) || PyFunction_Check(meth))) { post("py/pyext - Wrong argument types!"); } else { - const t_symbol *recv = MakeSymbol(name); -/* - if(GetBound(recv)) - post("py/pyext - Symbol \"%s\" is already hooked",GetString(recv)); -*/ - // make a proxy object - - if(PyMethod_Check(meth)) { - PyObject *no = PyObject_GetAttrString(meth,"__name__"); - meth = PyObject_GetAttr(self,no); - Py_DECREF(no); - } + py *th = GetThis(self); + FLEXT_ASSERT(th); + + const t_symbol *recv = pyObject_AsSymbol(name); void *data = NULL; - if(GetThis(self)->GetBoundMethod(recv,boundmeth,data)) { + if(recv && th->GetBoundMethod(recv,boundmeth,data)) { // already bound to that symbol and function bounddata *bdt = (bounddata *)data; FLEXT_ASSERT(bdt != NULL && bdt->self == self); - bdt->funcs.insert(meth); + + FuncSet::iterator it = bdt->funcs.find(meth); + if(it == bdt->funcs.end()) { + bdt->funcs.insert(meth); + Py_INCREF(meth); + } } else { + Py_INCREF(self); // self is borrowed reference + Py_INCREF(meth); + bounddata *data = new bounddata; data->self = self; data->funcs.insert(meth); - GetThis(self)->BindMethod(recv,boundmeth,data); - Py_INCREF(self); // self is borrowed reference + th->BindMethod(recv,boundmeth,data); } } @@ -91,34 +127,39 @@ PyObject *pyext::pyext_bind(PyObject *,PyObject *args) PyObject *pyext::pyext_unbind(PyObject *,PyObject *args) { - PyObject *self,*meth; - char *name; - if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth)) + PyObject *self,*meth,*name; + if(!PyArg_ParseTuple(args, "OOO:pyext_bind", &self,&name,&meth)) // borrowed references post("py/pyext - Wrong arguments!"); else if(!PyInstance_Check(self) || !(PyMethod_Check(meth) || PyFunction_Check(meth))) { post("py/pyext - Wrong argument types!"); } else { - const t_symbol *recv = MakeSymbol(name); - if(PyMethod_Check(meth)) { - PyObject *no = PyObject_GetAttrString(meth,"__name__"); - meth = PyObject_GetAttr(self,no); // meth is given a new reference! - Py_DECREF(no); - } + py *th = GetThis(self); + FLEXT_ASSERT(th); + + const t_symbol *recv = pyObject_AsSymbol(name); void *data = NULL; - if(GetThis(self)->UnbindMethod(recv,boundmeth,&data)) { + if(recv && th->GetBoundMethod(recv,boundmeth,data)) { bounddata *bdt = (bounddata *)data; FLEXT_ASSERT(bdt != NULL); - if(PyMethod_Check(meth)) Py_DECREF(meth); - // erase from map - bdt->funcs.erase(meth); + // ATTENTION: meth is different from the element found in the map + // it just points to the same instance method + FuncSet::iterator it = bdt->funcs.find(meth); + if(it != bdt->funcs.end()) { + Py_DECREF(*it); + bdt->funcs.erase(it); + } + else + post("py/pyext - Function to unbind couldn't be found"); if(bdt->funcs.empty()) { Py_DECREF(bdt->self); delete bdt; + + th->UnbindMethod(recv,boundmeth,NULL); } } } @@ -142,13 +183,11 @@ void pyext::ClearBinding() while(GetThis(pyobj)->UnbindMethod(sym,NULL,&data)) { bounddata *bdt = (bounddata *)data; if(bdt) { - for(FuncSet::iterator it = bdt->funcs.begin(); it != bdt->funcs.end(); ++it) { - PyObject *func = *it; - if(PyMethod_Check(func)) Py_DECREF(func); - } + for(FuncSet::iterator it = bdt->funcs.begin(); it != bdt->funcs.end(); ++it) + Py_DECREF(*it); Py_DECREF(bdt->self); - if(data) delete bdt; + delete bdt; } } } -- cgit v1.2.1