<commit_before>// @(#)root/pyroot:$Id$
// Author: <NAME>, Jan 2005

// Bindings
#include "PyROOT.h"
#include "structmember.h"    // from Python
#if PY_VERSION_HEX >= 0x02050000
#include "code.h"            // from Python
#else
#include "compile.h"         // from Python
#endif
#ifndef CO_NOFREE
// python2.2 does not have CO_NOFREE defined
#define CO_NOFREE       0x0040
#endif
#include "MethodProxy.h"
#include "ObjectProxy.h"
#include "TPyException.h"
#include "Utility.h"
#include "PyStrings.h"

// Standard
#include <algorithm>
#include <functional>
#include <vector>
#include <algorithm>


namespace PyROOT {

namespace {

// helper to test whether a method is used in a pseudo-function modus
   Bool_t inline IsPseudoFunc( MethodProxy* pymeth )
   {
      return (void*)pymeth == (void*)pymeth->fSelf;
   }

// helper for collecting/maintaining exception data in overload dispatch
   struct PyError_t {
      PyError_t() { fType = fValue = fTrace = 0; }

      static void Clear( PyError_t& e )
      {
      // Remove exception information.
         Py_XDECREF( e.fType ); Py_XDECREF( e.fValue ); Py_XDECREF( e.fTrace );
         e.fType = e.fValue = e.fTrace = 0;
      }

      PyObject *fType, *fValue, *fTrace;
   };

// helper to hash tuple (using tuple hash would cause self-tailing loops)
   inline Long_t HashSignature( PyObject* args )
   {
   // Build a hash from the types of the given python function arguments.
      ULong_t hash = 0;

      Int_t nargs = PyTuple_GET_SIZE( args );
      for ( Int_t i = 0; i < nargs; ++i ) {
         hash += (ULong_t) Py_TYPE( PyTuple_GET_ITEM( args, i ) );
         hash += (hash << 10); hash ^= (hash >> 6);
      }

      hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15);

      return hash;
   }

// helper to sort on method priority
   int PriorityCmp( PyCallable* left, PyCallable* right )
   {
      return left->GetPriority() > right->GetPriority();
   }

// helper to factor out return logic of mp_call
   inline PyObject* HandleReturn( MethodProxy* pymeth, PyObject* result ) {

   // special case for python exceptions, propagated through C++ layer
      if ( result == (PyObject*)TPyExceptionMagic )
         return 0;              // exception info was already set

   // if this method creates new objects, always take ownership
      if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsCreator ) {

      // either be a constructor with a fresh object proxy self ... 
         if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsConstructor ) {
            if ( pymeth->fSelf )
               pymeth->fSelf->HoldOn();
         }

      // ... or be a method with an object proxy return value
         else if ( ObjectProxy_Check( result ) )
            ((ObjectProxy*)result)->HoldOn();
      }

   // if this new object falls inside self, make sure its lifetime is proper
      if ( pymeth->fSelf && ObjectProxy_Check( result ) ) {
         Long_t ptrdiff = (Long_t)((ObjectProxy*)result)->GetObject() - (Long_t)pymeth->fSelf->GetObject();
         if ( 0 <= ptrdiff && ptrdiff < (Long_t)pymeth->fSelf->ObjectIsA()->Size() ) {
            if ( PyObject_SetAttr( result, PyStrings::gLifeLine, (PyObject*)pymeth->fSelf ) == -1 )
               PyErr_Clear();     // ignored
         }
      }

      return result;
   }


//= PyROOT method proxy object behaviour =====================================
   PyObject* mp_name( MethodProxy* pymeth, void* )
   {
      return PyROOT_PyUnicode_FromString( pymeth->GetName().c_str() );
   }

//____________________________________________________________________________
   PyObject* mp_module( MethodProxy* /* pymeth */, void* )
   {
      Py_INCREF( PyStrings::gROOTns );
      return PyStrings::gROOTns;
   }

//____________________________________________________________________________
   PyObject* mp_doc( MethodProxy* pymeth, void* )
   {
   // Build python document string ('__doc__') from all C++-side overloads.
      MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;

   // collect doc strings
      Int_t nMethods = methods.size();
      PyObject* doc = methods[0]->GetDocString();

   // simple case
      if ( nMethods == 1 )
         return doc;

   // overloaded method
      PyObject* separator = PyROOT_PyUnicode_FromString( "\n" );
      for ( Int_t i = 1; i < nMethods; ++i ) {
         PyROOT_PyUnicode_Append( &doc, separator );
         PyROOT_PyUnicode_AppendAndDel( &doc, methods[i]->GetDocString() );
      }
      Py_DECREF( separator );

      return doc;
   }

