MethodProxy.cxx

Go to the documentation of this file.
00001 // @(#)root/pyroot:$Id: MethodProxy.cxx 37462 2010-12-09 22:33:17Z wlav $
00002 // Author: Wim Lavrijsen, Jan 2005
00003 
00004 // Bindings
00005 #include "PyROOT.h"
00006 #include "structmember.h"    // from Python
00007 #if PY_VERSION_HEX >= 0x02050000
00008 #include "code.h"            // from Python
00009 #else
00010 #include "compile.h"         // from Python
00011 #endif
00012 #ifndef CO_NOFREE
00013 // python2.2 does not have CO_NOFREE defined
00014 #define CO_NOFREE       0x0040
00015 #endif
00016 #include "MethodProxy.h"
00017 #include "ObjectProxy.h"
00018 #include "TPyException.h"
00019 #include "Utility.h"
00020 #include "PyStrings.h"
00021 
00022 // Standard
00023 #include <algorithm>
00024 #include <functional>
00025 #include <vector>
00026 #include <algorithm>
00027 
00028 
00029 namespace PyROOT {
00030 
00031 namespace {
00032 
00033 // helper to test whether a method is used in a pseudo-function modus
00034    bool inline IsPseudoFunc( MethodProxy* pymeth )
00035    {
00036       return (void*)pymeth == (void*)pymeth->fSelf;
00037    }
00038 
00039 // helper for collecting/maintaining exception data in overload dispatch
00040    struct PyError_t {
00041       PyError_t() { fType = fValue = fTrace = 0; }
00042 
00043       static void Clear( PyError_t& e )
00044       {
00045          Py_XDECREF( e.fType ); Py_XDECREF( e.fValue ); Py_XDECREF( e.fTrace );
00046          e.fType = e.fValue = e.fTrace = 0;
00047       }
00048 
00049       PyObject *fType, *fValue, *fTrace;
00050    };
00051 
00052 // helper to hash tuple (using tuple hash would cause self-tailing loops)
00053    inline Long_t HashSignature( PyObject* args )
00054    {
00055       ULong_t hash = 0;
00056 
00057       Int_t nargs = PyTuple_GET_SIZE( args );
00058       for ( Int_t i = 0; i < nargs; ++i ) {
00059          hash += (ULong_t) Py_TYPE( PyTuple_GET_ITEM( args, i ) );
00060          hash += (hash << 10); hash ^= (hash >> 6);
00061       }
00062 
00063       hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15);
00064 
00065       return hash;
00066    }
00067 
00068 // helper to sort on method priority
00069    int PriorityCmp( PyCallable* left, PyCallable* right )
00070    {
00071       return left->GetPriority() > right->GetPriority();
00072    }
00073 
00074 // helper to factor out return logic of mp_call
00075    inline PyObject* HandleReturn( MethodProxy* pymeth, PyObject* result ) {
00076 
00077    // special case for python exceptions, propagated through C++ layer
00078       if ( result == (PyObject*)TPyExceptionMagic )
00079          return 0;              // exception info was already set
00080 
00081    // if this method creates new objects, always take ownership
00082       if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsCreator ) {
00083 
00084       // either be a constructor with a fresh object proxy self ... 
00085          if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsConstructor ) {
00086             if ( pymeth->fSelf )
00087                pymeth->fSelf->HoldOn();
00088          }
00089 
00090       // ... or be a method with an object proxy return value
00091          else if ( ObjectProxy_Check( result ) )
00092             ((ObjectProxy*)result)->HoldOn();
00093       }
00094 
00095    // if this new object falls inside self, make sure its lifetime is proper
00096       if ( pymeth->fSelf && ObjectProxy_Check( result ) ) {
00097          Long_t ptrdiff = (Long_t)((ObjectProxy*)result)->GetObject() - (Long_t)pymeth->fSelf->GetObject();
00098          if ( 0 <= ptrdiff && ptrdiff < (Long_t)pymeth->fSelf->ObjectIsA()->Size() ) {
00099             if ( PyObject_SetAttr( result, PyStrings::gLifeLine, (PyObject*)pymeth->fSelf ) == -1 )
00100                PyErr_Clear();     // ignored
00101          }
00102       }
00103 
00104       return result;
00105    }
00106 
00107 
00108 //= PyROOT method proxy object behaviour =====================================
00109    PyObject* mp_name( MethodProxy* pymeth, void* )
00110    {
00111       return PyROOT_PyUnicode_FromString( pymeth->GetName().c_str() );
00112    }
00113 
00114 //____________________________________________________________________________
00115    PyObject* mp_module( MethodProxy* /* pymeth */, void* )
00116    {
00117       Py_INCREF( PyStrings::gROOTns );
00118       return PyStrings::gROOTns;
00119    }
00120 
00121 //____________________________________________________________________________
00122    PyObject* mp_doc( MethodProxy* pymeth, void* )
00123    {
00124       MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
00125 
00126    // collect doc strings
00127       Int_t nMethods = methods.size();
00128       PyObject* doc = methods[0]->GetDocString();
00129 
00130    // simple case
00131       if ( nMethods == 1 )
00132          return doc;
00133 
00134    // overloaded method
00135       PyObject* separator = PyROOT_PyUnicode_FromString( "\n" );
00136       for ( Int_t i = 1; i < nMethods; ++i ) {
00137          PyROOT_PyUnicode_Append( &doc, separator );
00138          PyROOT_PyUnicode_AppendAndDel( &doc, methods[i]->GetDocString() );
00139       }
00140       Py_DECREF( separator );
00141 
00142       return doc;
00143    }
00144 
00145 //____________________________________________________________________________
00146    PyObject* mp_meth_func( MethodProxy* pymeth, void* )
00147    {
00148    // create and a new method proxy to be returned
00149       MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
00150 
00151    // method info is shared, as it contains the collected overload knowledge
00152       *pymeth->fMethodInfo->fRefCount += 1;
00153       newPyMeth->fMethodInfo = pymeth->fMethodInfo;
00154 
00155    // new method is unbound, use of 'meth' is for keeping track whether this
00156    // proxy is used in the capacity of a method or a function
00157       newPyMeth->fSelf = (ObjectProxy*)newPyMeth;
00158 
00159       return (PyObject*)newPyMeth;
00160    }
00161 
00162 //____________________________________________________________________________
00163    PyObject* mp_meth_self( MethodProxy* pymeth, void* )
00164    {
00165    // return the bound self, if any; in case of pseudo-function role, pretend
00166    // that the data member im_self does not exist
00167       if ( IsPseudoFunc( pymeth ) ) {
00168          PyErr_Format( PyExc_AttributeError,
00169             "function %s has no attribute \'im_self\'", pymeth->fMethodInfo->fName.c_str() );
00170          return 0;
00171       } else if ( pymeth->fSelf != 0 ) {
00172          Py_INCREF( (PyObject*)pymeth->fSelf );
00173          return (PyObject*)pymeth->fSelf;
00174       }
00175 
00176       Py_INCREF( Py_None );
00177       return Py_None;
00178    }
00179 
00180 //____________________________________________________________________________
00181    PyObject* mp_meth_class( MethodProxy* pymeth, void* )
00182    {
00183    // return scoping class; in case of pseudo-function role, pretend that there
00184    // is no encompassing class (i.e. global scope)
00185       if ( ! IsPseudoFunc( pymeth ) ) {
00186          PyObject* pyclass = pymeth->fMethodInfo->fMethods[0]->GetScope();
00187          if ( ! pyclass )
00188             PyErr_Format( PyExc_AttributeError,
00189                "function %s has no attribute \'im_class\'", pymeth->fMethodInfo->fName.c_str() );
00190          return pyclass;
00191       }
00192 
00193       Py_INCREF( Py_None );
00194       return Py_None;
00195    }
00196 
00197 //____________________________________________________________________________
00198    PyObject* mp_func_closure( MethodProxy* /* pymeth */, void* )
00199    {
00200       Py_INCREF( Py_None );
00201       return Py_None;
00202    }
00203 
00204 //____________________________________________________________________________
00205    PyObject* mp_func_code( MethodProxy* pymeth, void* )
00206    {
00207 #if PY_VERSION_HEX < 0x03000000
00208       MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
00209 
00210    // collect maximum number of arguments in set of overloads; this is also used
00211    // for the number of locals ("stack variables")
00212       int co_argcount = 0;
00213       MethodProxy::Methods_t::iterator maxargmeth;
00214       for ( MethodProxy::Methods_t::iterator imeth = methods.begin(); imeth != methods.end(); ++imeth ) {
00215          if ( co_argcount < (*imeth)->GetMaxArgs() ) {
00216             co_argcount = (*imeth)->GetMaxArgs();
00217             maxargmeth = imeth;
00218          }
00219       }
00220       co_argcount += 1;       // for 'self'
00221 
00222    // for now, code object representing the statement 'pass'
00223       PyObject* co_code = PyString_FromStringAndSize( "d\x00\x00S", 4 );
00224    //   PyObject* co_code = PyString_FromStringAndSize( "t\x00\x00d\x01\x00\x83\x01\x00}\x02\x00|\x02\x00S", 16 );
00225 
00226    // tuple with all the const literals used in the function
00227       PyObject* co_consts = PyTuple_New( 2 );
00228       Py_INCREF( Py_None );
00229       PyTuple_SET_ITEM( co_consts, 0, Py_None );
00230       PyObject* val1 = PyFloat_FromDouble( -1.0 );
00231       PyTuple_SET_ITEM( co_consts, 1, val1 );
00232 
00233       PyObject* co_names = PyTuple_New( 2 );
00234       PyTuple_SET_ITEM( co_names, 0, PyString_FromString( "dafunc" ) );
00235       PyTuple_SET_ITEM( co_names, 1, PyString_FromString( "acos" ) );
00236 
00237 
00238    // names, freevars, and cellvars go unused
00239       PyObject* co_unused = PyTuple_New( 0 );
00240 
00241    // variable names are both the argument and local names
00242       PyObject* co_varnames = PyTuple_New( co_argcount + 1 );
00243       PyTuple_SET_ITEM( co_varnames, 0, PyString_FromString( "self" ) );
00244       for ( int iarg = 1; iarg < co_argcount; ++iarg ) {
00245          PyTuple_SET_ITEM( co_varnames, iarg, (*maxargmeth)->GetArgSpec( iarg - 1 ) );
00246       }
00247       PyTuple_SET_ITEM( co_varnames, co_argcount, PyString_FromString( "d" ) );
00248 
00249    // filename is made-up
00250       PyObject* co_filename = PyString_FromString( "ROOT.py" );
00251 
00252    // name is the function name, also through __name__ on the function itself
00253       PyObject* co_name = PyString_FromString( pymeth->GetName().c_str() );
00254 
00255    // firstlineno is the line number of first function code in the containing scope
00256 
00257    // lnotab is a packed table that maps instruction count and line number
00258    //PyObject* co_lnotab = PyString_FromString( "\x00\x01" );
00259       PyObject* co_lnotab = PyString_FromString( "\x00\x01\x0c\x01" );
00260 
00261       PyObject* code = (PyObject*)PyCode_New(
00262          co_argcount,                             // argcount
00263          co_argcount + 1,                         // nlocals
00264          2,                                       // stacksize
00265          CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE, // flags
00266          co_code,                                 // code
00267          co_consts,                               // consts
00268          co_names,                                // names
00269          co_varnames,                             // varnames
00270          co_unused,                               // freevars
00271          co_unused,                               // cellvars
00272          co_filename,                             // filename
00273          co_name,                                 // name
00274          1,                                       // firstlineno
00275          co_lnotab );                             // lnotab
00276 
00277       Py_DECREF( co_lnotab );
00278       Py_DECREF( co_name );
00279       Py_DECREF( co_unused );
00280       Py_DECREF( co_filename );
00281       Py_DECREF( co_varnames );
00282       Py_DECREF( co_names );
00283       Py_DECREF( co_consts );
00284       Py_DECREF( co_code );
00285 
00286       return code;
00287 #else
00288 // not important for functioning of most code, so not implemented for p3 for now (TODO)
00289       pymeth = 0;
00290       Py_INCREF( Py_None );
00291       return Py_None;
00292 #endif
00293    }
00294 
00295 //____________________________________________________________________________
00296    PyObject* mp_func_defaults( MethodProxy* pymeth, void* )
00297    {
00298    // create a tuple of default values for the overload with the most arguments
00299       MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
00300 
00301       int maxarg = 0;
00302       MethodProxy::Methods_t::iterator maxargmeth;
00303       for ( MethodProxy::Methods_t::iterator imeth = methods.begin(); imeth != methods.end(); ++imeth ) {
00304          if ( maxarg < (*imeth)->GetMaxArgs() ) {
00305             maxarg = (*imeth)->GetMaxArgs();
00306             maxargmeth = imeth;
00307          }
00308       }
00309 
00310       PyObject* defaults = PyTuple_New( maxarg );
00311 
00312       int itup = 0;
00313       for ( int iarg = 0; iarg < maxarg; ++iarg ) {
00314          PyObject* defvalue = (*maxargmeth)->GetArgDefault( iarg );
00315          if ( defvalue )
00316             PyTuple_SET_ITEM( defaults, itup++, defvalue );
00317       }
00318       _PyTuple_Resize( &defaults, itup );
00319 
00320       return defaults;
00321    }
00322 
00323 //____________________________________________________________________________
00324    PyObject* mp_func_globals( MethodProxy* /* pymeth */, void* )
00325    {
00326    // could also use __main__'s dict here; used for lookup of names from co_code
00327    // indexing into co_names
00328       PyObject* pyglobal = PyModule_GetDict( PyImport_AddModule( (char*)"ROOT" ) );
00329       Py_XINCREF( pyglobal );
00330       return pyglobal;
00331    }
00332 
00333 //____________________________________________________________________________
00334    PyObject* mp_getcreates( MethodProxy* pymeth, void* )
00335    {
00336       return PyInt_FromLong(
00337          (Bool_t)(pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsCreator) );
00338    }
00339 
00340 //____________________________________________________________________________
00341    int mp_setcreates( MethodProxy* pymeth, PyObject* value, void* )
00342    {
00343       if ( ! value ) {        // means that _creates is being deleted
00344          pymeth->fMethodInfo->fFlags &= ~MethodProxy::MethodInfo_t::kIsCreator;
00345          return 0;
00346       }
00347 
00348       Long_t iscreator = PyLong_AsLong( value );
00349       if ( iscreator == -1 && PyErr_Occurred() ) {
00350          PyErr_SetString( PyExc_ValueError, "a boolean 1 or 0 is required for _creates" );
00351          return -1;
00352       }
00353 
00354       if ( iscreator )
00355          pymeth->fMethodInfo->fFlags |= MethodProxy::MethodInfo_t::kIsCreator;
00356       else
00357          pymeth->fMethodInfo->fFlags &= ~MethodProxy::MethodInfo_t::kIsCreator;
00358 
00359       return 0;
00360    }
00361 
00362 //____________________________________________________________________________
00363    PyObject* mp_getmempolicy( MethodProxy* pymeth, void* )
00364    {
00365       if ( (Bool_t)(pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsHeuristics ) )
00366          return PyInt_FromLong( Utility::kHeuristics );
00367 
00368       if ( (Bool_t)(pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsStrict ) )
00369          return PyInt_FromLong( Utility::kStrict );
00370 
00371       return PyInt_FromLong( -1 );
00372    }
00373 
00374 //____________________________________________________________________________
00375    int mp_setmempolicy( MethodProxy* pymeth, PyObject* value, void* )
00376    {
00377       Long_t mempolicy = PyLong_AsLong( value );
00378       if ( mempolicy == Utility::kHeuristics ) {
00379          pymeth->fMethodInfo->fFlags |= MethodProxy::MethodInfo_t::kIsHeuristics;
00380          pymeth->fMethodInfo->fFlags &= ~MethodProxy::MethodInfo_t::kIsStrict;
00381       } else if ( mempolicy == Utility::kStrict ) {
00382          pymeth->fMethodInfo->fFlags |= MethodProxy::MethodInfo_t::kIsStrict;
00383          pymeth->fMethodInfo->fFlags &= ~MethodProxy::MethodInfo_t::kIsHeuristics;
00384       } else {
00385          PyErr_SetString( PyExc_ValueError,
00386             "expected kMemoryStrict or kMemoryHeuristics as value for _mempolicy" );
00387          return -1;
00388       }
00389 
00390       return 0;
00391    }
00392 
00393 //____________________________________________________________________________
00394    PyObject* mp_getthreaded( MethodProxy* pymeth, void* )
00395    {
00396       return PyInt_FromLong(
00397          (Bool_t)(pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kReleaseGIL) );
00398    }
00399 
00400 //____________________________________________________________________________
00401    int mp_setthreaded( MethodProxy* pymeth, PyObject* value, void* )
00402    {
00403       Long_t isthreaded = PyLong_AsLong( value );
00404       if ( isthreaded == -1 && PyErr_Occurred() ) {
00405          PyErr_SetString( PyExc_ValueError, "a boolean 1 or 0 is required for _creates" );
00406          return -1;
00407       }
00408 
00409       if ( isthreaded )
00410          pymeth->fMethodInfo->fFlags |= MethodProxy::MethodInfo_t::kReleaseGIL;
00411       else
00412          pymeth->fMethodInfo->fFlags &= ~MethodProxy::MethodInfo_t::kReleaseGIL;
00413 
00414       return 0;
00415    }
00416 
00417 //____________________________________________________________________________
00418    PyGetSetDef mp_getset[] = {
00419       { (char*)"__name__",   (getter)mp_name,   NULL, NULL, NULL },
00420       { (char*)"__module__", (getter)mp_module, NULL, NULL, NULL },
00421       { (char*)"__doc__",    (getter)mp_doc,    NULL, NULL, NULL },
00422 
00423    // to be more python-like, where these are duplicated as well; to actually
00424    // derive from the python method or function type is too memory-expensive,
00425    // given that most of the members of those types would not be used
00426       { (char*)"im_func",  (getter)mp_meth_func,  NULL, NULL, NULL },
00427       { (char*)"im_self",  (getter)mp_meth_self,  NULL, NULL, NULL },
00428       { (char*)"im_class", (getter)mp_meth_class, NULL, NULL, NULL },
00429 
00430       { (char*)"func_closure",  (getter)mp_func_closure,  NULL, NULL, NULL },
00431       { (char*)"func_code",     (getter)mp_func_code,     NULL, NULL, NULL },
00432       { (char*)"func_defaults", (getter)mp_func_defaults, NULL, NULL, NULL },
00433       { (char*)"func_globals",  (getter)mp_func_globals,  NULL, NULL, NULL },
00434       { (char*)"func_doc",      (getter)mp_doc,           NULL, NULL, NULL },
00435       { (char*)"func_name",     (getter)mp_name,          NULL, NULL, NULL },
00436 
00437       { (char*)"_creates", (getter)mp_getcreates, (setter)mp_setcreates,
00438             (char*)"For ownership rules of result: if true, objects are python-owned", NULL },
00439       { (char*)"_mempolicy", (getter)mp_getmempolicy, (setter)mp_setmempolicy,
00440             (char*)"For argument ownership rules: like global, either heuristic or strict", NULL },
00441       { (char*)"_threaded", (getter)mp_getthreaded, (setter)mp_setthreaded,
00442             (char*)"If true, releases GIL on call into C++", NULL },
00443       { (char*)NULL, NULL, NULL, NULL, NULL }
00444    };
00445 
00446 //= PyROOT method proxy function behavior ====================================
00447    PyObject* mp_call( MethodProxy* pymeth, PyObject* args, PyObject* kwds )
00448    {
00449    // if called through im_func pseudo-representation (this can be gamed if the
00450    // user really wants to ... )
00451       if ( IsPseudoFunc( pymeth ) )
00452          pymeth->fSelf = NULL;
00453 
00454    // get local handles to proxy internals
00455       MethodProxy::Methods_t&     methods     = pymeth->fMethodInfo->fMethods;
00456       MethodProxy::DispatchMap_t& dispatchMap = pymeth->fMethodInfo->fDispatchMap;
00457 
00458       Int_t nMethods = methods.size();
00459 
00460       Long_t user = 0;
00461       if ( (Bool_t)(pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsHeuristics ) )
00462          user = Utility::kHeuristics;
00463       else if ( (Bool_t)(pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsStrict ) )
00464          user = Utility::kStrict;
00465       else
00466          user = Utility::gMemoryPolicy;
00467 
00468    // simple case
00469       if ( nMethods == 1 ) {
00470          PyObject* result = 0;
00471          if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kReleaseGIL ){
00472             Py_BEGIN_ALLOW_THREADS
00473             result = (*methods[0])( pymeth->fSelf, args, kwds, user );
00474             Py_END_ALLOW_THREADS
00475          } else
00476             result = (*methods[0])( pymeth->fSelf, args, kwds, user );
00477 
00478          return HandleReturn( pymeth, result );
00479       }
00480 
00481    // otherwise, handle overloading
00482       Long_t sighash = HashSignature( args );
00483 
00484    // look for known signatures ...
00485       MethodProxy::DispatchMap_t::iterator m = dispatchMap.find( sighash );
00486       if ( m != dispatchMap.end() ) {
00487          Int_t index = m->second;
00488          PyObject* result = 0;
00489 
00490          if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kReleaseGIL ){
00491             Py_BEGIN_ALLOW_THREADS
00492             result = (*methods[ index ])( pymeth->fSelf, args, kwds, user );
00493             Py_END_ALLOW_THREADS
00494          } else
00495             result = (*methods[ index ])( pymeth->fSelf, args, kwds, user );
00496 
00497          result = HandleReturn( pymeth, result );
00498 
00499          if ( result != 0 )
00500             return result;
00501 
00502       // fall through: python is dynamic, and so, the hashing isn't infallible
00503          PyErr_Clear();
00504       }
00505 
00506    // ... otherwise loop over all methods and find the one that does not fail
00507       if ( ! ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsSorted ) ) {
00508          std::stable_sort( methods.begin(), methods.end(), PriorityCmp );
00509          pymeth->fMethodInfo->fFlags |= MethodProxy::MethodInfo_t::kIsSorted;
00510       }
00511 
00512       std::vector< PyError_t > errors;
00513       for ( Int_t i = 0; i < nMethods; ++i ) {
00514          PyObject* result = 0;
00515 
00516          if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kReleaseGIL ){
00517             Py_BEGIN_ALLOW_THREADS
00518             result = (*methods[i])( pymeth->fSelf, args, kwds, user );
00519             Py_END_ALLOW_THREADS
00520          } else
00521             result = (*methods[i])( pymeth->fSelf, args, kwds, user );
00522 
00523          if ( result == (PyObject*)TPyExceptionMagic ) {
00524             std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
00525             return 0;              // exception info was already set
00526          }
00527 
00528          if ( result != 0 ) {
00529          // success: update the dispatch map for subsequent calls
00530             dispatchMap[ sighash ] = i;
00531             std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
00532             return HandleReturn( pymeth, result );
00533          }
00534 
00535       // failure: collect error message/trace (automatically clears exception, too)
00536          if ( ! PyErr_Occurred() ) {
00537          // this should not happen; set an error to prevent core dump and report
00538             PyObject* sig = methods[i]->GetPrototype();
00539             PyErr_Format( PyExc_SystemError, "%s =>\n    %s",
00540                PyROOT_PyUnicode_AsString( sig ), (char*)"NULL result without error in mp_call" );
00541             Py_DECREF( sig );
00542          }
00543          PyError_t e;
00544          PyErr_Fetch( &e.fType, &e.fValue, &e.fTrace );
00545          errors.push_back( e );
00546       }
00547 
00548    // first summarize, then add details
00549       PyObject* value = PyROOT_PyUnicode_FromFormat(
00550          "none of the %d overloaded methods succeeded. Full details:", nMethods );
00551       PyObject* separator = PyROOT_PyUnicode_FromString( "\n  " );
00552 
00553    // if this point is reached, none of the overloads succeeded: notify user
00554       for ( std::vector< PyError_t >::iterator e = errors.begin(); e != errors.end(); ++e ) {
00555          PyROOT_PyUnicode_Append( &value, separator );
00556          PyROOT_PyUnicode_Append( &value, e->fValue );
00557       }
00558 
00559       Py_DECREF( separator );
00560       std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
00561 
00562    // report failure
00563       PyErr_SetObject( PyExc_TypeError, value );
00564       Py_DECREF( value );
00565       return 0;
00566    }
00567 
00568 //____________________________________________________________________________
00569    MethodProxy* mp_descrget( MethodProxy* pymeth, ObjectProxy* pyobj, PyObject* )
00570    {
00571    // create and use a new method proxy (language requirement)
00572       MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
00573 
00574    // method info is shared, as it contains the collected overload knowledge
00575       *pymeth->fMethodInfo->fRefCount += 1;
00576       newPyMeth->fMethodInfo = pymeth->fMethodInfo;
00577 
00578    // new method is to be bound to current object (may be NULL)
00579       Py_XINCREF( (PyObject*)pyobj );
00580       newPyMeth->fSelf = pyobj;
00581 
00582       return newPyMeth;
00583    }
00584 
00585 
00586 //= PyROOT method proxy construction/destruction =================================
00587    MethodProxy* mp_new( PyTypeObject*, PyObject*, PyObject* )
00588    {
00589       MethodProxy* pymeth = PyObject_GC_New( MethodProxy, &MethodProxy_Type );
00590       pymeth->fSelf = NULL;
00591       pymeth->fMethodInfo = new MethodProxy::MethodInfo_t;
00592 
00593       PyObject_GC_Track( pymeth );
00594       return pymeth;
00595    }
00596 
00597 //____________________________________________________________________________
00598    void mp_dealloc( MethodProxy* pymeth )
00599    {
00600       PyObject_GC_UnTrack( pymeth );
00601 
00602       if ( ! IsPseudoFunc( pymeth ) ) {
00603          Py_XDECREF( (PyObject*)pymeth->fSelf );
00604       }
00605 
00606       pymeth->fSelf = NULL;
00607 
00608       if ( --(*pymeth->fMethodInfo->fRefCount) <= 0 ) {
00609          delete pymeth->fMethodInfo;
00610       }
00611  
00612       PyObject_GC_Del( pymeth );
00613    }
00614 
00615 
00616 //____________________________________________________________________________
00617    long mp_hash( MethodProxy* pymeth )
00618    {
00619    // with fMethodInfo shared, it's address is better suited for the hash
00620       return _Py_HashPointer( pymeth->fMethodInfo );
00621    }
00622 
00623 //____________________________________________________________________________
00624    int mp_traverse( MethodProxy* pymeth, visitproc visit, void* args )
00625    {
00626       if ( pymeth->fSelf && ! IsPseudoFunc( pymeth ) )
00627          return visit( (PyObject*)pymeth->fSelf, args );
00628 
00629       return 0;
00630    }
00631 
00632 //____________________________________________________________________________
00633    int mp_clear( MethodProxy* pymeth )
00634    {
00635       Py_XDECREF( (PyObject*)pymeth->fSelf );
00636       pymeth->fSelf = NULL;
00637 
00638       return 0;
00639    }
00640 
00641 //____________________________________________________________________________
00642    PyObject* mp_richcompare( MethodProxy* self, MethodProxy* other, int op )
00643    {
00644       if ( op != Py_EQ )
00645          return PyType_Type.tp_richcompare( (PyObject*)self, (PyObject*)other, op );
00646 
00647    // defined by type + (shared) MethodInfo + bound self, with special case for fSelf (i.e. pseudo-function)
00648       if ( ( Py_TYPE(self) == Py_TYPE(other) && self->fMethodInfo == other->fMethodInfo ) && \
00649            ( ( IsPseudoFunc( self ) && IsPseudoFunc( other ) ) || self->fSelf == other->fSelf ) ) {
00650          Py_INCREF( Py_True );
00651          return Py_True;
00652       }
00653       Py_INCREF( Py_False );
00654       return Py_False;
00655    }
00656 
00657 
00658 //= PyROOT method proxy access to internals =================================
00659    PyObject* mp_disp( MethodProxy* pymeth, PyObject* sigarg )
00660    {
00661       if ( ! PyROOT_PyUnicode_Check( sigarg ) ) {
00662          PyErr_Format( PyExc_TypeError, "disp() argument 1 must be string, not %.50s",
00663                        sigarg == Py_None ? "None" : Py_TYPE(sigarg)->tp_name );
00664          return 0;
00665       }
00666 
00667       PyObject* sig1 = PyROOT_PyUnicode_FromFormat( "(%s)", PyROOT_PyUnicode_AsString( sigarg ) );
00668 
00669       MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;
00670       for ( Int_t i = 0; i < (Int_t)methods.size(); ++i ) {
00671 
00672          PyObject* sig2 = methods[ i ]->GetSignature();
00673          if ( PyObject_RichCompareBool( sig1, sig2, Py_EQ ) ) {
00674             Py_DECREF( sig2 );
00675 
00676             MethodProxy* newmeth = mp_new( NULL, NULL, NULL );
00677             MethodProxy::Methods_t vec; vec.push_back( methods[ i ]->Clone() );
00678             newmeth->Set( pymeth->fMethodInfo->fName, vec );
00679 
00680             if ( pymeth->fSelf && ! IsPseudoFunc( pymeth ) ) {
00681                Py_INCREF( pymeth->fSelf );
00682                newmeth->fSelf = pymeth->fSelf;
00683             }
00684 
00685             Py_DECREF( sig1 );
00686             return (PyObject*)newmeth;
00687          }
00688 
00689          Py_DECREF( sig2 );
00690       }
00691 
00692       Py_DECREF( sig1 );
00693       PyErr_Format( PyExc_LookupError, "signature \"%s\" not found", PyROOT_PyUnicode_AsString( sigarg ) );
00694       return 0;
00695    }
00696 
00697 //____________________________________________________________________________
00698    PyMethodDef mp_methods[] = {
00699       { (char*)"disp", (PyCFunction)mp_disp, METH_O, (char*)"select overload for dispatch" },
00700       { (char*)NULL, NULL, 0, NULL }
00701    };
00702 
00703 } // unnamed namespace
00704 
00705 
00706 //= PyROOT method proxy type =================================================
00707 PyTypeObject MethodProxy_Type = {
00708    PyVarObject_HEAD_INIT( &PyType_Type, 0 )
00709    (char*)"ROOT.MethodProxy", // tp_name
00710    sizeof(MethodProxy),       // tp_basicsize
00711    0,                         // tp_itemsize
00712    (destructor)mp_dealloc,    // tp_dealloc
00713    0,                         // tp_print
00714    0,                         // tp_getattr
00715    0,                         // tp_setattr
00716    0,                         // tp_compare
00717    0,                         // tp_repr
00718    0,                         // tp_as_number
00719    0,                         // tp_as_sequence
00720    0,                         // tp_as_mapping
00721    (hashfunc)mp_hash,         // tp_hash
00722    (ternaryfunc)mp_call,      // tp_call
00723    0,                         // tp_str
00724    0,                         // tp_getattro
00725    0,                         // tp_setattro
00726    0,                         // tp_as_buffer
00727    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,      // tp_flags
00728    (char*)"PyROOT method proxy (internal)",      // tp_doc
00729    (traverseproc)mp_traverse, // tp_traverse
00730    (inquiry)mp_clear,         // tp_clear
00731    (richcmpfunc)mp_richcompare,                  // tp_richcompare
00732    0,                         // tp_weaklistoffset
00733    0,                         // tp_iter
00734    0,                         // tp_iternext
00735    mp_methods,                // tp_methods
00736    0,                         // tp_members
00737    mp_getset,                 // tp_getset
00738    0,                         // tp_base
00739    0,                         // tp_dict
00740    (descrgetfunc)mp_descrget, // tp_descr_get
00741    0,                         // tp_descr_set
00742    0,                         // tp_dictoffset
00743    0,                         // tp_init
00744    0,                         // tp_alloc
00745    (newfunc)mp_new,           // tp_new
00746    0,                         // tp_free
00747    0,                         // tp_is_gc
00748    0,                         // tp_bases
00749    0,                         // tp_mro
00750    0,                         // tp_cache
00751    0,                         // tp_subclasses
00752    0                          // tp_weaklist
00753 #if PY_VERSION_HEX >= 0x02030000
00754    , 0                        // tp_del
00755 #endif
00756 #if PY_VERSION_HEX >= 0x02060000
00757    , 0                        // tp_version_tag
00758 #endif
00759 };
00760 
00761 } // namespace PyROOT
00762 
00763 
00764 //- public members -----------------------------------------------------------
00765 void PyROOT::MethodProxy::Set( const std::string& name, std::vector< PyCallable* >& methods )
00766 {
00767 // set method data
00768    fMethodInfo->fName = name;
00769    fMethodInfo->fMethods.swap( methods );
00770    fMethodInfo->fFlags &= ~MethodInfo_t::kIsSorted;
00771 
00772 // special case: all constructors are considered creators by default
00773    if ( name == "__init__" )
00774       fMethodInfo->fFlags |= (MethodInfo_t::kIsCreator | MethodInfo_t::kIsConstructor);
00775 
00776 // special case, in heuristics mode also tag *Clone* methods as creators
00777    if ( Utility::gMemoryPolicy == Utility::kHeuristics && name.find( "Clone" ) != std::string::npos )
00778       fMethodInfo->fFlags |= MethodInfo_t::kIsCreator;
00779 }
00780 
00781 //____________________________________________________________________________
00782 void PyROOT::MethodProxy::AddMethod( PyCallable* pc )
00783 {
00784    fMethodInfo->fFlags &= ~MethodInfo_t::kIsSorted;
00785    fMethodInfo->fMethods.push_back( pc );
00786 }
00787       
00788 //____________________________________________________________________________
00789 void PyROOT::MethodProxy::AddMethod( MethodProxy* meth )
00790 {
00791     fMethodInfo->fMethods.insert( fMethodInfo->fMethods.end(),
00792        meth->fMethodInfo->fMethods.begin(), meth->fMethodInfo->fMethods.end() );
00793 }
00794 
00795 //____________________________________________________________________________
00796 PyROOT::MethodProxy::MethodInfo_t::~MethodInfo_t()
00797 {
00798    for ( Methods_t::iterator it = fMethods.begin(); it != fMethods.end(); ++it ) {
00799       delete *it;
00800    }
00801    fMethods.clear();
00802    delete fRefCount;
00803 }

Generated on Tue Jul 5 14:10:13 2011 for ROOT_528-00b_version by  doxygen 1.5.1