00001
00002
00003
00004
00005 #include "PyROOT.h"
00006 #include "structmember.h"
00007 #if PY_VERSION_HEX >= 0x02050000
00008 #include "code.h"
00009 #else
00010 #include "compile.h"
00011 #endif
00012 #ifndef CO_NOFREE
00013
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
00023 #include <algorithm>
00024 #include <functional>
00025 #include <vector>
00026 #include <algorithm>
00027
00028
00029 namespace PyROOT {
00030
00031 namespace {
00032
00033
00034 bool inline IsPseudoFunc( MethodProxy* pymeth )
00035 {
00036 return (void*)pymeth == (void*)pymeth->fSelf;
00037 }
00038
00039
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
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
00069 int PriorityCmp( PyCallable* left, PyCallable* right )
00070 {
00071 return left->GetPriority() > right->GetPriority();
00072 }
00073
00074
00075 inline PyObject* HandleReturn( MethodProxy* pymeth, PyObject* result ) {
00076
00077
00078 if ( result == (PyObject*)TPyExceptionMagic )
00079 return 0;
00080
00081
00082 if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsCreator ) {
00083
00084
00085 if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsConstructor ) {
00086 if ( pymeth->fSelf )
00087 pymeth->fSelf->HoldOn();
00088 }
00089
00090
00091 else if ( ObjectProxy_Check( result ) )
00092 ((ObjectProxy*)result)->HoldOn();
00093 }
00094
00095
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();
00101 }
00102 }
00103
00104 return result;
00105 }
00106
00107
00108
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* , 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
00127 Int_t nMethods = methods.size();
00128 PyObject* doc = methods[0]->GetDocString();
00129
00130
00131 if ( nMethods == 1 )
00132 return doc;
00133
00134
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
00149 MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
00150
00151
00152 *pymeth->fMethodInfo->fRefCount += 1;
00153 newPyMeth->fMethodInfo = pymeth->fMethodInfo;
00154
00155
00156
00157 newPyMeth->fSelf = (ObjectProxy*)newPyMeth;
00158
00159 return (PyObject*)newPyMeth;
00160 }
00161
00162
00163 PyObject* mp_meth_self( MethodProxy* pymeth, void* )
00164 {
00165
00166
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
00184
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* , 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
00211
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;
00221
00222
00223 PyObject* co_code = PyString_FromStringAndSize( "d\x00\x00S", 4 );
00224
00225
00226
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
00239 PyObject* co_unused = PyTuple_New( 0 );
00240
00241
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
00250 PyObject* co_filename = PyString_FromString( "ROOT.py" );
00251
00252
00253 PyObject* co_name = PyString_FromString( pymeth->GetName().c_str() );
00254
00255
00256
00257
00258
00259 PyObject* co_lnotab = PyString_FromString( "\x00\x01\x0c\x01" );
00260
00261 PyObject* code = (PyObject*)PyCode_New(
00262 co_argcount,
00263 co_argcount + 1,
00264 2,
00265 CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE,
00266 co_code,
00267 co_consts,
00268 co_names,
00269 co_varnames,
00270 co_unused,
00271 co_unused,
00272 co_filename,
00273 co_name,
00274 1,
00275 co_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
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
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* , void* )
00325 {
00326
00327
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 ) {
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
00424
00425
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
00447 PyObject* mp_call( MethodProxy* pymeth, PyObject* args, PyObject* kwds )
00448 {
00449
00450
00451 if ( IsPseudoFunc( pymeth ) )
00452 pymeth->fSelf = NULL;
00453
00454
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
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
00482 Long_t sighash = HashSignature( args );
00483
00484
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
00503 PyErr_Clear();
00504 }
00505
00506
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;
00526 }
00527
00528 if ( result != 0 ) {
00529
00530 dispatchMap[ sighash ] = i;
00531 std::for_each( errors.begin(), errors.end(), PyError_t::Clear );
00532 return HandleReturn( pymeth, result );
00533 }
00534
00535
00536 if ( ! PyErr_Occurred() ) {
00537
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
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
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
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
00572 MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );
00573
00574
00575 *pymeth->fMethodInfo->fRefCount += 1;
00576 newPyMeth->fMethodInfo = pymeth->fMethodInfo;
00577
00578
00579 Py_XINCREF( (PyObject*)pyobj );
00580 newPyMeth->fSelf = pyobj;
00581
00582 return newPyMeth;
00583 }
00584
00585
00586
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
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
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
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 }
00704
00705
00706
00707 PyTypeObject MethodProxy_Type = {
00708 PyVarObject_HEAD_INIT( &PyType_Type, 0 )
00709 (char*)"ROOT.MethodProxy",
00710 sizeof(MethodProxy),
00711 0,
00712 (destructor)mp_dealloc,
00713 0,
00714 0,
00715 0,
00716 0,
00717 0,
00718 0,
00719 0,
00720 0,
00721 (hashfunc)mp_hash,
00722 (ternaryfunc)mp_call,
00723 0,
00724 0,
00725 0,
00726 0,
00727 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
00728 (char*)"PyROOT method proxy (internal)",
00729 (traverseproc)mp_traverse,
00730 (inquiry)mp_clear,
00731 (richcmpfunc)mp_richcompare,
00732 0,
00733 0,
00734 0,
00735 mp_methods,
00736 0,
00737 mp_getset,
00738 0,
00739 0,
00740 (descrgetfunc)mp_descrget,
00741 0,
00742 0,
00743 0,
00744 0,
00745 (newfunc)mp_new,
00746 0,
00747 0,
00748 0,
00749 0,
00750 0,
00751 0,
00752 0
00753 #if PY_VERSION_HEX >= 0x02030000
00754 , 0
00755 #endif
00756 #if PY_VERSION_HEX >= 0x02060000
00757 , 0
00758 #endif
00759 };
00760
00761 }
00762
00763
00764
00765 void PyROOT::MethodProxy::Set( const std::string& name, std::vector< PyCallable* >& methods )
00766 {
00767
00768 fMethodInfo->fName = name;
00769 fMethodInfo->fMethods.swap( methods );
00770 fMethodInfo->fFlags &= ~MethodInfo_t::kIsSorted;
00771
00772
00773 if ( name == "__init__" )
00774 fMethodInfo->fFlags |= (MethodInfo_t::kIsCreator | MethodInfo_t::kIsConstructor);
00775
00776
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 }