//____________________________________________________________________________
   PyObject* mp_meth_func( MethodProxy* pymeth, void* )
   {
   // Create a new method proxy to be returned.
      MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );

   // method info is shared, as it contains the collected overload knowledge
      *pymeth->fMethodInfo->fRefCount += 1;
      newPyMeth->fMethodInfo = pymeth->fMethodInfo;

   // new method is unbound, use of 'meth' is for keeping track whether this
   // proxy is used in the capacity of a method or a function
      newPyMeth->fSelf = (ObjectProxy*)newPyMeth;

      return (PyObject*)newPyMeth;
   }

//____________________________________________________________________________
   PyObject* mp_meth_self( MethodProxy* pymeth, void* )
   {
   // Return the bound self, if any; in case of pseudo-function role, pretend
   // that the data member im_self does not exist.
      if ( IsPseudoFunc( pymeth ) ) {
         PyErr_Format( PyExc_AttributeError,
            "function %s has no attribute \'im_self\'", pymeth->fMethodInfo->fName.c_str() );
         return 0;
      } else if ( pymeth->fSelf != 0 ) {
         Py_INCREF( (PyObject*)pymeth->fSelf );
         return (PyObject*)pymeth->fSelf;
      }

      Py_INCREF( Py_None );
      return Py_None;
   }

//____________________________________________________________________________
   PyObject* mp_meth_class( MethodProxy* pymeth, void* )
   {
   // Return scoping class; in case of pseudo-function role, pretend that there
   // is no encompassing class (i.e. global scope).
      if ( ! IsPseudoFunc( pymeth ) ) {
         PyObject* pyclass = pymeth->fMethodInfo->fMethods[0]->GetScope();
         if ( ! pyclass )
            PyErr_Format( PyExc_AttributeError,
               "function %s has no attribute \'im_class\'", pymeth->fMethodInfo->fName.c_str() );
         return pyclass;
      }

      Py_INCREF( Py_None );
      return Py_None;
   }

//____________________________________________________________________________
   PyObject* mp_func_closure( MethodProxy* /* pymeth */, void* )
   {
   // Stub only, to fill out the python function interface.
      Py_INCREF( Py_None );
      return Py_None;
   }

