39 struct InitOperatorMapping_t {
41 InitOperatorMapping_t() {
111#if PY_VERSION_HEX < 0x03000000
117 } initOperatorMapping_;
120 inline void RemoveConst(std::string& cleanName) {
121 std::string::size_type spos = std::string::npos;
122 while ((spos = cleanName.find(
"const")) != std::string::npos) {
123 cleanName.swap(cleanName.erase(spos, 5));
134 unsigned long ul = PyLong_AsUnsignedLong(pyobject);
135 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
137 long i = PyInt_AS_LONG(pyobject);
139 ul = (
unsigned long)i;
141 PyErr_SetString(PyExc_ValueError,
142 "can\'t convert negative value to unsigned long");
143 return (
unsigned long)-1;
154 ULong64_t ull = PyLong_AsUnsignedLongLong(pyobject);
155 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
157 long i = PyInt_AS_LONG(pyobject);
161 PyErr_SetString(PyExc_ValueError,
162 "can\'t convert negative value to unsigned long long");
171 PyObject* pyclass,
const char* label, PyCFunction cfunc,
int flags)
176 static std::list<PyMethodDef> s_pymeths;
178 s_pymeths.push_back(PyMethodDef());
179 PyMethodDef* pdef = &s_pymeths.back();
180 pdef->ml_name =
const_cast<char*
>(label);
181 pdef->ml_meth = cfunc;
182 pdef->ml_flags = flags;
183 pdef->ml_doc =
nullptr;
185 PyObject* func = PyCFunction_New(pdef,
nullptr);
188 bool isOk = PyType_Type.tp_setattro(pyclass,
name, method) == 0;
193 if (PyErr_Occurred())
197 PyErr_Format(PyExc_TypeError,
"could not add method %s", label);
208 PyObject* pyfunc = PyObject_GetAttrString(pyclass,
const_cast<char*
>(func));
213 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, pyfunc) == 0;
225 (
CPPOverload*)PyObject_GetAttrString(pyclass,
const_cast<char*
>(label));
229 if (PyErr_Occurred())
234 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, (
PyObject*)method) == 0;
253 std::string opname =
"operator";
287 bool reverse =
false;
296 const std::string& lcname =
ClassName(left);
297 const std::string& rcname =
ClassName(right);
303 const std::string& lcname,
const std::string& rcname,
310 if (rcname ==
"<unknown>" || lcname ==
"<unknown>")
315 const std::string& lnsname = TypeManip::extract_namespace(lcname);
340 && lcname.find(
"__wrap_iter") == std::string::npos
353 std::stringstream fname,
proto;
354 if (strncmp(op,
"==", 2) == 0) { fname <<
"is_equal<"; }
355 else if (strncmp(op,
"!=", 2) == 0) { fname <<
"is_not_equal<"; }
356 else { fname <<
"not_implemented<"; }
357 fname << lcname <<
", " << rcname <<
">";
358 proto <<
"const " << lcname <<
"&, const " << rcname;
360 if (method) pyfunc =
new CPPFunction(s_intern, method);
378#if PY_VERSION_HEX < 0x03000000
379 long l = PyInt_AS_LONG(arg);
380 tmpl_name.append((
l < INT_MIN || INT_MAX <
l) ?
"long" :
"int");
382 Long64_t ll = PyLong_AsLongLong(arg);
383 if (ll == (
Long64_t)-1 && PyErr_Occurred()) {
385 ULong64_t ull = PyLong_AsUnsignedLongLong(arg);
386 if (ull == (
ULong64_t)-1 && PyErr_Occurred()) {
388 tmpl_name.append(
"int");
390 tmpl_name.append(
"ULong64_t");
392 tmpl_name.append((ll < INT_MIN || INT_MAX < ll) ? \
393 ((ll < LONG_MIN || LONG_MAX < ll) ?
"Long64_t" :
"long") :
"int");
396 tmpl_name.append(
"int");
397#if PY_VERSION_HEX < 0x03000000
398 }
else if (tn == (
PyObject*)&PyLong_Type) {
400 Long64_t ll = PyLong_AsLongLong(arg);
401 if (ll == (
Long64_t)-1 && PyErr_Occurred()) {
403 ULong64_t ull = PyLong_AsUnsignedLongLong(arg);
404 if (ull == (
ULong64_t)-1 && PyErr_Occurred()) {
406 tmpl_name.append(
"long");
408 tmpl_name.append(
"ULong64_t");
410 tmpl_name.append((ll < LONG_MIN || LONG_MAX < ll) ?
"Long64_t" :
"long");
412 tmpl_name.append(
"long");
414 }
else if (tn == (
PyObject*)&PyFloat_Type) {
416 tmpl_name.append(arg ?
"double" :
"float");
417#if PY_VERSION_HEX < 0x03000000
418 }
else if (tn == (
PyObject*)&PyString_Type) {
420 }
else if (tn == (
PyObject*)&PyUnicode_Type) {
422 tmpl_name.append(
"std::string");
423 }
else if (tn == (
PyObject*)&PyList_Type || tn == (
PyObject*)&PyTuple_Type) {
424 if (arg && PySequence_Size(arg)) {
425 std::string subtype{
"std::initializer_list<"};
426 PyObject* item = PySequence_GetItem(arg, 0);
429 tmpl_name.append(subtype);
430 tmpl_name.append(
">");
435 }
else if (CPPScope_Check(tn)) {
440 if (CPPInstance_Check(pyobj)) {
441 if (pyobj->
fFlags & CPPInstance::kIsRValue)
442 tmpl_name.append(
"&&");
444 if (pcnt) *pcnt += 1;
445 if ((pyobj->
fFlags & CPPInstance::kIsReference) || pref ==
kPointer)
446 tmpl_name.push_back(
'*');
448 tmpl_name.push_back(
'&');
452 }
else if (PyObject_HasAttr(tn, PyStrings::gCppName)) {
453 PyObject* tpName = PyObject_GetAttr(tn, PyStrings::gCppName);
456 }
else if (PyObject_HasAttr(tn, PyStrings::gName)) {
457 PyObject* tpName = PyObject_GetAttr(tn, PyStrings::gName);
460 }
else if (PyInt_Check(tn) || PyLong_Check(tn) || PyFloat_Check(tn)) {
479 bool justOne = !PyTuple_CheckExact(tpArgs);
482 std::string tmpl_name;
483 tmpl_name.reserve(128);
486 tmpl_name.push_back(
'<');
490 Py_ssize_t nArgs = justOne ? 1 : PyTuple_GET_SIZE(tpArgs);
491 for (
int i = argoff; i < nArgs; ++i) {
493 PyObject* tn = justOne ? tpArgs : PyTuple_GET_ITEM(tpArgs, i);
499 if (!
AddTypeName(tmpl_name, tn, (args ? PyTuple_GET_ITEM(args, i) :
nullptr), pref, pcnt)) {
500 PyErr_SetString(PyExc_SyntaxError,
501 "could not construct C++ name from provided template argument.");
508 tmpl_name.push_back(
',');
512 tmpl_name.push_back(
'>');
519 const std::vector<std::string>& argtypes, std::ostringstream& code)
522 int nArgs = (
int)argtypes.size();
525 bool isVoid = retType ==
"void";
527 code <<
" CPYCPPYY_STATIC std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>> "
528 "retconv{CPyCppyy::CreateConverter(\""
529 << retType <<
"\"), CPyCppyy::DestroyConverter};\n";
531 code <<
" CPYCPPYY_STATIC std::vector<std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>>> argcvs;\n"
532 <<
" if (argcvs.empty()) {\n"
533 <<
" argcvs.reserve(" << nArgs <<
");\n";
534 for (
int i = 0; i < nArgs; ++i)
535 code <<
" argcvs.emplace_back(CPyCppyy::CreateConverter(\"" << argtypes[i] <<
"\"), CPyCppyy::DestroyConverter);\n";
541 code <<
" " << retType <<
" ret{};\n";
544 code <<
" PyGILState_STATE state = PyGILState_Ensure();\n";
548 code <<
" std::vector<PyObject*> pyargs;\n";
549 code <<
" pyargs.reserve(" << nArgs <<
");\n"
551 for (
int i = 0; i < nArgs; ++i) {
552 code <<
" pyargs.emplace_back(argcvs[" << i <<
"]->FromMemory((void*)&arg" << i <<
"));\n"
553 <<
" if (!pyargs.back()) throw " << i <<
";\n";
555 code <<
" } catch(int) {\n"
556 <<
" for (auto pyarg : pyargs) Py_XDECREF(pyarg);\n"
557 <<
" PyGILState_Release(state); throw CPyCppyy::PyException{};\n"
565 bool isVoid = retType ==
"void";
568 code <<
" for (auto pyarg : pyargs) Py_DECREF(pyarg);\n";
569 code <<
" bool cOk = (bool)pyresult;\n"
570 " if (pyresult) {\n";
574 code <<
" if (!CPyCppyy::Instance_IsLively(pyresult))\n"
578 code << (isVoid ?
"" :
" cOk = retconv->ToMemory(pyresult, &ret);\n")
579 <<
" Py_DECREF(pyresult);\n }\n";
580 if (isPtr) code <<
" }\n";
581 code <<
" if (!cOk) {"
585 " /* do nothing */ }\n"
587 " PyGILState_Release(state); throw CPyCppyy::PyException{}; }\n"
589 " PyGILState_Release(state);\n"
591 code << (isVoid ?
";\n }\n" :
" ret;\n }\n");
599 const std::string& retType,
const std::string& signature,
void* address)
602 static int maker_count = 0;
605 PyErr_SetString(PyExc_TypeError,
"can not convert null function pointer");
611 Py_INCREF(pf->second);
619 std::ostringstream fname;
620 fname <<
"ptr2func" << ++maker_count;
622 std::ostringstream code;
623 code <<
"namespace __cppyy_internal { std::function<"
624 << retType << signature <<
"> " << fname.str()
625 <<
"(intptr_t faddr) { return (" << retType <<
"(*)" << signature <<
")faddr;} }";
628 PyErr_SetString(PyExc_TypeError,
"conversion to std::function failed");
633 maker = PyObject_GetAttrString(pyscope, fname.str().c_str());
644 PyTuple_SET_ITEM(args, 0, PyLong_FromLongLong((intptr_t)address));
645 PyObject* func = PyObject_Call(maker, args, NULL);
649 ((
CPPInstance*)func)->fFlags |= CPPInstance::kIsLValue;
664 if (PyType_Ready(pytype) < 0)
669 if (PyModule_AddObject(module, (
char*)
name, (
PyObject*)pytype) < 0) {
688 if ((!check || tc ==
'*' || tc ==
'B') && PyByteArray_CheckExact(pyobject)) {
689 buf = PyByteArray_AS_STRING(pyobject);
690 return PyByteArray_GET_SIZE(pyobject);
694 if (PyObject_CheckBuffer(pyobject)) {
696 memset(&bufinfo, 0,
sizeof(Py_buffer));
697 if (PyObject_GetBuffer(pyobject, &bufinfo, PyBUF_FORMAT) == 0) {
698 if (tc ==
'*' || strchr(bufinfo.format, tc)
699#
if defined(_WIN32) || ( defined(R__LINUX) && !defined(R__B64) )
702 || (tc ==
'I' && strchr(bufinfo.format,
'L')) || (tc ==
'i' && strchr(bufinfo.format,
'l'))
705 || (tc ==
'?' && strchr(bufinfo.format,
'b'))
708 if (buf && bufinfo.ndim == 0) {
709 PyBuffer_Release(&bufinfo);
710 return bufinfo.len/bufinfo.itemsize;
711 }
else if (buf && bufinfo.ndim == 1) {
712 Py_ssize_t size1d = bufinfo.shape ? bufinfo.shape[0] : bufinfo.len/bufinfo.itemsize;
713 PyBuffer_Release(&bufinfo);
719 PyBuffer_Release(&bufinfo);
727 PyBufferProcs* bufprocs =
Py_TYPE(pyobject)->tp_as_buffer;
729 PySequenceMethods* seqmeths =
Py_TYPE(pyobject)->tp_as_sequence;
730 if (seqmeths != 0 && bufprocs != 0
731#
if PY_VERSION_HEX < 0x03000000
732 && bufprocs->bf_getwritebuffer != 0
733 && (*(bufprocs->bf_getsegcount))(pyobject, 0) == 1
735 && bufprocs->bf_getbuffer != 0
740#if PY_VERSION_HEX < 0x03000000
741 Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))(pyobject, 0, &buf);
744 (*(bufprocs->bf_getbuffer))(pyobject, &bufinfo, PyBUF_WRITABLE);
745 buf = (
char*)bufinfo.buf;
747#if PY_VERSION_HEX < 0x03010000
748 PyBuffer_Release(pyobject, &bufinfo);
750 PyBuffer_Release(&bufinfo);
754 if (buf && check ==
true) {
756 PyObject* pytc = PyObject_GetAttr(pyobject, PyStrings::gTypeCode);
759 if (!(cpytc == tc || (tc ==
'?' && cpytc ==
'b')))
762 }
else if (seqmeths->sq_length &&
763 (
int)(buflen/(*(seqmeths->sq_length))(pyobject)) ==
size) {
766 }
else if (buflen ==
size) {
773 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
774 PyErr_Fetch(&pytype, &pyvalue, &pytrace);
776 (
char*)
"%s and given element size (%ld) do not match needed (%d)",
778 seqmeths->sq_length ? (
Long_t)(buflen/(*(seqmeths->sq_length))(pyobject)) : (
Long_t)buflen,
781 PyErr_Restore(pytype, pyvalue2, pytrace);
796 if (8 <
name.size() &&
name.substr(0, 8) ==
"operator") {
797 std::string op =
name.substr(8, std::string::npos);
800 std::string::size_type start = 0, end = op.size();
801 while (start < end && isspace(op[start])) ++start;
802 while (start < end && isspace(op[end-1])) --end;
803 op = op.substr(start, end - start);
820 }
else if (op ==
"*") {
822 return bTakesParams ?
"__mul__" :
"__deref__";
824 }
else if (op ==
"+") {
826 return bTakesParams ?
"__add__" :
"__pos__";
828 }
else if (op ==
"-") {
830 return bTakesParams ?
"__sub__" :
"__neg__";
832 }
else if (op ==
"++") {
834 return bTakesParams ?
"__postinc__" :
"__preinc__";
836 }
else if (op ==
"--") {
838 return bTakesParams ?
"__postdec__" :
"__predec__";
852 std::string cleanName =
name;
853 RemoveConst(cleanName);
856 for (
int ipos = (
int)cleanName.size()-1; 0 <= ipos; --ipos) {
857 char c = cleanName[ipos];
858 if (isspace(
c))
continue;
859 if (isalnum(
c) ||
c ==
'_' ||
c ==
'>' ||
c ==
')')
break;
876 std::string cleanName =
name;
877 RemoveConst(cleanName);
879 if (cleanName[cleanName.size()-1] ==
']') {
880 std::string::size_type idx = cleanName.rfind(
'[');
881 if (idx != std::string::npos) {
882 const std::string asize = cleanName.substr(idx+1, cleanName.size()-2);
883 return strtoul(asize.c_str(),
nullptr, 0);
894 std::string clname =
"<unknown>";
896 PyObject*
pyname = PyObject_GetAttr(pyclass, PyStrings::gCppName);
899 pyname = PyObject_GetAttr(pyclass, PyStrings::gName);
930#if PY_VERSION_HEX >= 0x02030000
931 PyGILState_STATE gstate = PyGILState_Ensure();
933 PyGILState_Release(gstate);
935 if (PyThreadState_GET())
936 return PyErr_Occurred();
948 if (PyErr_Occurred()) {
950 PyErr_Fetch(&
e.fType, &
e.fValue, &
e.fTrace);
953 return errors.size();
960 if (errors.empty()) {
971 for (
auto&
e : errors) {
972 if (!exc_type) exc_type =
e.fType;
973 else if (exc_type !=
e.fType) exc_type = defexc;
977 }
else if (
e.fValue) {
978 PyObject* excstr = PyObject_Str(
e.fValue);
990 Py_DECREF(separator);
1007 "#include \"CPyCppyy/API.h\"\n"
1010 "#include \"CPyCppyy/DispatchPtr.h\"\n"
1011 "#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
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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::map< std::string, PyObject * > sStdFuncMakerLookup
static std::set< std::string > gOpSkip
static std::map< void *, PyObject * > sStdFuncLookup
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
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)
PyObject * FuncPtr2StdFunction(const std::string &retType, const std::string &signature, void *address)
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()
Set of helper functions that are invoked from the pythonizors, on the Python side.
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)
R__EXTERN bool gDictLookupActive
dict_lookup_func gDictLookupOrg
bool CPPOverload_Check(T *object)
bool CPPScope_Check(T *object)
bool CPPInstance_Check(T *object)
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
ULong64_t PyLongOrInt_AsULong64(PyObject *pyobject)
RPY_EXPORTED TCppScope_t gGlobalScope
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED TCppIndex_t GetGlobalOperator(TCppType_t scope, const std::string &lc, const std::string &rc, const std::string &op)
RPY_EXPORTED bool Compile(const std::string &code)
static void Clear(PyError_t &e)