Utility.cxx

Go to the documentation of this file.
00001 // @(#)root/pyroot:$Id: Utility.cxx 38130 2011-02-18 03:46:16Z wlav $
00002 // Author: Wim Lavrijsen, Apr 2004
00003 
00004 // Bindings
00005 #include "PyROOT.h"
00006 #include "PyStrings.h"
00007 #include "Utility.h"
00008 #include "ObjectProxy.h"
00009 #include "MethodProxy.h"
00010 #include "FunctionHolder.h"
00011 #include "TCustomPyTypes.h"
00012 #include "RootWrapper.h"
00013 #include "PyCallable.h"
00014 #include "Adapters.h"
00015 
00016 // ROOT
00017 #include "TROOT.h"
00018 #include "TObject.h"
00019 #include "TClassEdit.h"
00020 #include "TClassRef.h"
00021 #include "TCollection.h"
00022 #include "TFunction.h"
00023 #include "TMethodArg.h"
00024 #include "TError.h"
00025 
00026 // CINT
00027 #include "Api.h"
00028 
00029 // Standard
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <algorithm>
00034 #include <list>
00035 #include <utility>
00036 
00037 
00038 //- data _____________________________________________________________________
00039 PyROOT::DictLookup_t PyROOT::gDictLookupOrg = 0;
00040 Bool_t PyROOT::gDictLookupActive = kFALSE;
00041 
00042 PyROOT::Utility::EMemoryPolicy PyROOT::Utility::gMemoryPolicy = PyROOT::Utility::kHeuristics;
00043 
00044 // this is just a data holder for linking; actual value is set in RootModule.cxx
00045 PyROOT::Utility::ESignalPolicy PyROOT::Utility::gSignalPolicy = PyROOT::Utility::kSafe;
00046 
00047 typedef std::map< std::string, std::string > TC2POperatorMapping_t;
00048 static TC2POperatorMapping_t gC2POperatorMapping;
00049 
00050 namespace {
00051 
00052    using namespace PyROOT::Utility;
00053 
00054    struct InitOperatorMapping_t {
00055    public:
00056       InitOperatorMapping_t() {
00057          // gC2POperatorMapping[ "[]" ]  = "__setitem__";   // depends on return type
00058          // gC2POperatorMapping[ "+" ]   = "__add__";       // depends on # of args (see __pos__)
00059          // gC2POperatorMapping[ "-" ]   = "__sub__";       // id. (eq. __neg__)
00060          // gC2POperatorMapping[ "*" ]   = "__mul__";       // double meaning in C++
00061 
00062          gC2POperatorMapping[ "[]" ]  = "__getitem__";
00063          gC2POperatorMapping[ "()" ]  = "__call__";
00064          gC2POperatorMapping[ "/" ]   = PYROOT__div__;
00065          gC2POperatorMapping[ "%" ]   = "__mod__";
00066          gC2POperatorMapping[ "**" ]  = "__pow__";
00067          gC2POperatorMapping[ "<<" ]  = "__lshift__";
00068          gC2POperatorMapping[ ">>" ]  = "__rshift__";
00069          gC2POperatorMapping[ "&" ]   = "__and__";
00070          gC2POperatorMapping[ "|" ]   = "__or__";
00071          gC2POperatorMapping[ "^" ]   = "__xor__";
00072          gC2POperatorMapping[ "~" ]   = "__inv__";
00073          gC2POperatorMapping[ "+=" ]  = "__iadd__";
00074          gC2POperatorMapping[ "-=" ]  = "__isub__";
00075          gC2POperatorMapping[ "*=" ]  = "__imul__";
00076          gC2POperatorMapping[ "/=" ]  = PYROOT__idiv__;
00077          gC2POperatorMapping[ "%=" ]  = "__imod__";
00078          gC2POperatorMapping[ "**=" ] = "__ipow__";
00079          gC2POperatorMapping[ "<<=" ] = "__ilshift__";
00080          gC2POperatorMapping[ ">>=" ] = "__irshift__";
00081          gC2POperatorMapping[ "&=" ]  = "__iand__";
00082          gC2POperatorMapping[ "|=" ]  = "__ior__";
00083          gC2POperatorMapping[ "^=" ]  = "__ixor__";
00084          gC2POperatorMapping[ "==" ]  = "__eq__";
00085          gC2POperatorMapping[ "!=" ]  = "__ne__";
00086          gC2POperatorMapping[ ">" ]   = "__gt__";
00087          gC2POperatorMapping[ "<" ]   = "__lt__";
00088          gC2POperatorMapping[ ">=" ]  = "__ge__";
00089          gC2POperatorMapping[ "<=" ]  = "__le__";
00090 
00091       // the following type mappings are "exact"
00092          gC2POperatorMapping[ "const char*" ] = "__str__";
00093          gC2POperatorMapping[ "char*" ]       = "__str__";
00094          gC2POperatorMapping[ "int" ]         = "__int__";
00095          gC2POperatorMapping[ "long" ]        = PYROOT__long__;
00096          gC2POperatorMapping[ "double" ]      = "__float__";
00097 
00098       // the following type mappings are "okay"; the assumption is that they
00099       // are not mixed up with the ones above or between themselves (and if
00100       // they are, that it is done consistently)
00101          gC2POperatorMapping[ "short" ]              = "__int__";
00102          gC2POperatorMapping[ "unsigned short" ]     = "__int__";
00103          gC2POperatorMapping[ "unsigned int" ]       = PYROOT__long__;
00104          gC2POperatorMapping[ "unsigned long" ]      = PYROOT__long__;
00105          gC2POperatorMapping[ "long long" ]          = PYROOT__long__;
00106          gC2POperatorMapping[ "unsigned long long" ] = PYROOT__long__;
00107          gC2POperatorMapping[ "float" ]              = "__float__";
00108 
00109          gC2POperatorMapping[ "->" ]  = "__follow__";       // not an actual python operator
00110          gC2POperatorMapping[ "=" ]   = "__assign__";       // id.
00111 
00112 #if PY_VERSION_HEX < 0x03000000
00113          gC2POperatorMapping[ "bool" ] = "__nonzero__";
00114 #else
00115          gC2POperatorMapping[ "bool" ] = "__bool__";
00116 #endif
00117       }
00118    } initOperatorMapping_;
00119 
00120 // for keeping track of callbacks for CINT-installed methods into python:
00121    typedef std::pair< PyObject*, Long_t > CallInfo_t;
00122    std::map< int, CallInfo_t > s_PyObjectCallbacks;
00123 
00124 } // unnamed namespace
00125 
00126 
00127 //- public functions ---------------------------------------------------------
00128 ULong_t PyROOT::PyLongOrInt_AsULong( PyObject* pyobject )
00129 {
00130 // convert <pybject> to C++ unsigned long, with bounds checking, allow int -> ulong
00131    ULong_t ul = PyLong_AsUnsignedLong( pyobject );
00132    if ( PyErr_Occurred() && PyInt_Check( pyobject ) ) {
00133       PyErr_Clear();
00134       Long_t i = PyInt_AS_LONG( pyobject );
00135       if ( 0 <= i ) {
00136          ul = (ULong_t)i;
00137       } else {
00138          PyErr_SetString( PyExc_ValueError,
00139             "can\'t convert negative value to unsigned long" );
00140       }
00141    }
00142 
00143    return ul;
00144 }
00145 
00146 //____________________________________________________________________________
00147 ULong64_t PyROOT::PyLongOrInt_AsULong64( PyObject* pyobject )
00148 {
00149 // convert <pyobject> to C++ unsigned long long, with bounds checking
00150    ULong64_t ull = PyLong_AsUnsignedLongLong( pyobject );
00151    if ( PyErr_Occurred() && PyInt_Check( pyobject ) ) {
00152       PyErr_Clear();
00153       Long_t i = PyInt_AS_LONG( pyobject );
00154       if ( 0 <= i ) {
00155          ull = (ULong64_t)i;
00156       } else {
00157          PyErr_SetString( PyExc_ValueError,
00158             "can\'t convert negative value to unsigned long long" );
00159       }
00160    }
00161 
00162    return ull;
00163 }
00164 
00165 //____________________________________________________________________________
00166 Bool_t PyROOT::Utility::SetMemoryPolicy( EMemoryPolicy e )
00167 {
00168    if ( kHeuristics <= e && e <= kStrict ) {
00169       gMemoryPolicy = e;
00170       return kTRUE;
00171    }
00172    return kFALSE;
00173 }
00174 
00175 //____________________________________________________________________________
00176 Bool_t PyROOT::Utility::SetSignalPolicy( ESignalPolicy e )
00177 {
00178    if ( kFast <= e && e <= kSafe ) {
00179       gSignalPolicy = e;
00180       return kTRUE;
00181    }
00182    return kFALSE;
00183 }
00184 
00185 //____________________________________________________________________________
00186 Bool_t PyROOT::Utility::AddToClass(
00187       PyObject* pyclass, const char* label, PyCFunction cfunc, int flags )
00188 {
00189 // use list for clean-up (.so's are unloaded only at interpreter shutdown)
00190    static std::list< PyMethodDef > s_pymeths;
00191 
00192    s_pymeths.push_back( PyMethodDef() );
00193    PyMethodDef* pdef = &s_pymeths.back();
00194    pdef->ml_name  = const_cast< char* >( label );
00195    pdef->ml_meth  = cfunc;
00196    pdef->ml_flags = flags;
00197    pdef->ml_doc   = NULL;
00198 
00199    PyObject* func = PyCFunction_New( pdef, NULL );
00200    PyObject* method = TCustomInstanceMethod_New( func, NULL, pyclass );
00201    Bool_t isOk = PyObject_SetAttrString( pyclass, pdef->ml_name, method ) == 0;
00202    Py_DECREF( method );
00203    Py_DECREF( func );
00204 
00205    if ( PyErr_Occurred() )
00206       return kFALSE;
00207 
00208    if ( ! isOk ) {
00209       PyErr_Format( PyExc_TypeError, "could not add method %s", label );
00210       return kFALSE;
00211    }
00212 
00213    return kTRUE;
00214 }
00215 
00216 //____________________________________________________________________________
00217 Bool_t PyROOT::Utility::AddToClass( PyObject* pyclass, const char* label, const char* func )
00218 {
00219    PyObject* pyfunc = PyObject_GetAttrString( pyclass, const_cast< char* >( func ) );
00220    if ( ! pyfunc )
00221       return kFALSE;
00222 
00223    Bool_t isOk = PyObject_SetAttrString( pyclass, const_cast< char* >( label ), pyfunc ) == 0;
00224 
00225    Py_DECREF( pyfunc );
00226    return isOk;
00227 }
00228 
00229 //____________________________________________________________________________
00230 Bool_t PyROOT::Utility::AddToClass( PyObject* pyclass, const char* label, PyCallable* pyfunc )
00231 {
00232    MethodProxy* method =
00233       (MethodProxy*)PyObject_GetAttrString( pyclass, const_cast< char* >( label ) );
00234 
00235    if ( ! method || ! MethodProxy_Check( method ) ) {
00236    // not adding to existing MethodProxy; add callable directly to the class
00237       if ( PyErr_Occurred() )
00238          PyErr_Clear();
00239       Py_XDECREF( (PyObject*)method );
00240       method = MethodProxy_New( label, pyfunc );
00241       Bool_t isOk = PyObject_SetAttrString( pyclass, const_cast< char* >( label ), (PyObject*)method ) == 0;
00242       Py_DECREF( method );
00243       return isOk;
00244    }
00245 
00246    method->AddMethod( pyfunc );
00247 
00248    Py_DECREF( method );
00249    return kTRUE;
00250 }
00251 
00252 //____________________________________________________________________________
00253 Bool_t PyROOT::Utility::AddUsingToClass( PyObject* pyclass, const char* method )
00254 {
00255 // helper to add base class methods to the derived class one (this covers the
00256 // 'using' cases, which the dictionary does not provide)
00257 
00258    MethodProxy* derivedMethod =
00259          (MethodProxy*)PyObject_GetAttrString( pyclass, const_cast< char* >( method ) );
00260    if ( ! MethodProxy_Check( derivedMethod ) ) {
00261       Py_XDECREF( derivedMethod );
00262       return kFALSE;
00263    }
00264 
00265    PyObject* mro = PyObject_GetAttr( pyclass, PyStrings::gMRO );
00266    if ( ! mro || ! PyTuple_Check( mro ) ) {
00267       Py_XDECREF( mro );
00268       Py_DECREF( derivedMethod );
00269       return kFALSE;
00270    }
00271 
00272    MethodProxy* baseMethod = 0;
00273    for ( int i = 1; i < PyTuple_GET_SIZE( mro ); ++i ) {
00274       baseMethod = (MethodProxy*)PyObject_GetAttrString(
00275          PyTuple_GET_ITEM( mro, i ), const_cast< char* >( method ) );
00276 
00277       if ( ! baseMethod ) {
00278          PyErr_Clear();
00279          continue;
00280       }
00281 
00282       if ( MethodProxy_Check( baseMethod ) )
00283          break;
00284 
00285       Py_DECREF( baseMethod );
00286       baseMethod = 0;
00287    }
00288 
00289    Py_DECREF( mro );
00290 
00291    if ( ! MethodProxy_Check( baseMethod ) ) {
00292       Py_XDECREF( baseMethod );
00293       Py_DECREF( derivedMethod );
00294       return kFALSE;
00295    }
00296 
00297    derivedMethod->AddMethod( baseMethod );
00298 
00299    Py_DECREF( baseMethod );
00300    Py_DECREF( derivedMethod );
00301 
00302    return kTRUE;
00303 }
00304 
00305 //____________________________________________________________________________
00306 Bool_t PyROOT::Utility::AddBinaryOperator(
00307    PyObject* left, PyObject* right, const char* op, const char* label )
00308 {
00309 // install the named operator (op) into the left object's class if such a function
00310 // exists as a global overload; a label must be given if the operator is not in
00311 // gC2POperatorMapping (i.e. if it is ambiguous at the member level)
00312 
00313 // this should be a given, nevertheless ...
00314    if ( ! ObjectProxy_Check( left ) )
00315       return kFALSE;
00316 
00317 // retrieve the class names to match the signature of any found global functions
00318    std::string rcname = ClassName( right );
00319    std::string lcname = ClassName( left );
00320    PyObject* pyclass = PyObject_GetAttr( left, PyStrings::gClass );
00321 
00322    Bool_t result = AddBinaryOperator( pyclass, lcname, rcname, op, label );
00323 
00324    Py_DECREF( pyclass );
00325    return result;
00326 }
00327 
00328 //____________________________________________________________________________
00329 Bool_t PyROOT::Utility::AddBinaryOperator( PyObject* pyclass, const char* op, const char* label )
00330 {
00331 // install binary operator op in pyclass, working on two instances of pyclass
00332    PyObject* pyname = PyObject_GetAttr( pyclass, PyStrings::gName );
00333    std::string cname = TClassEdit::ResolveTypedef( PyROOT_PyUnicode_AsString( pyname ) );
00334    Py_DECREF( pyname ); pyname = 0;
00335 
00336    return AddBinaryOperator( pyclass, cname, cname, op, label );
00337 }
00338 
00339 //____________________________________________________________________________
00340 static inline TFunction* FindAndAddOperator( const std::string& lcname, const std::string& rcname,
00341      const char* op, TCollection* funcs ) {
00342 // helper to find a function with matching signature in 'funcs'
00343    std::string opname = "operator";
00344    opname += op;
00345 
00346    TIter ifunc( funcs );
00347 
00348    TFunction* func = 0;
00349    while ( (func = (TFunction*)ifunc.Next()) ) {
00350       if ( func->GetListOfMethodArgs()->GetSize() != 2 )
00351          continue;
00352 
00353       if ( func->GetName() == opname ) {
00354          if ( ( lcname == TClassEdit::ResolveTypedef( TClassEdit::CleanType(
00355                   ((TMethodArg*)func->GetListOfMethodArgs()->At(0))->GetTypeName(), 1 ).c_str(), true ) ) &&
00356               ( rcname == TClassEdit::ResolveTypedef( TClassEdit::CleanType(
00357                   ((TMethodArg*)func->GetListOfMethodArgs()->At(1))->GetTypeName(), 1 ).c_str(), true ) ) ) {
00358 
00359          // done; break out loop
00360             return func;
00361          }
00362 
00363       }
00364    }
00365 
00366    return 0;
00367 }
00368 
00369 Bool_t PyROOT::Utility::AddBinaryOperator( PyObject* pyclass, const std::string& lcname,
00370    const std::string& rcname, const char* op, const char* label )
00371 {
00372 // find a global function with a matching signature and install the result on pyclass;
00373 // in addition, __gnu_cxx is searched pro-actively (as there's AFAICS no way to unearth
00374 // using information)
00375    static TClassRef gnucxx( "__gnu_cxx" );
00376 
00377    TFunction* func = 0;
00378    if ( gnucxx.GetClass() ) {
00379       func = FindAndAddOperator( lcname, rcname, op, gnucxx->GetListOfMethods() );
00380       if ( func ) {
00381          PyCallable* pyfunc = new TFunctionHolder< TScopeAdapter, TMemberAdapter >(
00382             TScopeAdapter::ByName( "__gnu_cxx" ), func );
00383          return Utility::AddToClass( pyclass, label ? label : gC2POperatorMapping[ op ].c_str(), pyfunc );
00384       }
00385    }
00386 
00387    if ( ! func )
00388       func = FindAndAddOperator( lcname, rcname, op, gROOT->GetListOfGlobalFunctions( kTRUE ) );
00389 
00390    if ( func ) {
00391    // found a matching overload; add to class
00392       PyCallable* pyfunc = new TFunctionHolder< TScopeAdapter, TMemberAdapter >( func );
00393       return Utility::AddToClass( pyclass, label ? label : gC2POperatorMapping[ op ].c_str(), pyfunc );
00394    }
00395 
00396    return kFALSE;
00397 }
00398 
00399 //____________________________________________________________________________
00400 Bool_t PyROOT::Utility::BuildTemplateName( PyObject*& pyname, PyObject* args, int argoff )
00401 {
00402 // helper to construct the "< type, type, ... >" part of a templated name (either
00403 // for a class as in MakeRootTemplateClass in RootModule.cxx) or for method lookup
00404 // (as in TemplatedMemberHook, below)
00405 
00406    PyROOT_PyUnicode_AppendAndDel( &pyname, PyROOT_PyUnicode_FromString( "<" ) );
00407 
00408    Py_ssize_t nArgs = PyTuple_GET_SIZE( args );
00409    for ( int i = argoff; i < nArgs; ++i ) {
00410    // add type as string to name
00411       PyObject* tn = PyTuple_GET_ITEM( args, i );
00412       if ( PyROOT_PyUnicode_Check( tn ) )
00413          PyROOT_PyUnicode_Append( &pyname, tn );
00414       else if ( PyObject_HasAttr( tn, PyStrings::gName ) ) {
00415       // this works for type objects
00416          PyObject* tpName = PyObject_GetAttr( tn, PyStrings::gName );
00417 
00418       // special case for strings
00419          if ( strcmp( PyROOT_PyUnicode_AsString( tpName ), "str" ) == 0 ) {
00420             Py_DECREF( tpName );
00421             tpName = PyROOT_PyUnicode_FromString( "std::string" );
00422          }
00423 
00424          PyROOT_PyUnicode_AppendAndDel( &pyname, tpName );
00425       } else {
00426       // last ditch attempt, works for things like int values
00427          PyObject* pystr = PyObject_Str( tn );
00428          if ( ! pystr ) {
00429             return kFALSE;
00430          }
00431 
00432          PyROOT_PyUnicode_AppendAndDel( &pyname, pystr );
00433       }
00434 
00435    // add a comma, as needed
00436       if ( i != nArgs - 1 )
00437          PyROOT_PyUnicode_AppendAndDel( &pyname, PyROOT_PyUnicode_FromString( "," ) );
00438    }
00439 
00440 // close template name; prevent '>>', which should be '> >'
00441    if ( PyROOT_PyUnicode_AsString( pyname )[ PyROOT_PyUnicode_GetSize( pyname ) - 1 ] == '>' )
00442       PyROOT_PyUnicode_AppendAndDel( &pyname, PyROOT_PyUnicode_FromString( " >" ) );
00443    else
00444       PyROOT_PyUnicode_AppendAndDel( &pyname, PyROOT_PyUnicode_FromString( ">" ) );
00445 
00446    return kTRUE;
00447 }
00448 
00449 //____________________________________________________________________________
00450 Bool_t PyROOT::Utility::InitProxy( PyObject* module, PyTypeObject* pytype, const char* name )
00451 {
00452 // finalize proxy type
00453    if ( PyType_Ready( pytype ) < 0 )
00454       return kFALSE;
00455 
00456 // add proxy type to the given (ROOT) module
00457    Py_INCREF( pytype );         // PyModule_AddObject steals reference
00458    if ( PyModule_AddObject( module, (char*)name, (PyObject*)pytype ) < 0 ) {
00459       Py_DECREF( pytype );
00460       return kFALSE;
00461    }
00462 
00463 // declare success
00464    return kTRUE;
00465 }
00466 
00467 //____________________________________________________________________________
00468 int PyROOT::Utility::GetBuffer( PyObject* pyobject, char tc, int size, void*& buf, Bool_t check )
00469 {
00470 // special case: don't handle character strings here (yes, they're buffers, but not quite)
00471    if ( PyBytes_Check( pyobject ) )
00472       return 0;
00473 
00474 // attempt to retrieve pointer to buffer interface
00475    PyBufferProcs* bufprocs = Py_TYPE(pyobject)->tp_as_buffer;
00476 
00477    PySequenceMethods* seqmeths = Py_TYPE(pyobject)->tp_as_sequence;
00478    if ( seqmeths != 0 && bufprocs != 0
00479 #if  PY_VERSION_HEX < 0x03000000
00480         && bufprocs->bf_getwritebuffer != 0
00481         && (*(bufprocs->bf_getsegcount))( pyobject, 0 ) == 1
00482 #else
00483         && bufprocs->bf_getbuffer != 0
00484 #endif
00485       ) {
00486 
00487    // get the buffer
00488 #if PY_VERSION_HEX < 0x03000000
00489       Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))( pyobject, 0, &buf );
00490 #else
00491       Py_buffer bufinfo;
00492       (*(bufprocs->bf_getbuffer))( pyobject, &bufinfo, PyBUF_WRITABLE );
00493       buf = (char*)bufinfo.buf;
00494       Py_ssize_t buflen = bufinfo.len;
00495 #endif
00496 
00497       if ( check == kTRUE ) {
00498       // determine buffer compatibility (use "buf" as a status flag)
00499          PyObject* pytc = PyObject_GetAttr( pyobject, PyStrings::gTypeCode );
00500          if ( pytc != 0 ) {     // for array objects
00501             if ( PyROOT_PyUnicode_AsString( pytc )[0] != tc )
00502                buf = 0;         // no match
00503             Py_DECREF( pytc );
00504          } else if ( seqmeths->sq_length &&
00505                      (int)(buflen / (*(seqmeths->sq_length))( pyobject )) == size ) {
00506          // this is a gamble ... may or may not be ok, but that's for the user
00507             PyErr_Clear();
00508          } else if ( buflen == size ) {
00509          // also a gamble, but at least 1 item will fit into the buffer, so very likely ok ...
00510             PyErr_Clear();
00511          } else {
00512             buf = 0;                      // not compatible
00513 
00514          // clarify error message
00515             PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
00516             PyErr_Fetch( &pytype, &pyvalue, &pytrace );
00517             PyObject* pyvalue2 = PyROOT_PyUnicode_FromFormat(
00518                (char*)"%s and given element size (%ld) do not match needed (%d)",
00519                PyROOT_PyUnicode_AsString( pyvalue ),
00520                seqmeths->sq_length ? (long)(buflen / (*(seqmeths->sq_length))( pyobject )) : (long)buflen,
00521                size );
00522             Py_DECREF( pyvalue );
00523             PyErr_Restore( pytype, pyvalue2, pytrace );
00524          }
00525       }
00526 
00527       return buflen;
00528    }
00529 
00530    return 0;
00531 }
00532 
00533 //____________________________________________________________________________
00534 std::string PyROOT::Utility::MapOperatorName( const std::string& name, Bool_t bTakesParams )
00535 {
00536 // map the given C++ operator name on the python equivalent
00537 
00538    if ( 8 < name.size() && name.substr( 0, 8 ) == "operator" ) {
00539       std::string op = name.substr( 8, std::string::npos );
00540 
00541    // stripping ...
00542       std::string::size_type start = 0, end = op.size();
00543       while ( start < end && isspace( op[ start ] ) ) ++start;
00544       while ( start < end && isspace( op[ end-1 ] ) ) --end;
00545       op = TClassEdit::ResolveTypedef( op.substr( start, end - start ).c_str(), true );
00546 
00547    // map C++ operator to python equivalent, or made up name if no equivalent exists
00548       TC2POperatorMapping_t::iterator pop = gC2POperatorMapping.find( op );
00549       if ( pop != gC2POperatorMapping.end() ) {
00550          return pop->second;
00551 
00552       } else if ( op == "*" ) {
00553       // dereference v.s. multiplication of two instances
00554          return bTakesParams ? "__mul__" : "__deref__";
00555 
00556       } else if ( op == "+" ) {
00557       // unary positive v.s. addition of two instances
00558          return bTakesParams ? "__add__" : "__pos__";
00559 
00560       } else if ( op == "-" ) {
00561       // unary negative v.s. subtraction of two instances
00562          return bTakesParams ? "__sub__" : "__neg__";
00563 
00564       } else if ( op == "++" ) {
00565       // prefix v.s. postfix increment
00566          return bTakesParams ? "__postinc__" : "__preinc__";
00567 
00568       } else if ( op == "--" ) {
00569       // prefix v.s. postfix decrement
00570          return bTakesParams ? "__postdec__" : "__predec__";
00571       }
00572 
00573    }
00574 
00575 // might get here, as not all operator methods are handled (new, delete, etc.)
00576    return name;
00577 }
00578 
00579 //____________________________________________________________________________
00580 PyROOT::Utility::EDataType PyROOT::Utility::EffectiveType( const std::string& name )
00581 {
00582    EDataType effType = kOther;
00583 
00584    G__TypeInfo ti( name.c_str() );
00585    if ( ti.Property() & G__BIT_ISENUM )
00586       return EDataType( (int) kEnum );
00587 
00588    std::string shortName = TClassEdit::ShortType( ti.TrueName(), 1 );
00589 
00590    const std::string& cpd = Compound( name );
00591    const int mask = cpd == "*" ? kPtrMask : 0;
00592 
00593    if ( shortName == "bool" )
00594       effType = EDataType( (int) kBool | mask );
00595    else if ( shortName == "char" )
00596       effType = EDataType( (int) kChar | mask );
00597    else if ( shortName == "short" )
00598       effType = EDataType( (int) kShort | mask );
00599    else if ( shortName == "int" )
00600       effType = EDataType( (int) kInt | mask );
00601    else if ( shortName == "unsigned int" )
00602       effType = EDataType( (int) kUInt | mask );
00603    else if ( shortName == "long" )
00604       effType = EDataType( (int) kLong | mask );
00605    else if ( shortName == "unsigned long" )
00606       effType = EDataType( (int) kULong | mask );
00607    else if ( shortName == "long long" )
00608       effType = EDataType( (int) kLongLong | mask );
00609    else if ( shortName == "float" )
00610       effType = EDataType( (int) kFloat | mask );
00611    else if ( shortName == "double" )
00612       effType = EDataType( (int) kDouble | mask );
00613    else if ( shortName == "void" )
00614       effType = EDataType( (int) kVoid | mask );
00615    else if ( shortName == "string" && cpd == "" )
00616       effType = kSTLString;
00617    else if ( name == "#define" ) {
00618       effType = kMacro;
00619    }
00620    else
00621       effType = kOther;
00622 
00623    return effType;
00624 }
00625 
00626 //____________________________________________________________________________
00627 const std::string PyROOT::Utility::Compound( const std::string& name )
00628 {
00629    std::string cleanName = name;
00630    std::string::size_type spos = std::string::npos;
00631    while ( ( spos = cleanName.find( "const" ) ) != std::string::npos ) {
00632       cleanName.swap( cleanName.erase( spos, 5 ) );
00633    }
00634 
00635    std::string compound = "";
00636    for ( int ipos = (int)cleanName.size()-1; 0 <= ipos; --ipos ) {
00637       char c = cleanName[ipos];
00638       if ( isspace( c ) ) continue;
00639       if ( isalnum( c ) || c == '_' || c == '>' ) break;
00640 
00641       compound = c + compound;
00642    }
00643 
00644    return compound;
00645 }
00646 
00647 //____________________________________________________________________________
00648 const std::string PyROOT::Utility::ClassName( PyObject* pyobj )
00649 {
00650    std::string clname = "<unknown>";
00651    PyObject* pyclass = PyObject_GetAttr( pyobj, PyStrings::gClass );
00652    if ( pyclass != 0 ) {
00653       PyObject* pyname = PyObject_GetAttr( pyclass, PyStrings::gName );
00654 
00655       if ( pyname != 0 ) {
00656          clname = PyROOT_PyUnicode_AsString( pyname );
00657          Py_DECREF( pyname );
00658       } else
00659          PyErr_Clear();
00660 
00661       Py_DECREF( pyclass );
00662    } else
00663       PyErr_Clear();
00664 
00665    return clname;
00666 }
00667 
00668 //____________________________________________________________________________
00669 void PyROOT::Utility::ErrMsgCallback( char* msg )
00670 {
00671 // Translate CINT error/warning into python equivalent
00672 
00673 // ignore the "*** Interpreter error recovered ***" message
00674    if ( strstr( msg, "error recovered" ) )
00675       return;
00676 
00677 // ignore CINT-style FILE/LINE messages
00678    if ( strstr( msg, "FILE:" ) )
00679       return;
00680 
00681 // get file name and line number
00682    char* errFile = (char*)G__stripfilename( G__get_ifile()->name );
00683    int errLine = G__get_ifile()->line_number;
00684 
00685 // ignore ROOT-style FILE/LINE messages
00686    char buf[256];
00687    snprintf( buf, 256, "%s:%d:", errFile, errLine );
00688    if ( strstr( msg, buf ) )
00689       return;
00690 
00691 // strip newline, if any
00692    int len = strlen( msg );
00693    if ( msg[ len-1 ] == '\n' )
00694       msg[ len-1 ] = '\0';
00695 
00696 // concatenate message if already in error processing mode (e.g. if multiple CINT errors)
00697    if ( PyErr_Occurred() ) {
00698       PyObject *etype, *value, *trace;
00699       PyErr_Fetch( &etype, &value, &trace );           // clears current exception
00700 
00701    // need to be sure that error can be added; otherwise leave earlier error in place
00702       if ( PyROOT_PyUnicode_Check( value ) ) {
00703          if ( ! PyErr_GivenExceptionMatches( etype, PyExc_IndexError ) )
00704             PyROOT_PyUnicode_AppendAndDel( &value, PyROOT_PyUnicode_FromString( (char*)"\n  " ) );
00705          PyROOT_PyUnicode_AppendAndDel( &value, PyROOT_PyUnicode_FromString( msg ) );
00706       }
00707 
00708       PyErr_Restore( etype, value, trace );
00709       return;
00710    }
00711 
00712 // else, translate known errors and warnings, or simply accept the default
00713    char* format = (char*)"(file \"%s\", line %d) %s";
00714    char* p = 0;
00715    if ( ( p = strstr( msg, "Syntax Error:" ) ) )
00716       PyErr_Format( PyExc_SyntaxError, format, errFile, errLine, p+14 );
00717    else if ( ( p = strstr( msg, "Error: Array" ) ) )
00718       PyErr_Format( PyExc_IndexError, format, errFile, errLine, p+12 );
00719    else if ( ( p = strstr( msg, "Error:" ) ) )
00720       PyErr_Format( PyExc_RuntimeError, format, errFile, errLine, p+7 );
00721    else if ( ( p = strstr( msg, "Exception:" ) ) )
00722       PyErr_Format( PyExc_RuntimeError, format, errFile, errLine, p+11 );
00723    else if ( ( p = strstr( msg, "Limitation:" ) ) )
00724       PyErr_Format( PyExc_NotImplementedError, format, errFile, errLine, p+12 );
00725    else if ( ( p = strstr( msg, "Internal Error: malloc" ) ) )
00726       PyErr_Format( PyExc_MemoryError, format, errFile, errLine, p+23 );
00727    else if ( ( p = strstr( msg, "Internal Error:" ) ) )
00728       PyErr_Format( PyExc_SystemError, format, errFile, errLine, p+16 );
00729    else if ( ( p = strstr( msg, "Warning:" ) ) )
00730 // either printout or raise exception, depending on user settings
00731       PyErr_WarnExplicit( NULL, p+9, errFile, errLine, (char*)"CINT", NULL );
00732    else if ( ( p = strstr( msg, "Note:" ) ) )
00733       fprintf( stdout, "Note: (file \"%s\", line %d) %s\n", errFile, errLine, p+6 );
00734    else   // unknown: printing it to screen is the safest action
00735       fprintf( stdout, "Message: (file \"%s\", line %d) %s\n", errFile, errLine, msg );
00736 }
00737 
00738 //____________________________________________________________________________
00739 void PyROOT::Utility::ErrMsgHandler( int level, Bool_t abort, const char* location, const char* msg )
00740 {
00741 // Translate ROOT error/warning to python
00742 
00743 // initialization from gEnv (the default handler will return w/o msg b/c level too low)
00744    if ( gErrorIgnoreLevel == kUnset )
00745       ::DefaultErrorHandler( kUnset - 1, kFALSE, "", "" );
00746 
00747    if ( level < gErrorIgnoreLevel )
00748       return;
00749 
00750 // turn warnings into python warnings
00751    if (level >= kError)
00752       ::DefaultErrorHandler( level, abort, location, msg );
00753    else if ( level >= kWarning ) {
00754    // either printout or raise exception, depending on user settings
00755       PyErr_WarnExplicit( NULL, (char*)msg, (char*)location, 0, (char*)"ROOT", NULL );
00756    }
00757    else
00758       ::DefaultErrorHandler( level, abort, location, msg );
00759 }
00760 
00761 
00762 //____________________________________________________________________________
00763 Long_t PyROOT::Utility::InstallMethod( G__ClassInfo* scope, PyObject* callback, 
00764    const std::string& mtName, const char* rtype, const char* signature,
00765    void* func, Int_t npar, Long_t extra )
00766 {
00767    static Long_t s_fid = (Long_t)PyROOT::Utility::InstallMethod;
00768    ++s_fid;
00769 
00770 // Install a python callable method so that CINT can call it
00771 
00772    if ( ! PyCallable_Check( callback ) )
00773       return 0;
00774 
00775 // create a return type (typically masked/wrapped by a TPyReturn) for the method
00776    G__linked_taginfo pti;
00777    pti.tagnum = -1;
00778    pti.tagtype = 'c';
00779    std::string tagname;                     // used as a buffer
00780    if ( rtype ) {
00781       tagname = rtype;
00782    } else {
00783       const char* cname = scope ? scope->Fullname() : 0;
00784       tagname = cname ? std::string( cname ) + "::" + mtName : mtName;
00785    }
00786    pti.tagname = tagname.c_str();
00787    int tagnum = G__get_linked_tagnum( &pti );     // creates entry for new names
00788 
00789    if ( scope ) {   // add method to existing scope
00790       G__MethodInfo meth = scope->AddMethod( pti.tagname, mtName.c_str(), signature, 0, 0, func );
00791    } else {         // for free functions, add to global scope and add lookup through tp2f
00792    // setup a connection between the pointer and the name (only the interface method will be
00793    // called in the end, the tp2f must only be consistent: s_fid is chosen to allow the same
00794    // C++ callback to serve multiple python objects)
00795       Long_t hash = 0, len = 0;
00796       G__hash( mtName.c_str(), hash, len );
00797       G__lastifuncposition();
00798       G__memfunc_setup( mtName.c_str(), hash,
00799         (G__InterfaceMethod)func, tagnum, tagnum, tagnum, 0, npar, 0, 1, 0, signature, (char*)0, (void*)s_fid, 0 );
00800       G__resetifuncposition();
00801 
00802    // setup a name in the global namespace (does not result in calls, so the signature does
00803    // not matter; but it makes subsequent GetMethod() calls work)
00804       G__MethodInfo meth = G__ClassInfo().AddMethod( mtName.c_str(), mtName.c_str(), signature, 1, 0, func );
00805    }
00806 
00807 // and store callback
00808    Py_INCREF( callback );
00809    std::map< int, CallInfo_t >::iterator old = s_PyObjectCallbacks.find( tagnum );
00810    if ( old != s_PyObjectCallbacks.end() ) {
00811       PyObject* oldp = old->second.first;
00812       Py_XDECREF( oldp );
00813    }
00814    s_PyObjectCallbacks[ tagnum ] = std::make_pair( callback, extra );
00815 
00816 // hard to check result ... assume ok
00817    return s_fid;
00818 }
00819 
00820 //____________________________________________________________________________
00821 PyObject* PyROOT::Utility::GetInstalledMethod( int tagnum, Long_t* extra )
00822 {
00823 // Return the CINT-installed python callable, if any
00824    CallInfo_t cinfo = s_PyObjectCallbacks[ tagnum ];
00825    if ( extra )
00826       *extra = cinfo.second;
00827    return cinfo.first;
00828 }
00829 
00830 //____________________________________________________________________________
00831 PyObject* PyROOT::Utility::PyErr_Occurred_WithGIL()
00832 {
00833 // re-acquire the GIL before calling PyErr_Occurred() in case it has been
00834 // released; note that the p2.2 code assumes that there are no callbacks in
00835 // C++ to python (or at least none returning errors)
00836 #if PY_VERSION_HEX >= 0x02030000
00837    PyGILState_STATE gstate = PyGILState_Ensure();
00838    PyObject* e = PyErr_Occurred();
00839    PyGILState_Release( gstate );
00840 #else
00841    if ( PyThreadState_GET() )
00842       return PyErr_Occurred();
00843    PyObject* e = 0;
00844 #endif
00845 
00846    return e;
00847 }

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