//____________________________________________________________________________
   PyObject* mp_func_code( MethodProxy* /* pymeth */, void* )
   {
   // Stub only, to fill out the python function interface.
      Py_INCREF( Py_None );
      return Py_None;<commit_msg>restore full co_code stub for help function<commit_after>// @(#)root/pyroot:$Id$
// Author: <NAME>, Jan 2005

// Bindings
#include "PyROOT.h"
#include "structmember.h"    // from Python
#if PY_VERSION_HEX >= 0x02050000
#include "code.h"            // from Python
#else
#include "compile.h"         // from Python
#endif
#ifndef CO_NOFREE
// python2.2 does not have CO_NOFREE defined
#define CO_NOFREE       0x0040
#endif
#include "MethodProxy.h"
#include "ObjectProxy.h"
#include "TPyException.h"
#include "Utility.h"
#include "PyStrings.h"

// Standard
#include <algorithm>
#include <functional>
#include <vector>
#include <algorithm>


namespace PyROOT {

namespace {

// helper to test whether a method is used in a pseudo-function modus
   Bool_t inline IsPseudoFunc( MethodProxy* pymeth )
   {
      return (void*)pymeth == (void*)pymeth->fSelf;
   }

// helper for collecting/maintaining exception data in overload dispatch
   struct PyError_t {
      PyError_t() { fType = fValue = fTrace = 0; }

      static void Clear( PyError_t& e )
      {
      // Remove exception information.
         Py_XDECREF( e.fType ); Py_XDECREF( e.fValue ); Py_XDECREF( e.fTrace );
         e.fType = e.fValue = e.fTrace = 0;
      }

      PyObject *fType, *fValue, *fTrace;
   };

// helper to hash tuple (using tuple hash would cause self-tailing loops)
   inline Long_t HashSignature( PyObject* args )
   {
   // Build a hash from the types of the given python function arguments.
      ULong_t hash = 0;

      Int_t nargs = PyTuple_GET_SIZE( args );
      for ( Int_t i = 0; i < nargs; ++i ) {
         hash += (ULong_t) Py_TYPE( PyTuple_GET_ITEM( args, i ) );
         hash += (hash << 10); hash ^= (hash >> 6);
      }

      hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15);

      return hash;
   }

// helper to sort on method priority
   int PriorityCmp( PyCallable* left, PyCallable* right )
   {
      return left->GetPriority() > right->GetPriority();
   }

// helper to factor out return logic of mp_call
   inline PyObject* HandleReturn( MethodProxy* pymeth, PyObject* result ) {

   // special case for python exceptions, propagated through C++ layer
      if ( result == (PyObject*)TPyExceptionMagic )
         return 0;              // exception info was already set

   // if this method creates new objects, always take ownership
      if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsCreator ) {

      // either be a constructor with a fresh object proxy self ... 
         if ( pymeth->fMethodInfo->fFlags & MethodProxy::MethodInfo_t::kIsConstructor ) {
            if ( pymeth->fSelf )
               pymeth->fSelf->HoldOn();
         }

      // ... or be a method with an object proxy return value
         else if ( ObjectProxy_Check( result ) )
            ((ObjectProxy*)result)->HoldOn();
      }

   // if this new object falls inside self, make sure its lifetime is proper
      if ( pymeth->fSelf && ObjectProxy_Check( result ) ) {
         Long_t ptrdiff = (Long_t)((ObjectProxy*)result)->GetObject() - (Long_t)pymeth->fSelf->GetObject();
         if ( 0 <= ptrdiff && ptrdiff < (Long_t)pymeth->fSelf->ObjectIsA()->Size() ) {
            if ( PyObject_SetAttr( result, PyStrings::gLifeLine, (PyObject*)pymeth->fSelf ) == -1 )
               PyErr_Clear();     // ignored
         }
      }

      return result;
   }


//= PyROOT method proxy object behaviour =====================================
   PyObject* mp_name( MethodProxy* pymeth, void* )
   {
      return PyROOT_PyUnicode_FromString( pymeth->GetName().c_str() );
   }

//____________________________________________________________________________
   PyObject* mp_module( MethodProxy* /* pymeth */, void* )
   {
      Py_INCREF( PyStrings::gROOTns );
      return PyStrings::gROOTns;
   }

//____________________________________________________________________________
   PyObject* mp_doc( MethodProxy* pymeth, void* )
   {
   // Build python document string ('__doc__') from all C++-side overloads.
      MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods;

   // collect doc strings
      Int_t nMethods = methods.size();
      PyObject* doc = methods[0]->GetDocString();

   // simple case
      if ( nMethods == 1 )
         return doc;

   // overloaded method
      PyObject* separator = PyROOT_PyUnicode_FromString( "\n" );
      for ( Int_t i = 1; i < nMethods; ++i ) {
         PyROOT_PyUnicode_Append( &doc, separator );
         PyROOT_PyUnicode_AppendAndDel( &doc, methods[i]->GetDocString() );
      }
      Py_DECREF( separator );

      return doc;
   }

//____________________________________________________________________________
   PyObject* mp_meth_func( MethodProxy* pymeth, void* )
   {
   // Create a new method proxy to be returned.
      MethodProxy* newPyMeth = (MethodProxy*)MethodProxy_Type.tp_alloc( &MethodProxy_Type, 0 );

   // method info is shared, as it contains the collected overload knowledge
      *pymeth->fMethodInfo->fRefCount += 1;
      newPyMeth->fMethodInfo = pymeth->fMethodInfo;

   // new method is unbound, use of 'meth' is for keeping track whether this
   // proxy is used in the capacity of a method or a function
      newPyMeth->fSelf = (ObjectProxy*)newPyMeth;

      return (PyObject*)newPyMeth;
   }

//____________________________________________________________________________
   PyObject* mp_meth_self( MethodProxy* pymeth, void* )
   {
   // Return the bound self, if any; in case of pseudo-function role, pretend
   // that the data member im_self does not exist.
      if ( IsPseudoFunc( pymeth ) ) {
         PyErr_Format( PyExc_AttributeError,
            "function %s has no attribute \'im_self\'", pymeth->fMethodInfo->fName.c_str() );
         return 0;
      } else if ( pymeth->fSelf != 0 ) {
         Py_INCREF( (PyObject*)pymeth->fSelf );
         return (PyObject*)pymeth->fSelf;
      }

      Py_INCREF( Py_None );
      return Py_None;
   }

//____________________________________________________________________________
   PyObject* mp_meth_class( MethodProxy* pymeth, void* )
   {
   // Return scoping class; in case of pseudo-function role, pretend that there
   // is no encompassing class (i.e. global scope).
      if ( ! IsPseudoFunc( pymeth ) ) {
         PyObject* pyclass = pymeth->fMethodInfo->fMethods[0]->GetScope();
         if ( ! pyclass )
            PyErr_Format( PyExc_AttributeError,
               "function %s has no attribute \'im_class\'", pymeth->fMethodInfo->fName.c_str() );
         return pyclass;
      }

      Py_INCREF( Py_None );
      return Py_None;
   }

//____________________________________________________________________________
   PyObject* mp_func_closure( MethodProxy* /* pymeth */, void* )
   {
   // Stub only, to fill out the python function interface.
      Py_INCREF( Py_None );
      return Py_None;
   }

//____________________________________________________________________________
   PyObject* mp_func_code( MethodProxy* pymeth, void* )
   {
   // Stub only, to fill out the python function interface.
#if PY_VERSION_HEX < 0x03000000
      MethodProxy::Methods_t& methods = pymeth->fMethodInfo->fMethods; 	 
	  	 
   // collect maximum number of arguments in set of overloads; this is also used 	 
   // for the number of locals ("stack variables") 	 
      int co_argcount = 0; 	 
      MethodProxy::Methods_t::iterator maxargmeth; 	 
      for ( MethodProxy::Methods_t::iterator imeth = methods.begin();
            imeth != methods.end(); ++imeth ) { 	 
         if ( co_argcount < (*imeth)->GetMaxArgs() ) { 	 
            co_argcount = (*imeth)->GetMaxArgs(); 	 
            maxargmeth = imeth; 	 
         } 	 
      } 	 
      co_argcount += 1;       // for 'self' 	 
	  	 
   // for now, code object representing the statement 'pass' 	 
      PyObject* co_code = PyString_FromStringAndSize( "d\x00\x00S", 4 ); 	 
	  	 
   // tuple with all the const literals used in the function 	 
      PyObject* co_consts = PyTuple_New( 2 ); 	 
      Py_INCREF( Py_None ); 	 
      PyTuple_SET_ITEM( co_consts, 0, Py_None ); 	 
      PyObject* val1 = PyFloat_FromDouble( -1.0 ); 	 
      PyTuple_SET_ITEM( co_consts, 1, val1 ); 	 
	  	 
      PyObject* co_names = PyTuple_New( 2 ); 	 
      PyTuple_SET_ITEM( co_names, 0, PyString_FromString( "dafunc" ) ); 	 
      PyTuple_SET_ITEM( co_names, 1, PyString_FromString( "acos" ) ); 	 
	  	 
   // names, freevars, and cellvars go unused 	 
      PyObject* co_unused = PyTuple_New( 0 ); 	 
	  	 
   // variable names are both the argument and local names 	 
      PyObject* co_varnames = PyTuple_New( co_argcount + 1 ); 	 
      PyTuple_SET_ITEM( co_varnames, 0, PyString_FromString( "self" ) ); 	 
      for ( int iarg = 1; iarg < co_argcount; ++iarg ) { 	 
         PyTuple_SET_ITEM( co_varnames, iarg, (*maxargmeth)->GetArgSpec( iarg - 1 ) ); 	 
      } 	 
      PyTuple_SET_ITEM( co_varnames, co_argcount, PyString_FromString( "d" ) ); 	 
	  	 
   // filename is made-up 	 
      PyObject* co_filename = PyString_FromString( "ROOT.py" ); 	 
	  	 
   // name is the function name, also through __name__ on the function itself 	 
      PyObject* co_name = PyString_FromString( pymeth->GetName().c_str() ); 	 
	  	 
   // firstlineno is the line number of first function code in the containing scope 	 
	  	 
   // lnotab is a packed table that maps instruction count and line number 	 
      PyObject* co_lnotab = PyString_FromString( "\x00\x01\x0c\x01" ); 	 
	  	 
      PyObject* code = (PyObject*)PyCode_New( 	 
         co_argcount,                             // argcount 	 
         co_argcount + 1,                         // nlocals 	 
         2,                                       // stacksize 	 
         CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE, // flags 	 
         co_code,                                 // code 	 
         co_consts,                               // consts 	 
         co_names,                                // names 	 
         co_varnames,                             // varnames 	 
         co_unused,                               // freevars 	 
         co_unused,                               // cellvars 	 
         co_filename,                             // filename 	 
         co_name,                                 // name 	 
         1,                                       // firstlineno 	 
         co_lnotab );                             // lnotab 	 
	  	 
      Py_DECREF( co_lnotab ); 	 
      Py_DECREF( co_name ); 	 
      Py_DECREF( co_unused ); 	 
      Py_DECREF( co_filename ); 	 
      Py_DECREF( co_varnames ); 	 
      Py_DECREF( co_names ); 	 
      Py_DECREF( co_consts ); 	 
      Py_DECREF( co_code ); 	 
	  	 
      return code; 	 
#else 	 
// not important for functioning of most code, so not implemented for p3 for now (TODO) 	 
      pymeth = 0;
      Py_INCREF( Py_None );
      return Py_None;
#endif
{'fraction_non_alphanumeric': 0.11044377711044377, 'fraction_numerical': 0.00717384050717384, 'mean_word_length': 2.4423813169984685, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 109, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3500075', 'n_tokens_mistral': 5613, 'n_tokens_neox': 5347, 'n_words': 1445}