38 struct InitOperatorMapping_t {
40 InitOperatorMapping_t() {
110#if PY_VERSION_HEX < 0x03000000
116 } initOperatorMapping_;
119 inline void RemoveConst(std::string& cleanName) {
120 std::string::size_type spos = std::string::npos;
121 while ((spos = cleanName.find(
"const")) != std::string::npos) {
122 cleanName.swap(cleanName.erase(spos, 5));
133 unsigned long ul = PyLong_AsUnsignedLong(pyobject);
134 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
136 long i = PyInt_AS_LONG(pyobject);
138 ul = (
unsigned long)i;
140 PyErr_SetString(PyExc_ValueError,
141 "can\'t convert negative value to unsigned long");
142 return (
unsigned long)-1;
153 ULong64_t ull = PyLong_AsUnsignedLongLong(pyobject);
154 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
156 long i = PyInt_AS_LONG(pyobject);
160 PyErr_SetString(PyExc_ValueError,
161 "can\'t convert negative value to unsigned long long");
170 PyObject* pyclass,
const char* label, PyCFunction cfunc,
int flags)
175 static std::list<PyMethodDef> s_pymeths;
177 s_pymeths.push_back(PyMethodDef());
178 PyMethodDef* pdef = &s_pymeths.back();
179 pdef->ml_name =
const_cast<char*
>(label);
180 pdef->ml_meth = cfunc;
181 pdef->ml_flags = flags;
182 pdef->ml_doc =
nullptr;
184 PyObject* func = PyCFunction_New(pdef,
nullptr);
187 bool isOk = PyType_Type.tp_setattro(pyclass,
name, method) == 0;
192 if (PyErr_Occurred())
196 PyErr_Format(PyExc_TypeError,
"could not add method %s", label);
207 PyObject* pyfunc = PyObject_GetAttrString(pyclass,
const_cast<char*
>(func));
212 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, pyfunc) == 0;
224 (
CPPOverload*)PyObject_GetAttrString(pyclass,
const_cast<char*
>(label));
228 if (PyErr_Occurred())
233 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, (
PyObject*)method) == 0;
252 std::string opname =
"operator";
286 bool reverse =
false;
295 const std::string& lcname =
ClassName(left);
296 const std::string& rcname =
ClassName(right);
302 const std::string& lcname,
const std::string& rcname,
309 if (rcname ==
"<unknown>" || lcname ==
"<unknown>")
339 && lcname.find(
"__wrap_iter") == std::string::npos
352 std::stringstream fname,
proto;
353 if (strncmp(op,
"==", 2) == 0) { fname <<
"is_equal<"; }
354 else if (strncmp(op,
"!=", 2) == 0) { fname <<
"is_not_equal<"; }
355 else { fname <<
"not_implemented<"; }
356 fname << lcname <<
", " << rcname <<
">";
357 proto <<
"const " << lcname <<
"&, const " << rcname;
359 if (method) pyfunc =
new CPPFunction(s_intern, method);
377#if PY_VERSION_HEX < 0x03000000
378 long l = PyInt_AS_LONG(arg);
379 tmpl_name.append((
l < INT_MIN || INT_MAX <
l) ?
"long" :
"int");
381 Long64_t ll = PyLong_AsLongLong(arg);
382 if (ll == (
Long64_t)-1 && PyErr_Occurred()) {
384 ULong64_t ull = PyLong_AsUnsignedLongLong(arg);
385 if (ull == (
ULong64_t)-1 && PyErr_Occurred()) {
387 tmpl_name.append(
"int");
389 tmpl_name.append(
"ULong64_t");
391 tmpl_name.append((ll < INT_MIN || INT_MAX < ll) ? \
392 ((ll < LONG_MIN || LONG_MAX < ll) ?
"Long64_t" :
"long") :
"int");
395 tmpl_name.append(
"int");
396#if PY_VERSION_HEX < 0x03000000
397 }
else if (tn == (
PyObject*)&PyLong_Type) {
399 Long64_t ll = PyLong_AsLongLong(arg);
400 if (ll == (
Long64_t)-1 && PyErr_Occurred()) {
402 ULong64_t ull = PyLong_AsUnsignedLongLong(arg);
403 if (ull == (
ULong64_t)-1 && PyErr_Occurred()) {
405 tmpl_name.append(
"long");
407 tmpl_name.append(
"ULong64_t");
409 tmpl_name.append((ll < LONG_MIN || LONG_MAX < ll) ?
"Long64_t" :
"long");
411 tmpl_name.append(
"long");
413 }
else if (tn == (
PyObject*)&PyFloat_Type) {
415 tmpl_name.append(arg ?
"double" :
"float");
416#if PY_VERSION_HEX < 0x03000000
417 }
else if (tn == (
PyObject*)&PyString_Type) {
419 }
else if (tn == (
PyObject*)&PyUnicode_Type) {
421 tmpl_name.append(
"std::string");
422 }
else if (tn == (
PyObject*)&PyList_Type || tn == (
PyObject*)&PyTuple_Type) {
423 if (arg && PySequence_Size(arg)) {
424 std::string subtype{
"std::initializer_list<"};
425 PyObject* item = PySequence_GetItem(arg, 0);
428 tmpl_name.append(subtype);
429 tmpl_name.append(
">");
440 if (pyobj->
fFlags & CPPInstance::kIsRValue)
441 tmpl_name.append(
"&&");
443 if (pcnt) *pcnt += 1;
445 tmpl_name.push_back(
'*');
447 tmpl_name.push_back(
'&');
459 }
else if (PyInt_Check(tn) || PyLong_Check(tn) || PyFloat_Check(tn)) {
478 bool justOne = !PyTuple_CheckExact(tpArgs);
481 std::string tmpl_name;
482 tmpl_name.reserve(128);
485 tmpl_name.push_back(
'<');
489 Py_ssize_t nArgs = justOne ? 1 : PyTuple_GET_SIZE(tpArgs);
490 for (
int i = argoff; i < nArgs; ++i) {
492 PyObject* tn = justOne ? tpArgs : PyTuple_GET_ITEM(tpArgs, i);
498 if (!
AddTypeName(tmpl_name, tn, (args ? PyTuple_GET_ITEM(args, i) :
nullptr), pref, pcnt)) {
499 PyErr_SetString(PyExc_SyntaxError,
500 "could not construct C++ name from provided template argument.");
507 tmpl_name.push_back(
',');
511 tmpl_name.push_back(
'>');
518 const std::vector<std::string>& argtypes, std::ostringstream& code)
521 int nArgs = (
int)argtypes.size();
524 bool isVoid = retType ==
"void";
526 code <<
" CPYCPPYY_STATIC std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>> "
527 "retconv{CPyCppyy::CreateConverter(\""
528 << retType <<
"\"), CPyCppyy::DestroyConverter};\n";
530 code <<
" CPYCPPYY_STATIC std::vector<std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>>> argcvs;\n"
531 <<
" if (argcvs.empty()) {\n"
532 <<
" argcvs.reserve(" << nArgs <<
");\n";
533 for (
int i = 0; i < nArgs; ++i)
534 code <<
" argcvs.emplace_back(CPyCppyy::CreateConverter(\"" << argtypes[i] <<
"\"), CPyCppyy::DestroyConverter);\n";
540 code <<
" " << retType <<
" ret{};\n";
543 code <<
" PyGILState_STATE state = PyGILState_Ensure();\n";
547 code <<
" std::vector<PyObject*> pyargs;\n";
548 code <<
" pyargs.reserve(" << nArgs <<
");\n"
550 for (
int i = 0; i < nArgs; ++i) {
551 code <<
" pyargs.emplace_back(argcvs[" << i <<
"]->FromMemory((void*)&arg" << i <<
"));\n"
552 <<
" if (!pyargs.back()) throw " << i <<
";\n";
554 code <<
" } catch(int) {\n"
555 <<
" for (auto pyarg : pyargs) Py_XDECREF(pyarg);\n"
556 <<
" PyGILState_Release(state); throw CPyCppyy::PyException{};\n"
564 bool isVoid = retType ==
"void";
567 code <<
" for (auto pyarg : pyargs) Py_DECREF(pyarg);\n";
568 code <<
" bool cOk = (bool)pyresult;\n"
569 " if (pyresult) {\n";
573 code <<
" if (!CPyCppyy::Instance_IsLively(pyresult))\n"
577 code << (isVoid ?
"" :
" cOk = retconv->ToMemory(pyresult, &ret);\n")
578 <<
" Py_DECREF(pyresult);\n }\n";
579 if (isPtr) code <<
" }\n";
580 code <<
" if (!cOk) {"
584 " /* do nothing */ }\n"
586 " PyGILState_Release(state); throw CPyCppyy::PyException{}; }\n"
588 " PyGILState_Release(state);\n"
590 code << (isVoid ?
";\n }\n" :
" ret;\n }\n");
599 if (PyType_Ready(pytype) < 0)
623 if ((!check || tc ==
'*' || tc ==
'B') && PyByteArray_CheckExact(pyobject)) {
624 buf = PyByteArray_AS_STRING(pyobject);
625 return PyByteArray_GET_SIZE(pyobject);
629 if (PyObject_CheckBuffer(pyobject)) {
631 memset(&bufinfo, 0,
sizeof(Py_buffer));
632 if (PyObject_GetBuffer(pyobject, &bufinfo, PyBUF_FORMAT) == 0) {
633 if (tc ==
'*' || strchr(bufinfo.format, tc)
636 || (tc ==
'I' && strchr(bufinfo.format,
'L')) || (tc ==
'i' && strchr(bufinfo.format,
'l'))
639 || (tc ==
'?' && strchr(bufinfo.format,
'b'))
642 if (buf && bufinfo.ndim == 0) {
643 PyBuffer_Release(&bufinfo);
644 return bufinfo.len/bufinfo.itemsize;
645 }
else if (buf && bufinfo.ndim == 1) {
646 Py_ssize_t size1d = bufinfo.shape ? bufinfo.shape[0] : bufinfo.len/bufinfo.itemsize;
647 PyBuffer_Release(&bufinfo);
653 PyBuffer_Release(&bufinfo);
661 PyBufferProcs* bufprocs =
Py_TYPE(pyobject)->tp_as_buffer;
663 PySequenceMethods* seqmeths =
Py_TYPE(pyobject)->tp_as_sequence;
664 if (seqmeths != 0 && bufprocs != 0
665#
if PY_VERSION_HEX < 0x03000000
666 && bufprocs->bf_getwritebuffer != 0
667 && (*(bufprocs->bf_getsegcount))(pyobject, 0) == 1
669 && bufprocs->bf_getbuffer != 0
674#if PY_VERSION_HEX < 0x03000000
675 Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))(pyobject, 0, &buf);
678 (*(bufprocs->bf_getbuffer))(pyobject, &bufinfo, PyBUF_WRITABLE);
679 buf = (
char*)bufinfo.buf;
681#
if PY_VERSION_HEX < 0x03010000
682 PyBuffer_Release(pyobject, &bufinfo);
684 PyBuffer_Release(&bufinfo);
688 if (buf && check ==
true) {
693 if (!(cpytc == tc || (tc ==
'?' && cpytc ==
'b')))
696 }
else if (seqmeths->sq_length &&
697 (
int)(buflen/(*(seqmeths->sq_length))(pyobject)) == size) {
700 }
else if (buflen == size) {
707 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
708 PyErr_Fetch(&pytype, &pyvalue, &pytrace);
710 (
char*)
"%s and given element size (%ld) do not match needed (%d)",
712 seqmeths->sq_length ? (
Long_t)(buflen/(*(seqmeths->sq_length))(pyobject)) : (
Long_t)buflen,
715 PyErr_Restore(pytype, pyvalue2, pytrace);
720 return buflen/(size ? size : 1);
730 if (8 <
name.size() &&
name.substr(0, 8) ==
"operator") {
731 std::string op =
name.substr(8, std::string::npos);
734 std::string::size_type start = 0, end = op.size();
735 while (start < end && isspace(op[start])) ++start;
736 while (start < end && isspace(op[end-1])) --end;
737 op = op.substr(start, end - start);
754 }
else if (op ==
"*") {
756 return bTakesParams ?
"__mul__" :
"__deref__";
758 }
else if (op ==
"+") {
760 return bTakesParams ?
"__add__" :
"__pos__";
762 }
else if (op ==
"-") {
764 return bTakesParams ?
"__sub__" :
"__neg__";
766 }
else if (op ==
"++") {
768 return bTakesParams ?
"__postinc__" :
"__preinc__";
770 }
else if (op ==
"--") {
772 return bTakesParams ?
"__postdec__" :
"__predec__";
786 std::string cleanName =
name;
787 RemoveConst(cleanName);
790 for (
int ipos = (
int)cleanName.size()-1; 0 <= ipos; --ipos) {
791 char c = cleanName[ipos];
792 if (isspace(
c))
continue;
793 if (isalnum(
c) ||
c ==
'_' ||
c ==
'>' ||
c ==
')')
break;
810 std::string cleanName =
name;
811 RemoveConst(cleanName);
813 if (cleanName[cleanName.size()-1] ==
']') {
814 std::string::size_type idx = cleanName.rfind(
'[');
815 if (idx != std::string::npos) {
816 const std::string asize = cleanName.substr(idx+1, cleanName.size()-2);
817 return strtoul(asize.c_str(),
nullptr, 0);
828 std::string clname =
"<unknown>";
864#if PY_VERSION_HEX >= 0x02030000
865 PyGILState_STATE gstate = PyGILState_Ensure();
867 PyGILState_Release(gstate);
869 if (PyThreadState_GET())
870 return PyErr_Occurred();
882 if (PyErr_Occurred()) {
884 PyErr_Fetch(&
e.fType, &
e.fValue, &
e.fTrace);
887 return errors.size();
894 if (errors.empty()) {
905 for (
auto&
e : errors) {
906 if (!exc_type) exc_type =
e.fType;
907 else if (exc_type !=
e.fType) exc_type = defexc;
911 }
else if (
e.fValue) {
912 PyObject* excstr = PyObject_Str(
e.fValue);
941 "#include \"CPyCppyy/API.h\"\n"
944 "#include \"CPyCppyy/DispatchPtr.h\"\n"
945 "#include \"CPyCppyy/PyException.h\"\n"
PyDictEntry *(* dict_lookup_func)(PyDictObject *, PyObject *, long)
#define CPyCppyy_PyText_InternFromString
#define CPyCppyy_PyText_Append
#define CPyCppyy_PyText_AsString
#define CPyCppyy_PyText_AppendAndDel
#define CPyCppyy_PyText_FromFormat
#define CPyCppyy_PyText_FromString
#define CPyCppyy_PyText_Check
unsigned long long ULong64_t
static TC2POperatorMapping_t gC2POperatorMapping
static CPyCppyy::PyCallable * BuildOperator(const std::string &lcname, const std::string &rcname, const char *op, Cppyy::TCppScope_t scope, bool reverse=false)
static std::set< std::string > gOpRemove
static std::set< std::string > gOpSkip
static bool AddTypeName(std::string &tmpl_name, PyObject *tn, PyObject *arg, CPyCppyy::Utility::ArgPreference pref, int *pcnt=nullptr)
std::map< std::string, std::string > TC2POperatorMapping_t
void AdoptMethod(PyCallable *pc)
Cppyy::TCppType_t fCppType
RooCmdArg ClassName(const char *name)
std::string extract_namespace(const std::string &name)
PyCallable * FindBinaryOperator(PyObject *left, PyObject *right, const char *op, Cppyy::TCppScope_t scope=0)
size_t FetchError(std::vector< PyError_t > &)
void ConstructCallbackPreamble(const std::string &retType, const std::vector< std::string > &argtypes, std::ostringstream &code)
void ConstructCallbackReturn(const std::string &retType, int nArgs, std::ostringstream &code)
std::string MapOperatorName(const std::string &name, bool bTakesParames)
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
std::string ConstructTemplateArgs(PyObject *pyname, PyObject *tpArgs, PyObject *args=nullptr, ArgPreference=kNone, int argoff=0, int *pcnt=nullptr)
PyCallable * FindUnaryOperator(PyObject *pyclass, const char *op)
void SetDetailedException(std::vector< PyError_t > &errors, PyObject *topmsg, PyObject *defexc)
bool InitProxy(PyObject *module, PyTypeObject *pytype, const char *name)
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Py_ssize_t ArraySize(const std::string &name)
const std::string Compound(const std::string &name)
std::string ClassName(PyObject *pyobj)
PyObject * PyErr_Occurred_WithGIL()
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
unsigned long PyLongOrInt_AsULong(PyObject *pyobject)
PyObject * CustomInstanceMethod_New(PyObject *func, PyObject *self, PyObject *pyclass)
dict_lookup_func gDictLookupOrg
bool CPPOverload_Check(T *object)
bool CPPScope_Check(T *object)
bool CPPInstance_Check(T *object)
ULong64_t PyLongOrInt_AsULong64(PyObject *pyobject)
RPY_EXPORTED bool Compile(const std::string &code)
RPY_EXPORTED TCppIndex_t GetGlobalOperator(TCppType_t scope, const std::string &lc, const std::string &rc, const std::string &op)
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED TCppScope_t gGlobalScope
static void Clear(PyError_t &e)